Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Esdieff documentation

Esdieff is a command-line toolkit and Rust library for connected-device models written in Semantic Definition Format, the SDF of IETF RFC 9880. It checks models, shows what a composed interface contains, compares revisions and turns model rules into test values. Every operation runs offline on the files you supply.

Start here

  • Install and try a model Install Esdieff, run the supplied thermostat model and read your first generated values.
  • Inspect and check a model Supply model files and shared definitions, run the checks and follow each finding back to its source.
  • Compare two revisions See which changes between two revisions break the apps that use a device, and acknowledge the ones you intend.
  • Test values against a model Check single samples, generate boundary and invalid values and check a log of recorded values in one run.

Guides

The guides walk through one task each with real commands and their output.

Reference

The reference pages are the contracts behind each command. They state what an operation promises, what its report contains and where its limits lie.

Design

The domain language defines the terms the reports and contracts use, such as catalogue, effective definition and breaking change. The architecture decisions record why Esdieff behaves as it does, from exact numbers to client-side revision comparison.

Install and try a model

This guide installs Esdieff and runs it on a supplied thermostat model. No device is needed, and nothing leaves your machine.

Install Esdieff

Esdieff supports macOS 15+, Linux and Windows. Prebuilt releases are available through Homebrew, apt and dnf, and as direct downloads.

macOS

Install the prebuilt command from the Esdieff Homebrew tap:

brew install pederbe/tap/esdieff

Update with brew update && brew upgrade esdieff. Remove it with brew uninstall esdieff.

Windows

Download the Windows ZIP, extract it, and add the folder containing esdieff.exe to your PATH. Open a new terminal and check the installation:

esdieff --version

To update, replace the extracted files with a newer release. To uninstall, remove the folder and its entry from your PATH.

A WinGet listing is being prepared. WinGet installation will become available after the community listing is approved.

Linux

Install on Debian, Ubuntu or Fedora:

curl -fsSL https://raw.githubusercontent.com/pederbe/esdieff/main/scripts/install.sh | sh

Updates arrive through your package manager.

Direct downloads and Cargo

Download a release archive, extract it and put the command on your PATH. Download a newer archive to update it. Remove the extracted command to uninstall it.

Rust users can install a prebuilt release with:

cargo binstall esdieff

To build from source, install a current Rust toolchain and run:

cargo install --locked esdieff

This builds the esdieff command and puts it in Cargo’s binary directory, normally ~/.cargo/bin. Make sure that directory is on your PATH.

From a checkout of the repository, install the same way with a path instead:

cargo install --locked --path .

Repeat the Cargo installation command to update. Use cargo uninstall esdieff to remove it.

Check that it works

$ esdieff --help
Usage:
esdieff check --plan PLAN [--format human|json]
esdieff acquire --github OWNER/REPOSITORY --commit COMMIT --path REPOSITORY_PATH --sha256 DIGEST --document-output DEST [--report-output DEST] [--format human|json]
esdieff check [--directory DIR] [--recursive] [--exclude RELATIVE_PATH] [--root INPUT] [--assessment initial-v1|expanded-modified-v1|expanded-units-v1|expanded-content-format-v1|expanded-pattern-syntax-v1|expanded-numeric-v1|expanded-consistency-v1|full-baseline] [--registry-knowledge recorded|withheld] [--strict-warnings] [--format human|json|sarif] [INPUT...]

The help continues with one line per command. If the command is not found, check that its installation folder is on your PATH and open a new terminal. Cargo installations normally use ~/.cargo/bin.

Try the thermostat example

The example is a room thermostat with two properties, one action and one event. Its writable targetTemperature accepts numbers from 5 to 30 °C in half-degree steps:

"targetTemperature": {
  "description": "Requested room temperature in half-degree increments",
  "type": "number", "nullable": false, "minimum": 5, "maximum": 30,
  "multipleOf": 0.5, "unit": "Cel", "readable": true, "writable": true
}

Download rich.sdf.json from the repository, or copy it from a checkout, and save it as thermostat.sdf.json in an empty directory. Take the rich model, not the smaller thermostat.sdf.json next to it in the repository: that one has no half-degree step, so it accepts 5.25. Then generate test values from its rules. The command names the document to generate for, followed by every model file to supply, which here is the same file:

$ esdieff generate --document thermostat.sdf.json thermostat.sdf.json
Generated values esdieff.generation/1: passed
Values: 15 admitted, 60 rejected, 0 undetermined
Descriptions: 4

property /sdfObject/Thermostat/sdfProperty/currentTemperature: complete
  ...

property /sdfObject/Thermostat/sdfProperty/targetTemperature: complete
  rejected     null          null (sample.null)
  admitted     minimum       5
  admitted     maximum       30
  rejected     below_minimum 4 (sample.bound)
  rejected     above_maximum 31 (sample.bound)
  rejected     not_multiple  5.25 (sample.multiple)
  rejected     wrong_type    "" (sample.type)
  rejected     wrong_type    true (sample.type)
  rejected     wrong_type    {} (sample.type)
  rejected     wrong_type    [] (sample.type)

action_input /sdfObject/Thermostat/sdfAction/configure: complete
  ...

The output is trimmed to the targetTemperature block. The full report lists 75 values across the two properties, the configure action input and the alarm event output.

Each line is one generated value. The middle column names the rule the value aims at, and the first column says what the model does with it:

  • 5 and 30 aim at the minimum and maximum and are admitted. They are the boundary values a device must accept.
  • 31 aims just above the maximum and is rejected, with the condition code sample.bound naming the rule it breaks.
  • 5.25 is a quarter-degree value, so it is rejected by the half-degree step, sample.multiple.

Admitted and rejected are not guesses. Esdieff checks every generated value against the model the same way it checks a sample you supply, so the labels are what the model actually says. A value nobody can settle would be listed as undetermined.

Next, check the model itself. --assessment full-baseline requests every model obligation Esdieff records from RFC 9880:

$ esdieff check --assessment full-baseline thermostat.sdf.json
Esdieff: passed
Complete: true
Errors: 0; warnings: 0; notices: 0; incomplete checks: 0
Scope: catalogue
Broader RFC coverage: complete
Recorded registry policy: use_recorded
Unit guidance: complete
Assessment area unit-spelling/1: assessed
Assessment area unit-registry-guidance/1: assessed
Unit counts: known_primary 4; known_secondary 0; unknown 0; unavailable 0; legacy 0; uri_names 0
Assessment area content-format-syntax/1: not_applicable
Assessment area content-format-registry/1: not_applicable
Registry iana.senml-units: available; snapshot iana.senml-units/2026-10-05/6246352c590e933b; scope senml-units; entries_count 67
Registry extraction_policy esdieff.unit-section-positives/1; digest 6246352c590e933b72c25ef9f363171e40fea347bb7e23d08b04f9436894ed34; raw_digest 3eff03640c5a5d2abd09e330488aeb9fae0b2766ea69b1114295bbec5c44e754; source_updated 2026-02-02; retrieved_at 2026-10-05T16:49:51Z
Requested assessment: rfc9880/base-1
Baseline: rfc9880/base-1 (RFC 9880)
Acceptance restrictions: A001, A002; strict warnings: false
Requested sources: [1]
Requested inventory: esdieff.full-model/1
Requested coverage (assessment_area): total 13; assessed 10; not applicable 3; unassessed 0; undetermined 0
Requirement inventory: rfc9880.model/1
Requirement coverage: total 54; assessed 28; not applicable 26; unassessed 0; undetermined 0
Source 1 ["input1"]: acquired / usable (1932 retained bytes, content complete: true)
Diagnostic details omitted: 0

The first line is the verdict. Complete: true means nothing was left unfinished, and the coverage lines account for every one of the 54 recorded requirements as assessed or not applicable to this model. The unit lines show that the four Cel unit names were found in the recorded SenML units registry snapshot, so the check needed no network access. The command exits with status 0 for a passed check, 1 for findings, and 3 when something could not be settled.

Next steps

Inspect and check a model

This guide checks a model that reuses a shared definition, reads the findings and looks at what the composed interface contains. It assumes Esdieff is installed and uses the thermostat.sdf.json from that page, plus two small files shown below.

Supply the files a model needs

An SDF model can reference definitions in other documents. Esdieff resolves such references only among the files you supply on the command line, so a check sees exactly what you give it and never fetches anything. Together, the supplied files are the catalogue.

Save these two files from the repository’s directory-check example next to each other. The sensor’s reading property reuses a Reading type from the second file through its namespace types:

{
  "info": { "title": "Directory sensor" },
  "namespace": { "types": "https://example.com/directory/types" },
  "sdfObject": {
    "Sensor": {
      "sdfProperty": {
        "reading": { "sdfRef": "types:#/sdfData/Reading" }
      }
    }
  }
}
{
  "info": { "title": "Shared reading type" },
  "namespace": { "types": "https://example.com/directory/types" },
  "defaultNamespace": "types",
  "sdfData": { "Reading": { "type": "number", "minimum": 0 } }
}

Checking the device on its own cannot finish, because the referenced definition is not in the catalogue:

$ esdieff check device.sdf.json
Esdieff: undetermined
Complete: false
Errors: 0; warnings: 0; notices: 0; incomplete checks: 6
Scope: catalogue
...
reference.unavailable: supplied global target unavailable
effective 1 "/sdfObject/Sensor/sdfProperty/reading"
  related source 1 "/sdfObject/Sensor/sdfProperty/reading/sdfRef"
  related source 1 "/sdfObject/Sensor/sdfProperty/reading"
coverage.unavailable: Requested assessment area has unfinished applicable work
...

The verdict is undetermined, not failed. Esdieff does not treat a missing dependency as a mistake in the model, and it never reports a definition as valid when it could not establish what it means. Supply both files, and name the device as the root so the check covers the device and whatever it needs:

$ esdieff check --root device.sdf.json device.sdf.json types.sdf.json
Esdieff: passed
Complete: true
Errors: 0; warnings: 0; notices: 0; incomplete checks: 0
Scope: selected
Broader RFC coverage: partial
Requested assessment: esdieff.initial/1
Baseline: rfc9880/base-1 (RFC 9880)
Acceptance restrictions: A001, A002; strict warnings: false
Requested sources: [1]
Requested inventory: esdieff.initial/1
Requested coverage (assessment_area): total 8; assessed 7; not applicable 1; unassessed 0; undetermined 0
Source 1 ["input1"]: acquired / usable (247 retained bytes, content complete: true)
Source 2 ["input2"]: acquired / usable (211 retained bytes, content complete: true)
Dependency sources: [2]
Diagnostic details omitted: 0

Scope: selected with Dependency sources: [2] records that the types file was used as a dependency of the root. Without --root, the scope is catalogue and every supplied file is checked in full, including definitions nobody uses. Both scopes are useful: catalogue scope for a collection you maintain, selected scope for one product and its dependencies.

Choose how much to check

--assessment selects an assessment level. The default initial-v1 covers the document envelope, names and roles, namespaces, composition, parameters and the other fundamentals in eight assessment areas. full-baseline requests all 13 areas and accounts for all 54 model requirements Esdieff records from RFC 9880, including unit names against a recorded registry snapshot and numeric contradictions. The expanded-* levels add one concern to the initial set, such as expanded-pattern-syntax-v1 for regular expressions. Two of them offer advice that full-baseline does not include. expanded-numeric-v1 finds number ranges that no integer or step value can satisfy, and expanded-consistency-v1 finds a const or default value that its own description excludes.

esdieff check --assessment full-baseline --root device.sdf.json device.sdf.json types.sdf.json

Every report says which inventory it assessed and how many areas were assessed, not applicable or undetermined, so a passed check always states what it covered. --strict-warnings turns warnings into a failed verdict, which is the setting to use in CI once a collection is clean. The model meaning contract and the assessment inventory describe each area.

Read findings and locations

A finding has a condition code, a message and a location. The example collection includes a draft with a broken type:

$ esdieff check draft/unfinished.sdf.json
Esdieff: failed
Complete: true
Errors: 1; warnings: 0; notices: 0; incomplete checks: 0
...
data.string: A textual data quality must contain a string
source 1 "/sdfData/Unfinished/type"
Diagnostic details omitted: 0

data.string is the stable code of the rule, and the message explains it. The location is a source location: source 1 is the first supplied file, and the JSON Pointer /sdfData/Unfinished/type is the member in that file. Findings come in four kinds. Errors fail the check, warnings and notices are advice that leave it passed unless --strict-warnings is set, and incomplete checks mark work Esdieff could not finish, which makes the verdict undetermined.

Some findings are about the composed interface rather than one file. The reference.unavailable finding earlier had an effective location, /sdfObject/Sensor/sdfProperty/reading, which is the property as the device presents it after references and overrides are applied. Its related source locations point at the sdfRef that caused it. The report contract describes both location kinds.

Inspect what the interface contains

esdieff inspect shows one definition in either view. The --view source form prints the member as written in the file, found by its JSON Pointer. The --view effective form prints the definition the device presents, with inherited qualities applied and RFC defaults filled in, and then lists where each quality came from. Inspect the thermostat’s target temperature:

$ esdieff inspect --view effective --document thermostat.sdf.json --pointer /sdfObject/Thermostat/sdfProperty/targetTemperature thermostat.sdf.json
Esdieff: passed
...
Inspection effective at "/sdfObject/Thermostat/sdfProperty/targetTemperature":
{"description":"Requested room temperature in half-degree increments","type":"number","nullable":false,"minimum":5,"maximum":30,"multipleOf":0.5,"unit":"Cel","readable":true,"writable":true}
Alternatives absent at effective 1 "/sdfObject/Thermostat/sdfProperty/targetTemperature"
source at effective 1 "/sdfObject/Thermostat/sdfProperty/targetTemperature"; source 1 "/sdfObject/Thermostat/sdfProperty/targetTemperature"
default true at effective 1 "/sdfObject/Thermostat/sdfProperty/targetTemperature/observable"
source at effective 1 "/sdfObject/Thermostat/sdfProperty/targetTemperature/description"; source 1 "/sdfObject/Thermostat/sdfProperty/targetTemperature/description"
...

The report before the inspection is trimmed. Every quality of this property is authored in the file itself, and observable is absent in the source, so the view records that its RFC default of true applies.

The sensor’s reading is more interesting, because its content comes from the other file:

$ esdieff inspect --view effective --document device.sdf.json --pointer /sdfObject/Sensor/sdfProperty/reading device.sdf.json types.sdf.json
...
Inspection effective at "/sdfObject/Sensor/sdfProperty/reading":
{"type":"number","minimum":0}
Alternatives absent at effective 1 "/sdfObject/Sensor/sdfProperty/reading"
inherited at effective 1 "/sdfObject/Sensor/sdfProperty/reading"; source 2 "/sdfData/Reading"; source 1 "/sdfObject/Sensor/sdfProperty/reading"; imported at source 1 "/sdfObject/Sensor/sdfProperty/reading/sdfRef"
default true at effective 1 "/sdfObject/Sensor/sdfProperty/reading/readable"; imported at source 1 "/sdfObject/Sensor/sdfProperty/reading/sdfRef"
default true at effective 1 "/sdfObject/Sensor/sdfProperty/reading/writable"; imported at source 1 "/sdfObject/Sensor/sdfProperty/reading/sdfRef"
default true at effective 1 "/sdfObject/Sensor/sdfProperty/reading/observable"; imported at source 1 "/sdfObject/Sensor/sdfProperty/reading/sdfRef"
default true at effective 1 "/sdfObject/Sensor/sdfProperty/reading/nullable"; imported at source 1 "/sdfObject/Sensor/sdfProperty/reading/sdfRef"
inherited at effective 1 "/sdfObject/Sensor/sdfProperty/reading/type"; source 2 "/sdfData/Reading/type"; imported at source 1 "/sdfObject/Sensor/sdfProperty/reading/sdfRef"
inherited at effective 1 "/sdfObject/Sensor/sdfProperty/reading/minimum"; source 2 "/sdfData/Reading/minimum"; imported at source 1 "/sdfObject/Sensor/sdfProperty/reading/sdfRef"

Each inherited line names the file and pointer the quality came from, and imported at names the sdfRef that brought it in. This is how you see whether a supplier’s property really has the bound you expect and which shared definition sets it.

The catalogue-check example works the same way for a reusable sdfData definition:

$ esdieff inspect --view effective --document count.sdf.json --pointer /sdfData/Count count.sdf.json
...
Inspection effective at "/sdfData/Count":
{"type":"integer","minimum":0,"maximum":100}
Alternatives absent at effective 1 "/sdfData/Count"
source at effective 1 "/sdfData/Count"; source 1 "/sdfData/Count"
default true at effective 1 "/sdfData/Count/nullable"
source at effective 1 "/sdfData/Count/type"; source 1 "/sdfData/Count/type"
source at effective 1 "/sdfData/Count/minimum"; source 1 "/sdfData/Count/minimum"
source at effective 1 "/sdfData/Count/maximum"; source 1 "/sdfData/Count/maximum"

Add --required-declarations to list which contained definitions an owner declares as required through sdfRequired, and --format json to get the same views as JSON for scripts.

Follow a finding to its source

A finding’s source location is a pointer you can inspect directly. Take the draft’s data.string finding at /sdfData/Unfinished/type and look at its owner:

$ esdieff inspect --view source --document draft/unfinished.sdf.json --pointer /sdfData/Unfinished draft/unfinished.sdf.json
...
Inspection source at "/sdfData/Unfinished":
{ "type": 7 }

The source view prints the member byte for byte as it appears in the file, so what you see is what you need to fix. For a finding with an effective location, inspect the effective pointer first to see the composed definition, then use its inherited and imported at lines to find the file to change. Source inspection also works when a check failed or could not finish, so you can always look at what was supplied.

Where to go next

Compose and edit models

This guide builds a new device description from reusable definitions and then makes repeatable edits to an existing document. Both commands read a small JSON plan, write a new file and leave every input unchanged. It assumes Esdieff is installed.

Compose a thing from reusable objects

In SDF, an sdfObject describes one capability and an sdfThing groups objects into a product. esdieff author creates a new sdfThing document whose objects reference the reusable ones through sdfRef, so the new document stays linked to its sources instead of copying them.

Save a reusable capabilities document as capabilities.sdf.json:

{
  "info": { "title": "Reusable climate capabilities" },
  "namespace": { "cap": "https://example.com/capabilities" },
  "defaultNamespace": "cap",
  "sdfObject": {
    "Thermostat": {
      "description": "Reusable thermostat capability",
      "sdfProperty": {
        "targetTemperature": {
          "type": "number", "nullable": false, "minimum": 5, "maximum": 30,
          "multipleOf": 0.5, "unit": "Cel", "readable": true, "writable": true
        }
      }
    },
    "Fan": {
      "sdfProperty": {
        "speed": { "type": "integer", "minimum": 0, "maximum": 3 }
      }
    }
  }
}

Then write the recipe as recipe.json. It names the new thing, binds the namespace prefixes the generated document will use, and declares each object: a name in the new thing, the supplied source and pointer to copy the reference from, the prefix that reference should use, a refinement patch and whether the object is required. The thermostat refinement lowers the maximum to 25 for this product:

{
  "key": "climate-recipe",
  "generated_key": "climate-unit",
  "thing_name": "ClimateUnit",
  "info": { "title": "Climate unit" },
  "namespace": {
    "cap": "https://example.com/capabilities",
    "product": "https://example.com/products"
  },
  "default_namespace": "product",
  "objects": [
    {
      "name": "thermostat",
      "source": "capabilities",
      "pointer": "/sdfObject/Thermostat",
      "prefix": "cap",
      "refinement": { "sdfProperty": { "targetTemperature": { "maximum": 25 } } },
      "required": true
    },
    {
      "name": "fan",
      "source": "capabilities",
      "pointer": "/sdfObject/Fan",
      "prefix": "cap",
      "refinement": {},
      "required": false
    }
  ]
}

source matches the key you give the file with --source KEY PATH. The key and generated_key name the request and the generated document in reports. Run the recipe, and ask for an initial check of the result in the same step:

$ esdieff author --plan recipe.json --source capabilities capabilities.sdf.json --document-output climate-unit.sdf.json --check initial-v1
Author ClimateUnit: passed
Generation: complete
Fidelity: established
Broader RFC coverage: partial
Errors: 0; warnings: 0; notices: 0; unfinished authoring units: 0
Baseline: rfc9880/base-1
Selected generated root: 2
Dependency sources: 1
Sources with attempted work: 2, 1
Unavailable required sources: none
Source 1 "capabilities": Model, Acquired
Source 2 "climate-unit": Generated, Generated
Requested checking esdieff.initial/1: passed (0 incomplete assessment units)
Requested check inventory: esdieff.initial/1
Requested check coverage (assessment_area): total 8; assessed 8; not applicable 0; unassessed 0; undetermined 0

Generation: complete says the document was assembled, and Fidelity: established says Esdieff verified that every generated reference still points at its source and every refinement value kept its exact spelling. The document is written only when both hold and the requested check passes. Here is the generated climate-unit.sdf.json:

{
  "namespace": {
    "cap": "https://example.com/capabilities",
    "product": "https://example.com/products"
  },
  "defaultNamespace": "product",
  "info": {
    "title": "Climate unit"
  },
  "sdfThing": {
    "ClimateUnit": {
      "sdfObject": {
        "thermostat": {
          "sdfRef": "cap:#/sdfObject/Thermostat",
          "sdfProperty": {
            "targetTemperature": {
              "maximum": 25
            }
          }
        },
        "fan": {
          "sdfRef": "cap:#/sdfObject/Fan"
        }
      },
      "sdfRequired": ["thermostat"]
    }
  }
}

The thermostat keeps its link to the capabilities document and overrides only the maximum. Inspect the effective property to confirm what the product presents, supplying both files:

$ esdieff inspect --view effective --document climate-unit.sdf.json --pointer /sdfThing/ClimateUnit/sdfObject/thermostat/sdfProperty/targetTemperature climate-unit.sdf.json capabilities.sdf.json
...
Inspection effective at "/sdfThing/ClimateUnit/sdfObject/thermostat/sdfProperty/targetTemperature":
{"type":"number","nullable":false,"minimum":5,"maximum":25,"multipleOf":0.5,"unit":"Cel","readable":true,"writable":true}
...
override at effective 1 "/sdfThing/ClimateUnit/sdfObject/thermostat/sdfProperty/targetTemperature/maximum"; source 1 "/sdfThing/ClimateUnit/sdfObject/thermostat/sdfProperty/targetTemperature/maximum"; source 2 "/sdfObject/Thermostat/sdfProperty/targetTemperature/maximum"; imported at source 1 "/sdfThing/ClimateUnit/sdfObject/thermostat/sdfRef"
inherited at effective 1 "/sdfThing/ClimateUnit/sdfObject/thermostat/sdfProperty/targetTemperature/multipleOf"; source 2 "/sdfObject/Thermostat/sdfProperty/targetTemperature/multipleOf"; imported at source 1 "/sdfThing/ClimateUnit/sdfObject/thermostat/sdfRef"

The maximum is an override from the generated document, and the step is inherited from the capabilities file. Running the same command again refuses to overwrite the output until you add --replace-document:

$ esdieff author --plan recipe.json --source capabilities capabilities.sdf.json --document-output climate-unit.sdf.json --check initial-v1
esdieff: existing output requires explicit replacement of a regular non-symlink file

Use --report-output report.json --format json to save the report beside the document, and --check full-baseline for the complete assessment. A refinement member set to null deletes the inherited member. The authoring contract lists every plan field, the refinement rules and the limits.

Edit qualities in an existing document

esdieff edit changes named qualities of definitions you already have, such as a description, a bound or a unit, and writes a new document. It is a way to make the same correction repeatably, review it as a plan and keep the original untouched.

Starting from the thermostat model as thermostat.sdf.json, save this plan as edits.json. Each edit names the definition that owns the quality, the quality, and either a replacement value or a removal:

{
  "key": "winter-edits",
  "source": "thermostat",
  "generated_key": "thermostat-winter",
  "edits": [
    {
      "owner": "/sdfObject/Thermostat/sdfProperty/targetTemperature",
      "quality": "maximum",
      "operation": "replace",
      "value": 25
    },
    {
      "owner": "/sdfObject/Thermostat/sdfProperty/targetTemperature",
      "quality": "description",
      "operation": "replace",
      "value": "Requested room temperature in half-degree increments, capped for winter"
    },
    {
      "owner": "/sdfObject/Thermostat/sdfProperty/currentTemperature",
      "quality": "description",
      "operation": "remove"
    }
  ]
}

Run it the same way as a recipe:

$ esdieff edit --plan edits.json --source thermostat thermostat.sdf.json --document-output thermostat-winter.sdf.json --check initial-v1
Edit winter-edits: passed
Generation: complete
Fidelity: established (esdieff.authored-quality-edit/1)
Substitution: source 1 with generated source 2
Root sources: [2]
Dependency sources: []
Assessed sources: [2]
Unavailable required sources: []
Requested editing coverage: total 1, assessed 1, undetermined 0
Checking: esdieff.initial/1: passed
Requested model coverage: total 8, assessed 8, not applicable 0, unassessed 0, undetermined 0
Broader RFC coverage: partial
Errors: 0, unfinished editing units: 0

Fidelity here means that every requested change was made and that everything else, including the spelling of every number, is unchanged. Esdieff reformats the output as indented JSON, so expect whitespace differences but no value differences. Each edit must target a member that exists: replace and remove both refuse an absent quality, which keeps a plan from silently doing nothing after the model changes under it.

Compare the result with the original to see exactly what changed and what it means for apps:

$ esdieff diff --old thermostat.sdf.json --new thermostat-winter.sdf.json --format markdown
# Model changes

Disposition: failed, with 1 breaking, 0 undetermined and 2 compatible differences.

## Breaking differences

- Changed quality `maximum` in `document` at `/sdfObject/Thermostat/sdfProperty/targetTemperature/maximum` (witness `30` for client-supplied data, earlier admitted, later rejected)

## Compatible differences

- Changed quality `description` in `document` at `/sdfObject/Thermostat/sdfProperty/targetTemperature/description`
- Changed quality `description` in `document` at `/sdfObject/Thermostat/sdfProperty/currentTemperature/description`

Lowering the maximum is breaking, because an app that used to write 30 would now be refused. Compare two revisions explains the classification. The editing contract lists the qualities each kind of definition accepts and the limits. Definitions behind an authored sdfRef cannot be edited in place, because the member lives in the referenced document.

Where to go next

Compare two revisions

This guide compares two revisions of a model before a change is published, reads which differences break the apps that use the device, and records the ones you intend. It assumes Esdieff is installed.

Build a before and after pair

Save the earlier revision as v1/thermostat.sdf.json. It is the thermostat’s target temperature on its own, with a version in its info block:

{
  "info": { "title": "Room thermostat", "version": "1.0.0" },
  "sdfObject": {
    "Thermostat": {
      "sdfProperty": {
        "targetTemperature": {
          "description": "Requested room temperature in half-degree increments",
          "type": "number", "nullable": false, "minimum": 5, "maximum": 30,
          "multipleOf": 0.5, "unit": "Cel", "readable": true, "writable": true
        }
      }
    }
  }
}

Save the later revision as v2/thermostat.sdf.json. It raises the maximum to 35, drops the half-degree step, shortens the description and leaves the version unchanged:

{
  "info": { "title": "Room thermostat", "version": "1.0.0" },
  "sdfObject": {
    "Thermostat": {
      "sdfProperty": {
        "targetTemperature": {
          "description": "Requested room temperature",
          "type": "number", "nullable": false, "minimum": 5, "maximum": 35,
          "unit": "Cel", "readable": true, "writable": true
        }
      }
    }
  }
}

Compare them

$ esdieff diff --old v1/thermostat.sdf.json --new v2/thermostat.sdf.json
Revision comparison esdieff.revision-comparison/2: breaking
Documents: 1 compared, 0 removed, 0 added
Differences: 1 breaking, 1 undetermined, 1 compatible
Warnings:
  comparison.version_not_increased in document: later version "1.0.0" does not compare higher than earlier version "1.0.0", after 1 breaking difference
Breaking differences:
  changed quality maximum (client-supplied and thing-supplied data)
    witness 35 for thing-supplied data: earlier rejected, later admitted
    earlier document /sdfObject/Thermostat/sdfProperty/targetTemperature/maximum
    later document /sdfObject/Thermostat/sdfProperty/targetTemperature/maximum
Undetermined differences:
  changed quality multipleOf (client-supplied and thing-supplied data): no breaking witness or compatibility proof
    earlier document /sdfObject/Thermostat/sdfProperty/targetTemperature/multipleOf
    later document /sdfObject/Thermostat/sdfProperty/targetTemperature/multipleOf (absent)
Compatible differences:
  changed quality description (client-supplied and thing-supplied data)
    earlier document /sdfObject/Thermostat/sdfProperty/targetTemperature/description
    later document /sdfObject/Thermostat/sdfProperty/targetTemperature/description

Esdieff takes the side of the client, the app or controller that talks to the device. Each difference is classified by what it means for a client built against the earlier revision:

  • Breaking means such a client can be surprised. Raising the maximum looks harmless for values the client writes, but the property is also readable, and a device may now report 35 where the client expects at most 30. The witness line shows the concrete value that proves it: 35 was rejected before and is admitted now, in the direction the device supplies.
  • Compatible means no client can tell the difference, as with a changed description.
  • Undetermined means Esdieff found neither a breaking witness nor a proof of compatibility, so the change needs a human look. Removing the step is such a case. An undetermined difference is never presented as safe.

The warning says that a breaking change shipped under an unchanged version, which RFC 9880 advises against. Warnings do not change the result. The command exits 1 for a breaking comparison, 3 for an undetermined one and 0 for a compatible one, so a CI job can stop a breaking change from merging.

Changes that reach other documents through a shared definition

A changed shared definition appears in every device model that reuses it, at the place where that device presents it. Compare two directories to see this. Put a types.sdf.json with a shared Celsius type and a thermostat that references it in v1/, then copy both to v2/ and lower the shared minimum from -40 to -50:

{
  "info": { "title": "Shared types" },
  "namespace": { "types": "https://example.com/types" },
  "defaultNamespace": "types",
  "sdfData": { "Celsius": { "type": "number", "minimum": -40, "maximum": 80, "unit": "Cel" } }
}
{
  "info": { "title": "Room thermostat" },
  "namespace": { "types": "https://example.com/types" },
  "sdfObject": {
    "Thermostat": {
      "sdfProperty": {
        "currentTemperature": { "sdfRef": "types:#/sdfData/Celsius", "writable": false },
        "targetTemperature": { "sdfRef": "types:#/sdfData/Celsius", "minimum": 5, "maximum": 30 }
      }
    }
  }
}
$ esdieff diff --old v1 --new v2
Revision comparison esdieff.revision-comparison/2: breaking
Documents: 2 compared, 0 removed, 0 added
Differences: 1 breaking, 0 undetermined, 0 compatible
Breaking differences:
  changed quality minimum (thing-supplied data)
    witness -50 for thing-supplied data: earlier rejected, later admitted
    earlier thermostat.sdf.json /sdfObject/Thermostat/sdfProperty/currentTemperature/minimum
      from types.sdf.json /sdfData/Celsius/minimum
    later thermostat.sdf.json /sdfObject/Thermostat/sdfProperty/currentTemperature/minimum
      from types.sdf.json /sdfData/Celsius/minimum

Documents in the two directories pair up by relative path, and files that end in .sdf.json are selected as for esdieff check --directory. The difference is reported on the thermostat’s currentTemperature, because that is what a client sees, and the from lines name the shared definition that caused it. targetTemperature overrides the minimum, so it is unaffected. Add --recursive and --exclude to select nested files, as Check a local model collection describes.

Acknowledge the changes you intend

When a breaking change is deliberate, record it so the comparison passes while the report still shows the break. First export the eligible differences for review:

esdieff diff --old v1/thermostat.sdf.json --new v2/thermostat.sdf.json --acknowledgements-output reviewed.json

The comparison report and exit status stay as before, and reviewed.json lists every breaking and undetermined difference with its exact identity:

$ jq . reviewed.json
{
  "differences": [
    {
      "classification": "breaking",
      "earlier": {
        "document": "document",
        "pointer": "/sdfObject/Thermostat/sdfProperty/targetTemperature/maximum"
      },
      "kind": "changed",
      "later": {
        "document": "document",
        "pointer": "/sdfObject/Thermostat/sdfProperty/targetTemperature/maximum"
      },
      "quality": "maximum",
      "subject": "quality"
    },
    {
      "classification": "undetermined",
      ...
    }
  ],
  "schema": "esdieff.acknowledged-differences",
  "version": "1"
}

Review the file, delete any entry you do not intend, add a note to each if you like, and keep it with the model. Then supply it:

$ esdieff diff --old v1/thermostat.sdf.json --new v2/thermostat.sdf.json --acknowledged reviewed.json
Revision comparison esdieff.revision-comparison/2: breaking
Disposition: passed, with 1 breaking and 1 undetermined differences acknowledged
Documents: 1 compared, 0 removed, 0 added
Differences: 1 breaking, 1 undetermined, 1 compatible
Warnings:
  comparison.version_not_increased in document: later version "1.0.0" does not compare higher than earlier version "1.0.0", after 1 breaking difference
Acknowledged differences:
  changed quality maximum (client-supplied and thing-supplied data), breaking
    witness 35 for thing-supplied data: earlier rejected, later admitted
    earlier document /sdfObject/Thermostat/sdfProperty/targetTemperature/maximum
    later document /sdfObject/Thermostat/sdfProperty/targetTemperature/maximum
  changed quality multipleOf (client-supplied and thing-supplied data), undetermined: no breaking witness or compatibility proof
    earlier document /sdfObject/Thermostat/sdfProperty/targetTemperature/multipleOf
    later document /sdfObject/Thermostat/sdfProperty/targetTemperature/multipleOf (absent)
Compatible differences:
  changed quality description (client-supplied and thing-supplied data)
    earlier document /sdfObject/Thermostat/sdfProperty/targetTemperature/description
    later document /sdfObject/Thermostat/sdfProperty/targetTemperature/description

The classification is still breaking, the disposition is passed and the exit status is 0. Only unacknowledged differences decide the result. An entry stops matching if the difference changes, for example when a later release can classify a former undetermined change as breaking, so a stale acknowledgement never hides a new problem. The version warning stays, so bump the version before publishing.

Share the comparison

--format markdown writes the comparison as a changelog for release notes, grouped by breaking, undetermined and compatible changes:

$ esdieff diff --old v1/thermostat.sdf.json --new v2/thermostat.sdf.json --format markdown
# Model changes

Disposition: failed, with 1 breaking, 1 undetermined and 1 compatible differences.

## Warnings

- Version `1.0.0` in `document` at `/info/version` does not compare higher than earlier version `1.0.0`, after 1 breaking difference (`comparison.version_not_increased`)

## Breaking differences

- Changed quality `maximum` in `document` at `/sdfObject/Thermostat/sdfProperty/targetTemperature/maximum` (witness `35` for thing-supplied data, earlier rejected, later admitted)

## Undetermined differences

- Changed quality `multipleOf` in `document` at `/sdfObject/Thermostat/sdfProperty/targetTemperature/multipleOf`: no breaking witness or compatibility proof (`comparison.unproven`)

## Compatible differences

- Changed quality `description` in `document` at `/sdfObject/Thermostat/sdfProperty/targetTemperature/description`

--format sarif writes a SARIF log that code-scanning tools such as GitHub’s show as annotations on the model file. Acknowledged differences are marked as suppressed, so reviewers still see them while scanning treats them as intended:

$ esdieff diff --old v1/thermostat.sdf.json --new v2/thermostat.sdf.json --acknowledged reviewed.json --format sarif | jq -c '.runs[0].results[] | {ruleId, level, suppressed: (.suppressions | length > 0)}'
{"ruleId":"comparison.version_not_increased","level":"warning","suppressed":false}
{"ruleId":"comparison.breaking","level":"error","suppressed":true}
{"ruleId":"comparison.unproven","level":"warning","suppressed":true}
{"ruleId":"comparison.compatible","level":"note","suppressed":false}

--format json gives the full report for scripts. A comparison can also run as a case in a check plan beside the model checks, as Repeat checks and share reports shows. The revision comparison contract explains how each kind of quality is classified and what a witness proves.

Test values against a model

This guide checks single values against a model, generates boundary and invalid values for tests, and checks a log of recorded values in one run. It uses the thermostat.sdf.json from Install and try a model, whose targetTemperature accepts 5 to 30 °C in half-degree steps.

Check one sample

A sample is one JSON value for one definition. Save 21.5 in comfortable.json and check it against the target temperature. --kind property and --pointer select the definition, and the trailing argument supplies the model file:

$ esdieff sample --document thermostat.sdf.json --kind property --pointer /sdfObject/Thermostat/sdfProperty/targetTemperature --sample comfortable.json thermostat.sdf.json
Esdieff: passed
Complete: true
Errors: 0; warnings: 0; notices: 0; incomplete checks: 0
Scope: selected
...
Selected property in model 1 at "/sdfObject/Thermostat/sdfProperty/targetTemperature"
Sample 2: admitted; context available
...

Sample 2: admitted is the verdict on the value. Now save 35 as too-hot.json:

$ esdieff sample --document thermostat.sdf.json --kind property --pointer /sdfObject/Thermostat/sdfProperty/targetTemperature --sample too-hot.json thermostat.sdf.json
Esdieff: failed
Complete: true
Errors: 1; warnings: 0; notices: 0; incomplete checks: 0
...
Sample 2: rejected; context available
...
sample.bound: Sample violates an exact numerical bound
source 2 ""
  related effective 1 "/sdfObject/Thermostat/sdfProperty/targetTemperature/maximum"
  related source 1 "/sdfObject/Thermostat/sdfProperty/targetTemperature/maximum"
...

The reports are trimmed to the lines about the sample. A rejected sample is a failed check with exit status 1, and the finding names the rule it broke and where that rule is defined. The other kinds are data for an sdfData definition, action_input, action_output and event_output, which select the data an action or event carries. Numbers compare exactly, so 30.0 and 30 are the same value and 0.1 is never rounded.

Generate values for every rule

esdieff generate builds values from the model’s rules, so your tests get expectations without hand-written payloads. Select one definition with --kind and --pointer, or leave them out to cover every property, action and event in the document:

$ esdieff generate --document thermostat.sdf.json --kind property --pointer /sdfObject/Thermostat/sdfProperty/targetTemperature thermostat.sdf.json
Generated values esdieff.generation/1: passed
Values: 2 admitted, 8 rejected, 0 undetermined
Descriptions: 1

property /sdfObject/Thermostat/sdfProperty/targetTemperature: complete
  rejected     null          null (sample.null)
  admitted     minimum       5
  admitted     maximum       30
  rejected     below_minimum 4 (sample.bound)
  rejected     above_maximum 31 (sample.bound)
  rejected     not_multiple  5.25 (sample.multiple)
  rejected     wrong_type    "" (sample.type)
  rejected     wrong_type    true (sample.type)
  rejected     wrong_type    {} (sample.type)
  rejected     wrong_type    [] (sample.type)

Each value aims at one target, named in the middle column: the two bounds, a value just outside each, a value off the step, and one wrong type of each kind. Esdieff then checks every value against the model, and the first column is the result of that check, not the intention. The two agree here, but a model that allows null would list the null target as admitted. For a map, generation also builds a value missing each required entry, and a wrong value for each entry, as the full thermostat output in the getting-started guide shows for the configure action.

Generation is deterministic. The same model and selection always give the same values in the same order, so the output can live under version control. Save the values as test vectors with --format jsonl, which writes one JSON object per line:

$ esdieff generate --document thermostat.sdf.json --kind property --pointer /sdfObject/Thermostat/sdfProperty/targetTemperature --format jsonl thermostat.sdf.json > vectors.jsonl
$ head -3 vectors.jsonl
{"kind":"property","pointer":"/sdfObject/Thermostat/sdfProperty/targetTemperature","value":null,"expected":"rejected","label":"null"}
{"kind":"property","pointer":"/sdfObject/Thermostat/sdfProperty/targetTemperature","value":5,"expected":"admitted","label":"minimum"}
{"kind":"property","pointer":"/sdfObject/Thermostat/sdfProperty/targetTemperature","value":30,"expected":"admitted","label":"maximum"}

Each line carries the selector, the value and its settled result as expected. Feed the values to the device or app under test and assert that it accepts the admitted ones and refuses the rejected ones. --format json gives the same values inside the full report. The generation contract lists every target.

Check a log of recorded values

esdieff trace checks a recorded trace, a JSON Lines file of values your device or app actually produced, in one run. Each line names a definition the way the generated vectors do, carries the value and may say what you expected. Save this as readings.jsonl:

{"kind":"property","pointer":"/sdfObject/Thermostat/sdfProperty/targetTemperature","value":21.5,"label":"evening"}
{"kind":"property","pointer":"/sdfObject/Thermostat/sdfProperty/targetTemperature","value":21.3,"label":"app bug"}
{"kind":"property","pointer":"/sdfObject/Thermostat/sdfProperty/currentTemperature","value":null,"label":"sensor offline"}
{"kind":"action_input","pointer":"/sdfObject/Thermostat/sdfAction/configure","value":{"targetTemperature":31,"mode":"heat"}}
{"kind":"event_output","pointer":"/sdfObject/Thermostat/sdfEvent/alarm","value":{"temperature":85,"reason":"overheat"},"expected":"rejected"}
$ esdieff trace --document thermostat.sdf.json --trace readings.jsonl thermostat.sdf.json
Recorded trace esdieff.trace/1: failed
Entries: 3 passed, 2 failed, 0 undetermined
Admissions: 2 admitted, 3 rejected, 0 undetermined

line 2 property "/sdfObject/Thermostat/sdfProperty/targetTemperature": failed
  label "app bug"
  admission rejected
  error sample.multiple at "/value" bytes 206..210: Sample is not an exact multiple of the positive step

line 4 action_input "/sdfObject/Thermostat/sdfAction/configure": failed
  admission rejected
  error sample.bound at "/value/targetTemperature" bytes 459..461: Sample violates an exact numerical bound

Only the failed lines are listed, each with its line number, the byte range of the offending part of the line and the rule it broke. Line 1 passed because 21.5 is admitted. Line 3 passed because the current temperature is nullable. Line 5 passed too: the alarm’s temperature of 85 is above its maximum of 80, and the line said that rejection was expected, so an expected rejection counts as a pass. Lines 2 and 4 failed because nothing was expected and the values were rejected.

Each line is checked on its own, so one malformed line fails only itself and the rest of the file still runs. The model is composed once, which keeps a trace of a hundred thousand values fast. The trace contract describes the line format and the limits.

Replay generated vectors against a new revision

Generated vectors are a recorded trace, so esdieff trace replays them. Against the model they were generated from, every line passes:

$ esdieff trace --document thermostat.sdf.json --trace vectors.jsonl thermostat.sdf.json
Recorded trace esdieff.trace/1: passed
Entries: 10 passed, 0 failed, 0 undetermined
Admissions: 2 admitted, 8 rejected, 0 undetermined

Against a revision that raised the maximum to 35 and dropped the half-degree step, exactly the vectors whose result changed fail:

$ esdieff trace --document revised.sdf.json --trace vectors.jsonl revised.sdf.json
Recorded trace esdieff.trace/1: failed
Entries: 8 passed, 2 failed, 0 undetermined
Admissions: 4 admitted, 6 rejected, 0 undetermined

line 5 property "/sdfObject/Thermostat/sdfProperty/targetTemperature": failed
  label "above_maximum"
  admission admitted, expected rejected
  error trace.expected at "/expected" bytes 648..658: The definite admission differs from the Expected admission

line 6 property "/sdfObject/Thermostat/sdfProperty/targetTemperature": failed
  label "not_multiple"
  admission admitted, expected rejected
  error trace.expected at "/expected" bytes 791..801: The definite admission differs from the Expected admission

This is a quick way to see what a model change does to values you already rely on. Compare two revisions explains the same change from the app’s point of view, and Repeat checks and share reports saves sample checks in a plan to run again.

Repeat checks and share reports

This guide saves checks so they run the same way every time, checks a whole directory of models, and brings the results into CI and code review. It assumes Esdieff is installed.

Save checks as a plan

A check plan is a JSON file that names the model and sample files to supply and the cases to run on them. One command then runs every case and reports each outcome by name. The repository’s thermostat-check example includes this plan.json:

{
  "schema": "esdieff.check-plan",
  "version": "1",
  "sources": [
    { "key": "thermostat", "path": "thermostat.sdf.json", "role": "model" },
    { "key": "comfortable", "path": "comfortable.json", "role": "sample" },
    { "key": "too-hot", "path": "too-hot.json", "role": "sample" }
  ],
  "cases": [
    { "name": "Catalogue", "operation": "check", "scope": { "kind": "catalogue" } },
    {
      "name": "Thermostat model",
      "operation": "check",
      "scope": { "kind": "selected", "roots": ["thermostat"] },
      "assessment": "full-baseline",
      "strict_warnings": true
    },
    {
      "name": "Comfortable target",
      "operation": "sample",
      "document": "thermostat",
      "kind": "property",
      "pointer": "/sdfObject/Thermostat/sdfProperty/targetTemperature",
      "sample": "comfortable"
    },
    {
      "name": "Too hot target",
      "operation": "sample",
      "document": "thermostat",
      "kind": "property",
      "pointer": "/sdfObject/Thermostat/sdfProperty/targetTemperature",
      "sample": "too-hot"
    }
  ]
}

Paths are relative to the plan, so the directory moves as a unit. Each case keeps its own scope, assessment level and warning policy. Copy the example directory and run it. The human report prints each case in full, so this command keeps the summary lines:

$ esdieff check --plan plan.json | grep -E '^(Case|Disposition|Admission|Check case summary)'
Case: "Catalogue"
Disposition: passed
Case: "Thermostat model"
Disposition: passed
Case: "Comfortable target"
Disposition: passed
Admission: admitted
Case: "Too hot target"
Disposition: failed
Admission: rejected
Check case summary: {"admission_undetermined":0,"admitted":1,"complete":true,"complete_cases":4,"failed":1,"incomplete_cases":0,"omitted_reports":0,"passed":3,"rejected":1,"request_errors":0,"total":4,"undetermined":0,"verdict":"failed"}

The run exits 1, because the rejected sample is a failed case. A plan has no expected-result field: a sample you intend to reject still fails, which keeps the verdict honest. Keep such samples in a separate plan, or check them with recorded traces, where an expected member turns an intended rejection into a pass. The catalogue-check example is the smallest model-only plan, and a diff case can compare two revisions beside the checks, as Repeatable catalogue checks shows.

Check a directory of models

--directory selects every regular file ending in .sdf.json in a directory, so a check follows the collection as files are added. Run this on the repository’s directory-check example, which holds a device, a shared type, a nested status model and an unfinished draft:

$ esdieff check --directory examples/directory-check --recursive --exclude draft --format json | jq -c '.sources[] | {id, label}'
{"id":1,"label":"examples/directory-check/device.sdf.json"}
{"id":2,"label":"examples/directory-check/nested/status.sdf.json"}
{"id":3,"label":"examples/directory-check/types.sdf.json"}

--recursive descends into subdirectories and --exclude prunes a literal file or subtree relative to each directory. Sample files, plans and a .bak lookalike are not selected. Without the exclusion, the draft’s broken type fails the run:

$ esdieff check --directory examples/directory-check --recursive
Esdieff: failed
Complete: true
Errors: 1; warnings: 0; notices: 0; incomplete checks: 0
...
data.string: A textual data quality must contain a string
source 2 "/sdfData/Unfinished/type"
Diagnostic details omitted: 0

Repeat --directory for several collections, add explicit files beside them, and name a discovered root by its joined path, such as --root examples/directory-check/device.sdf.json. Check a local model collection states the selection rules and limits.

Use JSON reports in automation

--format json writes the same report as a JSON document with a stable schema, for every command. The outcome member is the summary a script needs:

$ esdieff check --format json thermostat.sdf.json | jq '.outcome'
{
  "complete": true,
  "disposition": "passed",
  "errors": 0,
  "incomplete_checks": 0,
  "notices": 0,
  "strict_warnings": false,
  "warnings": 0
}

diagnostics.items holds each finding with its code, message, locations and the RFC section it rests on, and coverage records what was assessed. A plan run has its own schema, esdieff.check-run, whose summary counts the cases:

$ esdieff check --plan plan.json --format json | jq -c '.summary'
{"admission_undetermined":0,"admitted":1,"complete":true,"complete_cases":4,"failed":1,"incomplete_cases":0,"omitted_reports":0,"passed":3,"rejected":1,"request_errors":0,"total":4,"undetermined":0,"verdict":"failed"}

The report contract describes every member and how reports stay within their size limits. Additive fields can appear in later releases, so read the members you need rather than comparing whole documents.

Show findings in code review with SARIF

esdieff check --format sarif and esdieff diff --format sarif write a SARIF 2.1.0 log, the format code-scanning tools such as GitHub’s read to annotate files in a pull request. Each finding becomes a result with its code as the rule, a level and the file, line and column it is about:

$ esdieff check --directory examples/directory-check --recursive --format sarif | jq '.runs[0].results[] | {ruleId, level, message: .message.text, file: .locations[0].physicalLocation.artifactLocation.uri, line: .locations[0].physicalLocation.region.startLine}'
{
  "ruleId": "data.string",
  "level": "error",
  "message": "A textual data quality must contain a string",
  "file": "examples/directory-check/draft/unfinished.sdf.json",
  "line": 3
}

File paths are relative to the directory the command ran in, so run it from the repository root and upload the log with your code-scanning tool’s SARIF step. Acknowledged revision differences appear as suppressed results, as Compare two revisions shows.

Write change notes with Markdown

esdieff diff --format markdown writes a revision comparison as a changelog grouped by breaking, undetermined and compatible changes, ready to paste into release notes or a pull request description. Compare two revisions shows the output.

Use exit statuses

Every command uses the same exit statuses, so a shell or CI step can act on them without parsing a report:

StatusMeaning
0The requested work passed
1A finding failed it: an error, a rejected sample, a breaking change or a warning under --strict-warnings
2The invocation or plan was invalid, with the reason on standard error and nothing on standard output
3Nothing failed, but some work could not be settled, such as a missing dependency or an undetermined difference
4The report could not be written

esdieff generate never fails, so it exits 0 or 3. A status of 3 deserves attention in CI as much as 1 does: the model was not shown to be wrong, but it was not shown to be right either.

Use the Rust library

Everything the esdieff command does is available as a Rust library, so you can embed model checking, inspection, generation and revision comparison in your own tools. The library uses no unsafe code and performs no network access.

Add the crate

There is no release on crates.io yet, so depend on the repository directly:

[dependencies]
esdieff = { git = "https://github.com/pederbe/esdieff" }

The crate builds on stable Rust with the 2024 edition. Pin a commit with rev = "..." once you depend on it in CI.

The entry points

A Catalogue holds the documents you supply. Build one from SourceInput values, each with a key that names it in reports: SourceInput::file reads a path, SourceInput::supplied takes bytes you already hold, and .sample() marks a sample value rather than a model. Every operation is a method on the catalogue that takes a request and returns a result you can query or render:

OperationRequestResult
Check a modelCheckRequestReport
Inspect one definitionInspectRequestReport
Read the composed interfaceEffectiveRequestEffectiveModel
Check one sampleSampleRequestReport
Generate valuesGenerationRequestGenerationResult
Check a recorded traceTraceRequestTraceResult
Compose a thingAuthorRequestAuthorResult
Edit qualitiesEditRequestEditResult
Compare revisionsComparisonRequestRevisionComparison

Results borrow the catalogue, so keep it alive while you read them. Each has to_json() and to_human() for the same reports the command prints, and a disposition whose exit_code() matches the command’s exit status.

A complete example

This program checks the thermostat model from Install and try a model with the full assessment, reads the effective range of its target temperature and prints the property as written in the file. Create a new binary crate, add the dependency above, put thermostat.sdf.json in the crate directory and use this src/main.rs:

use esdieff::{Assessment, Catalogue, CheckRequest, Class, EffectiveRequest, InspectRequest, Lookup, SourceInput};
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Supply the model files. Every input is a candidate, and its key names it in reports.
    let catalogue = Catalogue::from_inputs(&[SourceInput::file(
        "thermostat",
        Path::new("thermostat.sdf.json"),
    )])?;
    let thermostat = catalogue.source_id("thermostat").expect("supplied source");

    // Check the thermostat against every RFC 9880 model requirement Esdieff records.
    let request = CheckRequest::new()
        .root(thermostat)
        .assessment(Assessment::FullBaseline);
    let report = catalogue.check(request)?;
    println!("check: {:?}", report.outcome().disposition());
    for condition in report.diagnostics().conditions() {
        println!("{}: {}", condition.code(), condition.message());
    }

    // Read the effective target temperature range, with inherited qualities applied.
    let effective = catalogue.effective(EffectiveRequest::new(thermostat))?;
    let Lookup::Found(object) = effective.definition(Class::Object, "Thermostat") else {
        panic!("Thermostat missing")
    };
    let (_, target) = object
        .children(Class::Property)
        .require()?
        .find(|(name, _)| *name == "targetTemperature")
        .expect("targetTemperature");
    let description = target.require()?.data_description().require()?;
    println!(
        "targetTemperature: {} to {}",
        description.minimum().require()?.lexeme(),
        description.maximum().require()?.lexeme()
    );

    // Show the authored source of that property as written in the file.
    let pointer = "/sdfObject/Thermostat/sdfProperty/targetTemperature";
    let inspection = catalogue.inspect(InspectRequest::new(thermostat, pointer))?;
    if let Some(json) = inspection.inspection_json() {
        println!("source: {}", json.raw_json());
    }
    std::process::exit(report.outcome().disposition().exit_code().into());
}
$ cargo run --quiet
check: Passed
targetTemperature: 5 to 30
source: {
          "description": "Requested room temperature in half-degree increments",
          "type": "number", "nullable": false, "minimum": 5, "maximum": 30,
          "multipleOf": 0.5, "unit": "Cel", "readable": true, "writable": true
        }

A few things to notice. Operations return Err(&'static str) only for an invalid request, such as an unknown source key. A model problem is never an error: it is a finding in the report, and the disposition says whether the check passed. Fields that may be absent, unfinished or outside the supported meaning are Field values, and require() turns anything but a present value into an error, which suits a tool that expects a complete model. Numbers are exact: lexeme() returns the text from the document, and ExactNumber compares values without converting them to floating point. The source view prints the member byte for byte, whitespace included.

Keep the memory and work bounded

Every operation runs within Limits, which cap input size, decoding depth, work and report size, so an untrusted document cannot make a tool run away. The defaults suit ordinary models. Catalogue::take_inputs_with_limits sets others, and an operation that reaches a limit reports the work it could not finish instead of failing silently. ADR 0009 explains the approach.

Where the contracts are

Each operation’s reference page states what its result promises, with a Rust example at the top:

The repository’s examples directory holds complete programs that read effective values and requirement coverage.

Public workflow and report contract

This text specifies the shared guarantees behind the library, command and JSON report. The reasons are ADR 0010: Domain-oriented library and caller simplicity, ADR 0011: Machine-readable report contracts, and ADR 0012: Exact numbers and JSON input policies. Domain terms follow the domain language. Standards semantics come from RFC 9880 Sections 4.4 and 4.7, RFC 6901 Sections 3 and 4 for pointer tokens, and RFC 7396 Section 2 for merge/deletion. Resource limits and report fields are toolkit contracts, not RFC limits.

Library work and ownership

The public boundary is document-supplied domain work. A Catalogue owns each supplied source’s identity, acquisition result and content. Construction accepts owned content, or converts borrowed caller content into owned storage once. Views borrow the catalogue/result; callers do not keep the original strings alive, own reference graphs, manually merge JSON, or expose a particular parser/numeric dependency. Internals may use immutable sharing and caches, but do not expose mutable checked state.

The operation families are check(request), source(document), effective(request), check_sample(request), author(request), edit(request) and compare(request), using the same source/result/report foundation. Requests use builders with private fields. Operations produce usable results alongside scoped conditions. Malformed source input, unavailable dependencies and exceeded admitted work budgets are domain results. Configuration errors, unknown selectors and hard ceilings that prevent complete plan/request admission are request errors. Neither is a panic contract.

Each acquisition attempt receives a unique request-local SourceId before reading. Identity is an opaque caller key, distinct from a bounded display label, optional acquisition URI, content identity and SDF namespace. Duplicate caller keys are request errors. Same bytes supplied twice are two contributors, with no deduplication or precedence. CLI paths have distinct explicit identities; input position is not a semantic role. Source content is immutable owned bytes; UTF-8 text is available if decoding permits it, and raw bytes remain inspectable after decoding failures. Partial read/size-limit content records retained bytes and content_complete:false; it never purports to be the whole source. Acquisition failure has no content and stays visible. An optional caller content-version token is opaque; no path or label is a content hash. Reproducible callers may provide a digest; mandatory library hashing is not required.

Before copying any caller metadata, request validation checks UTF-8 byte lengths: caller key at most 256, display label 512, optional acquisition URI 2,048, content-version token 128 and digest 256. It preflights all attempts together against 1 MiB combined caller metadata, including exact raw filesystem identity bytes, every repeated source/scope-reference representation and all model, sample and generated attempts. These roles share one ceiling of 256 source attempts. Internal/report SourceId is a compact nonzero u32 allocated per request; it is separate from the bounded unique caller key. UTF-8 keys compare exactly, without case folding or normalization. Raw filesystem identities can contain non-UTF-8 bytes and are retained exactly for acquisition; their bytes consume the combined metadata budget. CLI adapters use bounded opaque caller keys to associate these identities, rather than forcing raw path bytes into UTF-8 keys.

Oversized semantic keys, URI/version/digest metadata, or aggregate metadata are request errors before ownership/copying or model processing. Keys/version identifiers are never clipped to fit. Only a display label may be shortened or omitted for presentation with a structured label_omitted reason; its full accepted form can remain available in owned metadata. Oversized supplied labels are request errors unless the caller explicitly requests label omission before retention. Library-owned baseline, policy and inventory metadata share a 64 KiB request budget. The mandatory report envelope is reserved before work using worst-case JSON escaping (up to six output bytes per input byte), all accepted source counts, fixed field overhead, repeated source/scope references, outcome/coverage counters and omission records. A report configuration smaller than that reserve is rejected before copying or acquisition. Optional report details consume only the remaining budget. No source attempt, aggregate finding or semantic identity is erased to meet a small report budget.

The default request has catalogue scope, including all supplied definitions and all source attempts. Explicit selected scope contains a nonempty set of supplied SourceId roots. Other sources are lookup candidates; reports separately identify roots, needed dependency sources, independently assessed sources and unavailable required sources. A missing/failed root is incomplete; an unreadable unrelated candidate remains in sources without alone spoiling selected-model work. If inability to inspect a candidate prevents establishing a needed addressed contributor or ambiguity, that lookup is incomplete. No implied network fetching or first/last input preference applies. Selected scope is rooted in documents, not individual definitions.

Selected checks independently assess their roots and use the shared effective evaluator for surviving imported content. Dependency source membership does not promise independent assessment of every definition or Information quality in that source. Catalogue checks do independently assess all sources. Global target discovery uses exact decoded namespace text and decoded target-pointer identity after the needed critical-feature context is established, as ADR 0023: Supplied global composition and dependency scope specifies. Possible contributors with unavailable identity remain distinct from established dependencies.

Source views expose all retained JSON and raw content, even when effective work fails. Typed source projections distinguish malformed/unsupported fields from absent fields. Effective views expose Things, Objects, Properties, Actions, Events and sdfData definitions with class-specific grouping, affordance, input/output and data-description access. Consumers can traverse groupings, inspect required declarations, obtain effective Property capabilities, data types and constraints, choices/enum alternatives, declared defaults and opaque qualities without rebuilding their semantics. Data-entry required remains separate from declaration sdfRequired. Extended data types remain tagged known/extended/undetermined values, not guessed base types.

An effective definition handle is scoped to its owning result and points to a root-document/effective path. Available subviews remain usable if another subview is incomplete. Missing, present, deleted and unavailable are distinct outcomes. Known defaults are returned as effective semantic values with a default origin when established; source access does not insert them. A lookup supports Lookup::Found, NotFound, Ambiguous, and Unavailable, so uncertainty cannot be mistaken for absence. Domain accessors return Field::Absent, Present(T), or Unavailable(reason) as appropriate. Option<T> is reserved for an established optional absence.

The implemented effective owner is EffectiveModel, returned by Catalogue::effective(EffectiveRequest::new(source_id).pointer(selector)) or borrowed from Report::effective_model(). It owns compact derived records and borrows immutable catalogue sources; its views borrow that owner. Effective named collection rows are (name, Field<handle>), preserving known unavailable entries and accessible siblings without changing source iterator item types. A containing handle can retain independent subviews when one descendant is unavailable. Unknown needed identity makes the affected collection or lookup unavailable.

explanation(pointer) describes composed content and its nearest source, inheritance, override or deletion contributors. default_explanation(pointer) separately describes an established implicit semantic value without an authored contributor. Both can describe the same absent path: a null patch deleting inherited writable:false retains a Deleted content explanation and a Default explanation for the typed true capability. No defaults are inserted into JSON. Direct-item defaults and copied requiredness in full data descriptions remain scoped limitations, with raw syntax accessible. These guarantees follow ADR 0020: Owned effective views and nearest origins.

Explanation::consumer() returns the established importing source sdfRef as an optional immutable source view. Ordinary source content has no importing consumer. An outer consumer survives its mandatory target-root chain; separately composed nested references establish their own consumers. Human inspection and optional JSON consumer locations expose the same boundary without changing nearest content origins or fabricating authored default sources.

Checks evaluate independent source definitions and surviving effective vocabulary through one role and rule set. Distinct composed observations contribute to aggregate findings before detail retention. Unchanged local replay requires completed source evaluation, identical established role and clear feature context, and unchanged rule premises; traversal still reaches composed descendants. Initial and expanded source extension.optional_unsupported summaries count actually inspected source occurrences in observed_occurrences. Their effective summaries retain that code and basis but omit the source-only count. Condition, byte and pointer presentation limits leave semantic totals and requested-unit status unchanged.

Full reports retain extension.optional_unsupported per inspected occurrence, with its decoded Quality Name in arguments.quality and its source location as primary. A composed observation has its effective position as primary and the nearest source contribution as one related location. quality.unfamiliar conditions also carry arguments.quality, in every assessment. Human reports show the name separately from the pointer, so it remains visible when a pointer is omitted. These details identify unsupported content behind unfinished Full requirements without changing its severity, interpretation or coverage status. Full optional notices count occurrences rather than summaries. Each source notice keeps observed_occurrences: 1; effective notices omit that source-only argument. Existing condition and diagnostic-byte limits bound how many occurrences are retained. Existing pointer limits omit pointers with their structured reason, and the name is charged against the diagnostic-byte limit before retention. No additional location collection or independent limit is used.

Accessible JSON has an Esdieff wrapper providing JSON kind, map/array traversal, scalar access and bounded generation. It retains arbitrary JSON numbers as numbers. No serde_json::Value, decimal-library type or mutable graph escapes into the public contract. Opaque structural access does not prove unknown extension meaning or permit generic edits to checked state.

Numbers and locations

An exact numeric view exposes its accepted original JSON lexeme, mathematical sign/integrality and budgeted exact ordering. Explicit checked machine conversions may return not-representable; they never round silently and cannot replace exact access. Comparison and later equality have their own finite-work result. The public number type is independent of its private representation. Unchanged generated numbers preserve an accepted raw lexeme, including 10e1000000 and 1e-1000000. A normalized internal coefficient is not a mandatory emitted token. Exact access to a count such as 18446744073709551616 establishes mathematical information, not normative CDDL uint membership, as ADR 0012 requires.

Locations are tagged source, effective or sample locations. A source location contains source_id, an optional decoded RFC 6901 pointer, and an optional half-open UTF-8 byte span. Byte spans refer to the retained original source, including key/token spans where relevant, and are not recomputed offsets in generated JSON. A root pointer is the empty string. Failed acquisition has a source identity with no invented pointer/span. A sample location uses its separate sample-source identity and pointer/span. An effective location contains the selected root identity and effective pointer; it is not a claim that this path exists in a supplied source. Non-renderable paths have pointer:null and a structured omission reason, with available spans retained.

An available explanation identifies the effective target, explanation kind (source, inherited, override, deleted, or default) and relevant source location(s). It may identify only the nearest contributor and patch location; it does not promise a complete history. Unavailable is explicit. For Device.ambient’s temperature minimum, the effective path ends /minimum, with the Temperature source /sdfData/Temperature/minimum. Its maximum 100 points to the patch source /sdfThing/Device/sdfObject/ambient/sdfProperty/temperature/maximum. The removed description’s explanation targets effective /sdfThing/Device/sdfObject/ambient/description despite the quality’s absence, identifies deletion at the null patch source and, when available, the inherited Sensor description. Controller.level inherits minimum from the supplied Level document, while maximum 80 and removed description refer to the Controller patch. Explanations of relocated content keep their nearest content origins, and their importing consumer is the original authored reference, following ADR 0036: Copied reference relocation.

An established Boolean default explanation additionally carries optional default_value:true, with the same value shown in human output. The field is absent for other origin kinds. It covers the already-supported Property readable/writable/observable and full-description nullable defaults, preserves separate deletion and default rows, and adds no JSON quality or interaction value. Detail admission reserves the annotation before construction; omitted explanation rows keep an explicit reason and do not erase typed characteristic access. This additive 1.x field follows ADR 0022: Scalar constraints and characteristic states.

Effective inspection additionally reports optional result.alternatives owner records with an effective owner location and collection state of absent, present or unavailable. Present can be empty. Known branches retain an id tagged choice with name or enum with occurrence index; branch states are available, partial or unavailable, with independent complete, json_present, optional unavailable reason and nearest/default/consumer explanations. A partial branch’s derived json can retain opaque raw quality values while unavailable_qualities explicitly identifies unestablished meanings. Raw JSON is not sample admission or consistency evidence. The composed result.json and existing pointer selectors retain their meaning. Count, byte, pointer or work omissions use explicit reasons and never imply an absent collection or completed meaning. Human output exposes the same collection, branch and unavailable-quality distinctions. These additive fields deliberately retain emitted check/inspect version 1.0 and follow ADR 0024: Effective alternatives and nullable characteristics.

Required declaration relationships

Requested required-declaration inspection adds result.required_declarations to the existing inspect1.0 result. Its twelve mandatory fields are state, complete, unavailable_reason, owners_known, owners_retained, references_known, references_retained, targets_known, targets_retained, owners_omitted, traversal_complete and owners. Counts describe discovered work and retained or presented subsets; no total of undiscovered owners is inferred. available with completed empty owners differs from unavailable, while a retained unfinished traversal is partial. Known invalid findings can coexist with complete traversal. Optional owner rows separate source and effective locations, relationship status, importing consumer and target capability (established, partial, unavailable, not_requested). Missing targets produce the Advice notice required.target_missing and scoped incompleteness; established wrong roles and malformed syntax are independent RFC errors. This inspection keeps the one existing inspection unit and the initial assessment inventory unchanged, following ADR 0026: Required declaration relationships and source evidence.

The requested operation admits the existing mandatory envelope plus twelve times selector bytes plus 1024 bytes before semantic work. The same additional reserve is subtracted from optional wire and scratch allowances. The summary is emitted directly into the existing output buffers with exact decimal Counts, fixed printable ASCII reasons of at most 96 bytes and quote/backslash escaping. It creates no summary Value/map, owned escaped text, numeric string, redundant selector flag or hidden empty owner transport DTO. A fixed Counts record occupies 28 bytes and the optional presentation plan 48 bytes in the 64-bit test executable. The worst supported literal control with seven ten-digit Counts, a maximally escaped reason and the one owner suffix omission emits 636 bytes; the conservative global diagnostic addition is 40 bytes, below the 768-byte wire bound. The complete early human prefix is 497 bytes, below 512. JSON and human are alternative outputs within the existing buffer allowance.

Optional owners stop at the first failed admission. One directly emitted omissions record gives the exact retained-minus-shown owner suffix and that first cause (count_limit, byte_limit or report_limit). The mandatory summary remains with empty owners at the exact admitted report cap, where optional wire and scratch are zero. Global diagnostic truncation and deduplicated reasons reflect the omission. The current borrowed reason inventory is at most eight entries: count_limit, byte_limit, not_available, report_limit, location_limit, byte_or_count_limit and presentation_limit. One additional owner omission reason needs at most 128 bytes borrowed-vector growth, 128 bytes for a Value cell and 16 bytes reason-string capacity, 272 bytes within the 528-byte allowance and 4096-byte additional mandatory ownership share. Reasons are deduplicated before known-length JSON conversion. Admitted optional location limitations use fixed flags; their global reasons and per-location DTO metadata are covered by that owner’s optional precharge.

Each optional owner reserves 1024 wire bytes, each reference 2048 and each target 3072, plus 512 per source/effective/related location and six times measured pointer or text bytes. Checked sums refuse unfit owners before constructing DTOs. Scratch reserves 32768 plus eight times the complete owner wire bound, covering nested DTO maps, strings, vector growth, parent serialization and temporary encoding. Actual retained wire size, plus 64 bytes for human row framing, is verified against that admission. Fixed missing/syntax/context conditions use the existing 512-wire/32768-scratch diagnostic admission. Semantic traversal edges, source positions, coordinates, contributor context, record capacities and all four operation counters are precharged before their work or allocation. Semantic failure changes completion; presentation omission does not.

Assessment identities and coverage

esdieff.initial/1 is the immutable default model-assessment identity. Its inventory is the agreed initial structure/composition inventory, independent of implemented checks. The eight stable area identities are document-envelope/1, base-roles-names/1, metadata-namespaces/1, established-composition/1, basic-parameters/1, alternatives-requiredness/1, extensions-policies/1, and advisory-four/1. Precise membership and guards are as follows.

AreaIncluded meaning and boundary
Document envelopeEach input is one UTF-8 JSON text with one top-level map; source identities, decoding/acquisition limits, definition-group and effective-map shapes are visible. ADR 0012 separates decoding, capability and A002 duplicate-name refusal. No mandatory nonempty group is invented.
Base roles and namesAll six class roles and base containment, Given Name colon prohibition, case sensitivity, known Quality Name spelling and pointer escaping; permitted extension content is distinguished from base declarations. Closed validation grammar alone is not universal RFC-invalidity.
Metadata and namespacesinfo/namespace map shapes, ordinary information strings, namespace URI syntax, mapped defaultNamespace, absent-info warning, critical-feature forms and required understanding. modified is text only; no mandatory semantic-version/SPDX convention or guessed registry knowledge.
Established compositionSame-document JSON Pointers and supplied CURIE lookup; copy target then JSON Merge Patch with sdfRef removed, including deletion and target-root references. Internal copied references relocate to the importer under ADR 0036: Copied reference relocation. Missing/ambiguous lookup, effective cycles and Boolean or short-name sdfRef remain scoped incomplete.
Basic parametersKnown common strings/Boolean flags/type selectors, nonempty string enum and enum/choice exclusivity, choice/properties/items maps, Action input/output and Event output maps, required arrays in established contexts, JSON numeric shape, positive multipleOf, nonnegative mathematically integral lengths/counts. const/default remain JSON. Formal CDDL int/float/uint representability is separate broader work.
Alternatives and requirednessEstablished choice inheritance/overrides, enum expansion and documentary defaults; unambiguous sdfRequired references, including copied pointers relocated to the importer’s coordinate, directly-contained names and true for affordances/groupings. Map-data required stays separate; data-only questions limit needed conclusions.
Extensions and policiesOpaque retention, unfamiliar-unqualified-name warnings, recognized unsupported optional-extension notices, scoped unknown meaning/critical features. A001 historical vocabulary restriction only at assessed vocabulary positions; A002 is input policy, independently of SDF vocabulary.
Advisory fourGuarded empty numeric intervals across all four lower/upper pairings; inverted text lengths; inverted array counts; primitive scalar/null constant versus base type. Number/integer interval, text and array proofs require nullable false. Primitive constants use mathematical integrality and established null admission. No choices/enum or unresolved meaning may change a proof; direct items themselves excluded, full nested properties/alternatives eligible. sdfType meaning is not guessed. No integer-gap/step/grouping/complex-constant/choice/default/general-satisfiability proofs.

The eight areas are assessed through the original bounded traversal, composition and required-declaration resolver. Completion requires every applicable area to be assessed or established not applicable; a definite error can coexist with complete work. Needed acquisition, composition, critical meaning or checking limits leave affected areas undetermined. The advisory area completes its four local proofs when relevant meanings and traversal are established, is not applicable after reliable absence, and is undetermined when needed meaning or work is unavailable. Warnings retain their basis and severity under strict policy. See initial contradiction advice for guards, witnesses and numeric work.

Declared or specified-default nullable true excludes the first three classes before applicability is recorded. A failed derived numeric precharge also retains an operation.limit condition in advisory-four/1, with Operational basis advisory-numeric-work and fixed proof_class, operation and affected qualities arguments. Multiple specific limits still make only the one advisory requested area incomplete. Unavailable meaning and omitted presentation details retain their separate causes; Full includes the same advisory area once.

The parameter context matrix is part of that identity: full descriptions at Property, sdfData, Action input/output, Event output, properties entries and sdfChoice alternatives; direct items require a map and only their established sdfRef, description, $comment, optional number/string/Boolean/integer/object type, choice/enum, minimum/maximum, format, minLength/maxLength meanings. An object direct item additionally permits required/properties, whose property descriptions are full descriptions. Direct-item choice alternatives are full descriptions. Wider framework-admitted vocabulary is retained with scoped limitations, not silently imported full-description meanings. Direct format checks text shape; direct array/minItems/nullable/nested-items/default meanings remain limited as recorded in ADR 0012 and the standards questions.

Map-data required shape checking applies to a reliable explicit type:"object" in either data-description role. A missing, nonobject, extended or unavailable type does not establish that applicability; unknown member identity also prevents it. Borrowed required_entries() presents nonempty authored syntax independently of semantic applicability in full descriptions, with the established object guard in direct items. An available list alone is not proof of an applicable map constraint or mandatory sample entries. Composition applies null deletions before assessing surviving effective qualities, and replay must preserve the containing object-type premise, following ADR 0020: Owned effective views and nearest origins.

Broader omitted requirements include formal CDDL numeric admission, detailed modified/unit/content-format checks, ECMA-262 pattern syntax, broader const/default consistency, full sample matching, and unresolved grammar/reference-form/item/requiredness/group-presence questions. A successful initial result therefore always reports broader baseline coverage as partial. Absence of a proof never establishes satisfiability.

esdieff.expanded.modified/1 explicitly requests those unchanged eight areas plus modified-date-time/1. Its ninth area checks ordinary Information modified dates and UTC labels directly, with exact fractions and finite recorded leap knowledge. Its membership stays fixed; other expanded work does not silently enter it. The modified metadata contract and ADR 0021: Explicit modified metadata assessment specify the additional meaning.

esdieff.expanded.numeric/1 explicitly requests the unchanged Initial eight areas plus advisory-numeric-three/1. Its ninth area attempts integer interval gaps, numeric const against every applicable bound, and positive-step interval gaps in established effective Full descriptions. The numeric advice contract and ADR 0030: Bounded numeric advice specify the exact role, meaning, null and finite arithmetic guards. The added mandatory reserve is zero; requested aggregates remain nine even with all optional rows and condition details omitted. Other profiles and Full do not implicitly acquire the new area. Undetermined numeric rows use Operational expanded-numeric-establishment; numeric capability conditions use Operational expanded-numeric-capability with no citation key. Completed or not-applicable numeric rows use Advice advisory-numeric-three/1. Numeric proofs preserve four original operand identities and absent-type argument/location absence.

esdieff.expanded.consistency/1 explicitly requests the unchanged Initial eight areas plus const-consistency/1 and default-consistency/1, for ten areas. The declared-value consistency contract and ADR 0031: Bounded declared-value consistency specify candidate selection, complete alternative witnesses and supported reasoning. Each definitively excluded candidate adds one Warning/Advice, independently of existing Initial producers and rejected leaf count. Documentary defaults are not inserted. The nearest real candidate source is primary, with effective constraints, origins and consumers related. Unknown needed meaning or finite evaluation limits leave the affected area undetermined; independent established advice remains. The added mandatory reserve is zero. Omitted rows/details preserve the ten-area aggregates and warning counts. Other profiles and Full retain their inventories.

esdieff.expanded.content-format/1 explicitly adds content-format-syntax/1 and content-format-registry/1 to the unchanged initial eight. The content-format contract distinguishes whole declaration spelling, decimal range, dated positives, current registration unknown, needed withheld evidence and excluded parameter meaning. The two private area states contribute to existing mandatory requested aggregates; located coverage rows remain optional. No mandatory per-name result graph or duplicate status map is added. Available registry metadata means actual admitted consultation, including a later unfinished lookup; an unconsulted table is Absent, and needed withheld knowledge has unavailable state with snapshot null. Completing these two areas alone does not complete any unfinished initial work. This follows ADR 0029: Content-format declarations and recorded registry guidance.

esdieff.expanded.pattern-syntax/1 explicitly requests those same initial eight areas plus pattern-syntax/1. It checks surviving effective Full string patterns with partial Unicode ECMAScript syntax capability, independently of explicit string type. Syntax-admitted and independently invalid inputs are assessed; no applicable string patterns after complete traversal is not applicable. Needed unknown context/text, unsupported syntax capability and operational limits make the one area undetermined. Every new condition carries that area identity. pattern.syntax is an RFC/ECMA error, pattern.unsupported uses Operational pattern-syntax-capability, pattern.unavailable uses pattern-establishment, and syntax operation.limit uses pattern-syntax-capability. Optional omissions preserve counts and status. See the pattern contract and ADR 0028: Bounded effective model pattern syntax.

Both ExpandedPatternSyntax and Full reserve 171 additional report bytes above the actual existing request envelope before composition or syntax work. The same reserve is removed from optional wire/scratch space. Full binds pattern syntax to M047 and full.pattern-format/1; repeated findings or limits do not add requested units. Initial, modified, unit, content-format, inspect and sample inventories retain their meanings.

full-baseline selects the immutable assessment and baseline rfc9880/base-1, area inventory esdieff.full-model/1, and its 54-member model relation rfc9880.model/1. The cited inventory covers the normative body and Appendices A/C with exclusive clause ownership, formal CDDL number rules and explicit nonmodel roles. Its 13 area members are full.document-syntax/1, full.model-roles/1, full.metadata/1, full.namespace-reference/1, full.composition-requiredness/1, full.critical-extensions/1, full.data-grammar/1, full.formal-numbers/1, full.scalar-meaning/1, full.pattern-format/1, full.compound-meaning/1, full.special-type-unit/1 and advisory-four/1. Known membership is independent of implemented capability. Every applicable unfinished requirement remains unassessed or undetermined. Sample admission, registry administration, device/protocol/operator duties and optional general analyses do not enter the model denominator.

Each model requirement joins its occurrences using undetermined before unassessed, assessed, then not applicable. Its owning area joins requirements once; the separate advisory area retains its existing meaning. Definite errors are assessed work. Full incomplete_checks counts unfinished areas among 13, while optional requirement aggregates count unfinished requirements among 54. They are never summed together. Historical Full reports with null inventory and coverage.inventory_unavailable remain interpretable as unknown membership, never an empty inventory.

Full broader coverage names rfc9880.model/1 with available membership. Its state is complete exactly when those54 model obligations are all assessed or not applicable; otherwise it is partial. The separate advisory area still contributes to the13-area requested outcome. Thus a model-complete report may have an incomplete requested outcome if only advice is unfinished. Completed model work can contain errors and a failed disposition; complete never means valid, universally supported or successful sample/device/protocol behavior. Full omits the optional broader omitted_areas list; absence does not establish completion. Other operations retain their partial/unavailable broader representation. Human and JSON presentations use the same state calculation.

Reports identify requested inventory, completion within it, and broader coverage separately. Coverage statuses are assessed, not_applicable, unassessed, or undetermined; assessed includes findings and does not mean satisfied. Unsupported applicable requested work is incomplete. Excluded initial work is outside that request and appears in broader coverage; it does not alone make the initial incomplete. Adding checks to meet existing inventory obligations is implementation progress. Enlarging membership, guards or semantic scope requires a new assessment/requirement identity. A bug fix may change a result for unchanged input while preserving the advertised meaning; it cannot silently redefine the meaning to match new behavior.

Report::assessment_area_status(id) returns a typed semantic status independently of optional coverage rows and conditions. Field::Present(AssessmentStatus) identifies a requested area; Absent means outside a known requested inventory; Unavailable means complete inventory membership cannot be established. An inspection requests no model assessment areas. Requested-but-not-applicable differs from not requested. Report::requested_coverage() exposes typed inventory, count-unit and aggregate accessors. Unknown needed context in any requested document makes the one modified area undetermined while independent definite errors remain visible.

Full also exposes requirement_inventory(), requirement_coverage(), requirement_status(id) and requirement_descriptors(). These borrowed accessors do not render or allocate a report. Known members have authoritative Present statuses even with zero retained detail; an unknown member is Absent, and other operations return Absent because they do not request the model inventory. Descriptors supply a stable ID, RFC citations, owning area and current check/limitation description. The description is capability documentation, never a runtime verdict.

Conditions preserve their producing assessment_unit. Full may add optional coverage_owner for the actual requested area. Modified work owns M012; both unit dimensions join M023 once; content work owns M024 and pattern syntax M047. Recorded extension values own M028. Required relationships preserve producing inspection and own M020 only in the Full recording context. Generic data conditions use the actual role and parameter: selector admission M034, numeric bounds M036, formal counts M037 and literal admission M035. No universal code-to-owner map is invented. Missing owner detail does not remove typed semantic states or mandatory inventory binding.

The report baseline records the RFC edition, specifically adopted corrections, interpretations, deviations, acceptance restrictions, and recorded external knowledge actually used. Temporal facts have their own interval and evidence identities, separate from registry knowledge. No registry snapshot means unavailable knowledge, not zero relevant entries or an unregistered-name conclusion. Findings identify a baseline requirement citation, recorded registration, adopted interpretation/deviation identifier, acceptance-policy identifier, advice class or operational limitation. Policy A001/A002 identities remain separate from RFC requirements.

Full content-format rule consultation records content-format-model-meaning/1 under the content-format contract. This records admitted use independently of successful establishment and optional diagnostics; it does not expand the existing content-format assessment’s scope.

baseline.interpretations lists copied-reference-relocation/1 from ADR 0036: Copied reference relocation whenever a result relied on it. That is when requested work relocated a copied reference, read a copied CURIE reference with its authoring document’s namespace mappings, or found that a name reference target in the resolved model differs from the document as written. The target differs when the written document has no element at its pointer, when the selected element holds copied content or a deletion that the written element lacks, or when composition removed the element the written document has there. A copied CURIE counts even when its prefix has no mapping in its authoring document. Reports that did none of these omit the identifier.

baseline.interpretations lists undeclared-extensions-ignorable/1 from ADR 0037: Undeclared extension vocabulary whenever a reported conclusion relied on it. That is when Full model meaning, contextual equality, declared-value consistency, numeric advice or Sample admission set aside undeclared extension vocabulary in a description and established its conclusion as if that vocabulary were absent. Recorded extension vocabulary set aside the same way, such as oma:id under ADR 0038: Recorded extension vocabulary, counts too when the report did not consult its recorded registry evidence. That is the case in a Sample report, in an assessment other than FullBaseline and in a FullBaseline check that withholds recorded evidence. Where FullBaseline consulted the evidence, setting the recorded quality aside names nothing. The sample contract describes the Sample case. An extension quality that no such conclusion consulted names nothing. Neither does one in a description whose base meaning is already stopped, for example by a base quality outside its role. Initial contradiction advice never consults the vocabulary. Reports that relied on no such description omit the identifier.

Outcomes, conditions and truncation

outcome contains complete, retained aggregate errors, warnings, notices, incomplete_checks, strict_warnings, and disposition. Requested work is complete only when every applicable requested requirement is assessed or established not applicable. Definite errors and scoped incompleteness can coexist. failed means an error exists or strict warnings are selected and at least one warning exists; otherwise unfinished work gives undetermined; otherwise passed. A failed incomplete result keeps complete:false. Strict warning policy changes disposition/exit eligibility, not warning severity, condition code, baseline meaning or error count.

Conditions have stable string code, severity (error, warning, notice, incomplete), basis, requirement/proof identity where applicable, optional primary source/effective/sample location, related locations and bounded structured arguments. Human message is explanatory and unstable. Report ordering is deterministic for the same supplied identities/request/version where practical, but consumers must not rely on ordering or wording. Codes are not message templates. For example:

CodeMeaning / basis
json.syntaxEstablished JSON grammar violation; JSON decoding basis, not an SDF semantic error.
input.duplicate_nameDuplicate decoded object-member name refused under A002, including nested opaque content.
input.acquisitionRequired content could not be obtained; acquisition limitation.
reference.unavailableA needed addressed target could not be established from supplied content.
reference.ambiguousMultiple contributors to an addressed global definition; incomplete lookup with related sources.
reference.syntaxEstablished malformed CURIE prefix or relative-reference syntax; RFC error at the original reference.
reference.prefix_unmappedA reference prefix has no original namespace mapping; RFC error, distinct from unavailable target lookup.
reference.capability_unavailableA needed prefix, assembled global name or target form exceeds the supported selection capability; operational incompleteness.
reference.effective_cycleNeeded effective expansion cycle; incomplete with available cycle locations.
interpretation.unresolvedA requested conclusion depends on an unresolved recorded reading.
parameter.positive_stepAn applicable established multipleOf is nonpositive; RFC parameter error.
data.string / data.booleanWrong scalar kind for an established full-description or direct-item textual quality, or a data/Property flag; RFC parameter error.
data.numberWrong JSON kind for an applicable numeric bound or step; RFC parameter error, separate from unavailable numeric capability.
data.countApplicable length/count is not a nonnegative mathematically integral number; RFC parameter error.
data.enumApplicable enum is not a nonempty string array; unavailable decoded string meaning is separate.
data.requiredIn an established explicit-object context, map-data required is nonarray, empty or definitely contains a nonstring; RFC parameter-shape error, separate from sample-entry presence and sdfRequired.
data.enum_choiceBoth mutually exclusive qualities survive, including malformed ordinary null values; RFC parameter error.
data.map_shapeAn established collection, direct item or named full description has the wrong map shape; RFC parameter error.
data.number_unavailableExact-number capability needed to assess a numeric parameter is unavailable; scoped operational incompleteness.
quality.unfamiliarUnfamiliar unqualified Quality Name; warning advice, without claiming unregistered status.
quality.name_syntaxFullBaseline RFC error for malformed unqualified or qualified Quality Name spelling; M005 remains assessed work. Given Names and opaque value maps are outside this check.
extension.optional_unsupportedInformational notice of recognized spellings or selectors whose optional meaning is unsupported at that position. Full locates each occurrence and names its quality. Initial and expanded assessments summarize per source or effective model. Operational basis, without asserting registration.
extension.critical_unsupportedA readable critical-feature text list declares meaning the processor does not understand; scoped operational incompleteness.
extension.feature_declaration_unavailableA wider or unreadable critical-feature declaration cannot establish its meaning; scoped operational incompleteness rather than a closed-grammar error.
extension.recorded_value_excludedFullBaseline error for a Recorded extension vocabulary value outside its registered domain, such as an oma:id that is not a CDDL uint, at each effective coordinate. Its registration basis cites the OMNA SDF Quality Names registry and has the Quality Name as id. M028 is assessed in full.critical-extensions/1.
policy.historical_action_inputA001 refusal at assessed vocabulary positions.
proof.empty_numeric_intervalGuarded initial interval proof; advisory warning, not an RFC violation.
proof.inverted_text_lengthsEstablished minimum Unicode scalar length exceeds the maximum; advisory warning.
proof.inverted_array_countsEstablished minimum array count exceeds the maximum; advisory warning.
proof.primitive_const_typePrimitive scalar/null constant contradicts the established base type or null admission; advisory warning.
proof.integer_interval_gapEstablished ordinary integer bounds and null exclusion leave no integer; explicit numeric advisory warning.
proof.numeric_const_boundA sole ordinary numeric constant is excluded by an applicable bound; explicit numeric advisory warning with every surviving bound checked independently.
proof.step_interval_gapEstablished ordinary positive-step bounds and null exclusion leave no lattice point, intersected with integers for integer type; explicit numeric advisory warning.
proof.numeric_capability_unavailableA needed exact numeric value, meaning, work or storage capability is unavailable for an explicit numeric proof class; operational incompleteness with no citation key.
consistency.const_excludedA final effective const candidate is definitively excluded by its data description; one explicit consistency advisory warning per candidate.
consistency.default_excludedA documentary default candidate is definitively excluded by its data description; one explicit consistency advisory warning per candidate, without inserting it.
coverage.advisory_unavailableRelevant meaning or finite work prevents completing the one initial advisory area.
operation.limitNamed finite budget prevented affected requested work; incomplete capability.
coverage.inventory_unavailableComplete applicable baseline inventory is unavailable; full requested coverage is incomplete.

This minimum code catalogue can grow additively with new operation-specific codes. Existing codes keep severity and meaning; changing either allocates a new code. Code parameters grow through optional fields without changing existing parameter meanings. Future codes are handled as strings with an unknown-code fallback; a client must still use structural severity/outcome. Future disposition/severity/basis semantics require a report major version, so a 1.x client can safely classify the fixed values above. The registration basis kind is the one exception. It joined version 1.0 in place because no report reader predates the first release, as recorded in ADR 0038: Recorded extension vocabulary.

The metadata.info_absent and quality.unfamiliar warnings identify their advice rules with a basis.id equal to the condition code and retain the supporting RFC citation. Advice identifiers and citations serve separate roles and can appear together.

Selected civil-value conditions use the domain, severity and basis catalogue in the civil-time contract. Actual convention use adds ADR0018-selected-representation to the shared interpretation array. Temporal knowledge retains its existing optional shape and records only actual C72 queries. These fields survive optional condition/witness/coverage omission and discarded branch evidence. Declared-value consistency keeps its existing advisory codes and check report shape.

The optional-vocabulary summary’s arguments.observed_occurrences is a Count of unsupported optional occurrences actually inspected in that source. It is bounded detail and can be absent if the condition is omitted; unfinished checking can leave additional occurrences uninspected. Check reports identify A001 and A002 in policy.restrictions, while standalone source inspection applies A002 without assessing SDF vocabulary. The A001 condition keeps its acceptance basis and current Action-input guidance, following ADR 0008: Reject the historical Action input quality.

Diagnostic count and byte budgets limit detail storage and rendering, not assessment. Aggregate counts and completion are updated before any condition is dropped. diagnostics records retained/omitted counts and count/byte/location omission reasons; details can be entirely empty while errors remain nonzero. Aggregate requirement-status and outcome counters remain even when coverage rows/details are omitted. Presentation-only pointer omission or condition truncation leaves otherwise completed checking complete. A semantic ancestry/storage/work limit makes affected requested conclusions incomplete. Rendering never allocates a complete oversized report and cuts it afterward.

Finite default work and allocation

ADR 0012’s input/number defaults remain: 4 MiB per source, 32 MiB catalogue, 256 documents, 64 nested containers, 100,000 JSON nodes per source, 1,024 bytes per number token, 512 coefficient digits, explicit exponent magnitude 1,000,000, and 2,000,000 numeric units per request. The following additional defaults close catalogue/derived/report amplification. They are capability, not standards limits or performance targets.

BudgetDefault / charge before work
Catalogue parsed nodes500,000 total, including opaque content; count every value/container before retaining it.
Parsed representation allocation64 MiB total reserved allocation, excluding the separately bounded raw source bytes; account strings, maps, arrays, source spans, indices and capacity growth before allocation.
Derived effective content250,000 retained effective value nodes, 64 MiB total derived representation including ancestry and caches. Charge actual new allocation; shared immutable content charges its owner once.
Reference work100,000 expansion applications, dependency/effective chain depth 256. Charge each expanded application and copied/traversed node; deleted branches need not be expanded.
Check/composition work10,000,000 units: one per visited value/member/reference edge and one per traversed/copied text/token byte, plus separately metered numeric/pattern work. Charge before traversal/copy; aggregate limits apply across the whole request, not reset for each definition.
Compact ancestry1,000,000 path records, 16 MiB charged decoded path-token storage within the derived allocation budget. Share or span tokens/parent chains; no full ancestor-pointer String per retained node.
Materialized pointers8 KiB per rendered pointer, 8 MiB aggregate pointer output/work per operation. Count escaping bytes before allocation; excess is presentation omission where semantic path handles still work.
Conditions1,000 retained items, 1 MiB total serialized condition detail, 4 KiB message text per item. All larger explanatory collections also consume detail budget.
Report8 MiB total emitted JSON/human report, including source labels, location strings, coverage detail and escaping. Pre-reserve a bounded mandatory summary/source-identity/status/scope envelope; omit detail before this cap. Never omit aggregate outcome or source attempts.

Capacity arithmetic is checked. Check work admits effective-result storage before composing the next root. Failed admission retains an operation.limit cause at that checked effective root, preserves earlier findings and supplied scope, and contributes to aggregate diagnostics even if detail is omitted. No zero/unlimited sentinel is accepted. Configuration validation enforces finite representable values, supported stack/identity ceilings, and enough report space for the mandatory supplied-source inventory; invalid configurations are request errors before work. Independent definite results and raw retained content survive limits. Builders allow lowering/raising supported budgets, but no public guarantee of accepting every arbitrary usize value exists.

A parser may borrow immutable raw source spans or allocate compact decoded values. Composition may share immutable/COW values or materialize them only after charging nodes, bytes and byte work. Either strategy must obey the same public limits. In particular, a 4 MiB opaque source value expanded thousands of times cannot bypass derived-byte/work budgets merely because its expansion count is under 100,000. Traversing shared content still charges check work. No performance target is invented; ordinary catalogue evidence is structural operation/allocation evidence and a bounded representative timing observation, not throughput qualification.

JSON report 1.0 and compatibility

Every supported JSON result is a single UTF-8 JSON object with schema:"esdieff.report". Required top-level fields are operation, request, sources, baseline, policy, outcome, coverage, diagnostics and result. Check and inspect retain version 1.0. Sample and author use their distinct version 1.1 payloads, edit adds version 1.2, diff uses version 1.5 after 1.4, and generate and trace add version 1.5 below. The sample contract, authoring contract, editing contract, revision comparison contract, generation contract and trace contract specify these operation payloads without changing check/inspect meanings. A reader rejects an unknown operation before interpreting its result. request identifies assessment/inventory identity and scope. sources includes every acquisition attempt with role, bounded identity/label and acquisition/decode/content-completeness status and never embeds whole source content. baseline identifies actual standards/corrections/interpretations/knowledge. policy identifies acceptance restrictions and strict warnings. coverage carries requested and broader inventories with aggregate statuses and optionally bounded rows. diagnostics carries aggregates, omission reasons and retained conditions. result is tagged by operation.

The tables below specify the normative shared check/inspect version-1.0 envelope. Later operation contracts add their own fields and tags. R means required; O means optional and omitted when absent. Only explicit T|null permits null. No absent optional field is interpreted as an assessed result. All maps admit additional optional fields under version-1.x rules, but every listed field retains its meaning/type. Id is a nonzero JSON integer from 1 through 256, unique within sources; IDs are request-local handles, not durable namespace/content identities. All references must select listed IDs; all source roles share that ceiling. Count is a JSON integer from 0 through 4,294,967,295; aggregate counters must not saturate or wrap. The accepted finite-work ceilings guarantee count bounds; configurations that cannot do so are rejected. Bytes is a Count measured in UTF-8 bytes except explicit raw filesystem-byte identity. Spans are [start,end] Count pairs with start <= end; spans cannot exceed retained source bytes. General JSON model numbers remain exact and are not restricted to Count.

ObjectRequired fields and typesOptional fields and types / null meaning
Top levelschema:"esdieff.report"; version:"1.0"; operation:`“check”“inspect”`; request:Request; sources:Source[]; baseline:Baseline; policy:Policy; outcome:Outcome; coverage:Coverage; diagnostics:Diagnostics; result:CheckResult
Requestassessment:stringnull (<=256 UTF-8 bytes); inventory:string
Scopekind:`“catalogue”“selected”`; roots:Id[]; dependencies:Id[]; assessed:Id[]; unavailable_required:Id[]
Sourceid:Id; key:string (<=256); role:`“model”“sample”
Baselineid:string (<=256); rfc:"9880"; corrections:string[]; interpretations:string[]; deviations:string[]; registry_knowledge:RegistryKnowledge[]temporal_knowledge:TemporalKnowledge; metadata_omitted:Omission[]. Registry entries identify actual knowledge used. An empty array does not establish registration absence. Temporal knowledge is separate and present only when the recorded interval or adjustment facts were consulted, including an outside-interval query.
RegistryKnowledgeregistry:string; snapshot:stringnull; state:`“available”
TemporalKnowledgeid:string; from:string; through:string; transition_sha256:string; bulletin_sha256:stringNone. from/through are inclusive full dates; each SHA256 field is 64 lowercase hexadecimal digits identifying the recorded evidence. Actual-use metadata survives diagnostic/row omission.
Policyrestrictions:string[]; strict_warnings:booleanrecorded_registry:`“use_recorded”
Outcomecomplete:boolean; errors:Count; warnings:Count; notices:Count; incomplete_checks:Count; strict_warnings:boolean; disposition:`“passed”“failed”
Coveragerequested:RequestedCoverage; broader:BroaderCoverage; rows:CoverageRow[]; rows_omitted:Count; omissions:Omission[]requirements:RequestedCoverage; requirement_rows:CoverageRow[]; requirement_rows_retained:Count; requirement_rows_omitted:Count; requirement_omissions:Omission[]. These optional fields describe separate 54-member Full detail and may be wholly absent. rows remains area detail; empty does not imply complete scope.
RequestedCoverageinventory:stringnull; count_unit:`“assessment_area”
BroaderCoverageinventory:stringnull; state:`“partial”
CoverageRowid:string; count_unit:`“assessment_area”“requirement”; status:“assessed”
Diagnosticsretained:Count; omitted:Count; truncated:boolean; reasons:string[]; omissions:Omission[]; items:Condition[]None. retained equals items.length; truncated iff omitted>0 or presentation omissions exist. Reasons use count_limit, byte_limit, location_limit, report_limit and not_available. A location with unavailable decoded identity uses not_available; pointer size or work exhaustion uses location_limit. Counts remain exact even if every item is omitted.
Conditioncode:string (<=256); severity:`“error”“warning”
Basiskind:`“json”“rfc”
Omissionfield:string; reason:`“count_limit”“byte_limit”
SourceLocationkind:"source"; source_id:Id; pointer:stringnull (<=8192); span:[Bytes,Bytes]
EffectiveLocationkind:"effective"; root:Id; pointer:stringnull (<=8192)
SampleLocationkind:"sample"; source_id:Id; pointer:stringnull; span:[Bytes,Bytes]
CheckResultkind:"check"None.
InspectSelectorview:`“source”“effective”`; document:Id; pointer:string (<=8192)
InspectResultkind:"inspect"; view:`“source”“effective”; state:“available”
Explanationkind:`“source”“inherited”

The existing mandatory Full request.inventory binds both 13-area and 54-requirement memberships even when every new optional field is absent. Optional requirement rows have exact retained/omitted counts summing to54; a nonzero omission has one coverage.requirement_rows record with its reason and count. Area rows plus rows_omitted sum to the requested area total. Coverage-only omission also appears in diagnostics.omissions, sets truncated and links its reason in diagnostics.reasons. Consumers compare surviving condition multisets, including codes, bases, arguments, producing IDs and coordinates; duplicate facts cannot stand in for erased facts. Unknown additive fields, row order and human wording do not change meaning. Missing entire optional groups do not imply empty membership or finished per-requirement work. incomplete_checks counts each declared requested area once, independently of condition or row retention. Scope IDs and mandatory metadata remain within the original reserve; copied opaque source content is never automatically embedded.

Inspection does not implicitly request a model assessment. Its one declared inspection unit covers the acquisition, decoding, selection and, for an effective view, composition required to establish the requested view. Its explicit document selector supplies the root; unrelated candidate failures remain visible without alone making this work incomplete. Inspect outcome.complete is true only when that requested operation is complete, and incomplete_checks counts its one unfinished unit. An available subview does not erase other requested limitations. Broader coverage remains partial/undetermined: source inspection passing establishes a usable requested view, never RFC conformance. A presentation-only omission can produce a partial displayed payload while the operation’s semantic work remains complete. If required semantic view establishment is incomplete, the disposition is undetermined unless independent errors or strict warnings already make it failed. The operation tag and count_unit distinguish its one operation from check’s declared assessment areas without inventing a standards inventory.

Check result contains no additional payload beyond shared coverage. Inspection result contains a bounded source/effective selected view, explicit partial/unavailable state and explanations; large content is accessed via library-owned source or explicit CLI inspection output, never automatically included in every check report. Sample result contains separate sample source/selector, tagged admitted, rejected or undetermined conclusion and relevant effective model selector/locations. Authoring result contains generated-document identities/content availability, assessment and fidelity state (established or undetermined); generated bytes are obtained from owned result accessors or an explicit CLI document output. Its generated catalogue supports the same check and inspection operations. Failed or limited authoring never presents a partial candidate as faithfully completed output.

Report wire types are explicit DTOs, independent of Rust struct layout/private graph/enum serialization. JSON null means the explicitly unavailable/absent field defined by its containing tag, never a generic successful default. Version 1.x permits additive optional fields and condition codes; readers ignore unknown fields and retain unknown codes, and handle integer aggregates without lossy floating-point conversion. Existing required fields, fixed outcome/severity/basis/acquisition/decode values, units and absence semantics cannot change within 1.x. Renaming/removal/type changes need a major version. New operations have new tags: a check/inspect reader rejects an unknown operation before interpreting its result. Future sample/author tags can be added with their own pinned contracts, without changing existing check/inspect meanings. Rust views/builders use private fields, nonexhaustive extensible result enums and stable accessors; implementation dependencies and storage remain replaceable. Rust source compatibility is maintained for documented public callers within the supported crate version family, with breaking interface changes explicitly versioned independently of the JSON report.

Authored-quality editing report 1.2

Operation edit uses version 1.2 under ADR 0034: Authored-quality editing with source substitution. The shared source, scope, outcome and diagnostic meanings remain intact. The edit envelope adds the following mandatory operation fields.

ObjectRequired fields and typesMeaning
Edit requestassessment:null; inventory:null; scope:Scope; editing:EditingSummaryThe operation has its own editing identity. Requested checking has a separate assessment.
EditingSummarykey:string; original_source:Id; generated_source:Id; edit_count:Count; checking:`“not_requested”“requested”`
Edit requested coverageinventory:null; count_unit:"editing"; total:1; assessed:Count; not_applicable:0; unassessed:Count; undetermined:CountThe existing partition sums to one whole editing operation, including any requested check.
EditResultkind:"edit"; generation:`“complete”“partial”
EditingFidelitystate:`“established”“undetermined”; contract:“esdieff.authored-quality-edit/1”`
EditedDocumentsource_id:Id; state:`“available”“partial”
SourceSubstitutionoriginal_source:Id; generated_source:IdThe original remains retained evidence and is replaced by the generated contributor in the active Catalogue.
EditChecking, not requestedstate:"not_requested"No assessment or passing-check conclusion is fabricated.
EditChecking, requestedstate:"requested"; assessment:string; inventory:stringnull; scope:Scope; outcome:Outcome; coverage:Coverage
EditRequestLocationkind:"edit_request"; key:string; pointer:stringnull; span:[Bytes,Bytes]

Generation and fidelity may be complete/established while a requested check leaves editing coverage undetermined. Completed checking with findings completes assessment of the editing unit but gives a failed disposition. Available Full model inventories retain 13 assessment areas and 54 requirements, including mandatory aggregate coverage when optional rows are omitted. Unavailable inventories keep their ordinary null meaning. Individual edits never inflate RFC completion counts.

Every supplied/generated attempt stays in sources, including the substituted original evidence. active_sources excludes that original and retains every other distinct contributor. Scope identifies actual generated roots, needed dependencies, assessed sources and unavailable required sources. Optional detail omission cannot remove source identities, substitution, edit count, errors, candidate completeness, fidelity or established checking aggregates. Diagnostic omission remains explicit through ordinary omission records.

Original source locations refer to original bytes, generated locations to generated bytes, and effective locations to the active Catalogue. Replacement findings can have related original-member and edit-request locations. A removed generated member is absent and has no invented generated span. These bounded relationships do not claim exhaustive provenance.

Revision comparison report 1.5

Operation diff uses version 1.5 under ADR 0039: Client-side revision comparison, ADR 0040: Acknowledged revision differences and ADR 0044: Versions of breaking revisions. Version 1.4 succeeded 1.3, because Difference acknowledgements change what the outcome counts and the disposition mean and add required fields. Version 1.5 succeeds 1.4, because outcome.warnings now counts Version warnings and diagnostics.items holds them. Every diff report is emitted at 1.5. It reports one comparison of an earlier and a later Catalogue. The shared source, outcome and diagnostic meanings remain intact, and the revision comparison contract specifies every field.

ObjectRequired fields and typesMeaning
Diff requestassessment:null; inventory:null; comparison:"esdieff.revision-comparison/2"; scope:{earlier:Scope, later:Scope}The request names the comparison contract identity. Each revision has its own catalogue scope.
Diff sourceSource fields; revision:`“earlier”“later”`
Diff policy and baselinePolicy fields; recorded_registry; acknowledgements:Count; Baseline fieldspolicy.recorded_registry echoes the request’s recorded evidence policy, and policy.acknowledgements counts the supplied acknowledgement entries, because they change the disposition. baseline.registry_knowledge identifies the recorded unit sections and content-format registries that unit and content-format comparison actually consulted or found withheld, and baseline.interpretations names content-format-model-meaning/1 when content-format comparison consulted it, and the Sample-value interpretations that the checks of a Breaking witness relied on, as model reports name them.
Diff outcomeOutcome fieldsOnly unacknowledged differences count. errors counts unacknowledged breaking differences, and incomplete_checks is 1 when any unacknowledged difference is undetermined. The disposition is failed for an unacknowledged breaking difference, otherwise undetermined for an unacknowledged undetermined one, otherwise passed, so exit codes follow check. warnings counts Version warnings, which never change the disposition, and strict_warnings is false.
Diff diagnosticsDiagnostics fieldsEach retained item is a comparison.version_not_increased warning condition with an advice basis citing RFC 9880 Section 3.1. Its primary and related locations are source locations with a revision member, and its arguments carry both versions and the document pair’s breaking count.
Diff requested coverageinventory:null; count_unit:"comparison"; total:1; assessed:Count; not_applicable:0; unassessed:0; undetermined:CountOne comparison, assessed when no unacknowledged difference is undetermined.
DiffResultkind:"diff"; outcome; summary; documents; unused_acknowledgements:Count[]; differences; differences_omitted:Count; omissions:Omission[]Typed differences with their classifications, acknowledgement state, Client directions, effective locations, nearest content origins, Breaking witnesses and undetermined reasons. The outcome classifies every difference, acknowledged or not. Summary counts, the outcome and the unused entry positions survive omitted difference details.

Generated values report 1.5

Operation generate uses version 1.5 under ADR 0041: Generated values settled by Sample-value checking. It reports the Generated values of one selected model document and their admissions. Composition spends the request’s allowance, each description’s values are built on an allowance of their own, and each value is checked with the allowance one sample request receives, so running out leaves only the affected description partial. The 64-value and 1024-description ceilings keep the request finite, and every description and kept value is charged the report bytes its largest rendering needs, so every output format fits report_bytes. Values and descriptions that do not fit are counted with byte_limit and report_limit records and leave the operation undetermined. The shared source, outcome and diagnostic meanings remain intact, and the generation contract specifies every field.

ObjectRequired fields and typesMeaning
Generate requestassessment:null; inventory:null; generation:{contract:"esdieff.generation/1", document:Id, selector?:SampleSelector}; scope:ScopeThe request names the generation contract identity, the document and an explicit selector when one was given. Scope is selected, with the document as its root.
Generate outcomeOutcome fieldsGeneration reports no model findings, so the finding counts are 0 and the disposition is passed when generation completed for every selected description, otherwise undetermined. Exit codes follow check.
Generate requested coverageinventory:null; count_unit:"description"; total:Countnull; assessed:Count; not_applicable:0; unassessed:Count; undetermined:Count
GenerateResultkind:"generate"; summary:{admitted, rejected, undetermined}; selection; descriptions; descriptions_omitted:Count; omissions:Omission[]Typed descriptions with their selectors, effective locations, states and values of {target, value, admission, codes}. Summary counts and the outcome survive omitted description details.

Recorded trace report 1.5

Operation trace uses version 1.5 under ADR 0042: Recorded traces with independent entries. It reports one Recorded trace checked against one selected model document. The document is composed once on the request’s allowance, each distinct Sample selector is resolved once, and each Trace entry is decoded and checked with the allowances one sample request receives, so a malformed or heavy entry affects only itself. The file, line and entry ceilings are request errors, and each listed entry is charged the report bytes its larger rendering needs, so both formats fit report_bytes. Failed and undetermined entries that do not fit are counted with a report_limit record. The shared source, outcome and diagnostic meanings remain intact, and the trace contract specifies every field.

ObjectRequired fields and typesMeaning
Trace requestassessment:null; inventory:null; trace:{contract:"esdieff.trace/1", document:Id, source:Id}; scope:ScopeThe request names the trace contract identity, the document and the trace source. Scope is selected, with the document as its root.
Trace sourceSource fieldsThe trace file is the last source, with role sample.
Trace outcomeOutcome fieldserrors counts failed entries and incomplete_checks undetermined ones. The disposition is failed for any failed entry, otherwise undetermined for any undetermined entry, otherwise passed. Exit codes follow check.
Trace requested coverageinventory:null; count_unit:"trace_entry"; total:Count; assessed:Count; not_applicable:0; unassessed:0; undetermined:CountOne unit per Trace entry.
TraceResultkind:"trace"; summary:{passed, failed, undetermined, admissions}; entries; entries_omitted:Count; omissions:Omission[]Failed and undetermined entries with their line numbers, labels, selectors, expected admissions, admissions, outcomes and conditions, whose Sample locations have byte spans in the trace file. Passing entries are counted, not listed. Summary counts and the outcome survive omitted entries.

SARIF projection

check --format sarif and diff --format sarif emit a SARIF 2.1.0 log for code-scanning annotations, following ADR 0043: SARIF and Markdown report projections. The library gives the same log through Report::to_sarif(directory) for a check report and RevisionComparison::to_sarif(directory), where directory is the directory relative paths were resolved from. A log projects the same report as the JSON format. It renders only the conditions or differences that report retained and changes no conclusion, disposition or exit code.

The log has one run. tool.driver names Esdieff and the crate version, and lists one descriptor per result code in rules and one per notification code in notifications. Each descriptor has the code as its id and short description. Its full description names a condition code’s severity and basis kind, which the code keeps, or what a diff classification, undetermined reason or warning code means, and its help text points to the contract that describes the codes. run.columnKind is unicodeCodePoints. run.originalUriBaseIds gives %SRCROOT% the invocation directory as a file URI ending in /, when that directory is known. run.properties holds the report’s disposition and the omittedResults and omittedNotifications counts described below. The one invocation has executionSuccessful:true, because the report was produced, and holds the tool execution notifications.

A check result is a retained condition of severity error, warning or notice, at level error, warning or note, with its code as ruleId and its message. Errors come first, then warnings, then notes. A retained incomplete condition is a tool execution notification at level warning instead, with its code as descriptor, because unfinished checking is not a finding about the model.

The physical location of a check result comes from its primary source location, or else from its first related source location, and the other related locations follow in relatedLocations. The artifact URI is the source’s file path relative to the invocation directory, with / separators, percent-encoded segments, . and .. segments resolved as RFC 3986 resolves them, and the base %SRCROOT%, so code scanning finds the files when Esdieff runs from the repository root. A path outside the invocation directory, whether absolute or reached through .. segments, becomes an absolute file URI without a base. The region comes from the retained byte span. startLine and endLine count lines from 1, where CR, LF and CR LF end a line. startColumn and endColumn count Unicode code points from 1 within the line, and endColumn is the column just past the span. byteOffset and byteLength give the span itself. A location without a span, such as a source that could not be acquired, is a file-level location whose region is only startLine:1, because code scanning requires a start line. An effective location becomes a logical location whose fullyQualifiedName is the effective pointer, with properties view:"effective" and document, the label or else the key of its root document. A source without a UTF-8 file path, such as standard input, has no physical location, and its source pointer becomes a logical location with view:"source".

A diff result is a Version warning or a retained difference. Version warnings come first, each at level warning with its code as rule, located at the later document’s version or the nearest member that would hold it, with the earlier version as a related location. Differences follow in report order. A breaking difference is level error with rule comparison.breaking, an undetermined one is level warning with its reason code as rule, and a compatible one is level note with rule comparison.compatible. The message names the classification, then the kind, subject, document source key and effective pointer, and the undetermined reason or the Breaking witness with its admissions, in the words the Markdown changelog uses. Every diff result carries suppressions. An Acknowledged difference has one suppression of kind external with status accepted, so reviewers still see the break while code scanning treats it as intended, and the list is empty for every other difference and every Version warning. The later revision’s side locates the result when it has a nearest content origin, or when the earlier side has none either. Otherwise the earlier side does, as for a removed definition. The side’s origin gives the physical location, and its effective location gives a logical location with the property revision. The other revision’s side is a related location whose message names that revision.

The log stays within the report byte limit, which it applies on its own, so it can show differences whose details the JSON report left out for space, and the other way around. After the envelope, results and then notifications are kept in order while they fit, and the first that does not fit ends the list. omittedResults counts every finding the outcome counts that the log does not show, whether the report or the log left it out: the errors, warnings and notices of a check, and every Version warning and difference of a comparison. omittedNotifications counts the incomplete conditions of a check the same way. When either count is nonzero, a final notification at level warning states both.

Markdown changelog

diff --format markdown and RevisionComparison::to_markdown() give a Markdown changelog of a Revision comparison for release notes, following ADR 0043: SARIF and Markdown report projections. Like the SARIF log, it projects the same report as the JSON format, renders only the differences that report retained and changes no disposition or exit code.

It starts with the title # Model changes and a disposition line that counts breaking, undetermined and compatible differences, and the acknowledged ones when acknowledgements were supplied. A Warnings section lists each Version warning with the later document, its version or the place it is absent, the earlier version, the breaking count and the code. Sections follow for unacknowledged breaking, unacknowledged undetermined, compatible and acknowledged differences, in that order, and a section without differences is left out. Each item is one list entry naming the kind, the subject, the document’s source key and the effective pointer, taken from the later revision’s side when it has one. An undetermined item adds its reason and code, and an item with a Breaking witness adds the witness value, its Client direction and both admissions. An acknowledged item starts with its classification.

Model text appears only in code spans, including Given Names in pointers, quality names, source keys and witness values. A span’s fence is longer than any run of backticks inside it, and control characters, line breaks among them, become \uXXXX escapes, so a name can neither end its span nor start a new block. Reason messages are plain text with Markdown punctuation escaped.

The changelog stays within the report byte limit, which it applies on its own like the SARIF log. Items are kept in order while they fit, warnings first. When any difference or warning is not listed, whether the report or the changelog left it out, a closing line counts them.

CLI contract

The direct command is esdieff check [--directory DIR] [--recursive] [--exclude RELATIVE_PATH] [--root INPUT] [--assessment initial-v1|expanded-modified-v1|expanded-units-v1|expanded-content-format-v1|expanded-pattern-syntax-v1|expanded-numeric-v1|expanded-consistency-v1|full-baseline] [--registry-knowledge recorded|withheld] [--strict-warnings] [--format human|json|sarif] [INPUT...].

At least one positional INPUT or directory request is required. INPUT is an explicit file path or - for one stdin document. Repeat --directory DIR to prepare model sources from several directories. --recursive enables descent for all supplied directories, and repeatable --exclude RELATIVE_PATH omits literal files or subtrees relative to each directory. These traversal options require a directory request and apply only to direct checking and diff. Plan mode, inspect, sample, author and edit do not accept discovery options. The directory discovery contract defines selection, ordering, overlap and finite preparation limits.

An explicitly selected root must match exactly one supplied attempt by its exact native acquisition path. For a discovered root, this is the joined directory/file path. Directory, positional file and root paths resolve from the invocation directory. Repeated -, unknown or multiply matched roots and malformed options are usage errors. Positional files and discovered files are model candidates. Position never picks the root. Default roots are absent, which requests catalogue scope. Non-UTF-8 filesystem paths get a safe display label with their distinct identity preserved. Path labels are not namespace meanings.

The default is initial-v1; expanded-modified-v1 explicitly selects the fixed nine-area inventory, expanded-units-v1 selects the ten-area unit inventory, expanded-content-format-v1 selects the ten-area declaration inventory, expanded-pattern-syntax-v1 selects the fixed nine-area inventory comprising the initial eight plus pattern-syntax/1, expanded-numeric-v1 selects the Initial eight plus advisory-numeric-three/1, and expanded-consistency-v1 selects the unchanged Initial eight plus const-consistency/1 and default-consistency/1, with requested denominator 10. Explicit registry-knowledge values require an expanded unit/content or full-baseline assessment.

After successful invocation preparation, exactly one requested report goes to stdout, with a trailing newline. Directory preparation failures exit 2 with stderr and empty stdout before model content or stdin is read. Acquisition and decoding problems are in the ordinary report. stderr contains usage errors and output/host failures, not semantic conclusions omitted from JSON. Human and JSON formats use the same outcome/scope/coverage/baseline/policy. Exit 0 is passed requested work, 1 is failed (including strict warnings), 2 is invocation/configuration error, 3 is undetermined work without blocking errors, 4 is inability to emit the requested report or another host operation failure. Failed+incomplete uses 1 and keeps structural incompleteness. Truncated detail alone does not change exit status. stdin is read under input limits; no implicit retrieval/discovery occurs.

--format sarif emits the SARIF projection of a direct check or diff report, and --format markdown the Markdown changelog of a diff report, each with the exit code of that report’s disposition. Plan mode, inspect, sample and trace refuse --format sarif, and every operation other than diff refuses --format markdown, each with exit 2 and empty stdout.

esdieff diff --old PATH --new PATH [--recursive] [--exclude RELATIVE_PATH] [--acknowledged FILE] [--format human|json|sarif|markdown] compares an earlier and a later Model revision and emits one revision comparison report. Both PATHs are directories or both are files. Each directory is prepared separately with the directory discovery rules, and --recursive and --exclude apply to both. A document’s source key is its path relative to its directory, with components joined by /, so documents pair by location. In the two-file form both documents take the key document and correspond directly. A file beside a directory, - on either side, a missing --old or --new, a nonexistent PATH, and a relative path that is not UTF-8 or exceeds the 256-byte source key are invocation errors. Standard input is never read. --acknowledged FILE may appear once and names a file of Difference acknowledgements. The file is read and decoded before either revision’s content, and -, an unreadable file and any file the acknowledgement decoder refuses are invocation errors. Both revisions finish preparation before either one’s content is read, and both are acquired and compared under one operation allowance. Exit codes follow check and the disposition, which only unacknowledged differences decide: a comparison passes with exit 0, an unacknowledged breaking difference exits 1 and otherwise an unacknowledged undetermined one exits 3.

diff also accepts --acknowledgements-output FILE and --replace-acknowledgements. They write the JSON report’s eligible acknowledgement entries to a named file for review, following the acknowledgement export rules. Export preserves the report format and comparison exit status. Existing output requires explicit replacement and cannot alias a selected revision document or supplied acknowledgement file. Invalid destinations and exports the acknowledgement reader cannot accept exit 2 before delivery. Delivery failures exit 4.

esdieff generate --document MODEL [--kind KIND --pointer POINTER] [--format human|json|jsonl] MODEL_INPUT... emits the Generated values of one selected description, or of every affordance description of MODEL, as one human report, one generate report or JSON Lines Trace entries. MODEL, the inputs and - follow esdieff sample, and --kind and --pointer come together or not at all. A selector that selects nothing is an invocation error. Exit 0 is generation completed for every selected description and 3 is any other result, since generation never fails.

esdieff trace --document MODEL --trace FILE [--format human|json] MODEL_INPUT... checks the Recorded trace FILE against MODEL and emits one human report or one trace report. MODEL and the inputs follow esdieff sample. FILE is a path or -, and standard input may be used once across the inputs and the trace. The trace is read before any model input, and a trace that is missing, unreadable or larger than 64 MiB, a line over 1 MiB and more than 100,000 entries are invocation errors. A malformed entry fails only itself. Exit codes follow check: 1 for any failed entry, otherwise 3 for any undetermined entry, otherwise 0.

esdieff inspect --view source|effective --document INPUT --pointer POINTER ... is a complementary explicit inspect operation using the same report metadata/locations; callers can inspect retained source after assessment failures. Effective inspection never silently falls back to source. Its selector and requested output remain finite. Future sample/author commands use distinct operation tags and the shared source/report/exit rules, but operation-specific selectors, request options and document write/collision behavior are separately specified before those commands ship. Authoring’s report and document bytes have separate explicit destinations; it never mixes a report and generated SDF on stdout or writes an unasked destination.

Concrete cross-workflow obligations

The six-class Temperature/Sensor/Device fixture provides source and effective views: all six classes appear, ambient’s inherited minimum is -50, maximum 100, writable false, Event-output maximum 150, deleted description absent; source Sensor/Temperature are unchanged. The Controller/Level fixture uses explicit Controller roots, differently named prefixes for one namespace, minimum 0, maximum 80 and deleted description with unchanged source Level. Scope contrast adds an independently bad unused source: catalogue work fails, selected relevant work retains its appropriate outcome, and every supplied source remains visible.

For the selected temperature sample 101, a later sample request reports rejected, with sample root pointer ""/byte span [0,3] and model effective maximum path ending /maximum, related to the patch maximum 100; source Event-output maximum 150 is irrelevant to this selected description. Undetermined sample meaning cannot become rejection. Sample admitted/rejected is independent of strict-warning disposition. Sample request details remain future contract work, but its source/result/location foundation is settled here.

For a later authored Device Thing built from Sensor with the same override, the result owns generated SDF documents with new generated source identities, an assessed catalogue and effective views, while reusable source identities/content remain unchanged. Generated known numbers retain mathematical values and accepted unchanged lexemes. It reports any opaque-context fidelity limitation; structural retention alone is insufficient. Name/namespace request assembly, collision choices and file write policy remain the separate authoring decision. The shared contract does not force an internal flattened format, generic mutation API or speculative plugin system.

Explicit unit assessments add policy.recorded_registry, result.unit_guidance, and actual-use entries in baseline.registry_knowledge and baseline.interpretations under the existing 1.x additive field rules. The ten-area profile preserves the initial eight meanings. Fixed counters, null owner failure, scoped dated positives, withheld evidence and independent consultation/completion meanings are specified in the unit contract, following ADR 0027: Unit names and recorded registry guidance. Optional row and located-advice omission does not remove semantic summary fields. Full joins both unit dimensions into M023 and its requested special-type/unit area once.

Selected resource formats retain the Sample report version 1.1 and its nine-area inventory. baseline.format_knowledge contains only the six facts actually consulted by that Sample request, or null if its initial consultation owner could not be established. An established empty observation array differs from initial unavailability. The borrowed Report::format_knowledge getter and each static record’s four fields follow the URI and UUID sample contract. Non-Sample operations omit this field. UUID interpretation identities share the existing interpretation array; optional presentation omission preserves both.

Selected abstract-value meaning

Sample report version 1.1 adds mandatory result.meaning.abstract_values, result.meaning.const and result.meaning.admission. The two area objects have status, basis and limitations; their statuses exactly match sample-abstract-values/1 and sample-const/1. The admission object has basis and limitations, alongside the existing authoritative result.admission. The library exposes these same finite sets through SampleResult::meaning(). Not-applicable areas have empty sets. Undetermined admission has an empty supporting set. A definite independent rejection can retain its proof while an abstract obligation remains unfinished. A complete ordinary admission includes the general Appendix C reference without making absent const applicable.

References are unique complete (kind, id, citation) triples, in stable producing order. RFC references have a precise citation and no ID. Interpretation references have an immutable ID and precise citation. Operational references have an ID and preserve an existing precise citation when one exists. In particular, the temporal-knowledge, temporal-meaning and resource-meaning limitations retain their distinct cited triples even when IDs coincide with a general establishment limitation. The producer’s 24 support tags project to at most 23 unique references: temporal exceptional-slot and leap checks share the same RFC citation in this view. Original diagnostic and temporal-knowledge identities keep their existing shapes. The limitation inventory has nine unique triples. Borrowed iterator length and size hints count emitted unique references.

SampleResult::consulted_interpretations() observes actual request consultation of byte-string-json/1 and unix-time-posix-coordinate/1. Their union also appears in mandatory baseline.interpretations. An attempted interpretation survives discarded candidates, representation rejection and later limits. Consultation does not establish final support. Recognition alone, unavailable context, null-only admission and refused input preflight do not claim use. Existing civil and resource observations retain their separate contracts.

A later whole choice or enum witness replaces earlier tentative const proof and limitations. An unknown potentially matching branch prevents universal exclusion. Independent model findings and established sample areas remain authoritative. The human report prints the same three reference sets and consulted sample IDs; its labels and prose remain presentation details. Optional row/detail/location omission never removes mandatory statuses, references, consultation or counts.

The channels and their limits follow ADR 0007: Generated SDF and sample JSON, equality follows ADR 0015: Bounded value equality in a resolved data context, and ownership follows ADR 0025: Selected numeric samples. These are information-level conclusions, without a formal CDDL or protocol binding claim. Check and inspection retain their current payloads and report version. An older Sample 1.x report lacking the additive meaning fields leaves this capability unavailable; absence does not mean not applicable or established.

Supplied source documents

Esdieff accepts explicit SDF documents and retains every acquisition attempt. Source inspection and typed source projections are available independently of completed model assessment, following ADR 0013: Shared workflow and report guarantees.

For deliberate retrieval of a pinned public GitHub file into a new local snapshot, use the separate acquisition operation. Its receipt is independent of ordinary Model checking and is never loaded automatically.

The command accepts files and one standard-input document:

esdieff check --format json model.sdf.json
esdieff check --assessment expanded-modified-v1 --format json model.sdf.json
esdieff check --assessment expanded-pattern-syntax-v1 --format json model.sdf.json
esdieff check --root product.sdf.json common.sdf.json product.sdf.json
esdieff inspect --view source --document model.sdf.json --pointer /sdfData/Temperature model.sdf.json
esdieff check --format json -

All supplied files are candidates; their order selects no model role or precedence. A root or inspection document must explicitly name a supplied input. Use -- before a filename beginning with -. Paths retain their exact filesystem identities even when their display labels need Unicode replacement. Namespace URIs do not trigger acquisition.

Direct check also accepts repeatable --directory DIR inputs. It selects immediate regular .sdf.json files, or descends with --recursive, before ordinary acquisition. Repeatable --exclude RELATIVE_PATH prunes literal files or subtrees relative to every supplied directory. See directory discovery for selection, overlap and finite-work rules and a runnable mixed collection. Discovered roots use their joined acquisition paths relative to the invocation directory. Rust inputs and saved Check plan version 1 retain their existing explicit-source contracts. esdieff diff --old PATH --new PATH compares two Model revisions supplied as two files or two directories. Directories use the same discovery rules, and each discovered document is keyed by its path relative to its directory.

The Rust library supplies the same operations:

#![allow(unused)]
fn main() {
use esdieff::{Catalogue, Class, CheckRequest, InspectRequest, SourceInput};

let catalogue = Catalogue::from_inputs(&[
    SourceInput::supplied("sensor", br#"{"sdfData":{"Temperature":{"type":"number","maximum":100}}}"#)
        .label("Sensor description"),
])?;
let id = catalogue.source_id("sensor").expect("supplied source");
let report = catalogue.check(CheckRequest::new().root(id))?;
for condition in report.diagnostics().conditions() {
    println!("{}: {}", condition.code(), condition.message());
}
let source = catalogue.source(id).expect("listed source");
let temperature = source.definitions(Class::Data).require()?.next().expect("definition").1;
let maximum = temperature.data_description().require()?.number("maximum").require()?;
assert_eq!(maximum.lexeme(), "100");
let inspection = catalogue.inspect(InspectRequest::new(id, "/sdfData/Temperature"))?;
assert!(inspection.outcome().complete());
Ok::<(), &'static str>(())
}

Condition::primary() returns the location a condition is about and Condition::related() yields its related locations in report order, both as a ReportLocation. An absent primary means the condition has no single location, and an unavailable one means the report could not establish it. Source and sample locations carry their SourceId, pointer and any available byte span. Effective locations carry the root document of their effective-document space and a pointer, with no source id or span. Author and edit request locations keep their request key, pointer and any available plan span.

Catalogue::take_inputs consumes SourceInput::owned buffers; bounded buffers move into retained storage. Oversized spare capacity is reduced before retention, and retained capacity consumes the catalogue byte allowance. Borrowed inputs are copied into owned storage once. Identity metadata is validated before copying or acquisition. Limits changes supported finite acquisition, decoding and presentation allowances; zero and unsupported configurations are request errors.

Source views distinguish Field::Absent, Present and Unavailable. They expose all six classes, nested source groups, authored Property flags, Action input/output, Event output, data types, declared defaults, required map-entry syntax, choice branches and opaque JSON. They retain the full-description or direct-item context. Authored choice branches have no implied shared-quality inheritance; sdfRequired syntax has no implied resolved declaration identities. Source access inserts no effective defaults. Wider direct-item content remains accessible as raw JSON while unsupported typed meaning is unavailable.

Source and effective data descriptions expose minimum(), maximum(), exclusive_minimum(), exclusive_maximum(), multiple_of(), minimum_length(), maximum_length(), minimum_items() and maximum_items() as borrowed exact numbers. Positive steps and nonnegative integral lengths/counts distinguish malformed shape from absent or unavailable capability, without machine-sized count limits. Named pattern(), format(), sdf_type(), unit(), content_format() and unique_items() access preserves available scalar content without claiming syntax, registry, sample or consistency assessment. Unfamiliar selectors retain their text and unsupported meaning. constant() and declared_default() retain JSON without inserting values. These guarantees follow ADR 0022: Scalar constraints and characteristic states.

Property readable_characteristic(), writable_characteristic() and observable_characteristic() return Characteristic::Declared(bool) for an authored value in the inspected view, including inheritance, or SpecifiedDefault(true) for established effective absence. Source absence remains Field::Absent. The existing Boolean methods return the same values, and provenance remains available separately. A specified default characteristic is distinct from documentary default data.

Data-description nullable_characteristic() uses the same states for null admission. Full effective absence after inheritance/overrides has the specified value true; source absence stays absent. Direct-item nullable and its implicit default retain their unresolved meaning. Nullable, mandatory presence, documentary default and const are separate, following ADR 0024: Effective alternatives and nullable characteristics.

Grouping definitions expose repetition_minimum() and repetition_maximum() as authored exact numbers. Array-data descriptions keep their own minItems and maxItems qualities. A present class keyword outside an established base containment role has an unavailable typed child projection and retained raw JSON; its spelling alone does not establish an invalid model under the extensible framework.

An exact number retains its original JSON lexeme and offers sign, integrality, checked machine conversion and budgeted exact ordering. Scalar decoding limitations preserve raw source values and independent usable views. Duplicate decoded member names are refused at every depth under A002; no first or last value wins. These guarantees follow ADR 0012: Exact numbers and JSON input policies.

Checking identifies established source Given Name, document-block, definition-map and namespace-mapping problems. Names compare case-sensitively; spaces, slashes and tildes remain usable through escaped JSON Pointers. Literal data and opaque extension content do not acquire base definition roles merely because they contain familiar spellings.

Full data descriptions at Property and sdfData definitions, Action input/output, Event output and established nested properties or choice alternatives check parameter shapes recursively: strings, Boolean flags, numeric bounds, positive multipleOf, nonnegative integral lengths/counts, nonempty string-array enum, and map-shaped properties, sdfChoice, items and named full descriptions. Direct items descriptions check the restricted base shapes: number-valued minimum/maximum, nonnegative integral minLength/maxLength, text-valued type/format, nonempty string-array enum, and map-valued sdfChoice. Explicit object items check their properties map and each Full data description within it. Item choice alternatives are also Full data descriptions, so array alternatives and ordinary array-valued properties retain their recursive checks.

Map-data required receives its nonempty string-array shape check in Full data descriptions and Direct items descriptions when a reliable explicit type:"object" establishes its base context. Missing, nonobject, extended or unavailable type and unknown member identity do not establish that context. The borrowed required_entries() accessor presents nonempty authored syntax: Present alone does not establish an applicable object constraint, resolve sdfRequired, or check sample presence. Full descriptions retain documentary syntax access independently of applicability; Direct items descriptions retain their object guard. Empty lists and unavailable decoded entries remain typed Unavailable rather than authored absence. These source and effective distinctions follow ADR 0020: Owned effective views and nearest origins.

Surviving enum and sdfChoice conflict in both established roles independently of their values’ shape; ordinary null still occupies the quality, while possible reference-patch null deletion is deferred to composition. Unavailable decoded text does not become a nonstring error. Wider direct-item array, default, nullable, nested-items and other content stays available through raw JSON; needed typed meaning remains unavailable. It does not acquire full semantics or a blanket nested-array ban. Declaration requiredness, contradictions and sample admission remain separate unfinished work. The sdfType lexical restriction and wider extension meaning remain explicitly unassessed. These recursive role and provenance guarantees follow ADR 0020: Owned effective views and nearest origins.

The Information block’s title, description, version, modified, copyright, license and $comment entries receive string-shape checks. Established definitions and full data descriptions also check description, label and $comment; Direct items descriptions check their established description and $comment metadata. String contents do not acquire a semantic-version or SPDX requirement. The explicit expanded modified request additionally checks Gregorian dates and UTC labels, independently of composition, under the modified metadata contract. Its early Information pass records a reliable nonstring modified exactly once before unrelated traversal. Reliably absent info receives a nonblocking warning, following ADR 0003: Check findings and completeness. Strict warning policy changes the outcome disposition while retaining the warning’s severity and basis.

Unfamiliar unqualified Quality Names receive spelling advice. Familiarity covers the base spellings defined in the recorded RFC, including information qualities. Initial and expanded assessments give each assessed source at most one optional-vocabulary notice summarizing recognized qualified spellings, familiar names outside their established role and unfamiliar textual type, format or sdfType selectors. Its bounded observed_occurrences argument counts the occurrences actually inspected, which can be fewer than the source contains after a work limit. Full instead names and locates each inspected occurrence in its own notice, keeping observed_occurrences: 1 for source occurrences. It leaves out oma:id at its registered positions, because it checks that Recorded extension vocabulary itself. Both optional Full notices and unfamiliar-name warnings carry the decoded name in arguments.quality, also shown in human reports. The report contract describes bounded retention and omitted locations. Qualified spelling recognition establishes neither registration nor extension meaning. Given Names, namespace prefixes, literal const/default/enum content and opaque extension subtrees are excluded from Quality Name scanning. No registry snapshot or retrieval is implied, following ADR 0002: Recorded standards baseline.

Acceptance restriction A001 rejects sdfRequiredInputData at assessed vocabulary positions with guidance toward sdfInputData and an object input’s properties and required. The condition has acceptance basis A001, rather than an RFC-invalidity claim, following ADR 0008: Reject the historical Action input quality. A source composition patch’s null member is a deletion selector. A proven surviving non-null metadata or historical quality can retain a target-independent finding at a reliably established role; this does not establish the whole Effective definition. Unknown needed context and opaque keys remain deferred. Source inspection assesses no SDF vocabulary and remains available independently.

In established definition and data-description roles, any present sdfRef or unavailable member identity conservatively leaves possible merge/deletion context. Null members then cannot establish surviving qualities, including with wider reference forms. This uncertainty proves neither a valid reference nor resolved composition. An unsupported sdfRef spelling in an Information block or document map leaves its opaque content retained and does not import reference semantics into that role. These boundaries follow ADR 0006: Scoped reference failures and RFC 7396 Section 2.

Namespace mappings use generic RFC 3986 URI syntax, including percent escapes, bracketed IP literals, queries and fragments. Syntax checking introduces no scheme, DNS or retrieval requirement, and different documents may share a namespace URI. Grouping repetition counts must be nonnegative mathematically integral numbers; their shape check proves no grouping emptiness. In a source composition patch, null deletions are deferred to effective processing, while surviving names and definite non-null map/count overrides retain independent findings.

Before emitting structural or vocabulary findings, checking establishes the document’s declared critical-feature context. Reliably absent info, or a readable information map with reliably absent features or an empty feature array, permits ordinary base checking. Other declarations and unavailable relevant identities defer this source’s structural semantics, including namespace, metadata and A001 conclusions, with an explicit limitation. A readable text list of unsupported critical features receives its own explanation; wider or unreadable declarations receive a scoped inability-to-understand condition without a closed-grammar rejection. Supplied JSON decoding, duplicate-name refusal and the top-level map envelope remain independent; unaffected companion documents continue to receive their findings. Extension meaning remains unsupported, apart from the recorded value domain of oma:id.

Effective composition copies established definition and full-data targets, processes mandatory target-root references, then applies the consumer’s JSON Merge Patch without sdfRef before resolving surviving nested references. A consumer deletion can remove an otherwise unavailable nested reference. Opaque maps, Information blocks and direct-item imports do not gain full-definition meaning through map shape alone. Missing targets, cycles and unsupported reference forms leave affected portions explicitly unavailable, following ADR 0006: Scoped reference failures. A name reference selects the element at its pointer in the target document’s resolved model, for same-document pointers and CURIEs from other documents alike, so declarations that exist only through a copy can be referenced and required. Looking up the pointer composes each sdfRef on its path before descending, on the same work, node and reference allowances. Path compositions nested inside the lookups of other path compositions stop at a fixed stack bound of 32 levels, or the reference depth when that is lower, and exceeding it leaves the affected result undetermined with operation.limit. A copied sdfRef whose target, read in the context of the document that wrote it, is the copied definition or lies beneath it by pointer tokens relocates to the corresponding position in the importing definition and selects there in the resolved model. Relocation repeats at every enclosing copy boundary, so nested copies and target root chains follow the final importer’s refinements, while other copied references keep their original target. A target that a patch deleted is missing, with no fallback to the source, and a cycle through relocation or path composition is a scoped failure at the reference, following ADR 0036: Copied reference relocation.

Supplied CURIE composition uses the reference’s original namespace mapping and literal concatenation of its binding and reference tail. A copied CURIE keeps the mappings of the document that wrote it, even when the importer maps the same prefix differently, while one written in a composition patch uses the importer’s mappings even when its text equals the inherited one. A prefix that the writing document never mapped is the unmapped-prefix error at that original reference. Esdieff establishes a supplied target by exact decoded namespace text and a percent-decoded JSON Pointer fragment, without URI normalization, relative-URL resolution or retrieval. The supported prefix subset is ASCII [A-Za-z_][A-Za-z0-9_.-]*; wider NCName characters retain an explicit capability limitation. Multiple documents may contribute different addressed definitions to one namespace. Each contributor addresses the pointer in its resolved model, and an ambiguous or unavailable import met while composing its path leaves the lookup unavailable. Multiple contributors to the same address remain ambiguous even with identical content. Reliable missing prefix mappings and established malformed reference syntax are errors; a mapped but unavailable target is incomplete. Each such error is one finding at the reference as written, however many copies or checked documents reach it, while an unavailable target is reported at each effective position it leaves unfinished. Fragment-bearing bindings retain every character during assembly, so unsupported assembled forms cannot silently select another address. These boundaries follow ADR 0023: Supplied global composition and dependency scope.

Global candidate discovery first establishes the context needed for a contribution identity. Clear-context reliable absence of defaultNamespace excludes a contribution; raw absence under unknown critical features does not. An unreadable acquisition, envelope or relevant member also remains an unavailable possible contributor. Such uncertainty can prevent a unique lookup without making that candidate an established imported dependency or assessing unrelated definitions and metadata. Catalogue checks independently assess every supplied source; selected checks independently assess roots and examine only surviving dependency content through the shared effective evaluator. Imports met while composing a contributor’s path to a global target are needed dependencies too. Explicit expanded modified assessment additionally examines info.modified once per distinct needed dependency source, without assessing its other Information qualities. All supplied attempts remain visible.

Catalogue::effective(EffectiveRequest::new(id).pointer("/sdfThing/Device")) returns an owned effective result borrowing the catalogue. Its typed definitions, groupings, affordances and data descriptions use the same established roles as source access. A selected opaque map retains generic JSON access; typed class collections require an established parent role that permits that class. Known collection entries yield (name, Field<handle>), so an unavailable entry retains accessible siblings. Generic JSON traversal preserves independently established subviews; generating a semantically incomplete containing subtree returns Unavailable. Original scalars retain exact source lexemes and locations.

InspectRequest::required_declarations(true) requests declaration relationships in the selected source or effective subtree of a Model source. Sample sources are rejected before definition lookup in either view; ordinary raw source inspection of a Sample remains available. The command equivalent is esdieff inspect --required-declarations. Report::required_declarations() is Absent by default; when requested its collection reports state(), complete(), unavailable_reason() and owners(). Owner syntax and reference/target views preserve known invalid, missing, ambiguous and unavailable relationships independently. Short names select every directly contained affordance/grouping class sharing that Given Name, including the empty name; true array entries select the carrying affordance/grouping. These relationships do not interpret map-data required or nullable as declaration optionality.

An established outside pointer target has a source Definition, a complete relationship and capability NotRequested; its effective Definition is Absent. Request Catalogue::effective explicitly to examine that target’s content. In-scope targets expose actual processed coordinates and refinements, with capability completion separate from relationship completion. An authored pointer to an outside reusable contribution does not acquire the coordinate of a copy inside the selected subtree. Pointer entries resolve at their coordinate in the resolved model in both views, so an importer’s pointer to a declaration that exists only through its copy is resolved, and a deleted one is missing. The source view reports such a target with its source Declaration contribution and capability NotRequested. The target’s source Declaration contribution survives map refinement and root data-description substitution, while content origins and importing consumer retain their existing meanings. A copied pointer whose target, read in the context of the document that wrote it, is the copied definition or lies beneath it relocates to the importing definition’s coordinate like a copied sdfRef and selects the declaration there with its own Declaration contribution. Deleting that declaration leaves the relationship missing, and a declaration reinserted at the coordinate is the one selected. Data-only requiredness can remain unavailable while independent short-name or outside-pointer siblings are resolved. Source matches remain partial when unresolved inheritance could add matching classes. These distinctions follow ADR 0026: Required declaration relationships and source evidence.

EffectiveModel::explanation(pointer) identifies nearest content contributors, including deletion. Its consumer() identifies the source importing sdfRef when a composition boundary is established, independently of content origins. A mandatory target-root chain keeps the outer consumer; a separately composed nested reference starts its own boundary. default_explanation(pointer) separately identifies established implicit Property capability and full-description nullable defaults with no fabricated source. Deleting inherited writable:false leaves the JSON member absent, retains its deletion explanation and yields the typed true default. Defaults are never inserted into source or composed JSON. Copied sdfRequired pointers in definitions keep their authored text and available typed requiredness, and relocate when their relationships are resolved; independent targets and directly contained short names remain distinguishable. Copied prefixed sdfRef and sdfRequired references are read with their authoring document’s mappings, and both relocate when they point into the copied definition. Whether a reference is copied follows its own sdfRef member or sdfRequired array. Only one written in the composition patch belongs to the importer, so patching a sibling quality such as a description leaves a copied reference copied, following ADR 0036: Copied reference relocation. A copied pointer into the copied definition from a full data description, including Action input/output and Event output, keeps the separate data-only limitation with unavailable typed requiredness, while independent constraints remain accessible. Direct-item requiredness meaning remains unestablished. These ownership and provenance guarantees follow ADR 0020: Owned effective views and nearest origins and ADR 0023.

EffectiveDataDescription::alternatives() yields (AlternativeId, Field<EffectiveDataDescription>) after actual reference composition and shared-quality inheritance. Choice names and enum occurrence indices retain identity; enum values become const alternatives without changing composed JSON. Surviving explicit qualities replace whole shared qualities. Reference-deleted branch qualities permit shared fallback, while ordinary const null remains a value. Nested collections derive after their final inheritance. Absent, known empty and unavailable collections differ from individually unavailable branches. Known partial branches retain accessible independent qualities, including inherited bounds, while inherited restricted donor qualities stay typed-unavailable until explicitly overridden. source_alternatives() remains the composed branch syntax without shared inheritance. Existing pointer selectors select composed JSON; derived branch origins use direct EffectiveJson::explanation(), quality_explanation(key) and default_explanation(key) handles. This bounded view follows ADR 0024: Effective alternatives and nullable characteristics.

Checking assesses both source definitions and surviving effective vocabulary through shared rules. Composed contexts can produce distinct effective observations, even when a contribution retains a source origin. An unchanged local source observation is skipped only with proof of completed source evaluation, identical role and clear feature context, and unchanged rule premises. Source optional-vocabulary notices retain their actually-inspected observed_occurrences meaning; effective notices omit that source-count argument. Full effective notices identify the effective position and retain the nearest source contribution as a related location.

The initial assessment retains all eight fixed areas. Full has established immutable membership: thirteen assessment areas in esdieff.full-model/1 and fifty-four model requirements in rfc9880.model/1, described in the model assessment inventory. Applicable unfinished work still limits requested completion. Source acquisition and inspection do not imply completion of a requested assessment. Effective inspection establishes only its selected view and necessary composition, without implicitly assessing Information metadata or model vocabulary. A selected inspection can pass while an acquisition outside its needed work failed; a global lookup requiring that candidate’s contribution identity retains uncertainty. Every candidate still appears in its report.

Reports use JSON report 1.0. Human and JSON output share outcome, source identities, scope, requested assessment, standards basis and policy. Checks identify A001 and A002 as their acceptance restrictions; standalone inspection identifies A002. Detail or payload omission preserves aggregate findings and semantic completion. The CLI exits with 0 for passed requested work, 1 for failed work, 2 for invocation/configuration errors, 3 for undetermined work and 4 for host/output failures.

Additional source-workflow condition codes have these stable meanings:

CodeSeverity and basisMeaning
document.envelopeerror, RFC 9880 Section 3A complete supplied JSON value is not a document map.
input.encodingincomplete, operationalUTF-8 decoding is unavailable; raw bytes remain retained.
input.unicode_unavailableincomplete, operationalA grammar-valid escaped non-scalar string cannot establish decoded scalar identity or text.
coverage.unimplementedincomplete, operationalA fixed requested assessment area has not been fully implemented.
inspection.unavailableincomplete, operationalThe one requested view-establishment operation remains unfinished.
name.colonerror, RFC 9880 Section 2.3.1A Given Name contains a colon prohibited in base SDF.
structure.group_shapeerror, RFC 9880 Section 3.3An established base definition group is not a map.
structure.definition_shapeerror, RFC 9880 Section 3.3An established base named definition is not a map.
structure.block_shapeerror, RFC 9880 Sections 3.1 and 3.2A document information or namespace block is not a map.
namespace.urierror, RFC 9880 Section 3.2 and RFC 3986 Section 3A namespace mapping is not a syntactically valid URI string.
namespace.defaulterror, RFC 9880 Section 3.2The default namespace does not select an existing mapping by its case-sensitive prefix.
parameter.positive_steperror, RFC 9880 Appendix C.1An applicable exact multipleOf is zero or negative.
data.string / data.booleanerror, RFC 9880 Appendix A and Section 5.2An established full-description or direct-item textual quality, or a data/Property flag, has the wrong JSON kind.
data.number / data.counterror, RFC 9880 Appendix A and Appendix CA numerical parameter has the wrong shape, or a length/count is not nonnegative and mathematically integral.
data.enum / data.enum_choiceerror, RFC 9880 Section 4.7.2 and Appendix AAn enum is not a nonempty string array, or both mutually exclusive qualities survive.
data.requirederror, RFC 9880 Appendix AIn an established explicit-object context, map-data required is not a nonempty array of strings. This is parameter shape, separate from sample-entry presence and declaration requiredness.
data.map_shapeerror, RFC 9880 Appendix AAn established collection, direct item or named full description is not a map.
data.number_unavailableincomplete, operationalA numerical parameter requires unavailable exact-number capability.
grouping.counterror, RFC 9880 Sections 2.2.1 and 6.3, Appendix AA grouping repetition count is not a nonnegative mathematically integral number.
structure.data_shapeerror, RFC 9880 Sections 5.3 and 5.4An established Action input/output or Event output data description is not a map.
structure.role_unavailableincomplete, operationalRetained content has no established base role at its position; extension meaning is unavailable.
grouping.number_unavailableincomplete, operationalExact numeric capability cannot establish the grouping repetition parameter.
structure.feature_context_unavailableincomplete, operationalThe declared critical-feature context cannot establish this source’s structural semantics.
metadata.stringerror, RFC 9880 Sections 3.1 and 4.6, Appendix AAn ordinary metadata quality is not a string in an assessed vocabulary position.
metadata.info_absentwarning, advice grounded in RFC 9880 Section 3.1A document has no Information block.
quality.unfamiliarwarning, advice grounded in RFC 9880 Sections 2.3.1 and 2.3.3An unqualified Quality Name is unfamiliar to the recorded base vocabulary.
extension.optional_unsupportednotice, operationalRecognized spellings or selectors whose optional meaning is unsupported at that position. Full names and locates each occurrence. Other assessments summarize them.
extension.critical_unsupportedincomplete, operationalA readable critical-feature text list declares unsupported meaning.
extension.feature_declaration_unavailableincomplete, operationalA wider or unreadable critical-feature declaration cannot establish its meaning.
policy.historical_action_inputerror, acceptance restriction A001An assessed quality uses the refused historical Action-input mechanism.
reference.unavailableincomplete, operationalA needed effective reference target cannot be established.
reference.effective_cycleincomplete, operationalA needed expansion revisits an active target.
interpretation.unresolvedincomplete, operationalA needed target role, reference form, data-only requiredness or import meaning is unresolved.

Input size, decoded allocation, traversal, number and diagnostic budgets are finite operation bounds. Conservative report accounting covers bounded metadata DTOs, retained conditions, serializer capacity growth and output buffers under supported internal JSON layouts. These allowances do not promise a hard process RSS ceiling.

For effective unit spelling and dated registry guidance, request Assessment::ExpandedUnits or CLI --assessment expanded-units-v1. Report::unit_guidance() retains the six fixed observation counts and completion independently of located details. Report::registry_knowledge(id) and UnitGuidance::source_edition() borrow actual-use section and raw-edition facts. An embedding may deliberately withhold recorded evidence while retaining independent spelling errors. See the unit contract, following ADR 0027: Unit names and recorded registry guidance.

For complete content-format declaration spelling, separate decimal identifier range and dated registration guidance, request Assessment::ExpandedContentFormat or CLI --assessment expanded-content-format-v1. The two added area statuses and existing requested coverage aggregates distinguish finished syntax from unknown registration or unavailable evidence. Report::registry_knowledge(id) borrows actual-use CoAP, media-type and HTTP-coding facts; RecordedRegistryPolicy::WithholdRecorded keeps independent spelling errors while honestly withholding needed evidence. Parameters have explicit excluded-meaning Notices; payload validation and protocol binding remain separate. See the content-format contract, following ADR 0029: Content-format declarations and recorded registry guidance.

Assessment::FullBaseline also checks Recorded extension vocabulary. oma:id on an sdfObject or sdfAction definition or a full data description must be a whole number in the CDDL uint domain. So 3303 and 3303.0 are admitted, while "3303", -1 and 3303.5 are extension.recorded_value_excluded errors whose basis kind is registration, citing the OMNA SDF Quality Names registry with oma:id as id. Either way Full assesses M028. Each effective coordinate is checked, including inherited and overriding values, and at these positions oma:id does not stop base meaning. Report::registry_knowledge("omna.sdf-quality-names") borrows the recorded OMNA evidence once a value was checked against it. Withholding recorded evidence lists that record as unavailable, reports no excluded value and leaves M028 undetermined. oma:id elsewhere and other oma: names stay unsupported extension vocabulary. See Recorded extension vocabulary, following ADR 0038: Recorded extension vocabulary.

For effective model pattern syntax, request Assessment::ExpandedPatternSyntax or CLI --assessment expanded-pattern-syntax-v1. Its nine-area inventory adds pattern-syntax/1 to the initial eight, with typed status independent of optional detail. Full binds the same syntax work to M047 and its pattern/format area; broader applicable meaning may remain unfinished. Other profiles, inspection and Sample retain their purposes. Limits::pattern_bytes, pattern_nesting and pattern_alternatives reduce the supported ceilings; original operation work/allocation still cover all patterns together. See the pattern contract, following ADR0014: Bounded partial ECMAScript pattern capability and ADR0028: Bounded effective model pattern syntax.

AuthorRequest::new(catalogue, request_key, generated_key, thing_name) owns an explicit composition recipe. Add namespace bindings and AuthorObject declarations selecting supplied Source IDs and decoded pointers, then call author(). AuthorRequest::from_plan accepts the same bounded JSON recipe used by esdieff author; number lexemes in refinements stay exact. AuthorResult::generated_document() exposes a candidate independently of its generation(), fidelity() and outcome(). Its catalogue() includes immutable supplied sources and a distinct Generated SDF document, ready for the ordinary check, effective and inspect operations. document_deliverable() applies the CLI’s established-fidelity and requested-check policy. Author reports use the additive author operation in report 1.1, with separate authoring and requested-check coverage. This follows ADR 0017: Reference-preserving sdfThing authoring.

An authored refinement’s ordinary EffectiveModel::explanation keeps inherited, overridden and deleted source contributors. AuthorResult::request_origin(generated_source_view) adds the exact logical recipe coordinate and an available original-plan span; typed requests have no plan span. AuthorResult::checking() exposes its optional requested assessment, outcome and coverage without reparsing JSON. The authoring unit, assessment areas, full-baseline requirements and separate inspection unit retain distinct count meanings. See the refinement and explanation examples.

EditRequest::new(catalogue, request_key, source_id, generated_key) selects one existing document. Add explicit present-member replacements or removals with with_edit, then call edit(). The result retains original source evidence separately from its active catalogue(), where the generated document substitutes for that source. Candidate bytes and editing fidelity remain inspectable independently of optional Model checking. The editing contract defines the admitted owners and qualities, exact preservation, request locations and report version 1.2.

ComparisonRequest::new(earlier, later) compares two Model revisions supplied as Catalogues with the same limits, and compare() classifies each difference between their corresponding groupings as breaking, compatible or undetermined from the Client’s side. Documents correspond by source key. The RevisionComparison result borrows both Catalogues and exposes typed differences with their Client directions, effective locations in each revision and nearest content origins. ComparisonRequest::acknowledgements(&acknowledgements) supplies Difference acknowledgements of intended differences, which keep their classifications while only unacknowledged differences decide disposition(). The revision comparison contract defines correspondence, classification, acknowledgements, the shared allowance and report version 1.4, following ADR 0039: Client-side revision comparison and ADR 0040: Acknowledged revision differences.

Catalogue::generate(GenerationRequest::new(document)) builds Generated values for every affordance description of one model document, and select(kind, pointer) narrows the request to one description. Each value aims at one Generation target, such as a minimum or a value just below it, and Sample-value checking settles it, so the GenerationResult gives each description’s values with their targets and admissions. The generation contract defines the targets, their order, the ceilings, the JSON Lines Trace entries and report version 1.5, following ADR 0041: Generated values settled by Sample-value checking.

Catalogue::check_trace(TraceRequest::new(document, trace)) checks a Recorded trace, a JSON Lines file of Trace entries, against one model document. The document is composed once and every entry is checked on its own, so a malformed line fails alone, and the TraceResult counts passing entries and lists failed and undetermined ones with their line numbers, labels and conditions located in the trace file. The trace contract defines the entry format, the outcomes, the bounds and report version 1.5, following ADR 0042: Recorded traces with independent entries.

Repeatable catalogue checks

A Check plan saves supplied files and named model checks, sample checks and revision comparisons. Run the included model-only example from the repository root.

cargo run -- check --plan examples/catalogue-check/plan.json
cargo run -- check --plan examples/catalogue-check/plan.json --format json

The example plan checks the whole catalogue and then the selected Count model with Full baseline assessment. Each case keeps its own requested scope, profile, warning policy and outcome. Initial is the default assessment and still discloses broader partial RFC coverage. A passed case establishes completion of its requested assessment. Failed checking may also be complete. Missing input and unsupported meaning, such as a Boolean sdfRef, remain explicit incomplete work.

The mixed example adds two samples of Count to those same model checks.

cargo run -- check --plan examples/catalogue-check/mixed-plan.json
cargo run -- check --plan examples/catalogue-check/mixed-plan.json --format json

Count admits 25 and rejects 101. The example exits 1 because rejection is an actual failed check. Naming a sample does not turn rejection into an expected success or establish whole-model validity.

Use your own model and samples

The thermostat plan is a runnable template for a device property. Its model describes a readable and writable target temperature from 5 through 30 degrees Celsius. The supplied value 21.5 is admitted and 35 is rejected.

cargo run -- check --plan examples/thermostat-check/plan.json
cargo run -- check --plan examples/thermostat-check/plan.json --format json

Both model checks pass. All four cases are complete, with three passed cases and one failed case. The run exits 1 because 35 exceeds the property’s maximum. The sample checks assess values against the property description. They do not send commands to a thermostat or simulate property reads or writes.

The same directory also supplies minimal, rich and deliberately limited thermostat variants with an offline Rust regression runner. See the device Catalogue for direct plans, named cases and the device-and-constraint coverage matrix.

Copy the examples/thermostat-check directory to start your own checks, then adapt the files together.

  1. Replace thermostat.sdf.json with your model and update its source path in plan.json if you rename the file. Relative paths resolve beside the plan, so the directory can move as a unit.
  2. Replace the sample files with one complete JSON value each. Use the value described by the selected property, such as 21.5, rather than a device protocol’s message envelope.
  3. Set each sample case’s pointer to the property in your model. The template selects /sdfObject/Thermostat/sdfProperty/targetTemperature with kind: "property". Other selections are described under Plan input.
  4. Give cases descriptive names. If you rename source keys, update the model case’s roots and each sample case’s document and sample references. Add or remove sample sources with their corresponding cases.

Run the copied plan with cargo run -- check --plan path/to/plan.json from the repository root. Check each case’s outcome and completion separately. A sample you intend to reject still produces a failed case and exit 1.

Compare revisions in the same run

A diff case runs a Revision comparison beside the plan’s checks, so one command and one run report cover a release. The rich door lock plan checks the rich model and compares it with the minimal one.

cargo run -- check --plan examples/door-lock-check/rich-plan.json
{
  "name": "Minimal to rich revision",
  "operation": "diff",
  "earlier": {"document": "minimal.sdf.json"},
  "later": {"document": "rich.sdf.json"},
  "acknowledged": "acknowledged-differences.json"
}

earlier and later each map a source key to a literal file. Documents with the same key correspond, and a key on only one side is a removed or added document. Use each document’s path within its revision’s directory as its key, so that an acknowledgement file written for esdieff diff --old DIR --new DIR works unchanged. Two single files compared directly share the key document, which is why the door lock plan uses it.

The comparison reads its documents only when the case runs, into two Catalogues of its own, exactly as direct esdieff diff does. They never join the plan’s sources, so check and sample cases never see an earlier revision and its definitions cannot make references ambiguous. The optional acknowledged file holds the same Difference acknowledgements that esdieff diff --acknowledged reads. The door lock file acknowledges the added jammed state and the broader credential pattern, so the case passes while its classification stays breaking.

Plan input

Plans use schema esdieff.check-plan and string version 1. Both sources and cases are nonempty arrays. Every source has exactly key, path and role. Keys are unique after JSON decoding. Role is model or sample, and at least one source must be a model. Sample-role files are retained acquisition attempts but contribute no definitions to model checks.

Each model case requires a unique name, operation: "check" and scope. Use {"kind":"catalogue"} for all model sources, or {"kind":"selected","roots":["count"]} for one or more explicit model keys. Other supplied models remain dependency candidates. assessment accepts every profile supported by direct check, defaulting to initial-v1. strict_warnings is a Boolean, defaulting to false. Recorded registry knowledge uses the native profile defaults.

Each sample case requires a unique name, operation: "sample", document, kind, pointer and sample. document names a model key and sample names a sample key. kind is property, data, action_input, action_output or event_output. pointer is the effective-definition JSON Pointer, at most 8192 UTF-8 bytes, with ordinary ~0 and ~1 escapes. Action and Event pointers select the declaration, and kind selects its input or output data description. strict_warnings defaults to false. Sample cases use the existing Sample inventory. There is no model assessment selector or expected-result field. JSON null remains a supplied sample, and no default or sample value is inserted.

Each diff case requires a unique name, operation: "diff", earlier and later, and accepts an optional acknowledged path. Each side is an object of 1 through 256 members whose names are source keys of 1 through 256 UTF-8 bytes and whose values are nonempty paths. Duplicate decoded keys are refused. scope, assessment and strict_warnings do not apply. The comparison uses the native defaults, including the recorded registry evidence. Diff documents are acquisition attempts of their case, separate from plan sources, so naming a plan source’s file there acquires it again. A plan still needs a model source, so a comparison on its own belongs to direct esdieff diff.

Paths are literal local files. Relative source, diff document and acknowledgement paths use the parent of the CLI-supplied plan path made absolute. A symlinked plan uses the symlink’s parent, not the target’s directory. There is no globbing, variable expansion, discovery, remote retrieval, plan inclusion or stdin substitution. Repeated references to one key share one acquisition attempt. Different keys remain different attempts even for the same path or bytes. Reading a plan changes no input file.

Plan mode permits --format human|json and the ordinary color controls. Direct source arguments, roots, assessment and policy options are incompatible. Directory discovery options are also incompatible. Use a separate direct check with directory discovery when source selection should follow the current collection rather than the plan’s saved literal paths. Malformed or unreadable plans, duplicate decoded JSON members, unknown fields or versions, invalid roles, aliases, profiles or pointer syntax, empty or oversized diff sides, and acknowledgement files that cannot be read or decoded are configuration errors with exit 2 on stderr and no run report.

A content-dependent selection mistake, such as a definitely absent description or an established wrong class, becomes a named case request error. Later cases continue. Acquisition/decode failures and unavailable needed meaning remain native domain results, with the ordinary dependency rules and finite allowances. A diff document that cannot be read is such a result too. Its source row records the failed acquisition, and the comparison leaves the content it would have held undetermined.

Run output

JSON is plain under every color setting. Its separate schema is esdieff.check-run, version 1.1, with plan, sources, cases and summary. Version 1.1 adds diff cases to 1.0, and every run report is emitted at 1.1. plan records its acquisition path and accepted schema/version. Source rows use the existing report contract meanings and list the plan sources only. Cases retain plan order, with name, operation, request, state: "report", native outcome, baseline and policy. Sample cases also retain native admission as admitted, rejected or undetermined. Diff cases also retain a mandatory classification, the native result.outcome of breaking, compatible or undetermined, which acknowledgements leave unchanged while the disposition in outcome follows them. That outcome also counts the comparison’s Version warnings, which never change the case’s disposition, and the native diff report keeps its own version 1.5. request is the native requested scope, selector and assessment/inventory record, or for a diff case the comparison identity and both revisions’ scopes. A whole native report is optional. A diff case’s report is the native diff report with both revisions’ sources. When it cannot fit, report_omission.reason is run-report-budget. Native diagnostic truncation inside a retained report is a separate presentation limitation. Neither form of omission changes the case’s outcome or completion.

A case with state: "request_error" has exactly name, operation, request, state and request_error. Its request records the supplied native selector and sample IDs and strict_warnings. request_error has stable operational code: "sample.request", an explanatory message and location: {"kind":"plan","pointer":"/cases/N"} using the zero-based case index. It has no native outcome, baseline, policy, admission, coverage or report. Every source attempt remains visible even if every case is a request error.

summary counts total, passed, failed, undetermined, request_errors, complete_cases, incomplete_cases and omitted_reports. Sample admission counts admitted, rejected and admission_undetermined are independent of disposition, and are zero in model-only runs. Counts describe cases, not combined RFC obligations. A diff case counts by its native disposition after acknowledgements, so an acknowledged breaking comparison is a passed case. Request errors count as incomplete. Complete and incomplete counts sum to total cases, and failed cases can be complete. The aggregate complete flag requires every case to have a complete native result. verdict follows invalid before failed before undetermined before passed, with exits 2, 1, 3 and 0. Invalid describes request configuration, not SDF validity. Host reporting or output failure exits 4 and makes no success claim for partial or unavailable output. Human output lists the same named results and coverage, with accessible findings and locations when detail fits. A diff case adds a Classification: line and the native human diff report.

Finite allowances

Plans are at most 1 MiB, with the ordinary native JSON depth, node, decoding and allocation ceilings. There are at most 64 cases and 256 declared sources across both roles. Keys and names contain 1 through 256 UTF-8 bytes. Resolved source paths, plan identity, names and repeated references undergo a separate 1 MiB control-metadata admission before copying. Diff keys, diff document paths and acknowledgement paths count there as source keys and paths do. Ordinary Catalogue input and metadata admission also applies.

The entire mandatory envelope is reserved before acquiring sources or running cases. Its conservative reserve uses six bytes per control-metadata byte for escaping, 4096 bytes per source and per diff document, 16 KiB per case for native request, outcome, baseline/knowledge, policy and classification, and 16 KiB for the fixed run envelope and summary. An envelope that cannot fit fails configuration admission. Optional detail uses only the unreserved remainder of the 8 MiB complete-output ceiling.

Each acknowledgement file is read and fully decoded during admission, after the envelope fits and before any source is acquired. A file is at most 1 MiB, and a plan’s files together are at most 4 MiB. A diff case runs on its own native operation allowance, so its comparison spends nothing of the plan Catalogue’s work. Each diff document’s control metadata covers what its revision’s Catalogue admits for it, so an admitted comparison always fits its native report envelope.

The plan’s native decoder retains its bounded original input and parsed view. Control storage adds at most the admitted metadata, bounded case/source/document slots and the acknowledgements decoded from at most 4 MiB of files. The aggregate reserves one 8 MiB output buffer. Only one native case is active at a time, with its ordinary processing and presentation allowances. A diff case’s two Catalogues are released when the case ends. One native serialization is transient, with at most 8 MiB of content and a separate 16 MiB capacity allowance for String growth. Human rendering starts after that JSON serialization is released. The source envelope is appended directly without another whole-source formatting buffer. Borrowed raw fields and whole native JSON avoid a second full aggregation JSON graph or floating-point conversion. No native work allowance is replenished within a case.

Selectors and sample aliases are included in control-metadata admission before copying. The fixed case reserve also covers request-error messages up to 1024 bytes, tagged records and locations. One case record’s DTO and encoding use a separate 128 KiB staging allowance, covering the fixed fields and worst-case escaping of the ordinary 8192-byte selector. Source-view inspection supplies the native source metadata before cases start. It uses the same transient serialization allowance and releases its report before any case executes.

Check a local model collection

Direct check can select model files from explicitly supplied directories. Run the mixed collection from the repository root.

cargo run -- check --directory examples/directory-check --format json
cargo run -- check --directory examples/directory-check --recursive --exclude draft --format json
cargo run -- check --directory examples/directory-check --recursive --exclude draft --root examples/directory-check/device.sdf.json --format json

The shallow command selects device.sdf.json and types.sdf.json. Recursion with the exclusion adds nested/status.sdf.json. The selected-root command checks the device and its needed shared type, while the nested document remains a supplied candidate. Each command emits one ordinary model report. Sample JSON, Check plans, unrelated JSON and the suffix lookalike are not selected. Recursing without the exclusion includes the deliberately invalid draft and exits 1.

Repeat --directory DIR to select several collections. Positional files and one - stdin document can accompany discovery. Explicit files need no naming suffix. Their order is preserved, followed by each directory’s selection in option order. Within each directory, accepted relative paths are sorted by exact native encoded path bytes. Ordering is repeatable for unchanged arguments and tree on the same platform. It gives no reference-resolution precedence.

Selection matches regular files whose final filename ends exactly in the case-sensitive suffix .sdf.json. Without --recursive, only immediate entries are inspected. Matching hidden files and recursive hidden directories follow the same rules. There are no implicit exclusions or content sniffing.

Repeat --exclude RELATIVE_PATH to exclude a literal file or an entire subtree. The same exclusions apply independently relative to each supplied directory, and a subtree is pruned before type inspection or descent. An exclusion must be a nonempty relative component path without a root, . or .. component. Matching is case-sensitive on native components. There is no globbing, variable expansion, regular-expression or ignore-file interpretation. A nonexistent exclusion is harmless. Explicit file inputs are unaffected.

Directories, explicit files and --root paths resolve from the invocation directory. A discovered Root document must be named by its joined acquisition path, such as models/device.sdf.json for --directory models. Roots are never chosen automatically. Missing or multiply matched roots are invocation errors. Catalogue scope checks every supplied document, including unused definitions. Selected-model scope checks explicit roots and the dependencies needed for their checks, following ADR 0004, Supplied catalogues and checking scope.

An explicitly supplied directory may resolve through a link. Its displayed acquisition paths retain that spelling. Descendant file and directory links, including platform link equivalents, and known special files are skipped. Native paths select and open files even when a display label is omitted or uses Unicode replacement.

Each supplied directory must select at least one matching file after exclusions. Discovery refuses native-file overlap with another discovered or explicit file, including aliases and hard links. Exclude the automatic duplicate or remove the overlapping input to select one attempt explicitly. Explicitly repeated file inputs remain distinct attempts. Physically different files with equal bytes remain distinct sources and can retain ordinary namespace ambiguity.

Preparation has fixed ceilings, following ADR 0009, Bounded processing and reporting.

Preparation allowanceCeiling
Directory requests256
Literal exclusions256
Observed entries across all requests, including ignored and repeated work10,000
Recursive directory depth below each explicit root64
Assembled source attempts, including positional files and stdin256
Retained discovery path and option metadata, including repeated representations1 MiB

An included subtree beyond a ceiling fails preparation. Excluded subtrees are not enumerated. The ordinary Catalogue acquisition, parse, semantic-work and report budgets still apply separately. There are no discovery tuning flags or unlimited mode.

All option validation, enumeration, overlap checks, root selection and assembled metadata preflight finish before model content or stdin is read. Missing, wrong-kind, unreadable or empty directories, inspection failures, overlaps, invalid roots and exhausted allowances exit 2 with bounded stderr and empty stdout, including under --format json. They produce no partial Catalogue report and assert no RFC violation.

After successful preparation, a selected file that cannot be read or decoded remains an ordinary source result in the report. Failed and incomplete checks, warning policy, coverage, diagnostic omissions, color and output-failure exit 4 retain their existing report contract. Directory discovery is a bounded filesystem observation rather than an atomic snapshot. It changes no original bytes and promises no cross-file content consistency.

--recursive and --exclude require a directory input. Discovery options apply only to direct check and diff. Saved Check plan version 1, inspect, sample, author and edit do not accept them. Discovery adds no Rust filesystem API, report schema, assessment inventory or standards interpretation.

Compare two collections

esdieff diff --old DIR --new DIR prepares each Model revision’s directory with these rules. --recursive and --exclude apply to both sides alike. Each side is prepared separately, with its own ceilings and overlap check, so a directory can be compared with itself. Both sides finish preparation before either one’s content is read.

A document’s source key is its path relative to its directory, with components joined by /, such as nested/status.sdf.json. Documents with the same key correspond, so a moved or renamed document reads as a removal and an addition. A relative path that is not UTF-8 or exceeds the 256-byte source key cannot pair documents and is an invocation error. The revision comparison contract describes the comparison and its report.

Pinned document acquisition

Use esdieff acquire to save one deliberately selected public GitHub file as unchanged local bytes. Select its complete commit and establish the expected raw-file SHA-256 from separately reviewed source evidence before acquisition. The resulting Acquired snapshot is an ordinary input for offline checking, inspection, editing and literal Check plans. This follows ADR 0035: Explicit pinned document acquisition.

esdieff acquire --github OWNER/REPOSITORY --commit COMPLETE_40_HEX_COMMIT \
  --path repository/relative/file.sdf.json --sha256 EXPECTED_64_HEX_SHA256 \
  --document-output snapshot.sdf.json --format json

Every required option occurs exactly once. --format human|json is optional and defaults to human. --report-output RECEIPT_FILE selects a separate native file, and omission sends the receipt to stdout. Repeated, missing, unknown and unsupported options and positional model inputs are invocation errors. The document always needs a named native file. Acquisition offers no replacement flag or request plan.

Add --report-output acquisition.json to the command above to retain its JSON receipt in a new file. Use a different name for a human receipt. Both formats retain the same acquisition outcome and 64 KiB ceiling.

The repository has an owner and repository name. The commit is a complete 40-hex identity and the expected SHA-256 is 64 hex digits. The repository path excludes empty or dot segments, backslashes, absolute paths, controls, queries and fragments. Accepted UTF-8 path segments are encoded into the fixed https://raw.githubusercontent.com origin. SDF namespace URIs never select retrieval locations.

Request validation and native destination preflight finish before retrieval. Source metadata obeys applicable existing finite Source field ceilings, and the whole request is at most 64 KiB. Preflight also reserves worst-case escaping space for every mandatory receipt identity within the complete 64 KiB receipt envelope. Identity that cannot fit is rejected rather than clipped. Named outputs must be new, distinct native filesystem destinations. Existing files, aliases and collisions are refused. Display labels never reopen paths. Native non-UTF-8 destinations retain their actual same-platform identities.

Transport and content

The operation verifies HTTPS and sends no credentials, cookies or authorization headers. It does not follow redirects or retry. It requests identity content encoding, refuses other encodings and accepts only a complete HTTP 200 body. Authentication, other origins and proxy configuration are outside this operation.

The body ceiling is 4 MiB and the total header ceiling is 64 KiB. The connection deadline is 10 seconds and the whole-transfer deadline is 30 seconds. Streaming work and transport buffers are bounded, including responses without a trustworthy length. Oversize, incomplete and deadline-exhausted responses fail acquisition.

SHA-256 covers the exact complete response bytes. The document is committed only after comparison with the independent expected digest. Acquisition never parses, repairs or regenerates JSON. Empty bytes and malformed JSON are valid acquisition results when explicitly selected by a matching digest. Their later ordinary decode and Model checking outcomes remain separate.

Bytes are staged privately beside the document with bounded writes. Commit cannot replace an existing or concurrently created destination. Task-created staging removal is attempted after failure and after commit. Cleanup failure identifies retained staging, preserves any earlier failure and discloses whether a verified document was committed. Host failure does not promise removal.

Staging identity is checked before cleanup. That check and unlink are separate filesystem operations, so a further change to the staging name can race cleanup. Cleanup is not a transaction over the mutable directory.

Acquisition pins each native destination’s parent directory during preflight. Staging, document commit and named receipt creation use that directory’s retained identity, so an ancestor alias introduced later cannot redirect a write. Destination rechecks refuse changes observed before delivery. Named receipts use exclusive creation and bounded writes. Failed receipt delivery can leave a partial file, which is disclosed through stderr and exit 4 rather than treated as complete evidence.

Acquisition receipts

Human and JSON receipts express the same authoritative outcome. A JSON receipt is an object with schema equal to esdieff.acquisition and version equal to 1.0.

FieldMeaning
source.repositoryRequested OWNER/REPOSITORY
source.commitComplete requested commit identity
source.pathRequested repository-relative path
source.uriEncoded fixed-origin retrieval location
source.expected_sha256Independently supplied expected raw-file digest
result.statusacquired or failed
result.completeWhether acquisition completed successfully
result.document_committedWhether the verified document was committed
result.actual_sha256Lowercase digest of a complete transferred body, otherwise null
result.byte_countExact nonnegative complete-body byte count, otherwise null
result.failuresOrdered objects containing phase and message
document_outputReadable label and exact native_bytes array
staging_outputRetained document staging identity, or null

Native bytes are integers from 0 through 255 and represent a same-platform path identity, not a portable path serialization. A successful receipt has status acquired, complete and document_committed true and no failures. A complete digest-mismatching body retains its actual digest and count. An incomplete body records null for both.

Stable failure phases are transport, http, limits, digest, stage, commit, cleanup and receipt. Their order preserves causes, such as document commit failure followed by cleanup failure. Human message wording is explanatory rather than a stable identifier. Mandatory outcomes and identities take priority over optional explanatory detail within the 64 KiB envelope.

Human receipts follow the shared --color auto|always|never and --no-color controls, accepted before or after acquire. In auto, a receipt on terminal stdout can be styled, while redirected stdout and a --report-output file stay plain. always can style a human receipt file, and never removes all styling. Removing the style sequences gives exactly the plain receipt. If styling would push a receipt past the 64 KiB envelope, the plain receipt is delivered instead, so no detail is lost. JSON receipts and downloaded document bytes are identical in every mode.

Every valid, destination-preflighted request attempts one receipt after acquisition success or failure. Invocation and preflight errors write explanatory stderr without a receipt or retrieval request. A failed receipt delivery can leave partial evidence. Stderr identifies the receipt failure and whether a verified document exists. The document and receipt have no cross-output transaction.

Receipt delivery failure uses stderr and exit 4 as the authoritative outcome. Written bytes alone do not establish complete delivery, including when a later identity check finds that the requested path changed. A verified document commit remains recorded even if its requested path subsequently becomes unavailable or resolves elsewhere.

ExitOutcome
0Verified document committed and complete receipt delivered
1Transport, HTTP, limits or digest failure with receipt delivered
2Invocation or destination preflight error
4Staging, commit, cleanup or receipt delivery failure

Any applicable host-output or cleanup failure takes exit 4. A document already committed before receipt failure remains available. A partial receipt is not complete acquisition evidence.

Offline use and refresh

Ordinary CLI checks record their actual local file acquisition path. Library callers can explicitly provide the receipt’s URI, commit and digest through existing SourceInput::acquisition_uri, version_token and digest metadata. No operation automatically loads a receipt.

Checking selects no implied Root document, retrieves no unsupplied reference and gives repeated or overlapping contributors no deduplication or input-order precedence. These are the existing Catalogue and scoped-reference rules. A refresh deliberately selects newly reviewed revision and digest values and a different destination, leaving prior bytes available for identical replay.

The pinned OneDM example records independent source identity, retained notices and reproducible offline use. Historical interface examples with an unknown exact pre-RFC dialect are not current RFC-conformance or real-device acceptance oracles.

Model meaning assessment

FullBaseline establishes the interpretation of effective data descriptions under the immutable rfc9880.model/1 inventory. This work uses the same composition, roles and finite operation allowance as model checking. It neither requests a sample nor searches for a value satisfying the description. The distinction between assessed meaning, findings and unfinished work follows ADR 0003: Check findings and completeness.

Ordinary scalar descriptions

The scalar observations are made in the owning effective description, including the final inherited qualities of each effective alternative:

ObligationEstablished model meaning
M042number, mathematical integer, Unicode-scalar string, and boolean selectors have their base information-level interpretations. Mathematical integer meaning includes a value written 10.0.
M043An available ordinary scalar const fixes one exact value under the adopted equality contract. Numeric tokens retain mathematical value, strings retain decoded scalar identity, and Boolean and null constants retain their respective meanings.
M045Available exact numeric parameters establish inclusive and exclusive bounds and the positive integer-multiple meaning of multipleOf. Nonpositive steps and malformed parameters retain their existing definite findings.
M046Available exact nonnegative integral text lengths bound Unicode scalar counts inclusively. Supplementary characters count once; combining characters retain their individual scalar identities. Malformed parameters retain their existing definite findings.

Absence of type imposes no authored type or origin. It does not prevent an otherwise established numeric parameter or ordinary scalar constant from having meaning. Independent formal numeric and literal admission belongs to M035-M037, following ADR 0032: Formal model admission and the formal admission contract. For example, exact mathematical meaning for a count of 18446744073709551616 remains established when Full separately finds its exclusion from the imported CDDL uint domain. Extension-only final constants retain unavailable extension and const meaning, even when their framework literal admission is assessed. Ordinary type or const contradictions and inverted bounds can have established meaning and existing advisory findings; meaning assessment does not prove general satisfiability.

Reference composition and final alternatives determine the context. Established nonempty Choice and Enum collections supply the final descriptions whose meaning is assessed. Their shared owner and its original quality descendants do not impose additional semantic constraints. An explicit branch quality replaces the shared quality as a whole, including properties maps; surviving inherited qualities remain needed in every final branch. A pattern or const replaced in every branch therefore requests no additional matching or denotation capability. Source grammar and existing registry guidance remain independently checked, and an owner’s documentary default remains stated. Unknown, malformed and empty collections retain their existing handling. Restricted Direct items retain their admitted scalar vocabulary; wider retained qualities and their inherited donor meaning do not become Full meaning solely because a final alternative is Full. Explicit supported overrides are assessed in that final context, following ADR 0024: Effective alternatives and nullable characteristics.

Declared Extension features, unknown values of base qualities, unavailable interpretations, origins, member identities, scalar values or numeric magnitudes leave the affected observations undetermined. Independently established descriptions retain their own observations. Required semantic work is charged before scanning the description; exhausting it leaves requested work unfinished. Diagnostic or report omission does not change established meaning.

Undeclared extension vocabulary leaves the base meaning of its description intact, following ADR 0037: Undeclared extension vocabulary. That is a qualified or unqualified Quality Name outside base SDF, such as acme:note, sdfProtocolMap or a misspelled minimun, in a document that declares no Extension feature. Full scalar and compound meaning and contextual equality are established as if the quality were absent, and so are the declared-value consistency and numeric advice of the expanded assessments. Its own meaning stays unsupported, so M028 remains undetermined wherever it occurs, and its existing notice or unfamiliar-name warning is retained. A base quality outside its role, such as a wider Direct item quality, is not extension vocabulary and keeps its unfinished outcome. So do unknown values of base qualities, documents that declare an Extension feature and definitions composed from them. Reports name the reading as described in the report contract.

Initial and explicitly expanded assessments retain their existing scopes. FullBaseline requirement statuses remain available through typed report accessors even when optional detail is omitted. Human and JSON output preserve the same completion, disposition and inventory meanings described by the report contract.

Compound descriptions

An established Full array or map selector supplies its ordinary structural meaning for M042. M050 follows every authored final item description; M053 follows every authored final property description, including optional properties. Empty or passing sample values provide no credit for these model obligations. Nested Full properties and final alternatives can describe arrays; wider Direct items retain their own vocabulary and unavailable inherited meanings.

M051 establishes inclusive exact mathematical item counts, separately from formal CDDL admission in M037. M054 establishes decoded mandatory entry names under an explicit map description. Required entries need no property description, described entries remain optional unless required, and other entries remain unconstrained. Malformed parameters retain their existing findings; understood invalidity can still be assessed work.

M052 establishes adopted contextual equality capability for ordinary items and the supported canonical byte-string, opaque UUID, Gregorian-date and dated date-time conventional domains, recursively through maps, arrays and every final Choice interpretation. False uniqueness requests no comparison capability. It does not select whichever alternative admits a value or supplies a preferred equality result. Declared Extension features, unknown base values, base qualities outside their role and unsupported abstract interpretations remain unfinished, while undeclared extension vocabulary does not affect comparator capability. Every candidate at the same projected item or property must have compatible equality meaning. A missing description supplies ordinary unconstrained meaning, so it cannot silently select another alternative’s abstract interpretation. Distinct properties can retain distinct compatible meanings. Known time or URI names do not establish complete comparison capability for every representation; generic Unix-time equality retains the negative-coordinate gap. This is model capability assessment, not a theorem that every possible pair can be decided within any configured allowance.

UUID, Gregorian-date and dated date-time comparator capability require an established Full interpretation with known effective nullability in every relevant alternative. Known absence uses the Full default of true; explicit true and false are also supported. Null equals null and differs from an established nonnull value in that compatible format. Two nonnull dates must each establish valid Gregorian denotation before comparison; the same calendar date is equal and different calendar dates differ. Dated date-times compare their established UTC instants with exact fractions and distinct inserted-second slots under ADR 0018. Model capability does not assert that every possible dated operand has available adjustment knowledge. Unavailable or restricted Direct nullability stays undetermined. Model-only capability assessment does not parse a sample or record consultation of representation facts.

Actual formatted null constants can establish M043 in compatible civil, URI, URI-reference and UUID contexts. Null/null needs no nonnull representation scan; a mixed pair needs the nonnull operand’s established denotation. Invalid or uninterpreted operands retain unfinished equality. These null cases do not fill the nonnull time or URI comparator gaps in M052. Equality remains separate from admission, including when nullability excludes the constant.

For compound M043, contextual equality examines the actual effective const and its needed subtree against itself. This establishes that stated value’s denotation and equality capability without inventing a sample, checking its admission or proving satisfiability. Invalid abstract representations remain undetermined. The shared const is superseded by final alternative constants. The rules follow ADR 0015: Bounded value equality in a resolved data context and ADR 0016: Selected samples with explicit admission and coverage.

Every description, alternative and actual const uses the original request’s semantic work, allocation, numeric and equality allowances. Fixed owner costs are reserved before the Full interpretation phase; traversal capacities and growth are charged before allocation. No child or alternative refills an allowance. Limits keep the affected work unfinished, while optional report omission preserves established observations.

Patterns and known abstract interpretations

M048 establishes available modeled Unicode, unanchored matching by compiling the surviving effective pattern with the adopted matching implementation. It supplies no subject and invokes no match. M047 owns syntax independently; a matching-only capacity can leave M048 unfinished with syntax assessed. A pattern admitting no text, such as (?!), still has known matching meaning. Original worker, allocation, engine, interrupt and duration allowances remain shared. Compilation does not guarantee runtime capacity for arbitrary future subjects, following ADR 0014: Bounded partial ECMAScript pattern capability.

M026 and M027 establish the known byte-string and Unix-time model interpretations, and M049 establishes the six known base format interpretations. These observations require no constant, sample, denotation or temporal fact. Absent type does not prevent recognition of the named model meaning. A conflicting explicit type or combined abstract selectors can leave affected interpretations unavailable without erasing independently established type or numeric meaning. Actual special constants use their borrowed contextual denotation and self-comparison for M043. An unsupported URI scheme, unavailable temporal slot or negative POSIX denotation can therefore leave M043 unfinished while the named model interpretation is assessed.

Known declarations no longer block unrelated base constraints. Byte text qualities retain their specific limit: an authored length or pattern does not establish an encoded-text or decoded-byte interpretation, so affected M046 or M048 stays undetermined. Content-format declaration meaning belongs to M024; unknown payload equality stays scoped to M043 and M052. Neither declaration recognition nor comparator-capability assessment records actual operand or external-knowledge consultation. These limits follow ADR 0007: Generated SDF and sample JSON, ADR 0018: Civil date and time sample conventions and ADR 0019: URI, URI-reference and UUID sample conventions.

Recorded extension vocabulary

FullBaseline checks oma:id, the first Recorded extension vocabulary, under ADR 0038: Recorded extension vocabulary. Its registered CDDL sockets place it on sdfObject and sdfAction definitions and on every full data description: sdfData, sdfProperty, Action input and output data, Event output data, object property entries and choice alternatives. At those positions it does not stop the base meaning of its definition, and Full checks its value against the CDDL uint domain of ADR 0032: Formal model admission. A whole number from 0 through 2^64−1, such as 3303 or 3303.0, is admitted. A string, a negative or fractional number, a number above that range or any other JSON value is an extension.recorded_value_excluded error. Its basis has kind registration, the citation OMNA SDF Quality Names registry and the id oma:id, and it is owned by M028 in full.critical-extensions/1. Either way M028 is assessed. On an sdfEvent or sdfThing definition or a Direct item, oma:id stays undeclared extension vocabulary, and so does every other oma: name. The check covers value admission only, not whether an ID names a real LwM2M Object or Resource.

Like unit checking under ADR 0027: Unit names and recorded registry guidance, the check visits each final effective coordinate, including inherited values at every consuming definition, the importer’s overriding value and final alternatives. An excluded inherited value is reported once for each definition that copies it, and an importer’s whole-number override clears it. A null deletion removes the value from the effective definition. An unavailable value, an unfinished composition or exhausted work leaves M028 undetermined. The full-baseline optional-vocabulary notice leaves out oma:id at its registered positions. Initial and expanded assessments neither check it nor list its record, and their notice still counts it.

Where a FullBaseline check consulted the recorded evidence, a conclusion that set oma:id aside relies on no further reading. Where a report did not consult that evidence, such a conclusion relies on undeclared-extensions-ignorable/1 from ADR 0037: Undeclared extension vocabulary, and the report names it as the report contract describes. That covers the numeric advice and declared-value consistency of the expanded assessments and a FullBaseline check that withholds recorded evidence.

The check consults Recorded registry evidence omna.sdf-quality-names and lists it in baseline.registry_knowledge once a value was compared with the recorded domain. A caller that withholds recorded evidence gets that record as unavailable with reason caller_withheld, no value is reported as excluded and M028 stays undetermined. The evidence combines two sources, both retrieved on 16 October 2026. The IANA SDF registry XML was retrieved at 2026-10-16T08:38:44Z. Its SDF Quality Name Prefixes registry holds one record, oma, dated 2026-05-12 and referring to the OMNA registry. The XML’s SHA256 is 0fdb79625d83a034b53ef15a007bb07a0e695bb58a60996866641acb5c06333e, and its raw bytes are a test fixture. The OMNA SDF Quality Names registry page was retrieved at 2026-10-16T08:38:45Z, with server modification date 2026-10-15 and raw SHA256 98098ac43cd36acca64e73e95b78bc3caca10f9c9d174f431c935d413423a62f. The site’s terms leave the raw page out of the repository. Its introduction, registry table and CDDL are kept as extracted text of 810 bytes with SHA256 42c8be5e61ce56b45529160ec4e51d9cdaa4780cd5099948209f8c61c5b80b2f. Extraction policy esdieff.recorded-extension-vocabulary/1 writes one row per registered Quality Name, name<TAB>sockets<TAB>type<LF> with sockets in CDDL order and no header. The single oma:id row occupies 79 bytes with SHA256 58b2e81f1a27e35f2156f79c3361dc4fcd57d353831d3e62d466dec021392656, which is the record’s digest. Its snapshot is omna.sdf-quality-names/2026-10-16/58b2e81f1a27e35f, its scope oma-quality-names and its entries_count 1. The raw_digest and source_updated describe the OMNA page. A test compares the recorded positions, value domain and canonical bytes against both captured sources. Production reads neither.

The sixth record grows the full-baseline registry reserve. One more record map and its text add 4608 bytes to the Full extension bound, so D is 62792 and 2D+208=125792=4E with E=31448. Six synthetic all-cap records occupy 3175 bytes, and the projected fixed wire of 7271 bytes fits the new 7680-byte ceiling. The six actual records occupy 2647 bytes, the OMNA record 453 of them. Two generations, growth and owners of the actual maximum graph use 73732 of 125792 available bytes.

Formal model admission

FullBaseline checks M035-M037 of rfc9880.model/1 against the imported domains in RFC 9880 Appendix A, following ADR 0032: Formal model admission. Formal admission is grammar membership, separate from model meaning, actual const denotation, sample admission and general satisfiability. Initial and expanded assessments, source inspection, unchanged generated-token preservation and selected-sample workflows keep their existing exact-decimal contracts.

Number and count domains

number admits every JSON number, as an exact decimal without a precision or range limit. uint is the integer interval 0 through 2^64-1. Integrality is a mathematical property: 10, 10.0, 1e1 and 100e-1 have the same membership. Negative zero is zero. No decimal is rounded into a machine value for either check.

Supplied mathematical valueuintnumber
0, -0, 10.0, 1e1admittedadmitted
18446744073709551615admittedadmitted
18446744073709551616, -1excludedadmitted
0.5, 0.1, 5e-2excludedadmitted
1e400, 1e-400excludedadmitted

These results apply to successfully decoded exact numbers with sufficient work allowance. An operand beyond the 512-digit decoding capability leaves membership undetermined. It does not establish exclusion. Exact mathematical processing and retained source tokens remain governed by ADR 0012: Exact numbers and JSON input policies.

M036 checks the numeric parameters admitted in Full descriptions and Direct minimum and maximum entries. M037 checks Full lengths and array counts, Direct lengths and grouping repetition counts. A JSON number always satisfies M036. A known nonnegative integral count above 2^64-1 in a colon parameter produces a definite formal grammar error. Its owning requirement is assessed, and independent exact bound, type or count meaning remains assessed. Completed work can therefore have a failed disposition.

Object and Thing repetition entries use =>, allowing fallback to framework extension content. Full treats a known negative, fractional, nonnumeric or too large repetition value as admitted grammar: M037 is assessed, while M032 base repetition meaning and M028 extension meaning are undetermined. These cases produce no Full grouping-count grammar error. Initial and expanded grouping checks retain their narrower behavior.

Declared literals

Full const and default use allowed-types, including an any feature alternative. M035 is assessed when either base or framework-extension membership is established. The base alternatives are JSON numbers, decoded text, Boolean, null, homogeneous arrays of numbers, text or Boolean, and text-key maps with unrestricted values. An empty array is base-admitted.

LiteralFramework admissionSemantic consequence
0.1, [0.1,2], ["a","b"], [true,false]base alternativeordinary meaning can be established independently
{"x":[[0.1]],"n":1e400}base map with any valuesno recursive numeric restriction on map values
[null], [1,"x"], [[1]], [{}]extension alternativeM028 and needed final const meaning M043 remain undetermined

An extension-only default remains documentary and is not inserted. An extension-only const overridden by every final alternative does not constrain those alternatives. An extension-only const in an optional property still prevents claiming that property’s complete model meaning. Framework admission does not establish a registered extension interpretation or successful contextual equality. Unknown decoding, feature or effective context leaves needed membership undetermined.

Scope, limits and evidence

Formal checks examine effective definitions in their actual roles. Source patch nulls that delete an inherited parameter impose no final constraint. Selected root requests exclude unrelated supplied definitions; catalogue requests retain their wider scope. A finding on an inherited operand names the effective consumer and relates its original source span, preserving the authored number token.

All operands and phases share the original semantic, numeric and allocation allowances. Count comparisons avoid expanding authored exponents. No operand, child or replay replenishes a counter. Capability or work failure leaves only affected work unfinished. Human and JSON output share the same mandatory error and completion totals; omitted diagnostic detail does not erase established findings or make assessed membership unfinished.

Model coverage boundaries

Esdieff requests the whole recorded base-model scope through --assessment full-baseline. The model assessment inventory contains 54 obligations, grouped into 13 assessment areas. The clause-family trace also records sample, processor, converter, registry and operator duties that do not belong in that model count. This separation follows RFC 9880, including its normative Appendices A and C.

A complete report establishes the requested work for the supplied model. It does not establish that every SDF model is supported. For example, the combined ordinary model in tests/fixtures/model-meaning/ordinary.sdf.json exercises available scalar, compound, pattern, format, special-type and content-format meanings. An empty document, a Boolean sdfRef or an unavailable comparison interpretation has different applicable obligations.

The default Initial assessment retains its narrower scope. Choosing Full requests more conclusions; it does not supply missing interpretations or knowledge. Completion, findings and validity remain separate under ADR 0003: Check findings and completeness.

Available comparisons

The shared contextual equality contract supports exact ordinary numbers, decoded text, Boolean and null values, and supported maps, arrays and alternatives. Its specialized domains include canonical byte strings, opaque UUIDs, Gregorian dates, dated UTC instants and established nonnegative POSIX coordinates. Nullable UUID, Gregorian-date and dated date-time comparator capability includes known absent, true and false Full nullability. Dated instant comparison follows the existing civil denotation and recorded adjustment knowledge boundaries.

Null compares with null and with an established nonnull value in compatible date, date-time, time, uri, uri-reference and uuid contexts. A malformed or uninterpreted operand does not establish a difference. Identical established nonnull time and URI representations can establish equality, while their general nonnull comparison capability remains unavailable. Established date-times compare by UTC instant with exact fractional seconds and distinct inserted-second slots, after every relevant interpretation is compatible. These rules follow ADR 0015: Bounded value equality in a resolved data context, ADR 0018: Civil date and time sample conventions and ADR 0019: URI and UUID sample conventions.

Retained gaps

Each entry retains its affected obligations, actual unfinished outcome, reason and condition for reconsideration. These are capability boundaries, not another runtime status or a change to the immutable inventory. Where the reason is an RFC ambiguity, the retained outcome is deliberate Esdieff policy. Esdieff does not wait for author clarification. It adopts its own RFC interpretation, recorded in an ADR, when a real model or caller needs one, and treats any later author guidance as evidence. An affected model can also have independent assessed findings. The exact status depends on the final effective context and all applicable occurrences, as described in the model meaning contract.

CapabilityAffected obligations and current outcomeReason retainedReconsider when
Short-name and Boolean sdfRef processingM018/M019 where processing is needed: undeterminedFormal admission of a reference form does not establish its operational target selection. sdfRequired abbreviations have their own established declaration rules.Retained as policy: Esdieff gives these forms no processing meaning. A real model that needs one prompts an adopted interpretation.
Empty-document definition-group presenceM008: undetermined for a document without a populated groupSection 3.3 describes one or more groups; Appendix A makes the groups optional. No unsupported empty-document rejection is invented.Retained as policy until a real model or caller needs an interpretation, covering absent groups and present empty maps.
sdfRequired in data-only descriptionsM020: undetermined when its meaning is neededAppendix A admits the quality through common qualities; Section 4.5 explains requiredness through affordance and grouping declarations.Retained as policy until a real model or caller needs an interpretation of its applicability and carrier meaning, independent of map-entry required. See ADR 0026: Required declaration relationships and source evidence.
Wider Direct item descriptions and role-changing importsM041 and dependent M042/M050 or comparison obligations: undeterminedRestricted jso-items content and Full property/Choice descendants have different roles. Framework admission alone does not supply wider Direct meaning. Older exploratory models exercise Direct-item reference imports, so this is an observed compatibility limit.Deliberately deferred. A current model or named caller workflow must justify adopting a role-specific interpretation of wider qualities, defaults and imported descriptions. The older examples alone do not select that work. Full descendants keep their available meanings.
Byte-string length and pattern constraintsM046 for length or M048 for matching: undetermined when presentThe conventional channel denotes bytes through base64url text. The adopted rules do not decide whether these constraints operate on that text or the abstract bytes. Pattern syntax can still be assessed independently.Retained as policy until a real model or caller needs an interpretation of the length unit and pattern subject, with distinguishing encoded-text/byte examples. See ADR 0007: Generated SDF and sample JSON.
General date-free time equalityM052 general comparator capability: undeterminedA clock expression carries no date; offset wraparound and exceptional labels need their own comparison meaning.A recurring date-free workflow justifies a separate contract without supplying a host date. See ADR 0018.
General URI and URI-reference equalityM052 general comparator capability: undeterminedString difference is not a general resource-identity proof. Normalization, scheme meaning and a URI-reference base depend on the selected purpose.A concrete workflow establishes its equivalence purpose, scheme rules and explicit base requirements. See ADR 0019 and RFC 3986 Section 6.
Negative nonzero POSIX denotation and general Unix-time comparator capabilityM052 generic Unix-time capability: undetermined; actual M043 remains undetermined where denotation is unavailableExact negative numbers are retained, but their pre-epoch abstract denotation is outside the adopted bounded convention. Nonnegative operands retain their available equality.A real pre-epoch workflow justifies a separately evidenced convention. See ADR 0007 and ADR 0015.
Extended sdfType name admissionM025 for a non-base string: unassessedExtended lexical admission has not been implemented. This is separate from whether a particular extension’s meaning is known.Extension-bearing models need bounded name admission, with malformed spelling, framework fallback and M028 meaning kept distinct.
Unknown extension, critical-feature and abstract-selector meaningM028 where undeclared extension vocabulary occurs: undetermined. M013/M028 and dependent obligations for a declared Extension feature or an unknown base selector value: undetermined when neededA retained declaration or a registered spelling does not by itself provide an implemented interpretation. Undeclared extension vocabulary leaves base meaning intact under ADR 0037: Undeclared extension vocabulary, so only its own meaning stays unsupported. Recorded extension vocabulary is the exception. oma:id at its registered positions does not stop base meaning, and Full assesses M028 when its value is in the recorded uint domain. A value outside that domain is an extension.recorded_value_excluded error at each effective coordinate, with a registration basis, and M028 is still assessed.A selected extension has a stable specification, a real model workflow and explicit coverage rules. See ADR 0003 and ADR 0038: Recorded extension vocabulary.
Additional media-specific content-format parameters and meaningsM024: unassessed for unsupported media rules; undetermined for needed unavailable registration evidence or reserved identity meaningFull supports recorded numeric tuples and bounded JSON, CBOR and plain-text rules. Other media rules cannot be inferred from spelling or registration.A concrete media declaration needs its own primary specification and bounded parameter rules. See ADR 0033: Content-format model meaning.
ECMAScript patterns beyond bounded syntax or matching capabilityM047/M048: undetermined for needed unsupported capabilityThe supported engines and finite controls do not cover every valid construct or guarantee resources for every subject. Unsupported capability is not proof of invalid syntax.Representative model patterns establish a worthwhile missing construct and its bounded implementation. See ADR 0014: Bounded partial ECMAScript pattern capability.
Missing, withheld or out-of-edition registry and temporal knowledgeM012/M023/M024/M028 and dependent actual-value conclusions as applicable: undeterminedRecorded positive registry entries do not establish current absence, and missing leap knowledge does not establish a future adjustment. A withheld OMNA record leaves every oma:id value unchecked.Explicit evidence or knowledge policy supplies the needed facts. See ADR 0021: Modified metadata assessment, ADR 0027: Unit names and recorded registry guidance, ADR 0029: Content-format declarations and recorded registry guidance and ADR 0038: Recorded extension vocabulary.

Missing or ambiguous supplied dependencies, effective expansion cycles and exhausted operation budgets can also prevent conclusions. They are assessed through the existing scoped failure and finite-work contracts, rather than promising automatic acquisition, recursion or unlimited processing. See ADR 0004: Supplied catalogues and checking scope and ADR 0009: Bounded processing and reporting.

For unsupported vocabulary, Full conditions name each retained quality and its source location. Composed observations also identify the effective position. These details help locate the cause of unfinished work, including draft vocabulary and base qualities used outside their supported role. They do not provide the missing meaning. The report contract describes their bounded retention and omission reporting.

Scope beyond model checking

Whole interaction scenarios, protocol bindings, ecosystem conversions, device behavior, existing-document editing and separately specified extensions are additional workflows. General satisfiability and unrestricted refinement proofs are additional analyses. They do not silently increase this model inventory or become prerequisites for completing an ordinary supported model assessment.

Selected sample checking establishes outcomes for the actual supplied values. A passing sample does not discharge model obligations, and an available model interpretation does not guarantee every future sample’s denotation or processing capacity. The sample contract records that separate scope.

RFC 9880 model assessment inventory

The immutable fine-grained inventory rfc9880.model/1 contains 54 finite model obligations. It covers RFC 9880, including normative Appendices A and C. Appendix B is informative; Appendix D contains examples and Appendix E historical changes. Imported definitions apply only where a clause uses them. Each obligation counts once across the requested model scope, regardless of how many occurrences or supporting citations it has.

The Full request retains assessment and baseline identity rfc9880/base-1. Its area inventory esdieff.full-model/1 has 13 members. Initial retains its eight narrower areas and existing exclusions. Successful Initial assessment always discloses broader partial coverage. These identities follow ADR 0011: Machine-readable report contracts and ADR 0013: Shared workflow and report guarantees.

Completion and applicability

An obligation is assessed only when all applicable occurrences and subdimensions have been assessed, including definite invalidity. Established absence is not applicable. Missing implementation is unassessed; unknown needed meaning, context, knowledge or traversal is undetermined. Joining repeated observations uses undetermined before unassessed, then assessed, then not applicable. One finished occurrence cannot hide an unfinished sibling. Errors, warnings and notices remain independent of completion and of optional detail retention.

Full broader completion describes these54 model obligations. Requested outcome completion describes all13 selected areas, including the separate advisory area. All model work may therefore finish while advice remains incomplete. Assessed errors still constitute completed work; neither completion value certifies validity or universal capability. Full does not emit an optional omitted-areas list whose absence could be mistaken for completion.

Full establishes capability and meaning for the supplied model. Sample admission is a separate operation; a successful sample never completes a model obligation. Device behavior, protocol bindings, conversion, registry administration, operator duties and general satisfiability are outside this model denominator. Unknown extensions are retained without guessing their meaning or universally rejecting them.

Each subclause has one counting owner. The clause ownership table names supporting dependencies separately. The clause-family trace preserves all132 body/grammar/characteristic/process families and the explicit comment obligation with their model owners or excluded roles. These are traceability rows, not another denominator. For example, nullable belongs to M029, special-type selector admission to M025 and Property flags to M031; they do not also earn M022 credit. M022 owns only unit and content-format string shape. Direct-item container shape belongs to M040; Full properties and Choice descendants retain M038 and M030. Grammar family G013 therefore supports M039 for pattern/format/uniqueness shape and M040 for the restricted items container.

Obligations

IDs below expand to rfc9880.model.M001/1 through rfc9880.model.M054/1. The capability column describes current checking and limitations. Runtime status comes from the report, not this table.

The model coverage boundaries collect retained gaps with their current outcomes, reasons and conditions for reconsideration.

IDRFC 9880 citationFinite meaning and applicabilityFull areaCheck and limitation
M0011.2.3;3;7.1;A sdf-syntaxEvery assessed source: one UTF-8 JSON text, root map, JSON structure; supplied serialization onlyfull.document-syntax/1Decode complete supplied JSON while retaining acquisition failures; transport delivery duties are outside model assessment.
M0022.2;2.3.1;3.3-3.4;5.1-5.5;6.3;A named/paedataqualities/thing/object/action/eventAll six group/map/class roles; text named keys, map definitions; Object excludes grouping roles, Thing permits them; Action full input/output and Data, Event full output and Data; root reuse definitions; zero entries permittedfull.document-syntax/1Traverse named definitions and all admitted data-description containers in their actual roles.
M0031.2.3;2.2.2;2.2.5;3.3;4.5Definitions versus declarations and directly containing scope; Data reusable definition, Property state description, root affordance does not instantiate itselffull.model-roles/1Establish declaration classes in the resolved model, including copied declarations at their importing coordinates.
M0042.3.2-2.3.3Given Names are case-sensitive and contain no colon; arbitrary other text retainedfull.document-syntax/1Check case-sensitive definition names and reserved colon use.
M0052.3.3;A quality-nameUnqualified ASCII quality pattern and optional ASCII qualified-prefix pattern; case-sensitive names; registered prefix meaning is M028, registration process excludedfull.document-syntax/1Check ASCII unqualified and qualified spelling in actual Quality Name positions; preserve admitted unfamiliar vocabulary and opaque extension values.
M0062.3.2;4.1-4.3Definition-selecting JSON Pointer and tilde escaping before URI-fragment percent encodingfull.namespace-reference/1Resolve encoded reference names through the established namespace and pointer context.
M0073Absent and empty optional nested blocks equivalentfull.document-syntax/1Check the document envelope and supported top-level definition groups.
M0083.3 versus A sdf-syntaxDocument group-presence obligation: body one-or-more versus all-optional formal groupsfull.document-syntax/1Establish a populated definition group; empty documents retain the unresolved prose and CDDL distinction.
M0093.1;A sdfinfoinfo map and title/version/copyright/license text shapesfull.metadata/1Check the Information Block and its general string-valued metadata.
M0103.1;4.6Ordinary info/common fields optional, no inserted defaults; last pointer token only optional display conventionfull.metadata/1Expose absent Information metadata through the domain defaults without imposing lifecycle advice.
M0112.3.3;4.6 Table3;A optional-commentAt every admitted $comment position, presence/absence has no model meaningfull.metadata/1Preserve the descriptive comment as metadata without treating its text as a semantic command.
M0123.1;A modified-date-time/rfc3339zmodified text ABNF, calendar/date/time/fraction/T/Z and leap-second knowledgefull.metadata/1Check modified dates against the supported calendar, clock and recorded temporal knowledge.
M0133.1;A featuresFeature-list syntax includes framework arbitrary entries; declared critical feature understanding needed by requested semantics, no closed-empty grammarfull.critical-extensions/1Establish the required feature declaration before interpreting model qualities.
M0143.2;A sdf-syntaxnamespace map of text short names to URI textfull.namespace-reference/1Check namespace map shape and URI-valued bindings.
M0153.2;4defaultNamespace selects existing namespace; absent default gives no contribution only under established contextfull.namespace-reference/1Check that the declared default namespace has an established binding.
M0161.2.4;3.2;4.1-4.2;6.1Complete namespace URI plus pointer by concatenation, distinct definitions may share namespace across supplied contributors, no first/last precedencefull.namespace-reference/1Resolve local and cross-document references while retaining missing, ambiguous and unavailable contributors.
M0174.3CURIE resolution/global versus same-document #pointer meaning; outside reference uses declared prefix, no safe-CURIE/direct URI-scheme bypassfull.namespace-reference/1Establish the target role of each model reference.
M0184.3;4.6;A sdf-pointer/pointer-list/referenceable-nameAll sdfRef/sdfRequired occurrences: formal global/short/true union, short-name colon/hash exclusion, list shape including empty; short/true sdfRef meaning unresolvedfull.namespace-reference/1Check reference syntax and referenceable positions in Full and Direct data contexts.
M0194.4-4.4.1;6.2.1Target-root refs processed, copy qualities/children, remove sdfRef, RFC7396 merge/delete/replace, consumer-role result assessed, order-independent; internal copied references relocate; needed cycles scopedfull.composition-requiredness/1Compose inherited qualities and local overrides, relocating internal copied references to the importing definition.
M0204.5;4.6Mandatory grouping/affordance declaration selection: full,short all-matching classes,true carrier; copied pointers relocate by coordinate; data-only meaning unknown explicitlyfull.composition-requiredness/1Resolve grouping-required declarations in the resolved model, relocating copied pointers by coordinate under the existing requiredness policy.
M0213.1;4.6;A sdfinfo/commonqualities/jso-items/optional-commentdescription/label/$comment string shapes at their admitted positions: info description/comment, common all three, Direct description/commentfull.metadata/1Check descriptive metadata string shape in each admitted Full or Direct position.
M0224.7 Table4;A dataqualitiesFull unit and contentFormat string shapes onlyfull.data-grammar/1Check common data-quality admission in its actual data-description role.
M0234.7 note1;7.3-7.4Unit direct-name/URI distinction, forbidden unit URN except colon-name exception; SHOULD registry convention or unit-definition URI; absent dated record not proof unregisteredfull.special-type-unit/1Check unit spelling and recorded registry guidance under the selected knowledge policy.
M0244.7 note2;RFC9193 §6contentFormat text means Content-Format-Spec: code/media type/parameters/coding syntax and available recorded meaningfull.pattern-format/1Establish recorded numeric tuples and supported JSON/CBOR/plain-text parameters with ordered codings; other meaning and missing evidence remain scoped.
M0254.7.1;A sdftype-nameBase byte-string/unix-time or admissible registered/extension [a-z][-a-z0-9]* namefull.critical-extensions/1Recognize the two base special-type selectors; extended-name admission remains unfinished without a closed extension vocabulary.
M0264.7.1 Table5byte-string denotes bytes, conventional JSON unpadded base64url; establish modeled meaning when presentfull.special-type-unit/1Establish the known byte-sequence model interpretation without a value; decoded-byte length remains separately unfinished.
M0274.7.1 Table5unix-time denotes POSIX numerical civil time with leap-instant limitationfull.special-type-unit/1Establish the known POSIX-time model interpretation without assigning an actual value or leap-instant meaning.
M0282.3.3;4.7.1;7.5.2-7.5.3;A extension socketsApplicable registered prefix/type/format/quality description meaning, conventional type/JSON representation consistency where specifiedfull.critical-extensions/1Retain unknown extension meanings as unavailable rather than inferring universal invalidity.
M0294.7 Table4;A dataqualitiesNullable bool shape and default true meaning,distinct presence; constraint interaction uses recorded ADR0005 interpretationfull.scalar-meaning/1Check nullable shape and expose its established domain default.
M0304.7.2;A optional-choice/jsonschema/jso-itemsChoice map and Full branch shapes in Full and Direct positions,shared override semantics; nonempty string enum shape/expansion preserving occurrences; exclusive enum versus choicefull.composition-requiredness/1Check choice and enumeration syntax and establish inherited alternative scope.
M0315.2;A propertyqualitiesreadable,writable,observable booleans and specified true defaults, distinct documentary defaultfull.model-roles/1Check Property flags and expose their established domain defaults.
M0322.2.1;6.3Grouping repetition if minItems/maxItems present; inclusive count meaning onlyfull.formal-numbers/1Establish inclusive base count meaning for admitted uint values; framework fallback retains unavailable extension repetition meaning.
M033A EXTENSION-POINT and $$ quality socketsAdditional quality content admits any JSON at top/info/group/data/items quality sockets,without closed-grammar substitutionfull.document-syntax/1Check admitted extension sockets without claiming unsupported extension meaning.
M034A jsonschema/compound-type/jso-itemsType selector admission: Full six base selectors or extension; Direct base subset including explicit object or extension; type:null not basefull.data-grammar/1Check base-type selector shape separately from model-level type capability.
M035A allowed-types;RFC8610 3.3/D/Econst/default base number,text,bool,null, homogeneous scalar arrays,text-key maps plus allowed-extfull.data-grammar/1Establish base or framework-extension literal admission; extension semantics and needed const meaning remain separately unfinished.
M036A jsonschema/jso-items number;RFC8610 3.3/D/EFormal number admission for all Full numeric parameters and Direct min/max: every JSON number, read as an exact decimalfull.formal-numbers/1Establish formal CDDL number membership for bound parameters from their decoded JSON numbers.
M037A jsonschema/jso-items/arraydefinitionqualities uint;RFC8610 3.3/D/EFormal uint admission for all Full length/item counts,Direct lengths,and Object/Thing repetition countsfull.formal-numbers/1Establish formal CDDL uint membership for counts; exact nonnegative integer decoding alone is insufficient.
M038A compound-typeExplicit object required nonempty string array and properties named Full map; applicability in non-object/wider roles not guessedfull.data-grammar/1Check map-data properties and required syntax in the compound-type context.
M039A jsonschema/jso-itemsFull pattern text,Full six format literals or extension text,Direct format text,Full uniqueItems bool shapesfull.data-grammar/1Check pattern, format and uniqueness parameter shapes in Full and Direct items.
M040A jsonschema items/jso-itemsitems value must be a map in the restricted Direct rolefull.data-grammar/1Check the Direct items container and traverse its admitted Full descendants.
M041A jso-items/items-ext/itemtype-ext;4.4;C.4Wider Direct array/nested items/nullable/default/full import and role-dependent admitted content do not inherit Full meaning solely by spellingfull.critical-extensions/1Establish Direct-item extension meaning; preserved unsupported qualities remain unavailable.
M042C intro;C.1-5Base description type meaning: mathematical integer including10.0, number,Unicode-scalar string,true/false Boolean,array,string-key map; model establishes interpretation/role, not a supplied-value verdictfull.scalar-meaning/1Establish ordinary scalar, array and map type meaning in final effective contexts; unavailable extended meanings remain scoped.
M043C introconst fixes one value under exact adopted equality; applicable literal/type/alternatives meaning must be established; general satisfiability not requiredfull.scalar-meaning/1Establish scalar and compound const meaning under exact contextual equality for the actual final value; unavailable abstract denotation and extension meanings remain scoped.
M044C introdefault is documentary data for absence with no insertion process; permitted literal domain M035; consistency warning optionalfull.scalar-meaning/1Expose default values as optional descriptive metadata without executing them as required characteristics.
M045C.1Inclusive/exclusive mathematical numeric bounds and positive exact integer-multiple step; legacy Boolean exclusive endpoint not basefull.scalar-meaning/1Establish exact inclusive/exclusive bounds and positive-step meaning in an available ordinary effective context.
M046C.2String length constraints count Unicode scalars with inclusive boundsfull.scalar-meaning/1Establish inclusive Unicode-scalar text-length meaning in an available ordinary effective context.
M047C.2pattern syntax is ECMA262 Unicode; suggested portable subset not entire grammarfull.pattern-format/1Check effective pattern syntax within the supported bounded ECMAScript capability.
M048C.2pattern modeled matching meaning is unanchored Unicode substring unless anchorsfull.pattern-format/1Establish bounded Unicode unanchored model matching capability by compilation without a sample or satisfying witness.
M049C.2Base formats date/date-time/time RFC3339, uri/uri-reference RFC3986, uuid RFC9562; recorded representation conventions and external knowledge distinguishedfull.pattern-format/1Establish known civil, URI, URI-reference and UUID model interpretations independently of actual value denotation.
M050C.4When items is present,its established description constrains every array elementfull.compound-meaning/1Establish every final item description recursively in its actual role, independently of samples.
M051C.4Array element-count limits inclusivefull.compound-meaning/1Establish inclusive exact mathematical counts separately from formal uint membership and satisfiability.
M052C.4uniqueItems true uses adopted exact value equality over all elementsfull.compound-meaning/1Establish ordinary contextual equality capability recursively across final alternatives; abstract gaps remain scoped.
M053C.5object properties names identify allowable entries, values use Full description semanticsfull.compound-meaning/1Establish every final property description, including optional entries, under open map semantics.
M054C.5Map entries optional unless required key-name array, independent of affordance requiredness/nullabilityfull.compound-meaning/1Establish decoded mandatory map-entry names independently of property descriptions and grouping declarations.

Formal CDDL number membership is separate from mathematical decimal decoding. Appendix A imports the RFC 8610 domains: uint 0 through 2^64−1, nint −2^64 through −1, their int union, and binary16/32/64 floating-point values. Full admits every JSON number as number, following RFC 8610 Appendix E’s description of JSON numbers as decimal and RFC 9880’s own Figure 5, which uses 5e-2. Full checks uint as integral values from 0 through 2^64−1, without rounding. Numeric literals, bound parameters and count parameters have distinct owners M035, M036 and M037. Exact lexemes such as 0.1, 10.0, 18446744073709551616 and 1e400 remain inspectable. Colon entries reject established out-of-domain counts. Grouping counts use no-cut fallback and known literal extension alternatives remain framework-admitted, with their unavailable semantics scoped separately. Initial, expanded and selected-sample contracts remain unchanged. See ADR 0032: Formal model admission and the formal admission contract.

Full area membership

The fixed areas are document syntax, model roles, metadata, namespace/reference, composition/requiredness, critical extensions, data grammar, formal numbers, scalar meaning, pattern/format, compound meaning, special type/unit, and the four advisory classes. Their exact IDs are the distinct area entries in the table above plus advisory-four/1. The advisory area counts once in the 13 areas and contributes no extra RFC obligation to the 54 denominator.

Both unit subareas join once into M023. Both content-format subareas join once into M024. Modified metadata joins into M012 and pattern syntax into M047. Each resulting obligation joins once into its Full area. Producing condition IDs remain modified-date-time/1, unit-spelling/1, unit-registry-guidance/1, content-format-syntax/1, content-format-registry/1, pattern-syntax/1, inspection for required relationships, or advisory-four/1. Optional coverage_owner identifies their requested Full area without changing the producing assessment_unit. Generic findings use actual field and role context.

Roles outside model assessment

The following audit identities do not enter model counts. They distinguish standards duties from the model obligations above.

IdentityRole, citation and finite dutiesModel boundary
S001-S010Sample C intro/C.1-5/4.7.1: actual type, const equality, numeric bounds/step,Unicode lengths,pattern matching,formats,array elements/count/equality,map entries/required,special-type representation,nullable membershipM026-029,M042-043,M045-046,M048-054 establish modeled meaning; these S duties produce actual supplied-value outcomes only
CV001Converter C.6: legacy draft4 Boolean exclusivity import/exportNo current conversion request
CV002Translator7.3-7.4: unit-URN pchar percent encoding and registry nonoverlapM023 checks supplied unit meaning, does not translate/register
PR001Processor3.1: normally SHOULD NOT dereference feature URISupplied-only API; no network acquisition assertion
PR002Processor4.7 note1: normally SHOULD NOT dereference unit URISupplied-only API
PR003Processor8: robust bounded input/output processing, avoid unpredictable generated JSONOriginal public budgets/encoding; operational safety, not54 semantic duties
PR004Protocol/media7.1-7.2: application/sdf+json, no media parameters,CoAP434/delivery fragmentsM001 supplied UTF-8 JSON only; no device/protocol conformance
RG001Registry7.5.1: quality-name pattern,immutable reviewed reference,frugal allocationsRegistrant/expert duties
RG002Registry7.5.2: prefix pattern,contact,stability/transparency,Expert ReviewM005/M028 supplied usage separate
RG003Registry7.5.3: type pattern,meaningful specification,consistent conventional type/JSON representationM025/M028 relevant modeled meaning separate
RG004Registry7.5.4: feature-name syntax,immutable reviewed reference,frugalityM013 critical understanding separate
OP001Operator8: authenticity,integrity,applicability of each component/module/upgradeSourceId/digest does not authenticate
OP002Operator8: dynamic ecosystem acquisition,confidentiality,access controlNo fabricated trust or mechanism
AD001Author advice2.2.1 Object granularityOptional
AD002Author advice2.3.2-3 simple ASCII namesMandatory colon/name syntax M004 separate
AD003Validator RECOMMENDED3.1 warning absent infometadata.info_absent Advice,not RFC error
AD004Lifecycle RECOMMENDED3.1 lexicographic version increasePrior version absent is external context,not model syntax failure
AD005Author advice3.1 unambiguous license URI/SPDXOptional
AD006URI guidance3.2/4.1 no namespace fragment,https path,no queryOptional,not general URI syntax
AD007Author RECOMMENDED4.7.1 conventional type with sdfTypeOptional advice; M028 consistency meaning remains
AD008Optional6 refinement convention restrict reused setNo universal subset solver duty
AD009C.2 portable regex subset suggestionNo prohibition of broader ECMA syntax
AUTH0011.2.4 I-Regexp textual pattern convention and9.1 dependency importsSupporting M005/M017/M025/etc; no standalone conformance count
AUTH002A/C normative,B informative,D example,E historical authoritySupporting whole ledger; A001/A002 acceptance not RFC obligations

Consumer contract

The mandatory existing request.inventory identifies the immutable area membership. esdieff.full-model/1 also binds the 54-member rfc9880.model/1 inventory, even when every new optional section is absent. Historical Full reports with null inventory and coverage.inventory_unavailable mean unknown membership, never an empty inventory.

The borrowed descriptor and typed status accessors do not render or allocate a report. Full returns all 54 known descriptors and authoritative statuses; an unfamiliar requirement ID is absent. Other operations do not request this inventory. Optional wire aliases, summaries, rows and ownership detail may be omitted under presentation limits. Consumers preserve mandatory aggregates and surviving diagnostic facts, accept unknown additive fields and human wording changes, and validate unique retained identities and linked omission counts. See the report contract.

Modified metadata assessment

Revision metadata can be assessed through Catalogue::check(CheckRequest::new().assessment(Assessment::ExpandedModified)) or esdieff check --assessment expanded-modified-v1 .... The immutable esdieff.expanded.modified/1 inventory contains the unchanged eight areas of esdieff.initial/1 and modified-date-time/1. Initial requests continue to check ordinary Information strings without interpreting modified date content. Complete full-baseline membership remains unavailable. This boundary follows ADR 0021: Explicit modified metadata assessment.

The ninth area checks info.modified directly, independently of reference composition. Its normative RFC 9880 Appendix A production is full-date ["T" partial-time "Z"]: four ASCII year digits, Gregorian month/day, optional hour/minute/second with a dot-plus-digits fraction, and UTC Z termination. ABNF literals admit lowercase t/z under RFC 5234 Section 2.3. Numeric offsets, including +00:00, space separators and date-free clock forms fall outside this metadata grammar. Data sample conventions remain separate under ADR 0018: Civil date and time sample conventions.

Catalogue scope checks every supplied document. Selected scope checks every root and each distinct source needed by surviving composition once, including mandatory target-root chains. Dependency metadata uses the same source preflight and modified scanner without independently assessing unrelated Information qualities or definitions. Candidate uncertainty or unfinished dependency discovery prevents a roots-only NotApplicable conclusion. Effective construction and inspection request no metadata-date assessment. This scope follows ADR 0023: Supplied global composition and dependency scope.

Years 0000 through 9999 use Gregorian arithmetic, including the four/100/400 leap-year rule. Hours are 00..23, minutes 00..59 and seconds 00..60 subject to exceptional-second meaning. Fractions keep every digit. Checking introduces no library year range, host date/timezone, fixed fractional precision, version-string scheme, SPDX requirement or live source retrieval. Source bytes, escapes and unrelated exact numbers remain unchanged.

Dated exceptional seconds reuse the recorded IERS C72 knowledge and byte identities in the civil-time contract. A possible adjustment minute is UTC 23:59 on the final Gregorian day of any month, following RFC 3339 Section 5.7. Second 60 elsewhere is a definite error without consulting leap knowledge. At possible slots within the inclusive interval 1972-01-01 through 2026-12-31, recorded insertions admit 60 and other dates reject 60; no negative adjustment is recorded, so 59 is established. At possible slots outside that interval, 59 and 60 remain undetermined. Seconds 00..58 need no leap knowledge. Snapshot expiry does not extend the recorded interval.

Reports include optional baseline.temporal_knowledge when the interval or insertion facts are consulted, including an outside-interval query. Its id, inclusive from/through, transition_sha256 and bulletin_sha256 fields identify the actual knowledge used. This record is separate from vocabulary-registry knowledge and survives omission of every diagnostic and coverage row. Merely having the snapshot available does not mean a check used it.

Report::assessment_area_status("modified-date-time/1") exposes semantic status independently of presentation. An expanded request returns Field::Present(AssessmentStatus::Assessed), NotApplicable or Undetermined. Assessed includes established errors. NotApplicable requires reliable absence across every requested document. Any needed unavailable source, member identity, text, critical meaning, leap fact or work makes the one aggregate area Undetermined while independent definite findings remain. Initial and inspection return Absent. Full binds modified work to M012 and full.metadata/1, preserving the producing condition ID while the standalone expanded area is outside Full membership. requested_coverage() sums to nine for expanded modified, eight for Initial and13 for Full.

Shared source preflight establishes critical-feature context and reliable Information/member identity before dependent conclusions. Its early metadata pass records existing metadata.string exactly once for reliable nonstring modified. Later unrelated work exhaustion or omitted detail cannot erase that aggregate error or its semantic area status. Unknown critical meaning defers dependent conclusions. Definite findings refer to original source pointers/spans; unsupported text, needed knowledge and exhausted work yield operational incompleteness. The finite check/report/pointer controls follow ADR 0013: Shared workflow and report guarantees.

CodeMeaning and basis
metadata.modified_syntaxRFC finding: the decoded text is outside the modified production.
metadata.modified_calendarRFC finding: a Gregorian date field is impossible.
metadata.modified_clockRFC finding: a clock field is outside its range.
metadata.modified_exceptional_slotRFC finding: second 60 is outside a possible UTC adjustment slot.
metadata.modified_leap_secondRFC finding: recorded knowledge establishes no insertion at this possible slot; the basis also identifies the knowledge snapshot.
metadata.modified_knowledge_unavailableOperational incompleteness: a possible adjustment slot needs facts outside the recorded interval.
metadata.modified_unavailableOperational incompleteness: decoded modified text or needed capability is unavailable.

Critical/member uncertainty and work exhaustion retain their shared conditions. Exhaustion of modified’s own text work reports operation.limit with assessment_unit:"modified-date-time/1"; ordinary source structural limits keep their existing attribution. A nonstring retains metadata.string; it does not acquire a duplicate modified-syntax finding. These conditions explain one aggregate ninth area rather than creating one requested unit per source or finding.

Unit names and recorded registry guidance

Unit work follows ADR 0027: Unit names and recorded registry guidance. Authors opt into Assessment::ExpandedUnits or esdieff check --assessment expanded-units-v1. The immutable profile esdieff.expanded.units/1 consists of the eight initial areas plus unit-spelling/1 and unit-registry-guidance/1. Initial, expanded modified, inspection and sample requests retain their inventories. Full joins both unit dimensions into M023 and full.special-type-unit/1 once, preserving producing condition IDs. Completing unit work does not complete other unfinished Initial or Full areas.

#![allow(unused)]
fn main() {
use esdieff::{Assessment, Catalogue, CheckRequest, SourceInput, RecordedRegistryPolicy};
let catalogue = Catalogue::from_inputs(&[SourceInput::supplied("fixture", br#"{
  "info": {}, "sdfProperty": {"Temperature": {"type":"number", "unit":"Cel"}}
}"#)])?;
let report = catalogue.check(CheckRequest::new().assessment(Assessment::ExpandedUnits))?;
let units = report.unit_guidance().require()?;
assert_eq!(units.known_primary(), 1);
assert!(units.complete());
// An embedding can exclude this recorded edition under its evidence policy.
let withheld = catalogue.check(CheckRequest::new()
    .assessment(Assessment::ExpandedUnits)
    .recorded_registry_policy(RecordedRegistryPolicy::WithholdRecorded))?;
assert_eq!(withheld.unit_guidance().require()?.unavailable(), 1);
Ok::<(), &'static str>(())
}

The corresponding CLI option is --registry-knowledge recorded|withheld. Both explicit values require a registry assessment; they are refused for initial, modified, inspection and sample requests. The additive report field is only policy.recorded_registry, with use_recorded or withhold_recorded. No arbitrary snapshot input, automatic network lookup, refresh or symbol rewrite is performed.

Decoded JSON text remains exact. Ordinary kg and Cel have recorded SenML positives, ms and /100 have secondary positives, and cel remains a scoped unknown. % retains its legacy ratio meaning, distinct from /100 percentage. A URI containing a colon is checked against generic full URI syntax, without validating resource content or scheme-specific meaning. Recognizable urn:ietf:params:unit:kg is prohibited; urn:ietf:params:unit:m%2Fs represents m/s and is also prohibited. urn:ietf:params:unit:example%3Aratio establishes the colon exception only, without certifying membership or assignment. %253A decodes once to %3A and supplies no represented colon. A slash written directly in the unit index is a Section 7.3 spelling error. Case-conflicting markers and percent-encoded markers retain separate uncertainty diagnostics.

unit_guidance() is Absent when not requested. Present complete or partial retains every established count independently of optional diagnostics. A reliable no-unit result is complete with six zeros and no registry observation; partial zeros do not prove absence. Nontext unit shape has an independent error and no invented registry query. Fixed semantic owner admission failure is outer Unavailable and wire state: unavailable, counts: null, reason: owner_limit.

Within recognized unit URNs, an empty or non-pchar-first r/q component is unit.urn_components_syntax, an RFC 8141 Section 2 error. An ordinary first top-level question mark is unit.urn_delimiter_advice, notice/advice with the same citation and its code as basis id, preserving the SHOULD processor recommendation. Literal index slash retains unit.index_syntax and its Section 7.3 basis. Valid component questions and fragments remain data; malformed URI escapes fail the generic URI check first. These component classifications can finish with URI count1, all query counts0 and no registry record. Completed classification does not establish URN conformance, represented-symbol meaning, definition or assignment. Other successful queries keep their own actual-use metadata.

The six counters describe final effective Full unit-quality coordinates within the requested roots. An independently checked provider root and each consuming copied coordinate count separately. Selected unused providers do not contribute observations. Overrides use the surviving unit, deletions contribute none, opaque Direct donors and critical/unresolved contributors supply no invented meaning. Alternative refinements are distinct effective coordinates; raw source preflight and replay frequency add no observations.

CountMeaning
known_primaryCompleted exact positive in the SenML section
known_secondaryCompleted exact positive in the Secondary Units section, after a primary miss
unknownCompleted union miss in these dated tables; current registration unknown
unavailableEstablished needed lookup unfinished because of withholding, work or index meaning
legacySubset of positive counts with the retained legacy flag
uri_namesEstablished generic full-URI declarations, including prohibited unit URNs; independent of lookup outcomes

Only the first four are disjoint query outcomes. Neither their sum nor any counter asserts valid unit URN assignment. source_edition() returns borrowed raw edition facts when at least one section was consulted, even if later work stopped. It is Absent before any consultation or needed withholding, and Unavailable for needed withheld evidence. registry_knowledge("iana.senml-units") and registry_knowledge("iana.secondary-units") expose borrowed section-specific observations. Available means actual consultation, not match or completion. Needed withheld records contain only registry, state unavailable, snapshot null and reason caller_withheld. Before the first key comparison an operational stop produces no record; after it, the actual consulted section remains available. An unvisited secondary table stays Absent.

The raw IANA SenML XML was retrieved at 2026-10-05T16:49:51Z, with XML update date 2026-02-02. Its SHA256 is 3eff03640c5a5d2abd09e330488aeb9fae0b2766ea69b1114295bbec5c44e754. Raw bytes and section canonical bytes are retained as test fixtures. Canonical section extraction preserves XML row order and writes symbol<TAB>true|false<LF> with no header. Primary 67 rows occupy 630 bytes, SHA256 6246352c590e933b72c25ef9f363171e40fea347bb7e23d08b04f9436894ed34; secondary 39 rows occupy 398 bytes, SHA256 de5c5c009ffbc61aa66e71ee55065f95108709575906c6ec7cd64a2bbc7e173b. entries_count describes the extracted section, while raw_digest describes the common full XML edition. Generated Rust tables and public exact-name controls are checked against every captured row, flag and canonical byte. Production does not parse XML.

Before effective or registry scanning, Catalogue::check requires the existing source/scope reserve C plus E to fit report_bytes, after Catalogue acquisition and decoding. E is 21448 for expanded units and 31448 for full-baseline registry work; the separately prepared content contribution is 19116. These are ownership-derived reserves, not minimum wire lengths or measured resident-memory claims. A single supplied source key fixture contributes seven metadata bytes, giving C=20522 and exact unit admission 41970; 41969 refuses before checking work. At that cap every optional coverage row and diagnostic can be omitted without losing errors, counts or consulted evidence.

The fixed unit owner is bounded by 128 bytes and shared control by 16. Two complete extension DTO generations plus owners receive 4E; independent output and old/new buffer growth receive another 4E. Units D=42824 and owners144 imply 2D+144=85792=4E. Full registry composition has six possible records at array capacity8, D=62792 and owners208, giving 125792=4E. Shared parents, policy, profiles, arrays and control are paid once. Existing mandatory source/scope owners remain in C; optional detail and scratch use only the positive R-(C+E) remainder, preserving the existing total 8R accounting. No per-name mandatory graph is retained.

Qualification guards word<=8, String<=24, Value<=128, Map<=256 and alignment<=8. Up to ten entries fit a default BTree leaf or the qualified IndexMap growth from7 to14 dense buckets and8 to16 index buckets. Old/new controls include both bucket counts and group tails, 248 bytes on the qualified 8-byte-word backend; the guarded per-map bound4024 fits4096. Static record text has fixed safe ASCII caps and no caller strings. Synthetic simultaneous field caps produce a conservative 530-byte record bound including array punctuation; actual finite literals are qualified independently. The six-record synthetic array is3175 bytes and the projected full fixed wire7271 fits7680. This is a requested-capacity and source-specific accounting argument, not a portable allocator-overhead guarantee. Dependency or graph changes require renewed qualification.

Every new visited source row, node, member, ancestry/alternative step and examined key byte is precharged on the original operation allowance. Unit text receives a finite32-times-byte allowance for URI, markers, suffixes, pchar, UTF-8 and optional exact replacement passes; each registry comparison then precharges its row and both examined key lengths. No replay or per-value refill changes counters. With at most100000000 work units, each checked u32 observation count is bounded below u32 maximum. Optional replacement allocation is charged to diagnostic storage after the spelling premise and its copy work are admitted; detail omission cannot retract a prohibition or lookup result.

Content-format declaration contract

Assessment::ExpandedContentFormat, selected by CLI --assessment expanded-content-format-v1, requests the fixed inventory esdieff.expanded.content-format/1. It adds content-format-syntax/1 and content-format-registry/1 to the unchanged eight initial areas, following ADR 0029: Content-format declarations and recorded registry guidance. The initial, modified, unit and sample inventories keep their existing membership. FullBaseline additionally assesses the bounded declaration meanings below within M024 of its immutable model inventory, following ADR 0033: Content-format model meaning.

The population is final effective Full data descriptions at distinct consuming coordinates, including properties, reusable data, Action input/output, Event output, map properties and established alternatives. Reference overrides and deletions determine the surviving value. A selected check excludes unused donor declarations; a catalogue check independently includes reusable definitions. Each inherited consumer remains a distinct observation with an effective primary location and its nearest source contribution as related evidence. Raw bytes, authored case and coding order remain unchanged. Ordinary scalar getters and initial string-shape checks retain their meanings.

Direct items and opaque donor content do not acquire Full semantics from a familiar spelling. Deleted values and reliable absence are NotApplicable. Unavailable effective content, decoded text, member or role identity, donor meaning and critical-feature context prevent dependent conclusions. A known nonstring value receives the existing data.string error once; it is not invented lexical text. Independently established errors survive uncertainty elsewhere.

Complete spelling and separate range

RFC 9880 Appendix A note 2 references RFC 9193 Section 6. The complete string must follow that grammar. A decimal number is 0 or a nonzero digit followed by zero or more ASCII decimal digits, without a grammar digit ceiling. Signs, leading zeroes, whitespace, fractions and exponents fail spelling. A fully decimal spelling outside 0 through 65535 has a separate Section 3 range error under recorded interpretation I-CF-RANGE-1. Whole classification precedes range: 123456/application is a media name, not a decimal range error. Arbitrarily long decimal strings are compared by exact spelling and length, without machine-integer overflow.

Media type and subtype each contain 1 through 127 ASCII bytes. Their first byte is alphanumeric; remaining bytes may also be !#$&-^_.+. A single slash separates them. Wildcard media components, non-ASCII bytes and %, apostrophe, backtick, pipe or tilde in a media component fail this narrowed grammar. Registry comparison ignores ASCII case while retaining the original text.

Parameters follow optional ASCII SP, semicolon, optional SP, a nonempty tchar name, equals, and a nonempty tchar value or quoted value. tchar adds !#$%&'*+-.^_ followed by backtick, pipe and tilde to ASCII alphanumerics. There is no whitespace around equals. A quoted value may be empty; ordinary quoted bytes are SP, !, and ASCII ranges # through [ and ] through ~. Backslash pairs accept ASCII SP through ~. Tabs, controls, DEL and non-ASCII quoted bytes fail, including escaped forms. @, semicolon and equals inside quotes are data. Only SP before a following parameter semicolon is admitted; leading or trailing whole-string whitespace is not.

Each content coding is @ followed by a nonempty tchar token. There may be zero or more ordered tokens, including duplicate tokens. Comma lists, empty tokens, quoted tokens, whitespace and coding parameters fail spelling. An absent coding adds no implicit lookup. The explicit token identity passes spelling but has reserved meaning outside this inventory.

ExpandedContentFormat excludes parameter meaning, including duplicate-parameter meaning, and discloses this with a Notice. This permits completion of its advertised declaration inventory when syntax and dated queries finish. FullBaseline has the additional bounded meaning rules below. Neither operation establishes payload decoding, sample validity or a protocol binding.

Bounded Full model meaning

Established nonempty Choice and Enum collections request declaration meaning from their final inherited alternatives. Superseded shared declarations and their original descendants do not request an additional model interpretation. The existing spelling and registry-guidance passes retain their population and actual-use metadata; an unsupported declaration inherited by any final branch still leaves its meaning unfinished.

An available numeric Content-Format identifier designates its complete recorded CoAP tuple: content type including registered parameters, and its optional coding. All 119 captured positive tuples are retained exactly and independently checked against the canonical source records. No separate media or coding registry query is inferred for a numeric declaration. Withheld CoAP evidence cannot be recovered through another table.

Explicit media names use these supported rules:

Media typeEstablished parameter meaning
application/jsonNo parameter is required. A single charset parameter has no effect on compliant recipients, regardless of its value, as RFC 8259 Section 11 specifies. No JSON encoding is inferred from that parameter.
application/cborParameterless declarations have established meaning; RFC 8949 Section 9.1 defines no required or optional parameter.
text/plainAbsent charset denotes the US-ASCII default; a single charset=utf-8 or charset=us-ascii is established under RFC 2046 Section 4.1.2.

Media and parameter names compare without ASCII case. The supported charset values also compare without ASCII case; token and quoted spellings, including decoded quoted pairs, are equivalent under RFC 9110 Sections 5.6.6 and 8.3.1. Other media rules, parameters, charset meanings and duplicate parameters remain Unassessed, with content_format.model_meaning_unassessed as an Incomplete condition. A registered name such as multipart/mixed does not establish that required parameter knowledge is available. Unsupported meaning creates no invented definite RFC error.

Positive coding tokens denote their designated transformations in authored application order, including repeated occurrences, following RFC 9193 Section 3. No @ means no transformation and no coding query. Unknown codings and explicit reserved identity remain Undetermined; no HTTP negotiation meaning or header prohibition is silently imported. Raw case, parameter text, coding order and source origins remain intact.

Actual admitted consultation of these Full rules is recorded as content-format-model-meaning/1, independently of successful establishment or optional diagnostics. A numeric tuple consultation needs its available recorded evidence. A normative media-rule consultation may occur while a separate registration query is withheld. Neither fact hides unfinished registration or meaning.

Evidence and statuses

RecordedRegistryPolicy::UseRecorded is the default evidence policy for relevant checks. WithholdRecorded deliberately withholds recorded evidence according to an embedding’s trust decision. The CLI uses --registry-knowledge recorded|withheld; both explicit values require the content, unit or full-baseline assessment. Initial, modified, inspect and sample requests refuse that option. Reports emit one policy.recorded_registry=use_recorded|withhold_recorded value, without a competing request field.

Established observationSyntax areaRegistry areaCondition
Invalid complete spellingAssessedNotApplicable, if no other querycontent_format.syntax, Error, RFC 9193 Section 6
Decimal spelling outside the identifier rangeAssessedNotApplicable, if no other querycontent_format.number_range, Error, interpretation I-CF-RANGE-1
Dated positive registrationAssessedAssessedcontent_format.registry_known, Notice with dated flags
Completed positive-table missAssessedUndeterminedcontent_format.registration_unknown, Incomplete; current registration unknown
Needed evidence withheldAssessedUndeterminedcontent_format.registry_knowledge_withheld, Incomplete
Explicit reserved identity codingAssessedUndeterminedcontent_format.interpretation_unavailable, Incomplete
Parameters with otherwise finished queriesAssessedAssessedcontent_format.parameter_semantics_unassessed, Notice for excluded meaning
Unknown relevant text, role or effective contextUndeterminedUndeterminedExisting scoped capability or meaning condition

Statuses aggregate the entire requested effective population. An unfinished required pass remains Undetermined; a condition’s omission cannot make it Assessed. An unknown query cannot be relabeled an unavailable table. Current registration, available evidence and completed lookup are separate facts. The existing requested coverage counts remain authoritative even when every optional area row and located condition is omitted. Other unfinished Initial work can keep an expanded outcome incomplete. Full joins spelling, range, registration and bounded declaration meaning into M024 and full.pattern-format/1 once, preserving their producing IDs. One unsupported or unknown sibling keeps that obligation unfinished.

Report::registry_knowledge(id) borrows actual-use facts for coap-content-formats, media-types and http-content-codings. Before the first admitted key comparison, unavailable operation work fabricates no table consultation or entry. After a comparison, that table remains available even if lookup later stops. An unneeded table is Absent. Needed withholding produces registry, state unavailable, snapshot null and reason caller_withheld, without digest, dates or entry counts. Failure to admit the semantic metadata owner returns Unavailable for requested registry IDs. Existing wire states remain available and unavailable.

Recorded primary editions

All three raw XML editions were retrieved at 2026-10-05T16:55:20Z. Exact raw bytes and canonical extracted JSON are retained in tests/fixtures/content-format. Production uses static Rust key/flag projections, with no XML parser, network access or implicit refresh. Metadata scope is relevant_dated_positive_records; extraction policy is iana-content-format-positives/2.

Registry and sourceUpdate dateRaw SHA256Canonical extracted SHA256Positives
CoAP Content-Formats2026-08-1148a9f69ecbebcd8a091c3ec4680d36281da74da8734a133ea6a95d6203f137ea4dfa7aca5dc7d7f98e6d7ec354db0325373d55c12f2add1af096db92bec72a4a119
Media types2026-09-240cbb8819dfe01c1badc71f8ba836291ba43718a5e797287cd1ac00d49f168ffbdd7486a8665423f632da7f6d1a5f0c3321e39e94c43c0b983cd88131664f7e082361
HTTP content codings2025-10-02e4581c5fd5bd902d9b8de2a8e7cc855e5616e7a9b9d7fc00b070e94092ba2c67f853d2b95b1e723a3848787bdc48b68946e3fda93b6797338accc6dcc86ee30712

Canonical bytes are compact JSON arrays with fixed field order and one terminal LF. Numeric rows are sorted by exact u16 identifier and contain id, content_type, coding, flags, temporary_annotation and temporary_expires. Thirty-six Reserved/Unassigned records or ranges are excluded from 155 raw CoAP rows; all three temporary positives retain their dated annotations. Empty coding is null, without inventing identity. Media rows contain key, canonical, template and flags; coding rows contain key, canonical and flags. Each flags object orders obsolete, deprecated and temporary. Name keys are sorted ASCII lowercase solely for comparison. Media retains 24 obsolete and eight deprecated flags; HTTP retains two deprecated flags and excludes the reserved identity row from its 13 raw rows.

For media identity, a template file’s explicit name attribute takes precedence; otherwise its text is the identifier. The file text is also retained separately as the template target. Thus deprecated image/x-emf and image/x-wmf remain separate identifiers targeting image/emf and image/wmf. Display text is used only for dated status flags, without a guessed identifier-stripping rule. Global case-insensitive duplicate checks merge only fully identical records; conflicting canonical fields or flags stop extraction rather than choosing a winner. Every generated product key and flag is tested against all captured canonical rows, including both aliases.

Finite ownership and work

After Catalogue acquisition, check admission requires the existing source/scope reserve C plus E before new scanning. Econtent is19116, Eunits21448 and combined Full31448. C depends on actual caller metadata: one supplied key authored has eight bytes, C20528 and exact content admission39644;39643 refuses. Seven-byte fixture has C20522 and39638;39637 refuses. Applicable existing role and selector reserves remain independent.

Two complete extension DTO generations and fixed owners receive4E; independent encoding and old/new growth receive another4E. With the recorded extension record, the Full extension bound D62792 and owners208 give 2D+208=125792=4E. Its six registry records use array capacity8. The complete report may have eleven interpretations: four registry interpretations, civil representation, Byte and Unix conventions, both UUID interpretations, copied reference relocation and undeclared extension vocabulary. This grows the interpretation Vec from8 to16; an old8 backing may coexist with new16 and the registry8 backing. Qualification charges all32 Value slots plus eleven40-byte text caps against the existing combined array share1536. On the compiled32-byte Value backend this is1464. It also exercises both complete actual DTO generations, retained-result fallback and wholly omitted optional details at the original admission cap. The actual maximum extension graph bound is36634 bytes; two generations, growth and owners use73732 of125792 available bytes. The private content owner, its maximum alignment padding and borrowed view still fit64 bytes. These are source-specific ownership bounds, without a portable ABI, allocator-overhead or resident-memory claim. No existing allowance grows automatically.

Every visited source, effective node, member/key, ancestry, alternative and examined text byte is precharged on the original operation allowance, including excluded Sample rows. Whole borrowed classification pays a finite32-times-byte coefficient plus one; lookup separately precharges each compared row and both byte lengths, conservatively paying the complete static key maximum before reading a name row. No per-declaration refill, allocated lowercase copy or mandatory per-name graph is used. Four checked u32 counts remain bounded by the100000000 maximum work allowance. Optional finding capacity and retained unit replacement strings keep their already consumed diagnostic storage; beginning the content module cannot renew that credit. Presentation omission preserves errors, requested aggregate counts and actual-use evidence.

One shared borrowed walker first completes the eligible grammar/range population and then replays the already derived effective coordinates for registry queries. Candidate/classified observations, spelling/range findings and parameter-exclusion Notices occur once in the first pass; query/unresolved observations occur only for actual second-pass attempts. An interrupted first pass never starts registry replay. Operationally finished traversal is distinct from monotonic unknown meaning: a completed traversal with an unknown donor or critical premise may still query a different reliable coordinate. Every second-pass stop preserves the first pass’s syntax status, including any previous Undetermined state.

A finished first pass with no reliable query-needed bits omits replay, preserving earlier unknowns and fabricating no consulted or withheld facts. Otherwise replay pays traversal and full borrowed classification again from the same remainder, without re-composition, new arenas or a replenished allowance. This permits later independent grammar/range findings to survive lookup exhaustion. The ordinary cost is additional finite work and later first consultation: a tight request can stop before a table formerly reached. Work thresholds are source-specific capability observations, not public constants or a runtime-doubling claim. Under Full, the unit module still runs before content on the same allowance; this scheduling separates content grammar from content lookup.

Effective model pattern syntax

Model authors can request Assessment::ExpandedPatternSyntax or use esdieff check --assessment expanded-pattern-syntax-v1 model.sdf.json. This immutable profile is esdieff.expanded.pattern-syntax/1: the initial eight assessment areas plus pattern-syntax/1. It checks the syntax of effective string-valued pattern qualities. The reasons are ADR 0014: Bounded partial ECMAScript pattern capability and ADR 0028: Bounded effective model pattern syntax.

Syntax follows RFC 9880 Appendix C.2 and ECMA-262 2025 Section 22.2.1, with Unicode u semantics. The suggested portable subset is not a restriction on permitted syntax. A private pinned regress 0.12.0 parser uses Unicode mode with optimization disabled. This partial capability independently guards active Unicode escape spelling, escaped name terminators and decimal quantifier endpoints; an unverified parser rejection does not establish an RFC error.

Full descriptions at Property, sdfData, Action input/output, Event output, nested properties and final choice/enum alternatives are eligible. An explicit type:"string" is unnecessary for model syntax checking. A present nonstring retains its ordinary data.string shape error and supplies no string syntax operation. Restricted Direct items retain opaque pattern vocabulary; their eligible Full properties and alternatives are checked. A Direct donor’s unavailable pattern meaning stays unavailable in a Full receiving branch until a surviving explicit Full override establishes that quality.

Composition precedes this rule. A surviving inherited pattern is assessed at its consumer’s effective path with the nearest authored source token related. A surviving override uses its own authored token; a merge-patch null deletion removes the quality. Ordinary source null remains an ordinary nonstring value. Source structural replay does not cover syntax and cannot suppress this rule. Unknown needed critical context, role, member, contributor or text leaves affected work unfinished while available siblings remain usable. Source content is never substituted for unavailable effective meaning.

Catalogue checks independently root every model source, including unused definitions. Selected checks assess surviving content of their selected roots and needed imports. Listing a dependency does not separately assess its unused, overridden or deleted patterns. Source/effective inspection and other explicit assessment profiles retain their purposes. Selected sample checking checks needed pattern syntax as a model parameter before matching; it does not request the expanded model-syntax assessment or change that assessment’s inventory.

Established resultCondition and basisArea status
All applicable syntax evaluatedNo condition for admitted syntaxassessed, including any established errors
Invalid qualified syntaxpattern.syntax, error, RFC and ECMA citationsassessed when other needed work completes
Duplicate decoded capture names, unverified escaped names or parser rejectionpattern.unsupported, incomplete, pattern-syntax-capabilityundetermined
Needed effective meaning or text unavailablepattern.unavailable, incomplete, pattern-establishmentundetermined
Original work/allocation, admitted structure, parser or worker capacity exhaustedoperation.limit, incomplete, pattern-syntax-capabilityundetermined
Complete traversal finds no applicable string patternsNo syntax conditionnot_applicable

Every retained pattern condition has assessment_unit:"pattern-syntax/1". Fixed messages keep private parser text out of reports. Optional condition, coverage-row or pointer omission preserves established errors and semantic status. Failure to retain a finding after proving invalidity omits its detail without creating a semantic limit. Several unsupported patterns still leave only this one requested area undetermined.

FullBaseline also runs this available rule, owning M047 in full.pattern-format/1 of its fixed13-area inventory. Producing conditions retain pattern-syntax/1; optional coverage_owner identifies the Full area. Syntax completion is separate from the modeled matching capability M048. The report contract separates findings, requested coverage and broader coverage.

Only three syntax capacities are configurable: Limits::pattern_bytes at most 4096 UTF-8 bytes, pattern_nesting at most 64 group levels, and pattern_alternatives at most 512 total alternatives. Defaults are these ceilings; zero or larger values are configuration errors. Decimal quantifier endpoints at or above 1,000,000 exceed capability; reversed decimal bounds independently establish invalidity without machine-integer conversion. Capture-name length, matching capture slots and named-scope limits are matching capacities, not syntax restrictions.

Traversal, guard scans, decoded-name storage, comparisons, parser admission and pattern finding capacity use the original operation’s remaining work/allocation counters. Sources, branches and patterns receive no fresh allowance. Before its first worker, syntax reserves one logical 4 MiB stack slot from that original allocation allowance and retains it for sequential reuse. One worker is created lazily for the allowance and joined when it is dropped. Guards, parsing, emission and destruction stay inside it, and no engine object escapes. A lowered allocation limit unable to admit that slot leaves syntax unfinished.

Work accounting counts logical byte visits and admitted dependency invocations. Finite input/structure admission does not measure every parser/emitter instruction, bound its private heap, enforce cancellation or promise total resident memory or a wall-time deadline. The library owns the lifecycle, so embeddings need no executable discovery, caller runtime or regex-engine types.

Report admission adds 171 bytes to the existing applicable mandatory reserve for either invoking profile, before composition or syntax work, and subtracts the same amount from optional presentation space. Mandatory owners, optional owners and encoding/output buffers keep their existing independent partitions. This reserve adds no engine manifest or complete-conformance claim.

Model matching meaning

FullBaseline establishes M048 only when the surviving effective pattern can be compiled by the adopted Unicode, unanchored matching implementation. It supplies no subject, performs no match and does not seek a satisfying witness. A pattern such as (?!) therefore has established matching meaning despite admitting no text value. M047 independently owns syntax errors.

Compilation reuses the selected sample matching implementation, including its runtime allocation probe, matching-only capture/name/scope guards and original operation allowances. Syntax can be assessed while M048 remains undetermined because matching capacity is unavailable. Zero remaining interrupts or duration, worker/runtime capacity, unsupported interpretation and invalid syntax also leave matching meaning unfinished. The compiler uses the same paid sequential worker stack slot and configured heap reservation as sample matching. No new allowance is assigned to a pattern or alternative.

Byte-string model interpretation does not establish whether an authored text pattern constrains encoded text or byte data. That affected M048 meaning stays undetermined under ADR 0007: Generated SDF and sample JSON; the independently known byte interpretation, base type and pattern syntax retain their own observations.

This establishes the adopted modeled interpretation and available compilation capability. It does not promise that every future subject fits the subject, allocation, interrupt or duration allowance. Parsing and compilation retain the finite supplied-size guards and lack external cancellation, as documented in ADR 0014: Bounded partial ECMAScript pattern capability.

Selected sample matching

Catalogue::check_sample and the sample command apply Unicode u matching to needed ordinary nonnull string values. Matching is unanchored unless the authored pattern supplies anchors. Unicode escapes, character classes, lookaround and backreferences use the pinned ECMAScript engine selected by ADR 0014; the suggested portable subset is not imposed as a restriction.

A definite mismatch is sample.pattern, a sample-domain error with RFC 9880 Appendix C.2 as its basis. Its primary location is the actual sample value, with an original span for byte input and a null span for a typed input. Related locations identify the effective consumer pattern and nearest authored source token, including imported and overridden patterns. A mismatch can coexist with independent length or const failures. Optional diagnostic, witness and pointer omissions do not change the established rejection or its counts.

A malformed needed pattern remains a pattern.syntax model error. Its sample matching conclusion is undetermined; the malformed model alone does not prove a sample mismatch. A complete good choice alternative can admit the sample and finish the text area while the independently established model error still fails the operation. Nontext samples and null do not request text constraints. Opaque Direct items and inherited unavailable meanings remain unfinished.

Unsupported matching produces pattern.unsupported; finite matching work, subject, engine compilation, allocation or stack exhaustion produces operation.limit. Both use operational pattern-matching-capability and identify sample-text-boolean/1, preserving independent findings. Neither is a syntax violation or a sample acceptance restriction. The fixed nine-area esdieff.sample/1 inventory remains unchanged. Supported matching also feeds selected choice witnesses and declared-value consistency; documentary defaults are never inserted as sample data.

The supported controls are Limits::pattern_subject_bytes at most 1 MiB, pattern_heap_bytes at most 16 MiB of configured engine allocation, pattern_stack_bytes at most 256 KiB, pattern_interrupts at most 10,000 polls and pattern_deadline at most one second of accumulated cooperative engine time. Defaults are 1 MiB, 16 MiB, 256 KiB, 100 polls and 25 milliseconds. Subject, allocation and stack settings must be nonzero; zero polls or duration gives a work limit. Each engine call spends one entry poll, and engine interrupt callbacks spend the same shared remainder. Short matches therefore spend allowance even if the reused runtime does not reach its internal callback interval. The engine allocation setting excludes allocator rounding and overhead and is not a resident-memory guarantee. A minimal-limit runtime probe checks gross enforcement, including feature-unified embeddings. Pattern size, nesting and alternatives retain the syntax ceilings above.

Matching-only capacities are 124 decoded UTF-8 capture-name bytes, 254 explicit captures and 256 alternatives when any named capture occurs. These limits are applied after syntax admission and leave matching incomplete. Syntax and matching share the original operation work/allocation and one paid worker stack slot; the engine reservation, polling allowance and cooperative duration are retained across values, alternatives and declared-value candidates. Parsing and compilation remain finitely admitted but have no externally enforced cancellation. One runtime and context are initialized lazily and reused within the allowance. Each call compiles its own expression, clears pending exceptions and collects garbage. Request text is copied only after admission against the original work and allocation counters. The runtime is destroyed on its owning worker when the allowance is dropped.

Explicit numeric contradiction advice

Select Assessment::ExpandedNumeric or CLI --assessment expanded-numeric-v1. The request, inventory and requested-coverage identity are esdieff.expanded.numeric/1. It contains the Initial eight areas plus advisory-numeric-three/1, counted once across the selected model scope. This follows ADR 0030: Bounded numeric advice.

Warning codeSufficient local contradiction
proof.integer_interval_gapEstablished integer type, finite lower/upper bounds and null exclusion leave no integer between the adjusted endpoints.
proof.numeric_const_boundA sole ordinary numeric const is excluded by an applicable ordinary bound. All four surviving bound qualities are checked independently. Established absent type is permitted, with no invented type argument or origin.
proof.step_interval_gapEstablished number/integer type, a positive ordinary numeric multipleOf, finite bounds and null exclusion leave no lattice point. Integer type intersects the step lattice with integers.

Conditions have Warning severity, Advice basis, their warning code as basis ID, and RFC 9880 Appendix C.1 as the constraint citation. Strict warnings changes disposition while preserving severity, counts and completion. Failure to find a warning establishes no general satisfiability, sample admission or restrictive refinement. Initial, other expanded profiles and Full keep their existing scopes.

Final meaning and applicability

Only established effective Full data descriptions are evaluated: Property and sdfData definitions, Action input/output, Event output, properties entries and derived Choice alternatives. Direct items themselves are excluded. A receiving Full role does not upgrade unresolved Direct donor meaning. Surviving established overrides supply their own meaning and original token provenance. Enum text occurrences remain distinct existing alternatives; they are not parsed as numbers. Choice and Enum owners receive no union emptiness proof.

Quality or contextNumeric boundary
typeInteger enables integer-gap; number/integer enables step-gap and typed const-bound. Proven absence enables const-bound only. Known string/Boolean/array/object types are outside these classes; unknown or malformed relevant type leaves work undetermined.
constA final ordinary numeric root enables const-bound. Any independently established ordinary nonnull sole root kind can exclude null for interval proofs, including a compound root with unavailable deep payload. Unknown identity, donor or interpretation cannot supply that guard. Null remains an authored value where composition has not deleted it.
minimum, maximum, exclusiveMinimum, exclusiveMaximumAll surviving ordinary numeric bounds apply. Strongest known endpoints are selected; exclusivity wins equal ties. Unavailable magnitude leaves affected work incomplete while independent known subset contradictions can remain. Boolean exclusivity is not interpreted using older JSON Schema rules.
multipleOfPositive ordinary values enable step-gap. Zero, negative or wrong-kind values retain original parameter findings and are outside that class. Unavailable magnitude leaves the step obligation incomplete without removing an independent integer/const contradiction.
nullableFalse excludes null. True or default true admits it unless an independent nonnull const root excludes it. Unknown flag leaves dependent interval work incomplete; const-bound needs no false flag. default is never inserted or used as const.
sdfTypeAny present selector is outside ordinary numeric support and leaves otherwise relevant work undetermined.
formatAny present format leaves interval denotation unsupported. For an actual ordinary numeric const only, uri, uri-reference, uuid, date, time and date-time have independently irrelevant text meaning. Other, malformed or unavailable format selectors leave relevant work undetermined.
items, propertiesPresent structure must have independently established applicable array/map meaning. Numeric type or const does not license ignoring it. Established array/map containers are outside numeric classes; separately visited Full descendants can qualify.
requiredEstablished object-only data presence is irrelevant after an ordinary numeric domain/root establishes nonobject applicability. It does not establish properties structure.
minItems, maxItems, uniqueItemsEstablished Full array-only constraints are irrelevant after ordinary numeric applicability excludes arrays. Grouping-size meanings belong to grouping roles outside numeric classes.
minLength, maxLength, patternEstablished text-only meaning is irrelevant after ordinary numeric applicability excludes text. Pattern matching is not performed here.
default, unit, contentFormatEstablished documentary or representation-only meanings do not change numeric equality or bounds. Unavailable payload is independent only when meaning and role are established.
description, label, $commentEstablished metadata is independent in its legal role. label is not admitted as a Direct-item quality. Information metadata, including title/version/modified/copyright/license, is not whitelisted in Full data maps.
readable, writable, observableEstablished Property permission meaning is independent. Other Full placements leave relevant numeric work undetermined.
sdfRequiredEstablished Property/affordance/group declaration-presence meaning is independent. Data-only, IO, properties-entry and Choice placements remain unsupported for otherwise relevant numeric work. sdfRequiredInputData keeps the historical vocabulary refusal.
sdfThing, sdfObject, sdfProperty, sdfAction, sdfEvent, sdfData, sdfInputData, sdfOutputDataExisting legal parent roles govern traversal. Grouping and Action/Event owners are outside the classes; each independently established Full descendant is evaluated. Unavailable child identity/traversal leaves work incomplete.
info, namespace, defaultNamespace, featuresExisting feature and reference preflight establishes needed context before proofs. Unsupported critical features and unavailable needed bindings cannot be bypassed by numeric spelling.
Unclassified qualities, unsupported placement, unknown member/role/donor identityNo presumed irrelevance or restrictive meaning. Dependent work is undetermined; independent established descriptions keep their findings. Optional pointer/span omission alone does not change semantic eligibility.

Exact arithmetic and limits

The original exact number token is retained. Signed zero and equivalent decimal notation compare by mathematical value. Endpoint quotient rounding accounts for sign, remainder and exclusive integral endpoints. For positive decimal step p/q in lowest terms, integer values use the common lattice pZ. For example, integer [1,2] with step 1.5 has a gap, while number [1,2] includes 1.5.

Virtual long-division numerator/denominator widths are bounded at 1024 digits; adjusted quotient buffers allow 1025, and finite coefficient factor storage 513. A small-magnitude quotient shortcut precedes virtual-width admission. Large matching exponents can cancel; a large unmatched exponent can be unsupported. The integer intersection uses the numerator of the reduced decimal step. Thus integer [1,2] with step 0.6 has no admitted value, while step 0.2 admits both integers. A valid source number can exceed the derived quotient width without being a malformed model parameter. These are implementation capabilities, not restrictions on the standard’s mathematical numbers. No exponent-sized buffer or exponent-counting factor loop is used. The original numeric-work and derived-allocation remainders are shared across classes, models and alternatives, including input work already consumed.

Relevant unavailable meaning, magnitude, work or storage makes the one area Undetermined. A supported attempt is Assessed even without a warning; complete traversal with no eligible class is NotApplicable. An operational proof.numeric_capability_unavailable condition uses basis expanded-numeric-capability, its class and reason, and no citation key. The undetermined area uses expanded-numeric-establishment; completed and not-applicable area rows use Advice basis advisory-numeric-three/1.

The additional mandatory report reserve is zero. Coverage rows and located conditions can be omitted at the original report admission floor; exact nine-area counts, statuses and outcome remain available. Four operand positions preserve the existing first three meanings and add step/null-guard provenance where needed. Presentation omissions do not discard established warnings or hide unfinished siblings. See the report contract.

Initial contradiction advice

Esdieff explains four kinds of constraint contradiction in established effective Full Data Descriptions. Each proven contradiction produces warning advice with a stable proof.* code and assessment_unit:"advisory-four/1". This follows ADR 0003: Check findings and completeness, ADR 0009: Bounded processing and reporting, and ADR 0013: Shared workflow and report guarantees.

For example, type:"number", nullable:false, minimum:2, exclusiveMaximum:2 admits no numeric value. The warning explains the conflicting effective bounds, their nearest source contributors and the importing reference when present. Composition repairs and deletions are applied before proofs; the original source bytes remain available.

CodeEstablished premises and boundary
proof.empty_numeric_intervalBase number/integer, nullable false and an available lower/upper pair. Each present pairing of minimum/exclusiveMinimum with maximum/exclusiveMaximum is checked exactly. Lower greater than upper, or equal with an exclusive endpoint, warns once for that pair. Inclusive equality and integer gaps do not warn.
proof.inverted_text_lengthsBase string, nullable false and nonnegative mathematically integral minLength/maxLength, with minimum greater than maximum. Lengths count decoded Unicode scalars. Known uri, uri-reference, uuid, date, time and date-time formats preserve this independent constraint.
proof.inverted_array_countsBase array, nullable false and nonnegative mathematically integral minItems/maxItems, with minimum greater than maximum. No item or uniqueness consistency inference is made.
proof.primitive_const_typeBase number, integer, string or Boolean and an established scalar/null const. Integer constants use mathematical integrality, so 10.0 and 1e2 are integral. A nonnull wrong primitive kind is independent of nullable; const null contradicts nullable false, including with known string formats. Array/map constants and array/map base types are excluded.

Owners with enum or sdfChoice are excluded, including malformed selectors. Established derived alternatives and nested full properties have their own guards. Direct item descriptions themselves are excluded; inheriting a direct-item quality into a Full alternative does not establish a meaning that was unavailable in its donor. The effective alternatives contract preserves these distinctions.

Guard uncertainty affects only proofs that depend on it. Unrelated default, requiredness, unit, contentFormat or opaque descendants do not veto independent ordinary numeric bounds. Unsupported sdfType, byte-string, unix-time and unknown format meaning leave dependent conclusions unfinished. Recognized abstract formats alone do not establish nonnull primitive const compatibility from a conventional JSON representation. Unavailable roots, named entries, collections or traversal also defer the advisory area while independently established warnings remain available.

Acquisition spends numeric work across all supplied sources. Each check starts one counter from the immutable remaining acquisition budget and shares it across descriptions, inherited instances, classes and pairs. Exact comparison charges the longer normalized coefficient length plus one before comparing. Integrality premises charge one unit each. Exponent gaps do not allocate expanded numbers, and normalized powers do not reapply raw exponent limits. A failed numeric precharge leaves an unproved conclusion unfinished and produces operational operation.limit with the advisory area, proof class, comparison or integrality operation, and affected Quality Names. Independent nonnumeric proofs can still warn. Repeating a check uses the same immutable acquisition remainder.

These numeric limit conditions use Operational basis advisory-numeric-work. Their bounded arguments include proof_class with the corresponding proof.* code, operation with compare or integrality, and qualities with the one or two affected Quality Names in operand order. Available effective/source locations and optional exact lexemes follow the same witness bounds as warnings. Unavailable input meaning remains a separate establishment limitation; omitting a witness for presentation limits does not create another unfinished semantic check.

Optional witnesses retain at most eight locations: the effective description, up to three effective contradiction operands, their nearest source contributors and an importing consumer. Type is also a bounded argument. Numeric argument values retain original lexemes as strings when at most 1024 bytes; no floating conversion is used. Enum const contributors point to their actual authored occurrences. Count, byte and pointer limits can omit these details without changing aggregate warning counts or semantic coverage.

The fixed initial inventory has eight areas. These proofs determine advisory-four/1 independently of the seven structure/composition areas. The first three classes require established nullable false before becoming applicable; declared or specified-default true excludes them. Relevant uncertainty makes the advisory area undetermined once across the whole requested scope, regardless of how many specific numeric limits are reported. Full includes this same advisory area once alongside its12 model areas. Inspect does not perform these proofs. Absence of a warning does not establish general satisfiability. Strict warnings affect disposition, preserving warning severity and counts.

Declared-value consistency

Use Assessment::ExpandedConsistency in the library or esdieff check --assessment expanded-consistency-v1 in the command. The requested identity esdieff.expanded.consistency/1 contains the unchanged Initial eight areas and const-consistency/1 and default-consistency/1, counted once across model scope. Other assessments retain their membership, including Full’s fixed model inventory. See ADR 0031: Bounded declared-value consistency and the shared report contract.

const restricts data to a stated value. default is documentary data that may be used when interaction data is absent; base SDF defines no insertion process. This assessment checks stated values against their final effective data description. It does not modify either model or sample input, infer absent data, prove restrictive refinement or perform general satisfiability analysis.

Candidates and alternatives

Formatted-null equality follows ADR 0015 across the six base string formats. Null equals null and differs from an established nonnull formatted value; an invalid or uninterpreted nonnull operand leaves the comparison unfinished. Nullability can independently exclude a null constant or default. A null default can be excluded by a nonnull constant and vice versa without inserting any value. The same contextual comparison supports actual compound candidates, preserving one advisory warning per definitely excluded candidate and scoped uncertainty.

An ordinary description contributes its surviving const and default values. Choice overrides replace shared qualities, so each final alternative contributes its const candidate; an Enum occurrence is distinct even when two occurrences have equal text. A shared owner default is checked once against the complete Choice or Enum. An introduced or overridden branch default is checked separately. A branch reference introducing a donor default is local to that branch even when its source origin is inherited. Deleted branch overrides fall back to the surviving shared quality according to ADR 0024: Effective alternatives and nullable characteristics. Distinct importing consumers are assessed in their own effective contexts.

An alternative must admit the entire candidate. Constraints from different alternatives cannot supply different pieces of one witness. If one alternative admits it, the candidate is not excluded. If an unknown alternative could admit it, exclusion remains undetermined.

Supported reasoning and limits

The shared selected-value evaluator handles established ordinary scalar root kinds, null admission, exact numeric integrality and bounds, positive steps, Unicode scalar text lengths and supported Unicode ECMAScript patterns, map required entries and present properties, array counts, applicable items and contextual uniqueness. Equality preserves exact numbers, decoded text and structural values under the resolved description. Defaults are also checked against a surviving const restriction.

The same rules apply inside compound candidate values and nested named alternatives, including required presence, exact inherited/overridden numeric fields, compound const, contextual uniqueness, Unicode patterns, the six base string formats and the byte-string/POSIX conventions. A warning still belongs to one excluded declared-value candidate, with its actual decisive leaf and effective constraint. A sample mismatch remains a sample error in the separate sample operation. Documentary defaults do not fill missing required sample entries.

Civil date, time and date-time denotation follows ADR 0018: Civil date and time sample conventions through the same evaluator. An invalid civil candidate can supply established exclusion advice; unavailable leap meaning leaves consistency unfinished. Actual convention and C72 use are recorded even when an independent length restriction already excludes the candidate or a branch result is discarded. Under a common compatible format, established dates compare by calendar date and dated date-times by UTC instant with exact fractions and distinct inserted-second slots. Date-free time retains the identical-valid-representation boundary.

Unsupported needed pattern matching, other special formats or types, extension meaning, Direct item meaning, reference interpretation, unavailable data and finite semantic, numeric, equality or allocation limits leave the affected area unfinished. An empty array does not require unused item meaning, and an absent optional map property does not request its value constraints. Established independent restrictions can still produce advice while other work remains unfinished. Completing consistency does not complete Initial or other requested work.

Pattern matching follows the pattern contract. A malformed pattern actually consulted for a candidate is an independent model syntax error, recorded once per effective pattern even across const and default candidates or discarded alternatives. A complete admitting alternative can finish consistency while that model error still fails the operation. A dormant pattern without a candidate, or a constraint on an absent optional candidate entry, is not requested. The model-condition identity remains separate from optional diagnostic retention.

An established alternative collection may remain incomplete because some branch meaning is unfinished. Its owner candidate can still be evaluated when that deferral only summarizes the established branches. Every possible branch must independently exclude the entire candidate; a potentially admitting branch prevents advice. Local owner failures, unavailable candidates and unknown applicable constraint premises retain their existing limits. Aggregate deferral never makes the enclosing operation complete or supplies meaning to an unknown branch.

Each area uses assessed, not_applicable, unassessed or undetermined with shared status meanings. Assessed includes established exclusions. No applicable candidate after complete traversal is not applicable. Needed unsupported or unavailable evaluation makes the area undetermined. A completed or not-applicable row has Advice basis; an unfinished row has Operational basis without an RFC citation. The requested denominator stays ten when rows or condition details are omitted. Unavailable candidate-bearing containers also leave both areas unfinished when their descendants cannot be traversed. This includes hidden Full descriptions in Direct item properties or alternatives; it does not assess a Direct item’s own default or give unavailable descriptions evaluation capability. Established subtree overrides and opaque content retain their existing role boundaries.

Findings and provenance

consistency.const_excluded and consistency.default_excluded are advisory warnings, one per excluded candidate. They never add sample errors or turn advice into an RFC violation. Existing Initial warnings retain their producing identity and count: type: "boolean", const: 1 can produce the existing primitive contradiction and one const consistency warning, for two warnings in total. Strict warnings change disposition only. Aggregate counts survive zero diagnostic detail.

The source primary identifies the real decisive candidate leaf, or the real container when absence or structure is decisive. Related locations include actual effective description/constraint operands, paired values for uniqueness, a branch identity when needed, original contributions and the importing consumer. Composed values never claim a fabricated original Sample source or a donor’s whole compound token. Location or condition omission is explicit and preserves aggregate advice.

One request owns the remaining equality, numeric, semantic and allocation counters across all candidates and final alternatives. No per-candidate allowance, refill, refund or source-as-effective fallback is introduced. Existing mandatory report owners hold the two area aggregates; no added mandatory reserve is required.

Selected-sample operation contract

This extends the shared workflow and report contract under ADR 0016: Selected samples with explicit admission and coverage. It specifies observable behavior for the library, command, and versioned report. API spelling remains replaceable until implementation. Standards meanings follow the recorded baseline, RFC 9880 Sections 4.7, 5.2, 5.3, and 5.4, and normative Appendix C. This contract does not introduce a generic JSON Schema validator or a protocol payload binding.

The numeric workflow and typed projection boundary follow ADR 0025: Selected numeric samples. An ordinary Rust caller registers both roles together:

#![allow(unused)]
fn main() {
use esdieff::{Admission, Catalogue, SampleKind, SampleRequest, SourceInput};

let catalogue = Catalogue::take_inputs(vec![
    SourceInput::supplied("model", br#"{"sdfProperty":{"level":{"type":"number","maximum":100}}}"#),
    SourceInput::supplied("sample", b"101").sample(),
])?;
let report = catalogue.check_sample(
    SampleRequest::new(catalogue.source_id("model").unwrap(), SampleKind::Property,
        "/sdfProperty/level").sample(catalogue.source_id("sample").unwrap()),
)?;
assert_eq!(report.sample_result().unwrap().admission(), Admission::Rejected);
Ok::<(), &'static str>(())
}

For typed input, JsonBuilder constructs bounded values and SourceInput::typed registers their owned projection as a Sample source. Catalogue::take_inputs consumes inputs; Catalogue::from_inputs preserves the borrowed-input interface with bounded copies. Source::sample_value and SampleResult::sample_value expose the dedicated value view, whose span is optional. Source::has_original_bytes distinguishes original bytes from a projection, and Source::json returns unavailable for a typed projection because it cannot supply original-source spans.

Declaring selector identity is retained under a bounded metadata allowance, independently of displayed pointer limits and an older handle owner’s derived storage. Its ceiling is 8192 bytes; an Action/Event suffix can extend the internal description pointer to 8206 bytes. Mandatory sample reporting reserves 163930 additional wire bytes and a separate ownership/DTO share within the existing report allocation model. Exact requested string, ancestry and single-result capacities are precharged. Exhausted semantic storage, work, nodes or reference applications produce an unfinished domain result rather than losing the mandatory selector. The accounting and fixed-field inventory are recorded in ADR0025.

Conventional abstract samples

sdfType: "byte-string" selects canonical unpadded base64url decoded JSON text. Empty text is valid; padding, non-URL alphabet, whitespace and nonzero unused tail bits are rejected without repair. sdfType: "unix-time" selects exact numeric POSIX coordinates. Nonnegative fractions, large coordinates and -0 are supported within the existing exact-number capabilities. Negative nonzero numbers remain usable inputs with unfinished abstract denotation, rather than representation errors. Independent integer, null and other constraints retain their own conclusions. These conventions follow ADR 0007 and do not establish formal CDDL or protocol-payload admission.

Both const operands must establish their denotations in a common compatible context before equality or difference is concluded. Const, enum, compound values, uniqueness and consistency use that shared comparator. Applicable byte length or pattern qualities remain unfinished where their abstract interpretation has not been established; no decoded-byte length is invented from a text bound. Compatible POSIX numeric constraints use the original exact arithmetic allowance.

SampleResult::meaning() and mandatory result.meaning distinguish final abstract-values, const and admission support from their actual limitations. SampleResult::consulted_interpretations() records actual Byte/POSIX attempts, including discarded branches and failed work. A complete whole witness replaces tentative sample proof while preserving consultation and independent model findings. The shared report contract specifies reference identity, iterator length and optional-detail omission. For a decisive compound const difference, final proof retains the decisive rule and its established enclosing containers, excluding completed sibling meanings. Equal and undetermined pairs preserve complete or partial aggregate support; independent abstract-value support remains separate.

Selection and inputs

Catalogue::check_sample(request) selects exactly one description. A request carries one supplied model-document identity, an effective definition pointer, and one of five kinds: property, data, action_input, action_output, or event_output. The pointer names the Property, sdfData definition, Action, or Event, not an arbitrary nested constraint. For Action and Event selectors the kind selects its sdfInputData or sdfOutputData subdescription. For example, an action_input selector points to /sdfObject/Sensor/sdfAction/reset; its selected description is that effective Action’s sdfInputData. No Event-input or grouping selector exists. A typed effective description handle can construct the equivalent request without pointer reconstruction. The handle is bound to its owning catalogue/result and content identity; cross-owner or stale handles are request errors.

The selected document is the single model root. Other supplied model sources remain lookup candidates, with no position-based precedence or implicit fetching. Context includes the dependencies needed to establish that selected effective description and its constraint meanings. Catalogue source identities remain visible, including acquisition failures. An unrelated failed candidate does not alone obstruct sample admission. An unavailable candidate that could affect a needed contributor or ambiguity does obstruct the affected conclusion. Selecting a known absent definition or absent Action/Event description, the wrong class, an invalid pointer, an unknown root identity, or a nonmodel source as root is a request error. A selection that cannot be established because needed acquisition, decoding, composition, or interpretation is unavailable is a domain result with admission undetermined, rather than guessed absence or an error for an unknown selector.

Sample input is one whole supplied conventional JSON value, with a distinct request-local SourceId and source role sample. A conventional-JSON input owns immutable bytes and acquisition metadata; it must contain one JSON text without trailing second values. Exact original bytes remain available, including after decoding or A002 refusal. A typed Esdieff JSON value has null, Boolean, decoded scalar text, exact-number, array, and map constructors/accessors. Number construction accepts a checked JSON numeric lexeme or an exact checked machine conversion; it never rounds through a float. Map construction rejects duplicate decoded names under A002. Typed data is retained as owned values or immutable sharing and has a conventional JSON projection preserving accepted number lexemes. The projection is not an original source text: its sample locations have pointers, with span:null unless original supplied bytes and their token spans exist. Conventional byte strings and unix-time retain the representations in ADR 0007: Generated SDF and sample JSON; typed JSON is not an alternative binary/time encoding.

Missing sample input is a request error. A supplied JSON null has a value and is checked under ADR 0005: Nullability and presence, including const and choice constraints. No root-value omission or whole-interaction scenario is modeled. Required map entries are evaluated inside the supplied value; absent entries are not populated from default. Property readable/writable/observable and declaration sdfRequired remain model characteristics; choosing a Property sample does not simulate a read/write/notification or impose those capabilities as value constraints.

All model/sample/generated attempts share the 256-attempt and 1 MiB metadata preflight in ADR 0013: Shared workflow and report guarantees. The sample consumes one attempt and the shared acquisition/parsed-node/number/decoding budgets: 4 MiB per source, 32 MiB aggregate, depth 64, 100,000 nodes per source, 500,000 nodes per request, the exact-number token/coefficient/exponent/work caps, and shared checked semantic-work, derived-storage, location, diagnostic, and report limits. Sample acquisition is not an extra unlimited channel. Typed builders precharge nodes, text/key bytes, numeric tokens, and owned storage before copying or traversal. The same sample/effective evaluation shares the 10,000,000 work units and applicable equality/pair/pattern limits; repeated alternatives and nested values are charged. Default selection is at most 8 KiB of decoded JSON Pointer bytes; it is validated without clipping. Physical stack limits are supported bounds, never removed by raising a numeric configuration. A mandatory sample-report reserve includes both selectors, source roles, all nine area counters, admission, outcome, and omissions before acquisition. Presentation omissions preserve admission and aggregate counts; exhausted semantic work leaves affected admission or coverage unfinished.

Admission and conditions

A typed constructor shares one remaining decoding-work allowance across aggregate metadata visits, duplicate-name comparisons, decoded key/text scans, projection copying and decoding. Each traversal is charged before it runs; a new phase or key does not replenish the allowance.

The three conclusions are:

AdmissionRequired established basis
admittedAll constraints applicable to this sample in the selected effective description hold under an established common interpretation. For a choice, one complete effective alternative witness satisfies all its inherited and overriding qualities, with surrounding constraints that still apply.
rejectedAt least one violated applicable constraint supplies a proof unaffected by outstanding uncertainty. For a choice, every potentially admitting effective alternative is established not to admit, or an independent proof applies to all alternatives.
undeterminedNeither admission nor such rejection is established, including unavailable needed context, unsupported applicable meaning, unusable sample decoding, or required work limits.

The evaluator records the constraint/interpretation basis and sample/model locations. It does not create a synthetic RFC error solely from missing capability. Invalid JSON or A002 refusal is an input finding with admission undetermined; an invalid needed model parameter is a model finding with affected admission undetermined. Definite independent conditions survive scoped limitations.

Choice alternatives can overlap. A known matching branch is sufficient despite unrelated unknown alternatives when they cannot alter that complete witness. An unknown potentially matching branch blocks rejection when all known branches reject. Per-area successes from different branches cannot be combined into a fabricated witness. Effective inheritance and overrides are established before matching; a shared maximum overridden in one alternative cannot supply a proof against every alternative. Unavailable common/surrounding meaning that could invalidate the witness prevents admission. Known unknown branches irrelevant after a witness do not create unfinished requested units merely because they were not traversed. Their existence and witness basis can be explained without selecting an equality meaning.

Scalar and compound const compare ordinary values under ADR 0015: Bounded value equality in a resolved data context. Thus 10, 10.0 and 1e1 compare equal, escaped text compares after JSON decoding, and composed and combining text remain distinct. Different ordinary JSON kinds compare different without coercion. Arrays compare in order; maps compare decoded key sets and corresponding values without member-order significance. A definite ordinary length, key-set or sibling difference survives unavailable child meaning when the enclosing structure is established. Const contents are data: keys such as sdfRef or type inside a constant do not become vocabulary or reference instructions.

Before each const comparison, the evaluator establishes common meaning for that sample and effective constant across relevant local and enclosing final alternatives. Nested const and uniqueness retain those contexts through established ordinary array and map structure. An absent child description permits ordinary comparison after that structure is established; an unavailable child description leaves the affected comparison unfinished. A successful comparison or branch admission cannot establish an interpretation. Unknown or unavailable meaning blocks the affected equality proof. A conventional text-format branch can be irrelevant when an operand is an ordinary nonnull nontext value and the branch’s text representation domain is independently established; unfamiliar formats, unavailable type meanings and null do not supply that exclusion. A complete branch with no equality obligation can still admit independently of another branch’s unavailable equality. Each explicit const override creates its own obligation; it does not restore a replaced shared constant as a constraint on every branch. Enum retains each authored occurrence as a separate effective text-const alternative.

An established absent type adds no authored type constraint. For an ordinary nonnull number, applicable bounds and multipleOf still run; for ordinary nonnull text, scalar lengths and applicable unfinished pattern work still apply. A Full ordinary array or map with no authored items, properties or required can complete its structural family using the supplied kind, independently of const or uniqueness. Authored child qualities still require established applicable structure. Untyped unavailable count parameters remain unfinished, including beside assessed uniqueness. The evaluator uses the supplied kind without adding an effective type quality. Unknown explicit type, unsupported structural interpretation and unavailable inherited meanings retain their affected limitations. A matching const never bypasses another applicable constraint. Null retains nullable independently, and a nonnull const can exclude null even when nullability otherwise permits it.

Sample admission is independent of the shared disposition. A rejected sample emits at least one sample-domain error for its established violated constraint. Undetermined requested units contribute incompleteness, not a rejection error. Model-domain findings required to establish the selected context retain their original codes and bases. Strict warning policy can produce failed while admission is admitted. A definite rejection alongside an unfinished applicable constraint produces failed, complete:false, and admission rejected. Without blocking errors or strict warnings, unfinished requested work produces undetermined. Detail truncation changes none of these.

No whole-model assessment runs implicitly. result.context identifies selected-view availability and the needed model findings, independently of sample conclusions; it does not certify model validity. An explicitly performed catalogue or selected-model check remains a separate operation/result, reusable internally where source content, configuration, and baseline match. Its unrelated error does not become a sample rejection or a required sample error. Acquisition attempts remain visible in sources, even where their unrelated findings are outside the sample request.

Numeric sample types and bounds use the information-level meanings in RFC 9880 Appendix C.1, including mathematical integrality for tokens such as 10.0. They do not import Appendix A’s CDDL number/uint model-parameter grammar as a blanket sample-number width restriction. ADR 0012: Exact numbers and JSON input policies separately limits claims about formal model-parameter representability: exact access to a count parameter such as 18446744073709551616 does not certify that grammar. The sample result can establish an ordinary mathematical constraint conclusion without certifying the whole model’s grammar. Any actual needed uncertainty about the effective parameter or abstract data meaning leaves that affected sample work undetermined. Neither a failed machine conversion nor unassessed formal model-grammar work alone establishes that a supplied sample is rejected.

Ordinary string and Boolean admission uses the same selection, effective context, input locations and report. Boolean values require no coercion. Text minLength and maxLength are inclusive Unicode scalar counts under RFC 9880 Appendix C.2: "é" and "𝄞" each have length one, while "e\u0301" has length two. No Unicode normalization changes the supplied value. Count parameters retain the exact nonnegative mathematical meanings in ADR 0022: Scalar constraints and characteristic states, including counts larger than machine integers. Scalar traversal precharges decoded UTF-8 bytes against the work remaining after selected composition and checking, and both comparisons share the numeric allowance remaining after input parsing. Exhaustion leaves the affected area undetermined.

Length and pattern parameters are needed for an ordinary nonnull string. A different base type or a supplied null does not perform text matching; null still retains every other applicable obligation, including const and choice work. Documentary default never supplies a value. Supported Unicode ECMAScript matching follows the pattern contract. An unavailable matching capability or exhausted allowance keeps that work undetermined, while an independent established length violation can still reject the string. Needed format, abstract or alternative uncertainty prevents affected text proofs rather than being ignored. Unavailable Unicode scalar decoding remains a sample-input limitation even when no length bound is present.

Ordinary map samples

An established ordinary type: "object" follows RFC 9880 Appendix C.5. properties constrains described entries that are present; other entries remain unconstrained. required names mandatory entries, including names with no property description. Its whole nonempty list must have decoded names before any absence proof. Duplicate required names request presence once. Whole sample member identities must be available, including keys after a matching member. Unknown enclosing map meaning prevents structural admission or missing-entry rejection.

A present described entry uses its final composed description, real sample value and applicable scalar, null, map, array and alternative rules. An absent optional entry requests no child reference, invalid scalar parameter, array or format work. Neither default nor declaration sdfRequired supplies an entry. Unavailable equality context, unsupported format meanings and declared Extension features retain scoped limitations. Undeclared extension vocabulary does not, as described under Undeclared extension vocabulary. An independent missing entry or known sibling violation still supplies a rejection while another needed child remains unfinished.

Every map alternative needs a complete whole-map witness. A child’s known choice admission returns to its containing map, and different branches cannot supply different required entries for one fabricated witness. Raw branch roots settle before their final whole-quality overrides and present child references. Parameter finding storage, semantic work, derived storage and one numeric remainder remain shared across all pairs without refunds or resets.

For an Action input selected at /sdfAction/configure, an object requiring mode rejects {} at the sample map pointer "", with its real original span and the model’s /sdfAction/configure/sdfInputData/required/0 relation. A present null satisfies presence and is checked separately against the child’s nullable meaning. Required absence at a nested map uses that existing parent location; no missing-child location is invented. A wrong present scalar uses its own entry pointer and token span, or span:null for a typed projection. A declaration or payload key named sdfRequiredInputData remains an ordinary name; assessed legacy vocabulary retains the A001 restructuring guidance.

Ordinary array samples

An established ordinary type: "array" follows RFC 9880 Appendix C.4. minItems and maxItems are inclusive exact nonnegative mathematical counts, including authored counts larger than machine integers. Every actual element requests its established items description. Supported direct items include ordinary numeric, string, Boolean and object descriptions, and choices whose Full alternatives may contain nested arrays. Full object properties can also contain arrays. Wider direct-item array types, nested items, defaults, nullable meanings and reference imports retain the limits in ADR 0024: Effective alternatives and nullable characteristics. Unsupported needed item meaning prevents admission; an independent known count or child violation can still reject.

An empty array requests no element description. It can satisfy established outer array constraints even when the deferred item subtree has opaque meaning. This does not establish that subtree’s meaning or capability. A supplied element, including an empty inner array, requests its own actual item context and cannot use the outer array’s empty-case conclusion. For uniqueItems: true, one established equal pair disproves uniqueness, even beside other unknown pairs; proving uniqueness requires every necessary pair to differ. Empty and singleton arrays compare no pairs. False or absent uniqueness imposes no comparison obligation. Item checks and other constraints remain independent.

Const and uniqueness share the request-wide equality-pair ceiling, original structural/string/key work, numeric remainder and derived allocation allowance. The default pair ceiling is 100,000; Limits::equality_pairs can reduce it to a nonzero value. Every actual scalar or compound const and uniqueness pair spends one pair before comparison across nested values and alternatives. Work or representation exhaustion leaves the affected conclusion undetermined without refunding prior work. A duplicate condition uses the second element as primary, retains its real effective/source relation and appends the first element as related sample evidence. A const mismatch uses the real decisive leaf or structural root. Typed inputs have null spans; rendered pointer omissions preserve these conclusions.

Each element’s choice returns to the containing array conjunction. Different elements may satisfy different item alternatives, while a whole-array choice requires one complete whole-array witness. Shared item roots and final alternatives retain one identity and their real origins; present optional interests accumulate across elements. Absent optional entries never erase an earlier present interest. Common model conditions and newly needed parameter families are checked once per final description, including malformed conditions, without resetting work or finding storage. Inclusive count failures use sample.count with arguments.constraint naming minItems or maxItems, located at the actual array with its authored bound as related model evidence.

Combined compound descriptions

Compound descriptions combine these same rules recursively. Map entries and array elements can request named choices whose Full alternatives describe maps, arrays, ordinary scalars or supported abstract values. Shared qualities apply until an alternative explicitly replaces the whole quality. A complete alternative must establish the entire selected value; successful checks from separate alternatives cannot be assembled into one witness. Const and uniqueness still require a common established equality meaning under ADR 0015: Bounded value equality in a resolved data context, independently of which branch admits a value. Inherited object properties under an explicit array alternative can keep that common equality meaning unavailable. Nullable, required presence and documentary default remain separate.

The supported combination includes exact numeric fields, required map entries, contextual compound const and uniqueness, Unicode ECMAScript patterns, all six base string formats (date-time, date, time, uri, uri-reference, uuid), and the byte-string and POSIX conventions. These meanings use their existing representation contracts at every needed nested location. An inherited field can keep its donor minimum while a consumer overrides its maximum; findings identify the actual sample leaf and the effective constraint, with the applicable original contribution related. A missing required entry is located at its existing parent.

One known admitting compound alternative supplies a witness. A potentially admitting unresolved alternative prevents rejection by the other branches, while an independently violated enclosing or sibling constraint can still reject with unfinished coverage visible. Restricted Direct donor meaning stays unavailable when copied into a Full alternative until an explicit establishing override. Decoded-byte lengths, incompatible or unknown equality interpretations, declared Extension features and matching capabilities retain their existing scoped limits. All values, alternatives, equality pairs and matches share the original finite request allowances. Combining implemented capabilities does not establish whole-model conformance or general satisfiability.

Undeclared extension vocabulary

Undeclared extension vocabulary does not stop sample checking, following ADR 0037: Undeclared extension vocabulary. That is a qualified or unqualified Quality Name outside base SDF, such as acme:note, sdfProtocolMap or a misspelled minimun, in a document that declares no Extension feature. A selected Property, sdfData, Action input or output, or Event output description carrying it admits or rejects a sample on its base description, as if that quality were absent. The same holds for nested object properties, Direct items and choice alternatives. Const and uniqueItems comparisons use that base meaning too, so 7.0 matches const: 7 beside acme:note. Recorded extension vocabulary at a position its registration names, such as oma:id on a Property under ADR 0038: Recorded extension vocabulary, is set aside the same way. Sample checking does not check its value.

The extension’s own meaning stays unsupported, and a model check still reports the vocabulary’s notice or unfamiliar-name warning. A base quality outside its role, such as a wider Direct item quality, is not extension vocabulary and keeps its scoped limitation. So do unknown values of base qualities, such as format: "email", documents that declare an Extension feature and descriptions composed from them.

baseline.interpretations lists undeclared-extensions-ignorable/1 whenever a sample context set aside undeclared extension vocabulary and the sample conclusion went on from the base description. A Sample report omits it when the vocabulary lies outside every description the sample reached, for example on the enclosing Object or in an absent optional entry, and when a base quality outside its role or an unknown base value already stops the affected conclusion. Recorded extension vocabulary that a sample context set aside names it too, because a Sample report never consults recorded registry evidence. SampleResult::consulted_interpretations() still records only Byte and POSIX attempts.

Immutable requested coverage

FullBaseline separately establishes known byte-string and Unix-time model interpretations as M026 and M027. It supplies no synthetic value, decodes no bytes and assigns no time coordinate. The canonical unpadded base64url and exact POSIX numeric conventions above continue to govern actual constants and selected values. Model interpretation does not establish decoded-byte length, negative POSIX denotation, leap-instant representation or general satisfiability.

The default and first supported profile is esdieff.sample/1, requesting all applicable base-SDF admission obligations in the following nine areas. Membership is independent of implementation. Each area contributes exactly one status to the requested aggregate; applicable recursive constraints, values, alternatives, and limitations are summarized within that area and may have bounded per-location detail. A whole-model RFC inventory is not this inventory.

Area identityFixed membership and guards
sample-context/1Sample acquisition/decoding/policy, description selection, needed reference composition and critical-feature understanding. A failed needed prerequisite leaves this area unfinished and any dependent areas undetermined, not inapplicable.
sample-type-null/1Established effective base type, mathematical integrality, null admission, and their interaction at all needed data locations/alternatives. Null does not bypass other constraints; absent map entries are separate map obligations.
sample-numeric/1Inclusive/exclusive numeric bounds and positive multipleOf, exactly and recursively where applicable. Unknown abstract numerical meaning is not ignored.
sample-text-boolean/1Boolean value admission; Unicode scalar text lengths; ECMA-262 Unicode pattern syntax/matching where applicable. Abstract format denotation belongs in abstract-values; JSON escape decoding belongs in context.
sample-const/1Scalar/compound const matching using context equality from ADR 0015: Bounded value equality in a resolved data context; no fallback to representation equality. Documentary default never supplies sample data.
sample-alternatives/1Effective sdfChoice inheritance/overrides, enum expansion, and existential admission/rejection with complete witnesses. Recursive choices retain this meaning; ordering supplies no interpretation or witness by itself.
sample-map/1Established object structure, entry descriptions, allowed entries and required presence, recursively. Data required is distinct from declaration sdfRequired. Applicable unsupported item/object vocabulary remains unfinished rather than imported from a generic schema.
sample-array/1Array structure, inclusive counts, established item descriptions and uniqueness, recursively; grouping-array counts are outside a selected data description. Item vocabulary and equality limits remain explicit.
sample-abstract-values/1Applicable format/sdfType denotations and conventional representations, content-format meaning where relevant to admission, supported extensions and external knowledge needed to determine sample value meaning. Known names alone are not sufficient capability.

An area’s assessed status means its requested obligations have been established satisfied or violated; findings are compatible with assessed. not_applicable requires established irrelevance for the selected sample context, not an absent implementation. unassessed means needed applicable work has not run; undetermined means work was attempted but a needed conclusion remains unavailable. All nine statuses sum to nine. Requested completeness requires each area assessed or not applicable, even if an independent rejection already exists. If the context is unavailable, dependent membership cannot be declared not applicable. A profile may gain implemented checks under the same identity; new membership, standards meaning, or guards require a new profile identity. New profile identities are explicit caller choices, not silent aliases for whatever is currently supported.

Ordinary scalar descriptions, including scalar const, supported Unicode patterns, enum and nested choices with complete effective witnesses, can complete this profile when their other areas are established inapplicable. Needed unavailable equality, pattern, compound or abstract meaning keeps requested work unfinished. Pattern outcomes and their finite matching controls follow the pattern contract. Later implementations fill the existing obligations rather than silently replacing their meaning. Broader model-baseline coverage retains the shared partial/undetermined state and inventory availability; a sample pass supplies no model conformance claim.

Versioned report extension

Sample finding and rejection-witness bases identify the producing work: numeric type and arithmetic conclusions use RFC 9880 Appendix C.1, ordinary string type and scalar length conclusions use Appendix C.2, Boolean type conclusions use Appendix C.3, const uses Appendix C, alternatives use Section 4.7.2, and rejection of null by nullable:false uses Section 4.7 Table 4. Relevant established coverage carries the same type basis; combined type/null coverage cites Section 4.7 and Appendix C. Admission witnesses retain Appendix C and identify the complete alternative when applicable. Tentative branch failures become sample errors only when every potentially admitting alternative has been excluded; independently needed model conditions retain their own counts and bases. Context establishment uses sample-establishment, and applicable unimplemented work uses sample-implementation, including unfinished pattern work alongside an independent length rejection. Needed sample decoding limitations retain their original cause, domain and available location; optional omission does not remove them from diagnostic counts. Unrelated Model parser leaves do not become requested sample findings.

A const finding and its rejection witness cite Appendix C even when contextual equality uses Byte or POSIX meaning inside a scalar or compound value. The const coverage row summarizes established equality work and can instead carry the specialized Byte or POSIX interpretation when it is the sole abstract interpretation in the final const proof. Complete meaning.const and meaning.admission references retain that interpretation and any necessary container support alongside Appendix C. Consulted interpretations record actual use, including work that does not survive as final proof. These fields serve distinct purposes; a single finding or coverage basis does not replace the complete meaning references.

The sample report is schema:"esdieff.report", version:"1.1", operation:"sample". Check and inspect contracts, fields, units, values, null meanings, and exit rules remain unchanged. A reader supporting only check/inspect rejects the new operation before interpreting its payload. Existing shared objects apply unless specified below; these tables define the sample operation’s additional required fields and closed tags. IDs are compact nonzero u32; Count/Bytes retain shared checked-u32/nonnegative-byte meanings. All strings and details consume shared metadata/report budgets. Missing required fields are invalid reports.

ObjectRequired fields and typesOptional fields / null meaning
Top levelShared required fields, with operation "sample", request SampleRequest and result SampleResultNone.
SampleRequestassessment:"esdieff.sample/1"; inventory:"esdieff.sample/1"; scope:Scope; selector:SampleSelector; sample:IdNo nullable assessment/inventory. Scope selected roots is exactly selector.document; sample references a source with role sample and is not a model root/dependency.
SampleSelectorkind:`“property”“data”
RequestedCoverage for sampleinventory:"esdieff.sample/1"; count_unit:"sample_area"; total:9; assessed:Count; not_applicable:Count; unassessed:Count; undetermined:CountNone. Counters sum to9; no substitution of inspection or model-assessment units.
CoverageRow for sampleid:one of the nine area identities; count_unit:"sample_area"; status:shared coverage status; basis:BasisShared source_ids/reason_code. Any separately emitted requirement detail uses count_unit requirement; the two units are never summed.
Condition for sampleShared Condition fields plus domain:`“model”“sample”
SampleResultkind:"sample"; admission:`“admitted”“rejected”
SampleContextstate:`“available”“partial”
ContextFindingserrors:Count; warnings:Count; notices:CountCounts retained-or-omitted relevant model-domain conditions, not sample-domain errors. Unrelated catalogue findings from a different operation are not included. Incomplete requested units are counted only in the shared outcome, without duplicate area counts.
SampleWitnesskind:`“admission”“rejection”`; effective:EffectiveLocation; sample:SampleLocation; basis:Basis

SampleSource metadata uses the shared Source object. A typed input has acquisition supplied, conventional retained bytes if a bounded projection is retained, and no fabricated byte spans. Sample spans for byte input refer to its original immutable bytes. Pointer rendering omissions keep the source ID and available spans. The sample pointer root is ""; malformed/partially decoded nested input can have pointer null and span when available. Effective description locations use the selector root and the selected description path, including input/output suffixes; they claim no source span. Related source locations explain inherited and overriding constraints when available.

Witness arrays and diagnostic/coverage rows are optional-detail collections bounded by the shared limits; omitted witnesses do not change retained admission or counts. Omissions explicitly identify their report paths and reasons. Human output states selected kind, sample identity, admission, shared disposition/completeness, scope/coverage, and relevant sample/model locations. It derives these from the same result as JSON. No human wording or array order becomes the stable interface.

Adding optional sample fields/codes within 1.x follows the shared rules. Changing required field types, these null/tag/unit meanings, or admission semantics requires a major report version or a newly explicit operation/profile contract as appropriate. Rust builders/accessors keep private fields and extensible result enums; wire DTOs do not serialize internal enum layouts.

Civil date-time, date and time use the civil-time contract. Their denotation fills sample-abstract-values/1 without changing the nine-area inventory. Ordinary string lengths remain independent. Two established Gregorian dates compare equal for the same calendar date and different for different dates, independently of JSON escape spelling. Compatible established date-times compare by UTC instant, excluding offset annotations and preserving exact fractions and distinct inserted seconds. Date-free time retains equality for identical denoting representations and unavailable comparison for differing representations. Invalid or unavailable denotation supplies no temporal equality or difference. Unknown or incompatible meanings across alternatives remain explicit.

Command acquisition

The proposed command is esdieff sample --document MODEL --kind KIND --pointer POINTER --sample SAMPLE [--strict-warnings] [--format human|json] MODEL_INPUT.... MODEL must match one explicit model input; KIND is one of the five selector tags. SAMPLE is an explicit file path or -; model inputs also allow - for one stdin document. Only one total stdin use is permitted across model and sample acquisition, so a sample - excludes a model -. Duplicate stdin, missing sample/model/kind/pointer, unknown model roots, wrong known selector roles, invalid options, and malformed pointer are invocation errors with exit2. No default sample is invented and no default document is selected by input position.

The command registers all acquisition attempts before reading and applies shared limits. The sample gets its own identity even if its path equals a model path; roles remain separate, with bounded role-qualified opaque caller keys. Non-UTF-8 paths retain exact filesystem identity with safe bounded labels. File/stdin acquisition or decoding failures are structured domain results. They never make a definitely missing sample silently null. Exactly one chosen report and trailing newline goes to stdout; stderr contains invocation/host-output failures. Shared exits apply: 0 passed, 1 failed including strict warnings or established sample rejection, 2 invocation/configuration error, 3 undetermined without blocking errors, 4 report/host-output failure. Failed plus incomplete uses1 and retains complete:false.

Concrete observations

Temperature describes number, nullable false, minimum -50 and maximum150. Sensor.temperature inherits Temperature. Device.ambient overrides its Property maximum to100; its changed Event output retains maximum150. For the owned byte sample 101:

  • Property selector /sdfThing/Device/sdfObject/ambient/sdfProperty/temperature gives rejection at sample source root pointer "", span [0,3]; its effective /maximum is100, with source explanation at the Device override. Its initial numeric work can be complete if all other applicable sample obligations are assessed/not applicable.
  • Event-output selector /sdfThing/Device/sdfObject/ambient/sdfEvent/changed selects its /sdfOutputData; the same sample admits under maximum150. Source Temperature and Sensor bytes and source maximum150 remain unchanged. The Event result is independent of the rejected Property result.
  • A model warning relevant to the usable Event description with strict warnings yields admission admitted, disposition failed, complete true, warnings1/errors0. This is not a sample constraint rejection.
  • An independent violated established Property maximum plus an unsupported equality-changing const yields admission rejected, disposition failed, complete false, errors1 and one unfinished const area, only when that unsupported meaning cannot change the numeric rejection proof. If it could alter the applicable numeric meaning, this fixture would be undetermined instead.
  • A previously performed catalogue check can fail on an unrelated unused source while the selected sample still admits. The attempted source remains visible, but that separate check’s error is not counted as a sample condition. Unavailable needed composition gives context unavailable/partial and sample undetermined; dependent areas are not reported inapplicable.
  • A complete ordinary choice alternative admitting 101 establishes admission despite another unresolved potentially matching alternative. If the known alternative rejects and the other may match, admission is undetermined. An unresolved surrounding meaning that could invalidate the known witness also gives undetermined.

These observations guide implementation at the public domain boundary. Exact byte spans are supplied by parsing original inputs; expected effective outcomes in a contract exercise are supplied acceptance fixtures and are not evidence that a resolver or sample validator has executed.

Civil date and time sample contract

This specifies the conventional representation and established temporal meaning portion of the selected-sample operation, under ADR 0018: Civil date and time sample conventions. It applies after the selected effective data description, applicable format, conventional JSON value and decoded scalar text have been established. It does not select an alternative, acquire model data, infer a date from neighboring sample fields, or certify the whole model. RFC 9880 Appendix C.2 supplies abstract data meanings; RFC 3339 Section 5.6 names their conventional productions.

FullBaseline can establish the known date, date-time and time model interpretations without a supplied value. This M049 observation neither invokes the temporal evaluator nor consults leap-second knowledge. Actual constants and selected values still require their own established denotation under the rules below. An unavailable exceptional slot can leave constant meaning unfinished while the named model interpretation remains established.

Conventional values and calendar

SDF formatConventional decoded JSON stringEstablished meaning
date-timeYYYY-MM-DD + T/t + full-timeAbsolute point in civil time with its supplied offset annotation.
dateYYYY-MM-DDGregorian civil calendar date, without a time or timezone.
timeHH:MM:SS[.digits] + offsetDate-free clock coordinate with its supplied offset annotation, not a unique dated instant or a recurring schedule.

Every numeric component uses ASCII digits and the displayed fixed widths. Source year is 0000..9999; month 01..12; day 01 through its Gregorian month limit; clock hour 00..23 and minute 00..59. February has 29 days when the year is divisible by 4, except a century not divisible by 400. The same rule applies to source year 0000, as the published RFC 3339 Section 2 and Appendix C arithmetic specifies. Gregorian arithmetic is used across the four-digit range without a historical local-calendar cutover. Offset subtraction may use an adjacent internal year outside that textual range; that intermediate result alone does not reject an otherwise permitted source date.

Seconds are 00..59 ordinarily, with 60 and a missing 59 governed below. A fraction is a dot followed by one or more ASCII digits. All digits remain exact; there is no fixed decimal scale, float conversion, nanosecond rounding or truncation. A long fraction may exhaust supported work, which gives undetermined rather than an invalid-format finding. Conventional source bytes and their JSON escape spelling remain retained separately from decoded text and temporal projection.

Z/z and signed offsets +HH:MM or -HH:MM are admitted, including both zero signs and offset hours through 23 with minutes through 59. The UTC coordinate is local clock minus offset, following RFC 3339 Section 4.2; a real-world timezone database is unnecessary. -00:00 denotes known UTC time while the local offset is unknown. Under the recorded RFC 3339 Section 4.3 baseline, Z/z and +00:00 carry the preferred-UTC-reference annotation. Preserve these annotations even though all three spellings use the same zero coordinate for leap-slot checking.

RFC 9557 Section 2 changes the Z annotation, while leaving UTC coordinate and this admission unchanged. That update is not implicitly adopted; a later deliberate baseline update must state it. Bracketed IXDTF timezone/calendar suffixes are not selected representations here. Neither an absent offset nor a timezone name supplies the RFC 3339 full-time offset. The date format has no offset suffix.

T/t is the selected date-time separator. The RFC 3339 note permits applications to choose another separator, so a space-separated timestamp fails this selected conventional representation without a claim that its abstract instant cannot exist or that every application forbids that syntax. ISO 8601 week dates, ordinal dates, expanded years, compact forms, comma fractions, hour 24, reduced precision and offset seconds are likewise outside these selected named productions. Malformed JSON, A002 duplicate-key refusal and unsupported escaped scalar decoding remain their existing input/context outcomes; temporal checking does not reclassify them as invalid dates. A supplied nonstring is not coerced. Null and conflicting effective type are evaluated under the existing nullable/type/choice contract rather than an unconditional nonstring format rejection.

The metadata quality modified has its own RFC 9880 Appendix A grammar allowing full-date or Z-terminated date-time, described by RFC 9880 Section 3.1. It does not make these sample formats UTC-only. A model metadata timestamp is not a default date or timezone for a sample.

Exceptional seconds and recorded knowledge

RFC 3339 Section 5.7 makes seconds conditional on leap adjustments and shifts the insertion point by the supplied offset. UTC 23:59 on the final UTC day of a month is the possible adjustment minute. June and December are historical and preferred opportunities, not a silently hardcoded universal sample grammar. Negative adjustments remove second 59; positive adjustments insert second 60. Fractions refer to the represented second and never roll it into the following minute.

For a date-time, derive the UTC minute and UTC date by subtracting the offset, including a change of day, month or year. The source date can be the following local day, such as 2017-01-01T05:44:60+05:45, whose leap slot is 2016-12-31 UTC.

Dated slot and recorded knowledgeSecond 59Second 60
Away from a possible UTC month-end adjustment minuteAdmitted temporal meaningRejected as an impossible insertion slot
Known normal minuteAdmittedRejected, no inserted second
Known positive adjustmentAdmittedAdmitted, including its fractional portion
Known negative adjustmentRejected, deleted secondRejected, no inserted second
Possible adjustment minute with no established knowledgeUndeterminedUndetermined

Seconds 00..58 remain available independently of adjustment knowledge. A syntactic second greater than 60 rejects. An impossible insertion slot rejects even outside the recorded knowledge interval because the independent slot rule is established.

Initial deliberately recorded leap knowledge is IERS Bulletin C72, issued 2026-07-06, together with its Leap_Second.dat transition table and Bulletin C72 text. The inclusive knowledge interval is 1972-01-01 through 2026-12-31 UTC. Each listed +1 transition identifies an insertion on the preceding date; the initial 1972-01-01 offset is not an insertion event. No negative adjustment is recorded there. The bulletin explicitly establishes no insertion at the end of December 2026. The snapshot’s 2027-06-28 expiry is not a no-leap promise through that date. Before the interval and after it, needed adjustment facts remain unavailable. Processing never fetches a replacement implicitly. Record the snapshot’s byte identity in the standards knowledge basis; adopting new knowledge changes that basis deliberately, following ADR 0002: Recorded standards baseline.

The recorded knowledge identity is iers-bulletin-c72/2026-07-06. Snapshot SHA256 identities are 6cb6f5d4b819f2e568e25db4b0b26d89dedf031fdffb18bc94d40f4e94e268d7 for Leap_Second.dat and 310e172eadacacca3adf92cb9bd646fcc0d6320e35e996a106d2644ede3b52f0 for Bulletin C72. Its 27 positive insertion dates are:

1972-06-30  1972-12-31  1973-12-31  1974-12-31  1975-12-31
1976-12-31  1977-12-31  1978-12-31  1979-12-31  1981-06-30
1982-06-30  1983-06-30  1985-06-30  1987-12-31  1989-12-31
1990-12-31  1992-06-30  1993-06-30  1994-06-30  1995-12-31
1997-06-30  1998-12-31  2005-12-31  2008-12-31  2012-06-30
2015-06-30  2016-12-31

A date-free time has no UTC date by design. Ordinary seconds 00..59 are admitted as date-free clock coordinates without asserting occurrence on every calendar day. A possible inserted-second label 60 at UTC 23:59 is undetermined because its eligible leap-label interpretation is unestablished. This is not a missing required date field and does not establish invalidity. Second 60 at any other offset-adjusted UTC minute rejects. This is an explicitly selected conservative interpretation of RFC 3339 full-time as imported by SDF. An existential some-valid-date interpretation could admit eligible 60, but the RFC does not select that quantifier, so that alternative is deliberately deferred. The evaluator does not use a host date, a model metadata date or an unstated sample sibling. Date-free comparison, normalization modulo a day and recurring-schedule semantics are not established here.

Sample results, locations and finite work

The temporal obligation belongs to sample-abstract-values/1, keeping the immutable nine-area esdieff.sample/1 inventory. It is assessed when temporal admission or an independent representation/calendar/slot rejection is established. An unavailable needed interpretation or capability leaves that area undetermined. Applicable decoded JSON, scalar text length and patterns, const equality, nullable/type and alternatives keep their own areas. An established ordinary JSON string type does not complete abstract-values by itself. One complete admitting alternative can supply a witness; rejection still needs proof covering every potentially admitting alternative.

A rejected temporal form contributes an error in the sample domain with primary sample location and a related effective format constraint location, with source contributor locations when available. Its basis distinguishes selected representation convention from an established calendar/slot requirement and recorded leap knowledge. The space-convention condition must not assert an RFC-invalid abstract date-time. Undetermined leap or work contributes incompleteness with its reason and affected locations, not an invented rejection error. The versioned condition catalogue below preserves these distinctions.

For a supplied root JSON string, sample pointer is "" and its half-open span is the complete original JSON token, including quotes. Nested values use their actual sample pointer and original byte span. Effective location is the selected effective description’s applicable /format path; it is not a fabricated source location or byte span. Typed JSON inputs have a pointer and span:null unless genuine original bytes exist. Inherited or overridden format source locations are related explanations, not replacements for the sample identity. Presentation omissions preserve available identity/span and aggregate conclusions.

The implemented condition codes and bases are:

CodeDomain / severityBasis
sample.temporal_representationsample / errorInterpretation ADR0018-selected-representation, supported by RFC 9880 C.2 and RFC 3339 5.6.
sample.temporal_calendarsample / errorRFC 3339 5.7 and Appendix C, RFC 9880 C.2.
sample.temporal_clocksample / errorRFC 3339 5.6 and 5.7, RFC 9880 C.2.
sample.temporal_exceptional_slotsample / errorRFC 3339 5.7, RFC 9880 C.2.
sample.temporal_leap_secondsample / errorThe same slot basis, with recorded C72 identity.
sample.temporal_knowledge_unavailableoperation / incompleteOperational temporal-knowledge, supported by the slot basis.
sample.temporal_meaning_unavailableoperation / incompleteOperational sample-establishment, supported by ADR0018 and the selected productions.
operation.limitoperation / incompleteOperational sample-establishment, with affected abstract-values area.

Each specialized incomplete condition identifies sample-abstract-values/1. It replaces the generic coverage detail for that same cause, including when optional detail is omitted. Independent const, alternative or other unavailable meanings retain their own details; each requested area is still counted once. Incomplete conditions never supply rejection witnesses or sample errors.

baseline.interpretations records ADR0018-selected-representation when the convention is consumed. baseline.temporal_knowledge carries the C72 identity, interval and both snapshot digests only after an actual adjustment query, including outside-interval queries and discarded branches. Dates, ordinary seconds 00..58, second 59 away from a boundary, date-free time and independently impossible insertion slots do not consult C72. Established null and wrong-kind constraints exclude temporal grammar and record neither use flag.

The evaluator precharges 2 * decoded_length + 256 original semantic-work units for the borrowed representation scan, bounded calendar/offset arithmetic and at most 27 recorded insertion comparisons. Both const operands and every potentially relevant branch use that same remaining request allowance. No additional temporal counter, refill, owned fraction or normalized temporal value exists. Metadata modified keeps its separate Z-only wrapper and existing precharge.

Independent isolated-format resultArea countersAggregate / admission
Established good form, all other applicable work completeassessed 4, not_applicable 5, unassessed 0, undetermined 0complete true, errors 0, incomplete_checks 0, passed, admitted
Established bad form, all other applicable work completeassessed 4, not_applicable 5, unassessed 0, undetermined 0complete true, errors 1, incomplete_checks 0, failed, rejected
Unavailable temporal meaning, other work completeassessed 3, not_applicable 5, unassessed 0, undetermined 1complete false, errors 0, incomplete_checks 1, undetermined, undetermined

These projections assume exactly one effective full description with type:"string", nullable:false, one temporal format and no additional constraints. The four assessed areas are context, type/null, text/Boolean and abstract-values; the five remaining areas are established not applicable. The work-limit projection assumes only the temporal consumer’s budget is exhausted after the independent areas complete. They are expected contract observations, not executed product reports. A definite independent constraint rejection plus unavailable temporal meaning gives admission rejected, failed, complete false only when the unknown temporal meaning cannot change that proof. Strict warnings can fail disposition with admitted temporal/sample meaning. Detail truncation never changes admission, counters or aggregate errors.

All source, decoded text, parsed nodes, recursive alternatives, semantic work, location and report limits remain shared under ADR 0012: Exact numbers and JSON input policies, ADR 0013: Shared workflow and report guarantees and ADR 0016: Selected samples with explicit admission and coverage. Charge before scanning, copying or building exact fractions, offset projections and locations. Format capability is bounded independently of JSON source acquisition; raising one cap removes no other bound. No additional unbounded precision, live lookup, timezone database or calendar dependency is selected.

Representative observations and remaining scope

Under a common established civil format, null equals null and differs from an established nonnull civil value in either operand order. Malformed or uninterpreted nonnull values leave comparison undetermined. Null/null consults neither the nonnull representation convention nor leap knowledge; mixed pairs record only the nonnull interpretation and knowledge actually used. Null admission remains independent, including when nullable:false excludes it. Two nonnull dates with established Gregorian denotation compare by calendar date. The same date is equal and different dates differ, including day, month and year boundaries across the four-digit source range. The fixed-width convention permits validated decoded text to supply this comparison without a normalized retained value. JSON escape spelling does not matter; identical invalid dates do not establish equality and differing invalid dates do not establish a calendar disagreement.

Two nonnull date-times with established denotation compare by UTC instant under ADR 0018. Subtract the numeric offset with Gregorian day/year rollover, keeping UTC dates outside the source-year edges representable internally. Compare exact fractional digits after removing trailing zeros; absent and all-zero fractions are equal. An inserted second keeps its own slot, distinct from second 59 and the following day’s second 00. Offset annotations, letter case and JSON escapes do not distinguish instants. The RFC 3339 example 1996-12-19T16:39:57-08:00 equals 1996-12-20T00:39:57Z; .1 equals .100; an established Z value equals its +00:00 and -00:00 spellings. Invalid forms and absent needed adjustment knowledge prevent either an equality or a difference conclusion. Differing nonnull date-free time representations retain unavailable comparison meaning.

FormatAdmitted temporal representationRejected representation / meaningUndetermined needed work
date"0000-02-29", "2000-02-29", "9999-12-31""1900-02-29", "2024-04-31", "20240229""2024-02-29" when required temporal work cannot run within capability
date-time"1996-12-19T16:39:57-08:00", "1996-12-20t00:39:57z", "2017-01-01T05:44:60+05:45""2024-01-01T24:00:00Z", "2024-06-30T23:59:60Z", "2024-01-01 12:00:00Z" under the selected convention"2030-06-30T23:59:60Z", "2030-06-30T23:59:59.9Z" with this recorded knowledge
time"12:34:56.000000000000000000001+05:45", "23:59:59Z", "12:34:56-00:00""24:00:00Z", "12:34:56", "12:34:60Z""23:59:60Z", "05:44:60+05:45" with no date

Temporal denotation alone does not establish sample admission when other constraints remain unfinished. ADR 0015: Bounded value equality in a resolved data context applies separately: invalid or unresolved strings do not denote a temporal value merely because their representations match. Gregorian-date and dated date-time equality supply constant checks, supported compound comparisons, uniqueness and declared-value consistency through that one contract. Actual date comparison records the selected convention without consulting leap knowledge; dated date-time comparison records only actual slot consultations. Model-only comparator capability uses no operands and records no representation consultation. Nonnull date-free time comparison beyond established identical representations, epoch conversion, ordering, duration arithmetic, physical clock correctness, recurring schedules and additional representations remain outside this scope.

URI and UUID sample contract

This contract follows ADR 0019: URI, URI-reference and UUID sample conventions. It extends the selected-sample operation contract without changing the nine-area esdieff.sample/1 inventory, report version 1.1, selection, ownership or disposition rules. The adopted scope distinguishes representation, applicable URI scheme meaning, opaque UUID values and context-dependent equality.

FullBaseline establishes known uri, uri-reference and uuid model interpretations without supplying a value or invoking a representation check. This M049 observation asserts no scheme admission, target identity, constant denotation or comparator capability. Constants still need their actual contextual denotation; an unsupported URI scheme can leave M043 unfinished while the named model interpretation is established. Model selector recognition alone does not record consultation of the sample facts listed below.

Meanings and conventional inputs

FormatAbstract meaningConventional JSON
uriA full resource identifier under RFC 3986.A JSON string whose decoded text satisfies RFC 3986 URI, including a scheme and an optional fragment. No relative form or empty string is a URI.
uri-referenceA resource-reference expression under RFC 3986.A JSON string whose decoded text satisfies URI-reference: a URI or relative reference, including empty, query-only and fragment-only forms. It need not be resolved to a target for expression admission.
uuidAn opaque 128-bit UUID value under RFC 9562.A JSON string with exactly 32 ASCII hex digits and four hyphens at the 8-4-4-4-12 group boundaries, without a urn:uuid: prefix, braces or surrounding whitespace.

Primary definitions are RFC 9880 Appendix C.2, RFC 3986 Sections 3 and 4 and RFC 9562 Section 4. Conventional text is assessed after JSON decoding; alternate JSON escape spellings do not themselves change its content. This adds no alternative binary protocol representation.

URI generic syntax and scheme-specific semantics are separate. A generic representation conclusion names its syntax basis; abstract-format admission also needs an established compatible meaning, including applicable scheme requirements. HTTP(S) requires authority form and a nonempty host under RFC 9110 Sections 4.2.1 and 4.2.2. For example, https:device and https:// match generic grammar but fail those scheme requirements. An established scheme failure supplies rejection on its own cited basis, even when generic syntax succeeds. A finite HTTP/HTTPS identity-syntax capability supports ordinary cases without requiring an exhaustive scheme registry or communication behavior. Unknown schemes do not trigger an invented rejection allowlist. An unavailable needed scheme interpretation stays undetermined, and its abstract-values area remains unfinished. Relative references can be admitted as expressions without target resolution; needed base or inherited scheme meaning is separate. No network request, name lookup, existence check or retrieval is performed.

URI text retains supplied characters and percent encodings. Reject malformed percent escapes, spaces, backslashes, literal non-ASCII characters and invalid generic components; do not trim, repair, percent-decode before parsing or silently convert IRIs. Percent-encoded non-ASCII octets can satisfy generic grammar without establishing a particular scheme’s character encoding. IP literals and authority/path delimiters require their actual RFC 3986 grammar. Arbitrary bracket content is not an IP literal. Numeric port syntax does not by itself certify a protocol’s usable port range. Registered-name grammar is broader than DNS labels. A first relative path segment cannot contain a colon, while ./this:that can be a relative reference.

UUID text decodes to bytes in displayed/text order. Upper, lower and mixed-case hex name the same bytes. Esdieff interprets the base format as an opaque 128-bit value without a version/variant allowlist. This does not assert that every finer layout is defined or interoperable, certify uniqueness or randomness, validate timestamps, introspect application fields, or prove a generation algorithm. Nil and Max are ordinary representable sentinel UUID values, independent of JSON null. Requested layout-specific meaning must assess applicable variant requirements from RFC 9562 Section 4.1 and corresponding version/layout requirements. Unavailable needed layout meaning stays undetermined, even when the opaque representation is available. Alternate UUID formats are outside this conventional channel; describe that input failure with its convention basis instead of calling an abstract UUID universally invalid.

Equality and additional constraints

Use ADR 0015: Bounded value equality in a resolved data context for const and uniqueItems. In a common established UUID context, both bare representations must first denote UUID values; compare their 16 bytes. Case differences can establish equality, and a differing byte establishes difference. Invalid strings, unavailable interpretation, incompatible choice meanings and exhausted work stay undetermined, including identical text. A comparison result does not establish admission under every other constraint. Supplied output text is preserved; byte comparison does not mandate rewriting it.

No URI normalization or equivalence comparator is adopted. Differing case, percent spelling, paths or relative forms remain undetermined for value equality, even where a future purpose-specific comparator could prove equality. Identical valid representations establish equality only when their common compatible deterministic interpretation is known. If equality asks whether relative references identify the same target, an explicit applicable base is needed; it is never inferred from an SDF namespace, source path or acquisition URI. Expression admission requires no target resolution. A separately requested JSON representation comparison can report text differences without claiming different abstract identifiers.

Unicode scalar length and pattern constraints still apply to the conventional decoded text when their established meaning is needed. Constraints inherited through references or choices retain their effective meaning and overrides. A complete matching alternative can admit; unrelated unfinished alternatives cannot invalidate its established witness. Potentially matching unknown alternatives prevent unjustified rejection. These rules do not add URI-specific composition, a general scheme registry or a new interpretation of restricted item vocabulary.

Findings, locations and coverage

In an established common compatible context, null equals null and differs from an established nonnull URI, URI-reference expression or UUID. An invalid or uninterpreted nonnull operand leaves comparison undetermined. Null/null does not consume nonnull representation facts; mixed pairs retain the facts actually consulted for the nonnull value. Equality is independent of null admission. Full UUID comparator capability supports known absent, true and false nullability without operands, while restricted or unavailable meaning remains unfinished. These cases do not supply general nonnull URI equivalence or target identity.

A definitely invalid conventional representation rejects only under an established applicable format/context. Record a sample-domain constraint finding and the conventional/RFC generic grammar basis actually used. An unknown critical feature, unknown equality-changing extension, unavailable needed scheme/base interpretation or exhausted semantic work produces an affected undetermined conclusion instead. Invalid JSON or unusable decoding remains a context/input finding with sample admission undetermined. Unsupported decoded scalar content is not relabeled malformed URI text. Independent definite findings remain available only when unavailable meaning cannot change their proof.

Format denotation and needed external knowledge belong to sample-abstract-values/1; text lengths and patterns belong to sample-text-boolean/1; const and array uniqueness retain their own areas. Inapplicability requires an established reason. Full sample admission still requires every applicable area. A format success alone never claims sample completeness or model conformance. A definite representation rejection can coexist with unfinished independent pattern work: admission rejected, disposition failed and complete:false only when that unavailable work cannot change the representation rejection.

For data selection /sdfData/Uri, a format finding refers to effective location /sdfData/Uri/format in the selected document and to sample source pointer "". For supplied JSON "../device", the sample token span is [0,11] in its immutable source bytes. Related source locations identify the declared or inherited format where available. Typed sample input has pointer "" and span:null unless original supplied bytes exist. Const cases additionally identify effective /const; array uniqueness identifies the two item sample pointers. Nested map entries or array items use their actual sample pointers and selected effective description suffixes. No source span is invented for effective content.

Finite acquisition, decoded text, structural/pair, number, semantic work, derived storage, location and report limits remain those of ADR 0012: Exact numbers and JSON input policies, ADR 0013: Shared workflow and report guarantees, ADR 0015: Bounded value equality in a resolved data context and ADR 0016: Selected samples with explicit admission and coverage. Precharge representation scanning, decoding, comparison and repeated choice work before traversal or allocation. Avoid percent-decoded copies, target resolution and implicit fetching. Budget exhaustion leaves affected work undetermined. Pointer/report presentation omissions preserve established conclusions and aggregate counts separately. A parser’s own tighter capability must be disclosed, not treated as an RFC rejection. Algorithm improvements may change implementation, never these semantic boundaries.

Examples

Each ordinary case uses an available sdfData description with type: "string", nullable: false, the stated format and no extra constraints. HTTP(S) cases use the supported authority and host requirements under RFC 9110. Other needed scheme meaning remains unavailable.

FormatConventional sample JSONAdmission and basis
uri"https://example.test/device#reading"Admitted with generic syntax and applicable supported HTTPS meaning; the fragment is allowed.
uri"mailto:operator@example.test" or "urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6"Generic representation conforms; admission undetermined if the needed scheme interpretation is unsupported. No network/delivery claim or UUID-channel coercion.
uri"https://" or "https:device"Generic representation conforms; rejected on established HTTP(S) nonempty-host or authority-form basis respectively.
uri"../device" or ""Rejected: no scheme/full URI.
uri"https://example.test/%GG", "https://example.test/a b", "https://example.test/é"Rejected: invalid generic representation.
uri-reference"../device?mode=1#reading", "//example.test/device", "/device"Admitted as reference expressions, with no inferred base.
uri-reference"?mode=1", "#reading", ""Admitted as reference expressions.
uri-reference"1thing:part"Rejected: neither a legal scheme prefix nor a permitted first relative segment.
uri-reference"./1thing:part"Admitted; colon occurs after the first relative segment.
uri-reference"device%GG" or "device\\reading"Rejected: invalid generic representation.
uuid"f81d4fae-7dec-11d0-a765-00a0c91e6bf6" or mixed-case equivalentAdmitted; same 16-byte value.
uuid"00000000-0000-0000-0000-000000000000" or "ffffffff-ffff-ffff-ffff-ffffffffffff"Admitted Nil/Max values.
uuid"01890f3e-6c4a-7d4b-8e23-4d87b637659b" or "f81d4fae-7dec-f1d0-f765-00a0c91e6bf6"Admitted opaque values without layout proof.
uuid"urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6", braced or unhyphenated equivalentRejected under the explicit bare-text convention; these do not assert universal abstract invalidity.
uuid"g81d4fae-7dec-11d0-a765-00a0c91e6bf6" or truncated textRejected: invalid conventional representation.
Any of the threeRecognizable ordinary text plus unknown critical meaning or exhausted required scan workUndetermined for affected admission; capability/context basis, no invented format violation.

With an established matching UUID const whose hex case differs, the equality obligation succeeds; a one-byte difference supplies a const mismatch. uniqueItems:true in established UUID item meaning rejects mixed-case duplicate values. Identical malformed UUID operands give equality undetermined rather than a false equal proof; definite sample format rejection can still be independent. uri const operands differing by host case, or reference operands "device" and "./device", give equality undetermined under this contract. Identical valid relative-reference expressions can satisfy a constant under the same expression meaning. Target identity would additionally need an applicable base; Esdieff performs no target resolution. An independent matching choice retains an admission witness; unresolved surrounding meaning can prevent it.

Human, typed and JSON results agree on these conclusions, bases and locations under the selected-sample contract. Format findings use sample.uri_representation, sample.http_identity, sample.uuid_representation or sample.resource_meaning_unavailable for their distinct reasons. Required work exhaustion uses operation.limit.

Consulted format facts

Report::format_knowledge(id) returns a borrowed FormatKnowledgeView with static id, rfc, sections and scope text. Sample records the facts actually used by its request, including visited alternatives and constant comparisons. A later unfinished branch or omitted optional detail preserves earlier consultations. The six identities are:

IdentityConsulted scope
rfc3986-uri-syntax/1Generic URI representation
rfc3986-reference-expression/1Relative-reference expression
rfc9110-http-identity/1HTTP authority and nonempty host
rfc9110-https-identity/1HTTPS authority and nonempty host
rfc9562-bare-text/1Selected UUID text representation
uuid-opaque-value/1Decoded opaque UUID value

An unknown identity is absent. Non-Sample operations omit format_knowledge and return absent through this getter. Sample’s baseline field is an array of the consulted four-field records; an admitted consultation owner with no used facts produces []. Initial inability to establish that owner produces null and known getter identities are unavailable. Late work exhaustion retains the array of facts already consulted. These are request observations, not a capability inventory or evidence of external resource acquisition.

UUID findings identify uuid-bare-json/1 or uuid-opaque-value/1 as the selected interpretation. Their actual use also appears in baseline.interpretations. URI generic grammar and HTTP(S) identity findings retain separate RFC bases. Human output presents the same consulted facts and interpretations as JSON.

Generated values

Esdieff generates sample values for a selected effective data description, so firmware and app teams can test their code against a model without writing payloads by hand. Each Generated value aims at one Generation target, such as a minimum, a value just below it or a wrong type, and Sample-value checking settles it against the description it was generated for. Its admission, not its target, says whether the description admits it. The rules follow ADR 0041: Generated values settled by Sample-value checking, and the terms Generated value, Generation target, Representative value, Sample-value checking, Effective data description and Nullable come from the domain language.

#![allow(unused)]
fn main() {
use esdieff::{Admission, Catalogue, GenerationRequest, SampleKind, SourceInput};

let catalogue = Catalogue::take_inputs(vec![SourceInput::supplied(
    "model",
    br#"{"sdfProperty":{"level":{"type":"integer","minimum":10}}}"#,
)])?;
let request = GenerationRequest::new(catalogue.source_id("model").unwrap())
    .select(SampleKind::Property, "/sdfProperty/level");
let result = catalogue.generate(request)?;
let level = result.descriptions().next().unwrap();
let below = level.values().find(|value| value.target() == "below_minimum").unwrap();
assert_eq!((below.to_json(), below.admission()), ("9", Admission::Rejected));
Ok::<(), &'static str>(())
}

The generation contract identity is esdieff.generation/1. It binds the Generation targets, their order and the rules that build their values, so a release that changes any of them gets a new identity and a report keeps its meaning. Generation is deterministic, with no randomness or seed, so the same model and request give the same values in the same order.

Command line

esdieff generate --document MODEL [--kind KIND --pointer POINTER] [--format human|json|jsonl] MODEL_INPUT... generates values for descriptions of the model document MODEL, which must match one explicit MODEL_INPUT. Inputs are file paths, and - reads one document from standard input. --kind and --pointer select one description as esdieff sample does, with KIND one of property, data, action_input, action_output and event_output, and they come together or not at all. Without them every affordance description of the document is selected, as described under Selection. From the repository root, generate values for the rich thermostat model:

cargo run -- generate --document examples/thermostat-check/rich.sdf.json examples/thermostat-check/rich.sdf.json

--format human gives the human report, json the JSON report and jsonl the JSON Lines Trace entries. The shared color controls style the human report. Generation reports no model findings, so it exits 0 when generation completed for every selected description and 3 otherwise, including when any value stays undetermined. A missing --document, --kind without --pointer or the reverse, an unknown kind, format or option, a selector that selects nothing, a document that is not a supplied input and a second - are invocation errors that exit 2 with empty stdout. A report that cannot be written exits 4. The CLI contract states the shared rules.

Library operation

Catalogue::generate(request) performs one generation. GenerationRequest::new(document) selects every affordance description of a model document, and select(kind, pointer) narrows it to the one description that Sample selector selects. An unknown or non-model document, a malformed or oversized pointer, a selector whose definition is absent or has another kind, and a report allowance too small for the mandatory report envelope are request errors.

GenerationResult owns every value and borrows the Catalogue for its report. descriptions() yields each selected GeneratedDescription in selection order, and descriptions_omitted() counts selected descriptions beyond the ceiling or left out because their details did not fit the report byte limit. count(admission) counts the kept values Sample-value checking settled with that admission. selection_complete() is false when a grouping or affordance of the document could not be read, so some descriptions may be missing. complete() is true when the selection is complete, no description was omitted and every description is complete. disposition() is passed then and undetermined otherwise, never failed. document() and selector() echo the request. to_json(), to_json_lines(), to_human() and to_human_with_style(style) render the outputs below.

Each GeneratedDescription has its Sample selector kind() and pointer(), its state(), its kept values() in target order and values_omitted(), the distinct values left out beyond the ceiling, because they did not fit the report byte limit or because their Trace entry would be longer than a trace line. Its state is:

  • Complete when every applicable target was generated and every kept value is admitted or rejected.
  • Partial when generation ran out of the description’s allowance, values were omitted beyond the ceiling, for the report byte limit or for the trace line limit, or Sample-value checking left a value undetermined, including one whose check ran out of its own allowance.
  • Unavailable when the description’s effective meaning could not be established, so no value was generated.

Each GeneratedValue has its target(), its to_json() text, in which each number keeps the spelling it was generated with, its admission() and its codes(), the distinct condition codes behind a rejection, at most 8, such as sample.bound.

Selection

With a selector, generation covers the one description that Sample-value checking would select for that kind and pointer, including an sdfData definition. Without one, it covers every Property, Action sdfInputData, Action sdfOutputData and Event sdfOutputData reachable from the document’s top-level groupings and affordances, including nested groupings. They are taken in document order, and an Action’s input comes before its output. sdfData definitions are generated only when selected explicitly, and Event input and groupings have no description to generate. A description whose effective meaning is unavailable is listed as unavailable, and a grouping, Action or Event that cannot be read leaves the selection partial.

Generation targets

Each description’s targets come in four groups, in this order. A target that does not apply produces no value, and so does one whose value would exceed the value capabilities, such as a string longer than a document may be or a value nested deeper than the depth limit. pattern has no target in this contract, since Esdieff does not synthesize strings that match a pattern.

The first group is the Representative values of ADR 0039, with their number, string, map and array rules:

TargetApplies whenValueExample
constthe description has a consta copy of it, numbers in their authored spelling{"const":1e1} gives 1e1
enumthe description has an enum of stringseach enum value, in order{"enum":["off","heat"]} gives "off" and "heat"
defaultthe description has a documentary defaulta copy of it{"type":"number","default":21} gives 21
typealways, apart from a choiceone value of each base type the description admits{"type":"string"} gives "", {"type":"string","format":"date"} gives the conventional "1970-01-01", {"type":"object","required":["mode"],"properties":{"mode":{"enum":["off"]},"note":{"type":"string"}}} gives {"mode":"off"}, and a description without type gives 0, "", true, {} and []
alternativethe description has a choicethe first Representative value of each effective alternative{"sdfChoice":{"low":{"const":1},"high":{"const":9}}} gives 1 and 9
nullevery Full data descriptionnull, which settlement shows to be admitted only when the description is Nullable{"type":"number","nullable":false} gives a rejected null

The second group holds boundary values, which lie on an edge of the admitted range:

TargetApplies whenValueExample
minimumminimum or exclusiveMinimumthe tighter lower bound when it is inclusive, in its authored spelling, or one unit inside it when it is exclusive{"minimum":10} gives 10, and {"exclusiveMinimum":0} gives 1
maximummaximum or exclusiveMaximumthe same at the upper bound{"exclusiveMaximum":2.5} gives 2.4
min_lengthminLengthminLength copies of a{"minLength":2} gives "aa"
max_lengthmaxLengthmaxLength copies of a{"maxLength":4} gives "aaaa"
min_itemsminItemsan array of minItems items{"type":"array","minItems":2,"items":{"type":"integer","minimum":0}} gives [0,0], or [0,1] beside "uniqueItems":true
max_itemsmaxItemsan array of maxItems items{"type":"array","maxItems":4,"uniqueItems":true,"items":{"type":"integer","minimum":0}} gives [0,1,2,3]
all_entriesproperties with at least one entrya map holding every described entry in order, then every other required entry, each filled with the first Representative value of its description, or null for a required entry without one{"type":"object","properties":{"mode":{"enum":["off"]},"note":{"type":"string"}}} gives {"mode":"off","note":""}

The third group holds values just outside the admitted range:

TargetApplies whenValueExample
below_minimumminimum or exclusiveMinimumthe tighter lower bound when it is exclusive, or one unit below it when it is inclusive{"minimum":10} gives 9, and {"exclusiveMinimum":0} gives 0
above_maximummaximum or exclusiveMaximumthe same at the upper bound{"exclusiveMaximum":2.5} gives 2.5, and {"maximum":2.5} gives 2.6
not_multiplea positive multipleOfhalf a step above an inclusive minimum that is a multiple of the step, otherwise half a step above 0{"minimum":5,"multipleOf":0.5} gives 5.25, and {"multipleOf":3} gives 1.5
too_shorta minLength above 0one a fewer than minLength{"minLength":2} gives "a"
too_longmaxLengthone a more than maxLength{"maxLength":4} gives "aaaaa"
too_few_itemsa minItems above 0an array of one item fewer than minItems{"type":"array","minItems":2,"uniqueItems":true,"items":{"type":"integer","minimum":0}} gives [0]
too_many_itemsmaxItemsan array of one item more than maxItems{"type":"array","maxItems":4,"uniqueItems":true,"items":{"type":"integer","minimum":0}} gives [0,1,2,3,4]
duplicate_itemsuniqueItems is truean array repeating the first item, twice or as often as minItems requires{"type":"array","uniqueItems":true,"items":{"type":"integer","minimum":0}} gives [0,0]
missing_entryrequiredone value for each required entry, in order: a map holding every other required entry, filled as for all_entries, and lacking that one{"type":"object","required":["mode","level"],...} gives {"level":5} and {"mode":"off"} when mode and level are an enum starting with "off" and an integer with a minimum of 5
wrong_typea type that is one of the base typesone value of each base type it does not admit, from 0, "", true, {} and [], where integer data admits 0{"type":"integer"} gives "", true, {} and []

Array items

The items of an array value are copies of the first Representative value of its items description, or null without one. When the array requires unique items and holds two or more, its items are distinct instead: the Representative values of items in order, then further values that continue from the first of them. Numbers continue one unit at a time, strings vary their last character through a to z and then longer suffixes, and a boolean continues with the other boolean. Without an items description the items are the numbers from 0. When no such sequence has enough distinct items, such as for an items description with only a const, the target gives no value.

Nested targets

The fourth group holds the targets of each properties entry, in order, and then of items. Each is generated by these same rules for that nested description, including its own nested targets, and its value is placed where the nested description stands:

  • inside the map its entry belongs to, beside the first Representative value of every other entry that map requires, so the enclosing constraints still apply
  • among the items of its array, repeated as often as the array’s minItems requires and at least once, or beside other distinct items when the array requires unique items

A nested target is named after the path to it, as <entry>.<target> or items.<target>, so a minimum inside the level entry of settings data is level.minimum, and one inside the items of an array inside the readings entry is readings.items.minimum. With {"type":"object","required":["mode","level"],"properties":{"mode":{"enum":["off","heat"]},"level":{"type":"integer","minimum":5}}}, level.minimum is {"level":5,"mode":"off"} and level.below_minimum is {"level":4,"mode":"off"}. A nested value is often the same value as an earlier one, such as the map of Representative values, and is then kept once under the duplicate rules, which favor the nested boundary target. With {"type":"array","minItems":2,"uniqueItems":true,"items":{"type":"integer","minimum":3,"maximum":9}}, items.maximum is [9,3]. A Direct items description has no Nullable characteristic, so items never has a null target. Nested descriptions are followed only while their values can nest within the depth limit, and a value whose enclosing value cannot be built, such as one whose sibling entry has no Representative value, is not generated.

A unit follows the rules of the numeric bounds witnesses: it is 1 where the coefficient digit limit allows, and otherwise one of the bound’s last significant digit. So a maximum of 20.50 gives an above_maximum of 20.6, and a maximum of 1e600 gives 2e600, since adding 1 would need more digits than the limit allows. A count that is not an exact nonnegative integer within the value capabilities, and a step that is not a positive exact number, give no target.

Settlement and duplicates

Sample-value checking settles every kept value against the selected description, as it would a value supplied for that Property, sdfData definition, input or output. A target name never overrides admission. A below_minimum value that another constraint also rejects is just rejected, and a type value that a pattern rejects is rejected too. A value the checker cannot settle, such as one beside an unsupported pattern or one for map or array content without a type, is undetermined and leaves its description partial.

Each value is settled as soon as it is kept, so the admissions already settled stand when later generation runs out of the description’s allowance. Two targets can produce the same value, and it is then kept once. Values are the same when their JSON texts are, apart from the order of the entries in any map, so {"level":5,"mode":"off"} and {"mode":"off","level":5} are one value, while numbers compare by their exact spelling, so 10 and 1e1 are two. A duplicate is kept under the target with the highest precedence, so that a label names the constraint a value probes:

  1. Boundary and outside targets, every target of the second and third groups apart from all_entries, rank above the Representative-value targets const, enum, default, type, alternative and null, and above all_entries.
  2. Within each of these two classes, a nested target, <entry>.<target> or items.<target>, ranks above a top-level one.
  3. Between targets of equal rank, the first in contract order keeps the value.

The value stands at the place of the target that keeps it and shows that target’s text. So a typed description with a minimum of 10 lists 10 as its minimum rather than as its type, a const of 3 beside a minimum of 3 lists 3 as the minimum, a const of 0 beside a type of integer lists 0 as the const, and an array of at least two unique integer items with a minimum of 0 lists [0,1] as items.minimum rather than as min_items. In a map that requires a mode enum starting with "off" and a level with a minimum of 5, the type map {"mode":"off","level":5}, the first mode.enum value and the level.minimum value are one value, listed once as level.minimum with the text {"level":5,"mode":"off"}.

Bounds

One description keeps at most 64 distinct values, and one request selects at most 1024 descriptions. Distinct values beyond the first ceiling are counted in values_omitted and leave their description partial. Descriptions beyond the second are counted in descriptions_omitted, have no values and leave the operation undetermined. These two ceilings keep a request finite under ADR 0009: Bounded processing and reporting and ADR 0013: Shared workflow and report guarantees.

Each piece of work has an allowance of its own, with the work, allocation, numeric and equality limits that one esdieff sample request receives against the same Catalogue, as ADR 0041: Generated values settled by Sample-value checking states. Composing the document and finding its descriptions spend the request’s allowance. Building one description’s values spends that description’s allowance, and running out of it stops generation of that description and leaves it partial. Each kept value is checked with an allowance of its own, and a check that runs out leaves that value undetermined and its description partial. So one heavy description or value never leaves the others unsettled.

Checking a value against an enum or a choice costs work roughly linear in its number of alternatives, so even an enum of thousands of values settles within one check’s allowance. Values whose checks are costlier, such as long unique arrays, can still run out of that allowance and stay undetermined.

The values a request keeps always fit the report byte limit, Limits::report_bytes. After the Catalogue’s mandatory report reserve and the generate envelope’s own, every description is charged the bytes its details need before its values are generated, and every kept value is charged the bytes its largest rendering needs, as a JSON report record, a JSON Lines Trace entry or a human report line, before it is kept. The charge assumes the longest target name the description can give, so when a target of higher precedence later takes the value under the duplicate rules, its name always fits. A description whose details do not fit is left out, counted in descriptions_omitted with a report_limit record, and leaves the operation undetermined. A distinct value that does not fit is left out, counted in values_omitted with a byte_limit record, and leaves its description partial. So every output format fits the limit, whatever the model asks for, such as many strings with a maxLength of millions. A value whose Trace entry would be longer than 1 MiB, the longest line a Recorded trace accepts, is left out the same way, also charged as if under the longest target name, so every JSON Lines entry replays through esdieff trace.

Report 1.5

The JSON report is schema:"esdieff.report", version:"1.5", operation:"generate", extending the shared report contract with these fields:

ObjectRequired fields and typesMeaning
Generate requestassessment:null; inventory:null; generation:Generation; scope:ScopeGeneration names its own contract. Scope is selected with the document as its one root, the other model sources its composition used as dependencies, both as assessed, and the needed sources it could not use as unavailable.
Generationcontract:"esdieff.generation/1"; document:Idselector:SampleSelector, present only for an explicit selector.
Generate outcomeOutcome fieldserrors, warnings and notices are 0. incomplete_checks counts descriptions that are not complete, descriptions left out beyond the ceiling or for the report byte limit, and 1 more when the selection is partial. The disposition is passed or undetermined.
Generate requested coverageinventory:null; count_unit:"description"; total:Countnull; assessed:Count; not_applicable:0; unassessed:Count; undetermined:Count
GenerateResultkind:"generate"; summary:GenerateSummary; selection:`“complete”“partial”`; descriptions:GeneratedDescription[]; descriptions_omitted:Count; omissions:Omission[]
GenerateSummaryadmitted:Count; rejected:Count; undetermined:CountCounts every kept value, including those of descriptions whose details did not fit.
GeneratedDescriptionselector:SampleSelector; description:EffectiveLocation; state:`“complete”“partial”
GeneratedValuetarget:string; value:any JSON value; admission:`“admitted”“rejected”

baseline.interpretations names the value interpretations that the checks relied on, as model reports name them. Every source stays in sources. Description details are written in selection order within the report byte limit, and any that do not fit are counted, never silently dropped. The human report shows the disposition, the value counts, then each description with its state and one line per value with its admission, its target padded to at most 40 characters, its value and its rejection codes. It is written one description at a time and gives the JSON report instead as soon as it would not fit the report byte limit.

JSON Lines

--format jsonl and to_json_lines() write one Trace entry per admitted or rejected value, each a JSON map on its own line ending in LF: {"kind":KIND,"pointer":POINTER,"value":VALUE,"expected":ADMISSION,"label":TARGET}, with the description’s Sample selector, the generated value, its settled admission as expected and its target as label. A target longer than 256 bytes, which only a long nested entry name gives, is left out as a label rather than shortened. Undetermined values are left out, and the exit code still reports them, as it does values left out for the report byte limit or the trace line limit. A run without settled values writes nothing at all.

The output is a Recorded trace, so esdieff trace replays it as regression vectors, as the trace contract describes. Replayed against the same model, every entry passes, because each expectation is the admission Sample-value checking settled. Replayed against a later revision, exactly the entries whose admission changed fail, such as a former maximum that a narrowed maximum now rejects. The output is byte-identical for the same model and request, so the vectors can be kept under version control.

Recorded traces

Esdieff checks a Recorded trace, a JSON Lines file of Trace entries, against one model document, so device QA can find every logged value that a model rejects in one run. Each entry names a Sample selector, carries a value and may carry an Expected admission and a label. The document is composed once, each distinct selector is resolved once, and every entry is checked on its own, so one bad line never stops the run. The rules follow ADR 0042: Recorded traces with independent entries, and the terms Recorded trace, Trace entry, Expected admission, Sample selector and Sample-value checking come from the domain language.

#![allow(unused)]
fn main() {
use esdieff::{Admission, Catalogue, TraceOutcome, SourceInput, TraceRequest};

let catalogue = Catalogue::take_inputs(vec![SourceInput::supplied(
    "model",
    br#"{"sdfProperty":{"level":{"type":"integer","maximum":10}}}"#,
)])?;
let trace = concat!(
    r#"{"kind":"property","pointer":"/sdfProperty/level","value":7}"#, "\n",
    r#"{"kind":"property","pointer":"/sdfProperty/level","value":11,"label":"spike"}"#, "\n",
);
let request = TraceRequest::new(catalogue.source_id("model").unwrap(), trace.as_bytes());
let result = catalogue.check_trace(request)?;
let spike = result.entries().next().unwrap();
assert_eq!((spike.line(), spike.label()), (2, Some("spike")));
assert_eq!(spike.admission(), Some(Admission::Rejected));
assert_eq!(result.count(TraceOutcome::Passed), 1);
Ok::<(), &'static str>(())
}

The trace contract identity is esdieff.trace/1. It binds the Trace entry format and the rules that settle each entry’s outcome, so a release that changes either gets a new identity. A Recorded trace adds no sequence meaning, timing or protocol binding. Line order is presentation only, and the checks add nothing to any Model requirement inventory.

Command line

esdieff trace --document MODEL --trace FILE [--format human|json] MODEL_INPUT... checks the Recorded trace FILE against the model document MODEL, which must match one explicit MODEL_INPUT. Inputs are file paths, and - reads one document from standard input. FILE is a file path, or - for standard input, and standard input may be used only once across the model inputs and the trace. From the repository root, check a trace of thermostat readings:

cargo run -- trace --document examples/thermostat-check/rich.sdf.json --trace readings.jsonl examples/thermostat-check/rich.sdf.json

--format human gives the human report and json the JSON report. The shared color controls style the human report. The run exits 1 when any entry failed, otherwise 3 when any entry is undetermined, and otherwise 0, as check does. A missing --document or --trace, an unknown format or option, a document that is not a supplied input, a second -, a trace file that is missing, unreadable or larger than 64 MiB, a line over 1 MiB and more than 100,000 entries are invocation errors that exit 2 with empty stdout. The trace is read before any model input. A report that cannot be written exits 4. The CLI contract states the shared rules.

Library operation

Catalogue::check_trace(request) checks one Recorded trace. TraceRequest::new(document, trace) names the model document and the trace bytes. The trace becomes a source with role sample and the key trace, numbered after the Catalogue’s sources. key(key) gives it another caller key, label(label) a display label, such as its path, and omit_label() records that its label was left out, as for a path too long to show. An unknown or non-model document, a trace over TraceRequest::FILE_BYTES, a line over 1 MiB, more than 100,000 entries, a key over 256 bytes or equal to a Catalogue key, a label over 512 bytes, a Catalogue that already holds the most source attempts and a report allowance too small for the mandatory report envelope are request errors. A malformed entry is never a request error.

TraceResult owns every listed entry and borrows the Catalogue for its report. count(outcome) counts the entries that settled with that TraceOutcome, and admissions(admission) counts the checked entries that Sample-value checking settled with that admission. entries() yields the failed and undetermined entries in line order while they fit the report byte limit, and entries_omitted() counts those that did not. Passing entries are counted, not listed. disposition() is failed for any failed entry, otherwise undetermined for any undetermined entry, otherwise passed. document() echoes the request and trace_source() gives the trace source’s identity in the report. to_json(), to_human() and to_human_with_style(style) render the outputs below.

Each TraceEntry has its line(), counting from 1, its label(), its selector() when it names a valid kind and a pointer string of at most 8192 bytes, whether or not that selects anything, its expected() admission, its admission() when its value was checked, its outcome() and its conditions(), at most eight, with conditions_omitted() counting the rest. Each TraceCondition has its code(), severity(), message(), its pointer() within the entry’s JSON map, such as /value/mode, and its span(), the byte range in the trace file.

Trace entries

The trace is split into lines at each LF, and a CR before an LF is ignored. The last line may omit its LF, and an empty last line is no entry, so a file holding one empty line has no entries. Every other line, including an empty one, is one Trace entry, and lines are numbered from 1 in file order.

Each entry is one JSON map with these members:

MemberRequiredValue
kindyesproperty, data, action_input, action_output or event_output, as for esdieff sample
pointeryesthe effective definition pointer of the Sample selector, as for esdieff sample
valueyesany JSON value, checked as a Sample value for the selected description
expectednothe Expected admission, admitted or rejected
labelnoa string of at most 256 bytes that names the entry in the report

Each line is decoded on its own under the ordinary JSON input policies of ADR 0012: Exact numbers and JSON input policies. Numbers keep their exact values, so 9007199254740993 stays distinct from 9007199254740992, and a repeated member name anywhere in the line is refused, including inside the value. Each line has the decoding allowances one Sample source would have in the same Catalogue, so its depth, node count and number sizes have the shared limits.

Entry outcomes

Each entry settles on its own, in this order:

  1. A line that is not valid JSON, or repeats a member name, fails with its json.syntax or input.duplicate_name condition. A line that is not UTF-8 or exceeds a decoding limit cannot be read and is undetermined.
  2. A line that is not a JSON map fails with trace.entry. An unknown member fails with trace.unknown_member, a missing required member with trace.missing_member and a member with an invalid value with trace.invalid_member. Every such member is reported.
  3. A selector that selects nothing fails with trace.unselectable. That covers a malformed or oversized pointer, a definition that does not exist, and a definition of another kind, such as an Event pointer with kind property. A description whose meaning cannot be established, such as one behind an unavailable reference, leaves the admission undetermined with trace.unavailable.
  4. Otherwise Sample-value checking settles the value against the selected description. The entry passes when the value is admitted and nothing else was expected, or when its definite admission equals expected. It fails when the value is rejected and nothing was expected, or when its definite admission differs from expected, which adds a trace.expected condition. An undetermined admission leaves the entry undetermined whatever was expected.

The conditions of a failed or undetermined entry explain its outcome: the decoding issue, the member conditions, trace.expected, and the conditions behind a rejection or an undetermined admission, such as sample.bound, in that order.

Composition and allowances

The selected document is composed once, on the request’s own allowance, as esdieff generate composes it. Each distinct selector, a kind and a pointer, is resolved once against that composition, and later entries reuse its resolution. Each entry is checked with an allowance of its own, with the work, allocation, numeric and equality limits that one esdieff sample request receives against the same Catalogue, as ADR 0042: Recorded traces with independent entries states. A check that runs out of its allowance leaves only that entry undetermined, with an operation.limit condition.

Bounds

A Recorded trace holds at most 64 MiB, 100,000 entries and 1 MiB per line, apart from its line ending, under ADR 0009: Bounded processing and reporting. Going beyond any of them is a request error before any entry is checked, so a run never reports a partial file.

The report fits the report byte limit, Limits::report_bytes. After the Catalogue’s mandatory report reserve and the trace envelope’s own, each failed or undetermined entry is charged the bytes of its larger rendering, as a JSON report record or human report lines, in line order. The first entry that does not fit, and every failed or undetermined entry after it, is counted in entries_omitted with a report_limit record and is not listed. Counts, the outcome and the disposition always cover every entry.

Report 1.5

The JSON report is schema:"esdieff.report", version:"1.5", operation:"trace", extending the shared report contract with these fields:

ObjectRequired fields and typesMeaning
Trace requestassessment:null; inventory:null; trace:Trace; scope:ScopeTrace names its own contract. Scope is selected with the document as its one root, the other model sources its composition used as dependencies, both as assessed, and the needed sources it could not use as unavailable.
Tracecontract:"esdieff.trace/1"; document:Id; source:Idsource is the trace source.
Trace sourceSource fieldsThe trace is the last source, with role sample, acquisition supplied, decode partial when some line could not be decoded completely and otherwise usable, and retained_bytes the trace’s length.
Trace outcomeOutcome fieldserrors counts failed entries and incomplete_checks undetermined entries. warnings and notices are 0. complete is true when no entry is undetermined. The disposition is failed for any failed entry, otherwise undetermined for any undetermined entry, otherwise passed.
Trace requested coverageinventory:null; count_unit:"trace_entry"; total:Count; assessed:Count; not_applicable:0; unassessed:0; undetermined:CountOne unit per entry. Passed and failed entries are assessed, and undetermined entries undetermined.
TraceResultkind:"trace"; summary:TraceSummary; entries:TraceEntry[]; entries_omitted:Count; omissions:Omission[]entries lists failed and undetermined entries in line order. omissions has a report_limit record for entries that did not fit, which also appears in diagnostics.omissions and makes the report truncated, and a count_limit record for conditions beyond each entry’s eight.
TraceSummarypassed:Count; failed:Count; undetermined:Count; admissions:{admitted:Count, rejected:Count, undetermined:Count}Counts every entry, listed or not. admissions counts the entries whose value was checked or whose selected description was unavailable.
TraceEntryline:Count; label:stringnull; selector:SampleSelector
Condition for traceShared Condition fields plus domain:`“sample”“operation”`

baseline.interpretations names the value interpretations that the checks relied on, as model reports name them. Every source stays in sources. diagnostics.items is empty, since every condition belongs to an entry. The human report shows the disposition, the entry and admission counts, then each listed entry with its line, selector and outcome, its label, its admission and Expected admission, and one line per condition with its severity, code, pointer and byte range. It gives the JSON report instead if it would not fit the report byte limit.

Replaying Generated values

esdieff generate --format jsonl writes one Trace entry per admitted or rejected Generated value, with its settled admission as expected and its Generation target as label, as the generation contract describes. So its output is a Recorded trace. Checked against the same model, every entry passes. Checked against a later revision, exactly the entries whose admission changed fail, so last release’s values become regression vectors for the next.

cargo run -- generate --document examples/thermostat-check/rich.sdf.json --format jsonl examples/thermostat-check/rich.sdf.json > vectors.jsonl
cargo run -- trace --document examples/thermostat-check/rich.sdf.json --trace vectors.jsonl examples/thermostat-check/rich.sdf.json

Generation leaves undetermined values out, so a replay never expects an admission that checking did not establish. It also leaves out any value whose Trace entry would be longer than the 1 MiB line limit, so every line it writes replays. The selectors keep their pointers, so a revision that renames or removes a definition fails its entries with trace.unselectable.

Composed sdfThing authoring contract

This contract specializes ADR 0013: Shared workflow and report guarantees for Model authoring under ADR 0017: Reference-preserving sdfThing authoring. Domain terms come from the domain language. SDF composition follows RFC 9880 Sections 4.4 and 6; namespace identity follows Sections 3.2 and 4.2. Patch deletion follows RFC 7396 Section 2. Resource, output and API limits below are toolkit capabilities.

Request and library ownership

A private-field authoring builder accepts an owned Catalogue, one generated-source key and optional bounded label, a new sdfThing Given Name, an explicit namespace map with an optional chosen default prefix, and a nonempty list of sdfObject declarations. Each declaration has an exact new Given Name, a supplied source ID plus decoded pointer selecting an sdfObject, an explicit output namespace prefix for that sdfObject’s established global namespace, an owned JSON map Composition patch, and an explicit declaration-requiredness flag. The sdfThing can also have caller-supplied common qualities and information-block metadata. New generation creates one document; existing-document editing, nested sdfThing recipes and flattened export are later capabilities.

The sdfObject selector never selects by display label, filename or input order. Unknown IDs, malformed/overlong pointers, a present non-sdfObject selector, repeated declaration names, duplicate namespace prefixes with different bindings, duplicate generated keys and conflicting builder settings are request errors. A selector whose source/definition is unavailable produces scoped domain incompleteness; an established missing pointer is a request error. Prefixes and Given Names compare exactly after JSON decoding, contain no colon and receive no case folding or Unicode normalization. The toolkit bounds each newly supplied Given Name or prefix to 1,024 UTF-8 bytes, requires a nonempty prefix for its authored CURIE capability, permits at most 256 sdfObject declarations and 256 namespace bindings, and bounds each selector to the shared 8 KiB semantic-pointer cap before copying. These are new-request capabilities rather than RFC restrictions on source names; larger source names remain accessible.

The required flag authors an entry in the new sdfThing’s sdfRequired. Under RFC 9880 Section 4.5, an abbreviated Referenceable name excludes # and :; Given Names can contain #. When the declaration’s Given Name is a valid abbreviated name, emit that exact decoded name without JSON Pointer escaping. Otherwise, preserve the Given Name and emit a correctly encoded same-document SDF pointer reference to the newly authored declaration. Form decoded RFC 6901 tokens first, escaping token ~ and / as ~0 and ~1, then UTF-8/percent-encode the URI-fragment representation. An internal # becomes %23 in that fragment, not a second fragment delimiter. Decoded source/effective pointers retain the literal #. Inherited internal sdfRequired content is unchanged unless explicitly refined; this generation rule does not rewrite copied absolute pointers, which relocate during composition under ADR 0036: Copied reference relocation.

The explicit output prefix must already map to the selected sdfObject’s established global namespace URI. Authoring constructs the CURIE from that prefix and the selected definition’s namespace-rooted pointer; it does not copy a source prefix spelling. The target must be unambiguous in the supplied/generated catalogue. A requested generated namespace/global name that collides with an existing contributor is refused with author.identity_collision; no coalescing or precedence applies. Multiple bindings to the same URI are allowed; one prefix cannot denote two URIs. A missing source default namespace leaves reuse by this operation unsupported with author.local_only_object, rather than assigning a new source namespace or diagnosing an RFC violation. Namespace URI spelling and declared source identities remain unchanged; no network retrieval occurs.

The patch is SDF-authored JSON, not a generic mutable graph. It excludes an authored top-level sdfRef, since the builder owns that reference. sdfThing common-quality input excludes structural declaration groups and sdfRef; the builder owns declaration names and sdfRequired. Bad JSON and duplicate decoded names use the shared input/acceptance policies. Patch null retains its Merge Patch deletion meaning; it is not coerced into an explicit model value. Nested introduced references remain authored in the generated document’s explicit namespace context, while copied source references retain any interpretation limitation. Ordinary supported composition does not wait for interpretations that are irrelevant to its selected definitions.

The operation owns accepted request metadata, patch content and raw source bytes. Views borrow its owned result. Callers can retrieve a generated document’s bounded JSON bytes, the generated Catalogue, typed source/effective views and explanations using the same check/inspect operations as supplied models. Every generated source has a new compact SourceId and unique caller key; it does not reuse a supplied identity. Supplied raw bytes, names, number tokens and metadata remain unchanged. Authored declaration identities belong to the new sdfThing, while available origins point to selected reusable sources and request patches. This does not promise complete provenance history.

Fidelity, checking and failures

Generation state is complete, partial or unavailable. complete establishes a complete readable JSON document whose requested assembly is finished; partial means some requested assembly is unfinished even when a structurally complete candidate JSON exists. A candidate’s content_complete only describes its bytes. A fidelity state established or undetermined is independent: established requires all requested known-semantic/name/number and permitted opaque-structure preservation established, with no unresolved context meaning. A proven loss is an error and cannot yield faithful success. Preserving unknown extension JSON alone cannot establish preservation of its meaning after containment or reference context changes. Independent known observations and retained opaque content remain inspectable with affected locations and reasons.

Generated known JSON values preserve meaning; unchanged accepted numbers preserve their raw lexemes, including lexical exponent-boundary tokens. New patch numbers preserve their accepted request tokens. Mathematical number fidelity does not establish formal normative CDDL number admission, which remains a separately assessed requirement under ADR 0012: Exact numbers and JSON input policies. Names preserve decoded scalar values, without promising original escape spelling. Output is readable UTF-8 JSON with indentation and a trailing newline. Source whitespace, member order, original escape spelling and byte-for-byte regenerated documents are outside the guarantee. The operation introduces no computed numeric normalization that would cross the accepted output limits.

Checking is explicitly not_requested or requested with initial-v1 or full-baseline and the shared strict-warning policy. A requested check applies to selected generated-document roots and needed dependencies; every supplied input remains visible. It uses the same immutable inventory and baseline as ordinary checking. Its completion/findings remain separate from generation/fidelity. Checking can fail while generated content is available, or be incomplete while fidelity is established. Requested broader omissions cannot become a pass. No sample checker or every specialized validator is a prerequisite for established authoring. No general proof that a patch is a Restrictive refinement is promised.

Overall author disposition is failed for established errors or selected strict warnings, otherwise undetermined if generation, fidelity or requested checking is unfinished, otherwise passed. complete means that this one requested authoring operation, including fidelity and requested checking, finished; independent errors can coexist with complete work. Top-level author incomplete_checks counts this one unfinished authoring unit at most once. The separately represented checking outcome counts its own assessment units, never added to author coverage counters. Detail omission alone changes neither completion nor fidelity.

Sources unavailable, global contributor ambiguity, effective cycles, Boolean or short-name sdfRef without processing meaning, unknown critical features and semantic work/output limits are conditions with their existing basis or the author’s operational reason. author.local_only_object is an operational unsupported capability; author.identity_collision is an authoring assembly conflict, not an invented RFC rule; author.fidelity_unknown names affected unknown context; author.generation_limit is operational unfinished work. Unknown request selectors and invalid output configurations are request errors before generation. Sources and useful candidate views survive failures.

Limits and locations

All model, sample and generated attempts share the 256-attempt ceiling. Reserving one generated identity reduces available supplied attempts to 255. All caller metadata, including request keys, new names, prefixes, URI strings and repeated source selectors, consumes the shared 1 MiB pre-copy budget and worst-escaping mandatory-report reserve. Source key/label/URI/version/digest bounds remain unchanged. New semantic identities are never clipped. The accepted plan is owned only after preflight.

The CLI author plan is one bounded JSON request text, at most 4 MiB, with the shared decoding, duplicate-name, depth and numeric policies. Its parsed nodes and storage share the request’s 500,000-node/64 MiB parsed allocation budgets. It has no SDF source role or namespace identity. Builder requests have the same new-name, patch-depth/node/byte and metadata charges. Raw plan bytes are additional bounded request storage, not an unbounded metadata escape.

Raw generated bytes share the 4 MiB/document and 32 MiB catalogue ceilings with supplied content. Before appending emitted bytes, the writer checks emitted UTF-8 bytes, including escaping, indentation and newline, against remaining output/input and derived-allocation budgets. Generated representation shares 250,000 effective nodes/64 MiB derived allocation, ancestry and 10,000,000 work units with composition and requested checking. Already charged immutable content can be shared, but traversal still charges work. No phase resets the 2,000,000 numeric units or report/location limits. Request configurations cannot disable finite caps. Exhaustion yields explicit operational incompleteness; a partially built buffer is never a completed generated SDF document or ordinary CLI output.

Source and effective locations retain the shared meanings. Author-request locations add a distinct kind:"author_request", request key, decoded pointer and optional original-plan byte span. A typed builder has a pointer into its logical request shape and a null span because no textual offsets exist. A CLI span belongs to the retained plan text, never a generated source. A generated-source span belongs to its emitted candidate bytes. For a refined maximum, the effective location names the generated root, with related locations in the original sdfObject and /objects/0/refinement/sdfProperty/temperature/maximum of the author request. A deletion can identify an absent effective quality. Pointer/detail truncation keeps compact identity and explicit omission reasons; it does not invent a source span.

Author report JSON 1.1

The author operation extends the shared supported wire contract in minor version 1.1 with a new tag. Check/inspect readers continue rejecting this unknown operation before reading its payload; existing 1.0 tags, units, fields and null meanings do not change. The following additions apply only to operation:"author". Count, Bytes, SourceId, Outcome, Scope, Coverage, Basis and diagnostic omission types retain the shared bounds and meanings. There is no mandatory embedded generated SDF payload in the report.

JSON objectRequired fieldsAbsence and null rules
Top levelschema:"esdieff.report"; version:"1.1"; operation:"author"; request:Author Request; sources:Source[]; baseline:Baseline; policy:Policy; outcome:Outcome; coverage:Coverage; diagnostics:Diagnostics; result:AuthorResultAll fields are required. Source/Baseline/Policy/Outcome/diagnostic definitions retain shared 1.0 meanings. Only the author-specific request, coverage unit, result and request-location additions below apply.
Author Requestassessment:null; inventory:null; scope:Scope; authoring:AuthorPlanSummaryNull assessment/inventory means the author operation has no model-assessment identity. Optional checking has its separate explicit identity below. scope is selected with the reserved generated root, dependencies/assessed/unavailable_required report actual established work.
AuthorPlanSummarykey:string (<=256); thing_name:string (<=1024); generated_source:Id; declaration_count:Count; checking:"not_requested"|"requested"Optional label uses the shared presentation-label omission rule. Complete recipe/content is accessed through owned request views rather than repeated in every report.
Author RequestedCoverageinventory:null; count_unit:"authoring"; total:1; assessed:Count; not_applicable:0; unassessed:Count; undetermined:CountThe three counters sum to 1. Assessed means the author work finished, including any requested checking; unassessed/undetermined explicitly identify unfinished work. BroaderCoverage still discloses RFC coverage independently.
AuthorResultkind:"author"; generation:"complete"|"partial"|"unavailable"; fidelity:Fidelity; documents:GeneratedDocument[]; checking:AuthorChecking; omissions:Omission[]No fields are omitted. documents includes the reserved generated identity even if content is unavailable. One document is requested in this contract.
Fidelitystate:"established"|"undetermined"; known_semantics:"established"|"undetermined"; opaque_content:"none"|"retained"|"unavailable"; limitation_count:CountBounded location-bearing conditions carry detail. An empty retained condition list does not override limitation_count or aggregate state.
GeneratedDocumentsource_id:Id; state:"available"|"partial"|"unavailable"; content_complete:boolean; retained_bytes:Bytes; faithful:booleanSource role is generated, acquisition generated. Unavailable has false content_complete, zero retained_bytes and false faithful. faithful requires generation complete and fidelity established; it does not assert model-check success. Report carries identities/statuses only.
AuthorCheckingstate:"not_requested" OR state:"requested"; assessment:string; inventory:string|null; scope:Scope; outcome:Outcome; coverage:CoverageThe five additional fields are required only for requested; they are absent for not_requested, never null success defaults. Requested assessment is initial/full, inventory null explicitly means unavailable requested inventory. Its counts use the shared assessment_area/requirement conventions. Diagnostics stay in the top-level collection with named assessment units and are not double-counted.
AuthorRequestLocationkind:"author_request"; key:string (<=256); pointer:string|null (<=8192); span:[Bytes,Bytes]|nullOptional omission follows shared rules. Null pointer/span means unavailable; empty pointer is the plan root. The key identifies owned request metadata, not a SourceId or SDF namespace.

Rust result enums use stable accessors/private fields with future-compatible variants. Existing check/inspect readers are not required to understand author-request locations. A known operation’s meanings cannot silently change within report 1.x; breaking fields/tags/units require a major version. The author DTO is independent of parser, graph and Rust serialization layout.

CLI and destinations

The command is esdieff author --plan PLAN --document-output DEST [--report-output DEST] [--check initial-v1|full-baseline] [--strict-warnings] [--format human|json] [--replace-document] [--replace-report] --source KEY PATH.... Repeat the two-argument --source KEY PATH option for each explicit supplied model path; keys use the shared bounded unique caller-key contract. Paths supply candidates, not declaration roles. PLAN is an explicit path or -, distinct from SDF inputs. At most one input/plan uses stdin. --document-output is required; report defaults to stdout. Each DEST is an explicit file or -. Document and report cannot both use stdout or name the same filesystem target. No directory discovery, parent-directory creation, source mutation or implicit writes occur.

The JSON plan contains key, generated_key, optional generated_label, thing_name, namespace map, optional default_namespace, optional info and thing_qualities maps, and objects array. Each object contains name, source (the exact supplied KEY, solely for source selection), pointer, prefix, refinement map and required boolean. CLI acquisition associates each key with its explicit raw filesystem path, then translates selectors to the same library request. This supports non-UTF-8 paths without placing them in JSON or deriving identity from labels. Plan source selectors must exactly select one supplied key; file aliases under distinct keys remain distinct contributors and never silently coalesce. Duplicate plan members are refused. New names/namespaces are deliberate request data, not inferred filenames.

Before generation, the adapter validates destinations and source aliases. The plan path is a protected input alongside every supplied model path. An existing output requires its corresponding replacement flag and a regular, non-symlink file; the flag does not authorize an input alias. A replacement option for stdout is a configuration error. Existing destination identities are compared to input identities and each other, including hard links and resolved parent-directory aliases; source overlap is refused. Absent paths use resolved parent identity plus exact basename to detect aliases. File commits recheck identity/collision policy and use create-without-replacement or explicit replacement of the validated destination. Unexpected changes cause a host failure rather than overwriting a newly appeared path. No portability claim of preventing every adversarial filesystem race is made; stronger platform primitives are separate implementation choices.

Only generation complete, fidelity established and a passed requested check permit ordinary document delivery. When checking is not requested, established generation/fidelity permits delivery. Failed or undetermined authoring emits its report and exits 1 or 3 with no generated document write. Library candidates remain available for explicit inspection; this first CLI has no flag that presents an uncertain candidate as ordinary output. Domain failures do not erase source attempts. Invocation/configuration errors exit 2; host acquisition/output failure follows the shared distinctions, including reportable input acquisition conditions versus exit 4 when an output cannot be emitted. Strict warnings can prevent document delivery without changing semantic fidelity.

For files, output is staged under a bounded temporary file in the existing destination directory and committed only after successful generation and policy checks; abandoned staging is cleaned up. Each file commit is atomic where the platform supports it, without a two-file transaction or stdout rollback guarantee. A permitted generated document is delivered before emitting the passed CLI report. The report’s domain outcome does not itself assert host delivery; successful process status establishes delivery of both requested outputs. If the report later fails, exit 4 and stderr identify any document already delivered. A stdout document may be partially emitted on host failure and cannot be withdrawn; exit 4/stderr make the failure explicit. Reports go to their separate destination with a trailing newline and equivalent human/JSON conclusions. No report prose is mixed into document stdout.

Ordinary acceptance fixture

The reusable source contributes Sensor / indoor in https://example.com/esdieff/capabilities, with inline temperature Property data: type number, nullable false, minimum -50, maximum 150, multipleOf 0.10, a maxLength of 18446744073709551616 that FullBaseline reports outside the CDDL uint domain, unit Cel, writable false; an inline Action input/output and Event output contain no references. It also declares sdfRequired:["temperature"] and a source description. An additional inline reusable Switch sdfObject provides a Boolean enabled Property in the same document. The reusable source remains byte-identical.

The request chooses sdfThing Room / Monitor, declarations ambient / sensor and switch, explicit reuse binding to the source namespace and product default namespace https://example.com/esdieff/products. The temperature refinement deletes the sdfObject description with null and overrides maximum with the accepted token 1e2; the source maximum remains 150 and Event-output maximum remains 150. ambient / sensor is required, switch optional. Generated sdfRef uses reuse:#/sdfObject/Sensor%20~1%20indoor, the URI-fragment spelling of the pointer whose decoded token is Sensor / indoor. The effective maximum is mathematically 100 with raw patch lexeme 1e2; minimum -50, step 0.10, nullable false and writable false are inherited. The generated effective path is /sdfThing/Room ~1 Monitor/sdfObject/ambient ~1 sensor/sdfProperty/temperature/maximum.

A second supplied acceptance variant names the required declaration ambient#sensor and selects the reusable sdfObject Sensor# / indoor. The decoded source selector is /sdfObject/Sensor# ~1 indoor; its generated CURIE is reuse:#/sdfObject/Sensor%23%20~1%20indoor. The new sdfThing’s sdfRequired entry is #/sdfThing/Room%20~1%20Monitor/sdfObject/ambient%23sensor, not the invalid abbreviation ambient#sensor. The decoded effective declaration pointer is /sdfThing/Room ~1 Monitor/sdfObject/ambient#sensor. Inherited sdfRequired:["temperature"] remains exact. The slash/space control ambient / sensor remains a valid exact abbreviated name, without ~1 or percent encoding in that abbreviated entry. These are supplied, unexecuted semantic acceptance expectations, not evidence of a current emitter defect. Copied absolute pointers relocate under ADR 0036: Copied reference relocation without being rewritten.

Acceptance checks the generated catalogue with explicit generated roots and inspects the effective Property and required declarations. Comparison uses these independently worked semantic observations and exact values, not whitespace/key order. A permitted optional opaque quality remains structurally retained but leaves affected fidelity undetermined when its new containment meaning is unknown. A copied Boolean or short-name sdfRef, which has no processing meaning, likewise leaves only affected composition/fidelity incomplete. A generated global-name collision, a duplicate declaration name, a 256-supplied-plus-generated attempt request, a too-small generated-byte budget and conflicting CLI destinations have explicit failure expectations. These are contract acceptance obligations; a supplied expected fixture is not evidence that product composition has executed.

Using the authoring operation

The library accepts explicit source selection and retains the complete result for inspection:

#![allow(unused)]
fn main() {
use esdieff::{Assessment, AuthorObject, AuthorRequest, AuthorResult, Catalogue, SourceId};

fn product(catalogue: Catalogue, reusable: SourceId) -> Result<AuthorResult, &'static str> {
    AuthorRequest::new(catalogue, "room-recipe", "room-product", "Room")?
        .namespace("reuse", "https://example.com/capabilities")?
        .namespace("product", "https://example.com/products")?
        .default_namespace("product")?
        .object(AuthorObject::new("sensor", reusable, "/sdfObject/Sensor", "reuse", true)?)?
        .checking(Assessment::Initial)?
        .author()
}
}

AuthorResult::outcome() describes the entire requested operation. generation() and fidelity() retain the independent assembly and Authoring fidelity conclusions. generated_document() returns available candidate bytes even when requested checking fails or remains unfinished. catalogue() supplies immutable source and effective inspection through the ordinary operations. Only document_deliverable() permits the CLI’s ordinary generated-document output.

For the CLI, save an explicit recipe such as:

{
  "key": "room-recipe",
  "generated_key": "room-product",
  "thing_name": "Room",
  "namespace": {
    "reuse": "https://example.com/capabilities",
    "product": "https://example.com/products"
  },
  "default_namespace": "product",
  "objects": [
    {
      "name": "sensor",
      "source": "reusable",
      "pointer": "/sdfObject/Sensor",
      "prefix": "reuse",
      "refinement": {},
      "required": true
    }
  ]
}

Run esdieff author --plan recipe.json --source reusable capabilities.sdf.json --document-output room.sdf.json --check initial-v1 --format json. The report goes to stdout. Use --report-output report.json for a separate report file, or use --document-output - --report-output report.json to send only the generated document to stdout. --replace-document and --replace-report separately authorize replacing an existing regular output, while protected input aliases remain refused.

Destination identity uses retained filesystem handles, including parent handles for absent paths, with checks before individual commits. Identity or hard-link support unavailable on a host produces an explicit failure. Conservatively reported filesystem identity collisions can refuse output, including wider filesystem identifier limits on Windows. This operation does not claim universal race prevention or a transaction across document and report delivery.

Refinements and explanations

Refinements are owned JSON maps. JsonBuilder retains exact accepted number lexemes; a null in an actual Composition patch deletes an inherited quality:

#![allow(unused)]
fn main() {
use esdieff::{Assessment, AuthorObject, AuthorRequest, AuthorResult, Catalogue, JsonBuilder, SourceId};

fn refined_product(catalogue: Catalogue, reusable: SourceId) -> Result<AuthorResult, &'static str> {
    let json = JsonBuilder::new();
    let patch = json.map(vec![
        ("description", json.null()?),
        ("sdfProperty", json.map(vec![
            ("temperature", json.map(vec![
                ("description", json.text("Product temperature")?),
                ("maximum", json.number("1e2")?),
            ])?),
        ])?),
    ])?;
    AuthorRequest::new(catalogue, "room-recipe", "room-product", "Room / Monitor")?
        .namespace("reuse", "https://example.com/capabilities")?
        .object(AuthorObject::new(
            "ambient / sensor", reusable, "/sdfObject/Sensor ~1 indoor", "reuse", true,
        )?.refinement(patch)?)?
        .checking(Assessment::Initial)?
        .author()
}
}

The reusable source keeps its original description, maximum and number tokens. The generated effective Property inherits its minimum, step and capability flags while overriding the maximum with the accepted 1e2 token. The Object description is absent, with its deletion explanation retained. Unrefined Action and Event descriptions keep their inherited values.

Use the ordinary EffectiveModel::explanation interface, then map a generated-source contributor back to its recipe:

#![allow(unused)]
fn main() {
use esdieff::{AuthorResult, EffectiveRequest};

fn inspect_refinement(result: &AuthorResult) -> Result<(), &'static str> {
    let effective = result.catalogue().effective(EffectiveRequest::new(result.generated_source()))?;
    let maximum = effective.explanation(
        "/sdfThing/Room ~1 Monitor/sdfObject/ambient ~1 sensor/sdfProperty/temperature/maximum",
    ).require()?;
    let generated_origin = maximum.sources().next().ok_or("maximum origin unavailable")?;
    let recipe = result.request_origin(generated_origin).require()?;
    assert_eq!(recipe.pointer().require()?, "/objects/0/refinement/sdfProperty/temperature/maximum");
    Ok(())
}
}

request_origin accepts a view belonging to this result’s Catalogue. A reusable-source contributor yields Absent; a foreign Catalogue view yields Unavailable, even if its compact Source ID and path coincide. Textual plans expose exact original-plan byte spans. Typed builders expose the logical recipe pointer with no fabricated textual span. Effective locations and generated-source byte spans keep their existing meanings. Author report 1.1 adds related recipe locations to located generated-source findings; ordinary check and inspection report tags retain their established contracts.

AuthorResult::checking() exposes the requested assessment, outcome, source roots and coverage through typed accessors. Its requested assessment-area and requirement counts remain separate from the single authoring unit in AuthorResult::requested_coverage(). full-baseline can remain unfinished while the candidate and independent inspection are available. Strict warnings can prevent document delivery while Authoring fidelity stays established. Limitations from Boolean or short-name sdfRef and from opaque contexts identify affected effective and source coordinates without hiding independent refinements or established errors.

For a delivered CLI result, inspect it with its explicit reusable inputs, for example esdieff inspect --view effective --document room.sdf.json --pointer '/sdfThing/Room ~1 Monitor/sdfObject/ambient ~1 sensor/sdfProperty/temperature' capabilities.sdf.json room.sdf.json. The ordinary inspection report exposes inherited, overridden and deleted observations and their nearest source origins. Use --format json for the shared structured inspection contract.

Authored-quality editing

Esdieff revises present authored qualities in one supplied SDF document. An owned EditRequest selects the original model source, a request key and a distinct generated key. Each Edit selects one authored named definition by decoded JSON Pointer and one exact Quality Name. replace requires an accepted JsonValue, including JSON null. remove carries no value. Both require a present original member.

The operation supports label, description and $comment on the six base named-definition classes, including ordinary nested definitions. Property and sdfData definitions additionally support exactly type, sdfType, const, default, enum, minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, minLength, maxLength, pattern, format, minItems, maxItems, uniqueItems, nullable, contentFormat and unit. Those data qualities remain unsupported on Thing, Object, Action and Event owners. Information blocks, arbitrary JSON, effective-only content, Action input/output, Event output, direct items, map-data entries and Choice alternatives are outside this owner capability. The operation refuses an owner or enclosing definition/data-description context with an authored sdfRef, irrespective of its value shape. Untouched Composition branches remain preserved.

A const or documentary default object/array is one literal value, never model structure or a Composition patch. Replacing it replaces the whole value. Literal null remains a present member, while removal makes the member absent. Replacement values are retained faithfully without quality-shape repair or coercion. Documentary values do not specify device behavior.

All targets are established against the original document before application. Empty or excess requests, malformed or overlong pointers, known missing owners/members, unsupported roles/qualities, duplicate decoded targets, contradictory operation fields, unknown source identities and generated-key collisions are request errors. Unreadable or incompletely decoded content and exhausted target-establishment work instead return scoped operational incompleteness.

EditRequest::from_plan(catalogue, bytes) accepts a UTF-8 JSON map with string key, source and generated_key, optional string generated_label, and a nonempty edits array. Each edit has string owner, quality and operation, with operation exactly replace or remove. value must be present for replacement, including explicit null, and absent for removal. Unknown fields, duplicate decoded members and repeated decoded targets are refused. source matches one supplied key exactly, without consulting labels or filenames. The generated key must differ from every retained source key, including substituted original evidence.

The plan retains original bytes and spans independently of model-source bytes. Public request locations retain the request key, logical /edits/index coordinate and original-plan span when available. Nested replacement coordinates remain below /edits/index/value. Typed requests retain the same logical coordinates with null textual spans.

Ownership and inspection

EditResult owns accepted intent, immutable original evidence, available candidate bytes and the active result Catalogue. original_source() exposes exact original bytes, path/URI, version and digest metadata. catalogue() and into_catalogue() expose active sources after replacing exactly the selected original contributor with the generated source. retained_sources() includes every retained attempt, including substituted evidence. Other contributors retain their identities and metadata. Explicit aliases remain distinct. Original evidence is never a name-resolution fallback.

The generated source has a new identity, caller key, Generated role and Generated acquisition state. Its acquisition URI, path, version and digest are absent. Same-document references stay within the generated document, and unchanged global names remain available to other contributors. A local-only source needs no namespace assignment.

target(index) relates one accepted edit to its original owner/member and request intent. Original spans describe original bytes. Generated-member spans describe generated bytes. Removed members return Field::Absent and receive no generated span. Typed request locations use /edits/index with no textual-plan span. request_origin() relates generated replacement content to /edits/index/value and any nested literal coordinate. These relationships do not promise exhaustive provenance.

Preservation and completion

Editing fidelity has identity esdieff.authored-quality-edit/1. Established fidelity verifies every requested change and every other authored JSON value, Given Name, definition position, namespace mapping and reference spelling. Unchanged and replacement numbers retain accepted lexemes, including exponents and numbers inside opaque or literal containers. Opaque content stays in its original authored position without a claim about unknown meaning.

Generated output is indented UTF-8 JSON with a trailing newline. Original whitespace, escape spelling, member order and byte spans are presentation details and are not reproduced. No numeric float conversion, normalization or coercion occurs.

Generation is independently complete, partial or unavailable. Fidelity is independently established or undetermined. A proven wrong edit or preservation loss fails the operation. Exhausted application, emission, decoding or fidelity work cannot produce completed editing or a deliverable document. Available candidate bytes remain inspectable. Successful editing without a requested Model check establishes faithful source changes, including intentionally invalid quality shapes, without claiming a valid model.

Optional Model checking

EditRequest::checking(Assessment::Initial) and checking(Assessment::FullBaseline) request one ordinary assessment. Other assessments or a repeated checking selection are request errors. strict_warnings(true) applies the ordinary warning policy. Checking selects the entire generated source as its root and uses the active Catalogue to establish needed dependencies. It neither independently certifies unrelated sources nor all consumers of the revised definitions. A subsequent ordinary Catalogue check can request that wider scope.

EditResult::checking() exposes the assessment, outcome, requested root IDs and assessment-area coverage. Full checking separately exposes its 54-requirement coverage. No check has an absent assessment/outcome/coverage, rather than a fabricated passed assessment. Complete candidate bytes and established Editing fidelity remain inspectable when a requested check fails or is unfinished. Ordinary delivery additionally requires that check to pass under its warning policy.

Source decoding, plan admission, transformation, fidelity and checking retain cumulative numeric, allocation and work allowances. A late limit preserves earlier established findings and leaves the whole requested editing operation unfinished. It never replenishes the check budget or turns an available candidate into delivered output.

Report 1.2

The supported esdieff.report envelope adds operation edit and version 1.2. Older operation meanings and unknown-operation guards remain unchanged. Top-level request.assessment and request.inventory are null. request.editing contains key, original_source, generated_source, edit_count and checking. The no-check slice reports checking as not_requested in both request summary and result.checking.state.

Requested coverage has count unit editing, total 1, and the existing assessed/unassessed/undetermined partition. This unit covers the whole request, including optional checking. An unfinished requested check therefore leaves this unit undetermined even when generation is complete and fidelity established. A completed check with findings still completes assessment of the unit, while the aggregate disposition fails. Broader RFC coverage remains partial. result retains generation, fidelity state and contract identity, generated document state/content completeness/retained bytes, original-to-generated substitution, active_sources, checking state and omissions. No generated JSON payload is mandatory.

Requested result.checking separately carries its assessment, inventory, scope, outcome and coverage. Its existing assessment_area and requirement units never count individual edits or the editing operation. Available Full inventories retain totals of 13 assessment areas and 54 requirements. Both established inventory aggregates remain mandatory when optional requirement rows or diagnostics are omitted. An unavailable inventory keeps its ordinary null inventory/total meaning. Ordinary source/effective check locations keep their meanings. Findings on revised replacement content can relate the generated span to the original member and /edits/index/value or its nested literal coordinate. These bounded relationships do not promise complete causality, and removed members receive no invented generated span.

Mandatory source records include all supplied/generated attempts, including original evidence. Scope roots identify the active generated source. Aggregate errors, completeness, identities, substitution and edit count remain present when optional diagnostics or pointers are omitted. Human and JSON conclusions use the same bounded projection. Editing diagnostics use separate edit_request locations with request key, logical decoded pointer and available textual-plan span. Typed spans are null. Existing source and effective locations retain their meanings.

Finite operation

The generated attempt and mandatory report envelope are reserved before request content is copied. All retained attempts share the configured ceiling of 256. Request/generated keys are at most 256 bytes, labels at most 512 bytes, selectors at most the configured 8 KiB default, and the nonempty request has at most 256 edits. Caller metadata shares the 1 MiB pre-copy ceiling. Original and generated raw bytes both count toward 4 MiB per-document and 32 MiB aggregate defaults, including after reuse of an active result Catalogue.

Source decoding, replacement admission, selection, traversal, transformation, verification and generated decoding share finite parsed-node/allocation, derived-node/allocation, numeric and work allowances. Storage and work are charged before allocation and emission, including JSON escaping, indentation and the trailing newline. Report detail has separate finite count, byte and pointer presentation limits. No phase replenishes an allowance. Reusing an active result Catalogue retains identity, acquisition-attempt and stored-byte accounting.

Plans are at most 4 MiB and obey any smaller configured document-byte ceiling. Generated-attempt and mandatory metadata/report reservation precede retained plan/request copying. Plan storage, JSON decoding and owned replacement copies consume the operation’s remaining allowances. Already charged replacement copies are admitted without charging their storage twice. Plan traversal carries its derived/work remainder into target establishment and generation.

Syntax and established field-shape errors are request errors. A hard decoding or admission ceiling that prevents a complete root, exact edit count or owned bounded request is a distinct admission-limit error and generates no document. Once request identity and the complete edit list are admitted, unavailable numeric capability, replacement copying or target-establishment work instead retains an unfinished result with the exact accepted edit count, original plan evidence and source substitution. It never permits ordinary document delivery.

Command and document delivery

The command accepts only explicit sources and a saved plan.

esdieff edit --source KEY PATH --plan PLAN --document-output DEST
  [--report-output DEST] [--check initial-v1|full-baseline]
  [--format human|json] [--strict-warnings]
  [--replace-document] [--replace-report]

Repeat --source KEY PATH for other contributors. The plan’s source selects exactly one supplied key. Document output is required, and report output defaults to stdout. One source or the plan may use - for stdin. Document and report may each use - for stdout, but never together. There is no directory discovery, implicit acquisition or parent-directory creation. Plans are bounded by 4 MiB, CLI metadata by 1 MiB, and supplied source attempts by 255 so that the generated attempt remains reserved within 256.

An ordinary document is delivered only after complete generation and established Editing fidelity, plus a passing requested check under the warning policy. Without a check, the report explicitly says not_requested. Failed or unfinished work emits a report without writing the ordinary document. Exit codes are 0 for passed work, 1 for findings or strict warnings, 2 for invalid invocation/request, 3 for unfinished work without independent failure, and 4 for host or output failure. Hard pre-admission plan ceilings produce exit 2 before an owned editing request exists. Admitted incomplete requests retain a report and use their ordinary outcome code.

Human/JSON reports and generated JSON use distinct destinations. Report color never changes generated document bytes or JSON reports. Source and plan bytes remain immutable. File destinations protect every supplied source and the plan against direct, symlink, hard-link and resolved-parent aliases. Document/report file identities must also differ. Existing outputs require their corresponding replacement flag and must be regular non-symlink files. A replacement flag never permits an input alias, and it does not apply to stdout.

Each file output rechecks destination and protected-input identities, writes and syncs bounded staging in the existing destination directory, rechecks again and then commits individually. Create-only output uses a hard link so an existing file cannot be overwritten. Explicit replacement of an existing file uses rename. There are at most 100 staging-name attempts. Named FIFO input identities are retained without opening their streams before acquisition.

The document is delivered before the report. On any abandoned-staging failure, cleanup is attempted explicitly. Cleanup failure returns exit 4 and names the retained staging path, the original failure when present and whether the document was committed/delivered. A report failure after document delivery identifies that delivered document on stderr. Failed stdout delivery can leave partial bytes. There is no transaction across the two destinations or stdout rollback.

Reacquire a delivered file through ordinary checking or inspection, supplying needed dependencies and the edited file rather than its original contributor. For example, esdieff inspect --view source --document revised.sdf.json --pointer /sdfObject/Sensor revised.sdf.json examines the revised authored owner, and esdieff check --assessment full-baseline revised.sdf.json requests ordinary Model checking.

This contract follows ADR 0034: Authored-quality editing with source substitution. Renaming/moving definitions, inserting absent qualities, reference rewriting, namespace rebinding, in-place source writes, composition-patch editing and before-and-after equivalence remain separate capabilities.

Revision comparison

Esdieff compares two Model revisions from the Client’s side and classifies each difference between their corresponding groupings as breaking, compatible or undetermined. The rules follow ADR 0039: Client-side revision comparison, and the terms Model revision, Corresponding definition, Client, Client-supplied data, Thing-supplied data, Client direction, Breaking change, Meaning quality, Breaking witness, Representative value, Monotone rule, Compatibility proof, Difference acknowledgement, Acknowledged difference and Version warning come from the domain language. A difference Esdieff cannot classify stays undetermined, so it is never presented as safe.

#![allow(unused)]
fn main() {
use esdieff::{Catalogue, ComparisonRequest, SourceInput};
use std::path::Path;

let earlier = Catalogue::from_inputs(&[SourceInput::file("device.sdf.json", Path::new("v1/device.sdf.json"))])?;
let later = Catalogue::from_inputs(&[SourceInput::file("device.sdf.json", Path::new("v2/device.sdf.json"))])?;
let comparison = ComparisonRequest::new(&earlier, &later).compare()?;
println!("{}", comparison.to_human());
std::process::exit(comparison.disposition().exit_code().into());
}

The comparison contract identity is esdieff.revision-comparison/2. It binds which differences are classified and how. A release that classifies more differences gets a new identity, so a report keeps its meaning.

Command line

esdieff diff --old PATH --new PATH compares an earlier and a later Model revision. Each PATH is a directory, prepared with the directory discovery rules, or a single file, and both take the same form. --recursive and --exclude RELATIVE_PATH select both directories alike. Each document’s source key is its path relative to its directory, so documents correspond by location. Two single files correspond directly, whatever their names. From the repository root, compare the minimal and rich door lock models:

cargo run -- diff --old examples/door-lock-check/minimal.sdf.json --new examples/door-lock-check/rich.sdf.json

--format human|json selects one of the reports below, and the shared color controls style the human report. --format sarif emits the report’s SARIF projection for code-scanning annotations, and --format markdown its Markdown changelog for release notes. --acknowledged FILE supplies the acknowledged differences of an intended revision. Exit codes follow check and the disposition: a comparison without unacknowledged breaking or undetermined differences exits 0, one with an unacknowledged breaking difference 1 and otherwise one with an unacknowledged undetermined difference 3. Without --acknowledged, a compatible comparison exits 0, a breaking one 1 and an undetermined one 3. Version warnings never change the exit code. Invocation errors, such as a file beside a directory, - on either side, a missing --old or --new, an empty directory, a repeated --acknowledged, --acknowledged -, or an acknowledgement file that cannot be read or decoded, exit 2 with empty stdout before any document content is read. A report that cannot be written exits 4. The CLI contract states every rule.

Library operation

ComparisonRequest::new(earlier, later) takes the earlier and the later Catalogue, and compare() performs the comparison in one operation. Both Catalogues must use the same Limits, which set the one operation allowance described below. Different limits, or a report allowance too small for both revisions’ mandatory report envelopes, are request errors. recorded_registry_policy(policy) sets the recorded evidence policy for unit names and Content-Format identifiers and codings, described under Units and Content formats. As for check, the default uses the recorded evidence. acknowledgements(&acknowledgements) supplies the Difference acknowledgements described under Acknowledged differences.

RevisionComparison borrows both Catalogues and owns their effective models, which its typed differences and reports borrow, in the way model reports do. catalogue(revision) returns either Catalogue. outcome() returns the comparison’s Classification. It is breaking when any difference is breaking, otherwise undetermined when any difference is undetermined, otherwise compatible. Classification::disposition() maps it to the check dispositions: compatible is passed and breaking is failed. disposition() is the comparison’s own disposition, which only unacknowledged differences decide. Without acknowledgements it equals outcome().disposition(). complete() is true when no unacknowledged difference is undetermined, as the report’s outcome.complete states. count(classification) counts every difference, including any whose details could not be retained, and acknowledged_count(classification) counts the acknowledged ones. unused_acknowledgements() yields the zero-based positions of the supplied entries that acknowledge no difference. differences() yields the retained differences with unacknowledged breaking ones first, then unacknowledged undetermined, acknowledged breaking, acknowledged undetermined and compatible. compared_documents(), removed_documents() and added_documents() describe document correspondence. version_warnings() yields the Version warnings in the earlier revision’s source order. registry_knowledge(id) returns the recorded registry evidence that unit and content-format comparison consulted or found withheld. to_json(), to_human() and to_human_with_style(style) render the reports below, to_sarif(directory) renders the SARIF projection and to_markdown() the Markdown changelog.

Each Difference has:

  • kind(): Removed when only the earlier revision has the content, Added when only the later one has it, Changed for a quality whose effective value differs, including one present in only one revision, and Unavailable when an effective view could not establish the content, so whether it changed is unknown.
  • subject(): a whole Document, a grouping or affordance as Definition(class), a map properties Entry, or a Quality(name).
  • classification() and reason(). The reason is present exactly when the difference is undetermined, with a stable code() and an explanatory message(). A unit change the recorded evidence cannot settle has the reason Unit(UnitReason), and a contentFormat change whose meanings cannot be compared has the reason ContentFormat(ContentFormatReason).
  • directions() and affects(direction): the Client directions of the data the difference affects.
  • witness(): the Witness of a data difference that is breaking because of one, described under Breaking witnesses and compatibility proofs.
  • side(revision): the difference in the earlier or later revision, absent when that revision lacks the corresponding definition, properties entry or document. A side has its presence() (present, absent or unavailable), its root_document() numbered within its revision, its effective pointer(limit), and its origin(). The origin is the Explanation of the nearest content origin, or of the composition patch deletion that removed an absent quality.
  • acknowledged(): whether a supplied entry acknowledges the difference, and acknowledgement(): the DifferenceAcknowledgement that would, present when the difference can be acknowledged and its effective pointers can be rendered.

Each VersionWarning has its code(), the earlier and later source IDs of its document pair as documents(), its earlier_version(), its later_version(), absent when the later document has none, and the pair’s breaking difference count as breaking(). location() is the later document’s source view at /info/version, or at /info or the document root when that member is absent, and related() the earlier document’s /info/version.

Acknowledged differences

A maintainer who publishes an intended breaking revision, or has reviewed an undetermined change, supplies Difference acknowledgements, following ADR 0040: Acknowledged revision differences. An Acknowledged difference keeps its classification, and the comparison’s result.outcome stays as it is. Only unacknowledged differences decide the disposition, so an acknowledged breaking comparison passes while its report still says it breaks Clients.

An acknowledgement file is one JSON object:

{
  "schema": "esdieff.acknowledged-differences",
  "version": "1",
  "differences": [
    {"kind": "removed", "subject": "sdfProperty", "classification": "breaking",
     "earlier": {"document": "lock.sdf.json", "pointer": "/sdfObject/Lock/sdfProperty/credential"},
     "later": null, "note": "Release 2 drops the credential"},
    {"kind": "changed", "subject": "quality", "quality": "minimum", "classification": "breaking",
     "earlier": {"document": "meter.sdf.json", "pointer": "/sdfObject/Meter/sdfProperty/power/minimum"},
     "later": {"document": "meter.sdf.json", "pointer": "/sdfObject/Meter/sdfProperty/power/minimum"}}
  ]
}

Each entry has a kind of removed, added or changed, a subject as in the report, a quality exactly when the subject is quality, a classification of breaking or undetermined, and earlier and later members. Each side is null or names the source key of the document holding the difference in that revision and its effective pointer, and at least one side is not null. An optional note is a comment for readers. An empty differences array is allowed. Unknown and duplicate members, two entries with the same identity, an entry of kind unavailable and an entry whose classification is compatible are refused.

DifferenceAcknowledgements::from_json(bytes, limits) decodes a file within the JSON decoding limits of limits, normally those of the revisions, and refuses limits a Catalogue would refuse, and DifferenceAcknowledgements::new(entries) builds the same value from typed entries. DifferenceAcknowledgement::new(kind, subject, classification) starts an entry, earlier(document, pointer) and later(document, pointer) locate it, and with_note(note) adds a note. Each validates as the file does, and DifferenceAcknowledgements::new refuses an entry without a location and duplicate identities. entries() lists them in file order, and each entry returns its kind(), subject(), classification(), document(revision), pointer(revision) and note().

An entry acknowledges a difference when the kind, subject, quality and classification are equal and, for each revision, both sides are null or the side’s root document source key and rendered effective pointer equal the entry’s document and pointer as exact decoded text. The note takes no part, and neither do request-local source IDs, content origins, directions, reasons or witnesses. An acknowledgement therefore still matches after an unrelated document is added to both revisions, and a shared definition seen through two groupings gives two differences that need two entries. Matching runs after the comparison over the retained differences, so it changes no classification. Breaking differences can be acknowledged, and so can undetermined differences of kind removed, added or changed whose content was examined, such as a reviewed added unit. A difference whose content nobody examined is never acknowledged: an Unavailable difference, a difference whose reason is UndeterminedReason::Unavailable, and a difference whose details the operation allowance could not retain. That reason covers the codes of unavailable content, such as reference.unavailable, data.number_unavailable, comparison.directions_unavailable and required.unavailable, and operation.limit. A difference whose pointer cannot be rendered within the materialized-pointer allowance also stays unacknowledged. Each pointer an entry needs is rendered once, so the report’s acknowledgement member and acknowledgement() give exactly the entry that matching compares. Because the classification is part of the identity, comparison rules that later classify an acknowledged undetermined difference as breaking bring it back for review: it is unacknowledged and its entry is unused. An entry that matches nothing is listed as unused and leaves the disposition unchanged.

The disposition is failed when any unacknowledged difference is breaking, undetermined when any unacknowledged difference is undetermined, and passed otherwise. outcome.errors counts unacknowledged breaking differences. outcome.complete, incomplete_checks and the requested coverage count unacknowledged undetermined differences.

Write an acknowledgement file for review with --acknowledgements-output FILE:

esdieff diff --old v1 --new v2 --acknowledgements-output reviewed.json

The file contains every eligible difference retained in the JSON report, including already acknowledged differences. Compatible differences and unavailable content have no entry. An empty comparison writes an empty differences array. Review the file before supplying it with --acknowledged. Exporting leaves the comparison report on standard output and preserves its exit status, so a breaking comparison still exits 1.

The destination must be a named file with an existing parent directory. An existing file requires --replace-acknowledgements, which permits replacement only of a regular non-symlink file. The destination cannot alias a selected document from either revision or the supplied acknowledgement file, including through hard links or parent-directory aliases. Destination validation precedes reading revision content. Delivery uses the same staged-write and input identity protections as edit. Destination or export-limit errors exit 2 with empty stdout. A write failure exits 4. If writing the report fails after export, the acknowledgement file has already been committed.

The file must fit the acknowledgement reader’s limits below. Export refuses an oversized or otherwise unreadable file before changing the destination. It covers the differences retained by the JSON report, so consult its omissions when comparison details were truncated. All report formats export the same entries.

Each difference that can be acknowledged also carries the exact entry that would acknowledge it in the report, so you can project a file yourself:

esdieff diff --old v1 --new v2 --format json | jq '{schema: "esdieff.acknowledged-differences", version: "1", differences: [.result.differences[].acknowledgement // empty]}'

This covers the differences the report kept within its allowance. An acknowledgement file is at most 1 MiB, which DifferenceAcknowledgements::FILE_BYTES states, decoded with the ordinary JSON input policies, and holds at most 4096 entries. Each document holds 1 to 256 bytes, each pointer at most 8192 bytes with RFC 6901 syntax, each quality at most 256 bytes and each note at most 1024 bytes. The mandatory report envelope reserves five bytes per supplied entry for the unused positions, and a report allowance too small for that reserve is a request error.

Correspondence

Documents correspond by source key, so the caller decides how documents pair. A document’s path within its revision’s directory is a natural key, and then a moved or renamed document has no correspondent. A model document only one revision has is a removed or added document, and each of its top-level groupings is a removed or added difference.

Top-level groupings correspond by their position in corresponding documents: the same class and Given Name. Nested groupings, affordances and map properties entries correspond by Given Name within their owner. A renamed definition therefore reads as a removal and an addition. Enum values correspond by value, so reordering an enum changes nothing. Choice alternatives correspond by Given Name and compare as the effective alternatives they derive, as described under Choices. Corresponding properties entries are compared at any depth of Map data with the same rules as the data description that holds them, and each difference inside an entry is located at that entry. An array’s items is compared in the same way, as the nested description of its values, described under Array data.

Every grouping of each corresponding document is compared through the effective view, including reusable Objects in shared documents. Top-level affordances and sdfData definitions are not compared as interfaces. Their changes appear through the effective groupings that use them, at any depth in their data, with the shared definition as the content origin.

Whether a quality changed

Exact numbers and Value equality decide whether an effective quality changed at all, following ADR 0012: Exact numbers and JSON input policies and ADR 0015: Bounded value equality in a resolved data context. Numbers compare their exact values, so 10 and 1e1 are the same bound. Text compares decoded Unicode scalar values, arrays are ordered and maps unordered. enum values and map-data required names compare as sets. An absent readable, writable or observable characteristic, or an absent Nullable characteristic of a data description, equals its explicit Specified default true, and an absent uniqueItems equals an explicit false. Inside items neither default applies. A representation that ordinary equality cannot settle under another meaning, such as two spellings of one instant, counts as a change and is classified like any other. Two contentFormat declarations in data with one established meaning, such as 50 and application/json, are the same, as described under Content formats.

Unchanged qualities produce no difference. sdfRequired instead compares by the requiredness it resolves to, described under Requiredness.

Classification

DifferenceClassification
Removed grouping or affordanceBreaking
Added grouping or affordanceCompatible
Property readable, writable or observable characteristic that becomes false, including a Specified default true replaced by an explicit falseBreaking
Property characteristic that becomes true, including an explicit false that becomes absentCompatible
Input data added to an Action that had none, since existing invocations send noneBreaking
Input data removed from an Action, or output data removed from an Action or EventBreaking
Output data added to an Action or Event that had none, which no Client of the earlier revision readsCompatible
A declaration of both revisions that stops being mandatory in a corresponding groupingBreaking
A declaration that becomes mandatory in a corresponding groupingCompatible
Such a change, or a changed sdfRequired, while either revision’s requiredness resolution is partial or unavailableUndetermined, required.unavailable
Narrowed instance count range of a Grouping array in both revisionsCompatible
Any other changed minItems or maxItems of a Grouping array in both revisionsBreaking
Changed minItems or maxItems of a grouping that becomes or stops being an array, or whose counts do not form a range of exact nonnegative integersUndetermined, comparison.not_classified
Changed description, label or $comment, or documentary default in data, other than a label or default inside an items description that carries a quality outside the Direct items vocabularyCompatible
Changed minimum, maximum, exclusiveMinimum, exclusiveMaximum, minLength, maxLength, multipleOf, enum, const, pattern, checked format, type, minItems, maxItems, uniqueItems or Nullable characteristic in data, or an items description added to or removed from data, with a Breaking witnessBreaking
Such a change with a Compatibility proofCompatible
Such a change without eitherUndetermined, with a witness reason
An alternative removed from a choice in data or added to one, or sdfChoice added to or removed from data as a whole, with a Breaking witnessBreaking
Such a change with a Compatibility proof, such as an alternative added to Client-supplied data or removed from Thing-supplied dataCompatible
Such a change without eitherUndetermined, with a witness reason
Changed sdfChoice in data whose alternatives either revision does not establish, such as beside an enumUndetermined, comparison.not_classified
Changed map-data required that newly requires an entry in Client-supplied data, or drops a requirement from Thing-supplied data, with a Breaking witnessBreaking
Changed required with a Compatibility proof, such as a requirement added to Thing-supplied data or dropped from Client-supplied dataCompatible
Changed required without eitherUndetermined, with a witness reason
A properties entry that only the later revision describes and the earlier revision does not requireCompatible
A properties entry removed from map data, or one that only the later revision describes and the earlier revision requires, with a Breaking witnessBreaking
Such an entry with a Compatibility proof, such as one removed from Client-supplied dataCompatible
Such an entry without eitherUndetermined, with a witness reason
Any changed data quality or properties entry of a Property whose revisions offer no common Client directionCompatible
Changed quality inside an items description, other than its description or $comment, when either revision’s items carries a quality outside the Direct items vocabularyUndetermined, comparison.not_classified
Changed unit, contentFormat or sdfType beside a choice in data, when every alternative replaces itCompatible
Changed unit in data between two different current names in the recorded SenML evidenceBreaking
Any other changed unit in dataUndetermined, with its unit reason
Changed contentFormat in data between two different established meaningsBreaking
Any other changed contentFormat in dataUndetermined, with its content-format reason
Changed sdfType in data between byte-string and unix-timeBreaking
sdfType added to or removed from data, with a Breaking witnessBreaking
sdfType added to or removed from data without a witnessUndetermined, with a witness reason
Any other changed sdfType in dataUndetermined, comparison.not_classified
Changed format in data that either revision has outside the six checked formats or beside no type: "string"Undetermined, comparison.not_classified
Any other changed qualityUndetermined, comparison.not_classified
Content an effective view could not establishUndetermined, with the view’s reason

Client directions

Each difference in a data description names the Client directions it affects. A writable Property’s data and Action input are Client-supplied data. A readable or observable Property’s data, Action output and Event output are Thing-supplied data. A Property that is readable and writable carries data in both directions. Effective Property characteristics, including Specified default characteristics, decide which directions each revision offers, and data is compared only in the directions both revisions offer, since gaining or losing a direction is a characteristic change. When a needed characteristic is unavailable, the Property’s non-documentary data differences are undetermined with the reason comparison.directions_unavailable, apart from properties entries that no Client of the earlier revision uses, described under Map entries.

A Property whose revisions offer no common direction carries data to or from no Client in both of them, so each of its data differences is compatible and names no direction. The characteristic changes decide, as when a Property stops being readable and becomes writable.

A changed characteristic names the direction it allows. writable allows Client-supplied data, and readable and observable allow Thing-supplied data, so a characteristic that becomes false names the direction it removes. Input or output data added to or removed from an affordance names its own direction. Other differences outside data descriptions, such as removed affordances and grouping qualities, affect no data direction.

Breaking witnesses and compatibility proofs

A change to the values a data description admits is breaking only with a Breaking witness and compatible only with a Compatibility proof. Each changed quality that constrains admitted values has a monotone rule, which states whether the later revision admits more values than the earlier one under that quality, fewer, the same, or none of these. A Compatibility proof covers every changed quality of one data description: a Property’s data, an Action’s input or output, an Event’s output, or one map properties entry, array items description or choice alternative of them. It holds when each changed quality’s rule loosens in the safe direction for every Client direction the data carries, and nothing else in the description changed apart from documentary qualities. Client-supplied data may only widen and Thing-supplied data only narrow, so a readable and writable Property’s value set cannot change compatibly. An added or removed properties entry has a rule of its own, and one that no Client of the earlier revision uses leaves the proof as it is, as described under Map entries. A changed quality without a rule, another quality classified breaking or undetermined on its own, such as a breaking unit change or a changed contentFormat meaning, or unavailable content in the description leaves no proof. A changed sdfType changes how values read, so it never loosens in a safe direction.

Without a proof, Esdieff settles the candidate witnesses that the changed quality itself suggests, and for some qualities the representative values of the revision that must admit a candidate. At most 8 candidates are tried for one change, in the order its rule gives them, which bounds what settling a change costs. Sample-value checking checks each candidate against the effective description in both revisions, as it would a value supplied for that Property, input or output. A candidate that the earlier revision admits and the later one rejects is a witness for Client-supplied data, and one that the later revision admits and the earlier one rejects is a witness for Thing-supplied data. A witness counts only in a direction the data carries. Any other admission, including a candidate that another constraint such as a const excludes in both revisions, establishes nothing. A difference without a proof or a witness is undetermined with one of these reasons:

CodeApplies when
comparison.unprovenNo applicable candidate is a witness.
comparison.witness_unsettledSample-value checking left a candidate’s admission undetermined, and no other candidate is a witness.
operation.limitGenerating representative values or a witness check ran out of the operation allowance. A check that runs out stays undetermined even after an established rejection.

A candidate for a change inside a map properties entry is placed at that entry and checked against the whole Property data, input or output. Each enclosing map also holds a representative value of every other entry that either revision requires there, from the description of the revision that must admit the candidate, so the enclosing constraints still apply. So a candidate 23 for the end entry of a window entry is checked as {"window":{"end":23}}, or as {"window":{"end":23},"level":0} when the enclosing map requires an integer level with a minimum of 0. When a filled entry has no representative value, or its description rejects that value in both revisions, the difference stays undetermined with comparison.unproven. A candidate for a change inside an array’s items is placed as the items of that array, which holds it as often as the minItems of either revision requires, and at least once. So a candidate 100 inside the items of levels is checked as [100], or as [100,100] when levels requires two items. Repeated items are not unique, so an enclosing array that requires two or more unique items rejects the candidate in both revisions, and an enclosing minItems beyond the value capabilities gives no candidate. Either leaves the difference unproven.

The other revision must read the enclosing values as the admitting revision does, or it could reject the candidate for another change alone. So a candidate is not placed when the revisions describe a filled entry differently apart from its documentary qualities, such as its description or a $comment deep inside it, or when the other revision’s enclosing array could reject it for its length alone, with a maxItems below that length or with uniqueItems true for two or more items. Its difference then stays unproven unless another candidate witnesses it. So when two entries that a map requires both change what they admit, neither change gets a candidate placed beside the other entry. A candidate for a change inside a choice alternative stands where the description holding the choice does, since each alternative describes that description’s values, so a candidate 5 for a fan entry of the manual alternative of a mode entry is checked as {"mode":{"fan":5}}.

Representative values

A representative value is a simple value that an effective data description may admit. Esdieff generates them from the revision that must admit a candidate: the earlier revision for Client-supplied data and the later one for Thing-supplied data. A description’s representative values are, in order:

  1. a copy of its const, in which each number keeps its authored spelling
  2. its enum values
  3. a copy of its documentary default
  4. one value for each base type it admits, every base type when it has no type, in the order number, string, boolean, map and array, or for a choice the first representative value of each of its effective alternatives, in their order
  5. null, when it is Nullable

A number lies at the description’s lower bound, or else at its upper bound: the bound itself when it is inclusive, and one unit inside it when it is exclusive, where the unit is 1 for an integer bound and one of the bound’s last digit otherwise. Without a bound it is 0. A string is a conventional value of a format that Sample-value checking checks beside type: "string": "1970-01-01T00:00:00Z" for date-time, "1970-01-01" for date, "00:00:00Z" for time, "https://example.com" for uri, "" for uri-reference and "00000000-0000-0000-0000-000000000000" for uuid. Otherwise it is minLength copies of a, which is "" without a minLength. Boolean data gives true. A map holds every entry the description requires, each filled with the first representative value of its own description, and null for a required entry without a description. An array holds minItems copies of the first representative value of its items, or of null without an items description, and is [] without a minItems. A Direct items description has no Nullable characteristic, so null is never a representative value of items.

A value that would nest deeper than a generated value may, or a count beyond the value capabilities, is never generated. A representative value that its own description rejects, such as an empty string beside a pattern, is no witness, so the change it was generated for may stay unproven. Generation is charged to the one operation allowance, and generation that runs out of it leaves its difference undetermined with operation.limit.

A Witness has its value() as JSON text, its direction(), and its admission(revision) in each revision. The JSON report gives the same as the difference’s witness, and the human report shows it on its own line beneath the difference.

Numeric bounds

Bounds compare as exact numbers. minimum and exclusiveMinimum together set a description’s lower bound, the tighter of the two, and maximum and exclusiveMaximum its upper bound. A change to either quality of a pair is judged by the effective bound the pair leaves. So an exclusive bound replacing an inclusive one at the same value narrows by that value alone, and a redundant bound can change without changing the admitted values. A raised lower bound, a lowered upper bound or an added bound narrows, and the reverse widens.

The candidates lie among the values the wider of the two revisions’ bounds admits and the tighter one rejects. They are the tighter bound when it is exclusive and the wider bound when it is inclusive, each in its authored spelling, so a bound written 1e2 is the witness 1e2. When neither bound value lies there, the candidate is one unit of the finer bound’s last digit across an open edge, or half a unit when one unit reaches the other edge. Without a wider bound the unit is 1 where the coefficient digit limit allows, so integer data gets an integer. An exclusive minimum of 0 replaced by a minimum of 10 has the candidate 1, a removed maximum of 2.5 the candidate 2.6, and a removed maximum of 100 the candidate 101.

String lengths

minLength and maxLength bound how many Unicode scalar values a string holds, inclusively, and compare as exact nonnegative integer counts. An absent minLength reads as 0 and an absent maxLength as unbounded. So a raised minLength, a lowered maxLength or an added maxLength narrows, and the reverse widens, while an added minLength of 0 leaves the admitted values as they are. The first candidate is a string of a whose length lies just across the tighter bound: one shorter than a tighter minLength and one longer than a tighter maxLength. The representative values of the revision that must admit a candidate follow it. So a minLength of Client-supplied data raised from 2 to 4 is breaking with the witness "aaa", a maxLength of Thing-supplied data raised from 6 to 8 with the witness "aaaaaaa", and a minLength of 3 removed from Thing-supplied data with the witness "aa". A length beyond the value capabilities is never generated, so such a change stays undetermined unless a representative value witnesses it. A count that is not an exact nonnegative integer neither narrows nor widens.

Steps

multipleOf admits the exact integer multiples of a positive step, and the comparison decides multiples exactly. Every multiple of the earlier step is a multiple of the later one exactly when the earlier step is a multiple of the later step. So a later step that divides the earlier one widens, such as 0.5 replaced by 0.25, and a later step that the earlier one divides narrows, such as 0.25 replaced by 0.5. Any other change, such as 0.3 replaced by 0.5, does neither. An added step narrows and a removed one widens. The earlier step is a candidate for Client-supplied data unless it is a multiple of the later step, and the later step is a candidate for Thing-supplied data unless it is a multiple of the earlier step, each in its authored spelling. Half a step is never a multiple of it, so half an added or removed step is the candidate, followed by 1 for an added or removed step above 1, which integer data may admit. The representative values of the revision that must admit a candidate come last. So 0.25 replaced by 0.5 breaks Client-supplied data with the witness 0.25, 0.5 replaced by 0.25 breaks Thing-supplied data with the witness 0.25, 0.3 replaced by 0.5 breaks them with 0.3 and 0.5, a step of 0.5 added to Client-supplied data breaks it with 0.25, a step of 3 added to integer Client-supplied data breaks it with 1, and the same step removed from integer Thing-supplied data breaks it with 1. A step that is not a positive exact number neither narrows nor widens.

Patterns and formats

A pattern restricts string data to the strings it matches, so an added pattern narrows and a removed one widens. Esdieff does not decide whether one pattern matches every string another matches, so a changed pattern neither narrows nor widens. The candidates are the representative values of the earlier revision for Client-supplied data, when the later revision has a pattern, and those of the later revision for Thing-supplied data, when the earlier revision has one. So a pattern ^[0-9]+$ added to write-only string data is breaking with the witness "", and a removed one is compatible there. A changed pattern is breaking only when a representative value matches one pattern and not the other, and otherwise stays undetermined with comparison.unproven.

A format follows the same rule for the six formats that Sample-value checking checks beside type: "string": date-time, date, time, uri, uri-reference and uuid. So date-time added to write-only string data is breaking with the witness "", and date replaced by date-time there is breaking with "1970-01-01", the conventional value of the earlier format. Every URI is a URI-reference, and Sample-value checking reads it as the same URI under either format, so uri replaced by uri-reference widens and the reverse narrows. So uri replaced by uri-reference is compatible for Client-supplied data and breaking for Thing-supplied data with the witness "", which is a URI-reference but no URI. A change where either revision’s format is another value, or sits beside no type: "string", is undetermined with comparison.not_classified.

Enum values

Enum values correspond by value as decoded strings, so reordering them changes nothing. A value only the earlier revision lists narrows the data, and a value only the later revision lists widens it, so an enum that loses some values and gains others does neither. Each such value is a candidate in the direction it breaks: a removed value for Client-supplied data and an added value for Thing-supplied data. So a value removed from a write-only Property’s enum, or added to a read-only Property’s enum, is breaking with that value as the witness, such as "off", while the reverse changes are compatible. An enum added to a description narrows it and a removed enum widens it. The candidates of an added enum are the representative values of the earlier revision, for Client-supplied data, and those of a removed enum the representative values of the later revision, for Thing-supplied data. So an enum added to write-only string data is breaking with the witness "", which the enum excludes.

Each enum value becomes an alternative whose own const replaces any const beside the enum, and an enum beside an sdfChoice gives no alternatives, following ADR 0024: Effective alternatives and nullable characteristics. So an enum beside a const or an sdfChoice, or one that is not a nonempty array of strings, neither narrows nor widens.

Choices

A choice admits the values that any of its effective alternatives admits, following ADR 0024: Effective alternatives and nullable characteristics. Alternatives correspond by Given Name, and each is compared as the effective alternative it derives, with the shared qualities it inherits and the branch qualities that replace them. Comparing the authored branches instead would read a branch that overrides a shared maximum of 10 with 20 as an added bound, although that alternative widened.

An alternative that only the earlier revision’s choice has is a Removed difference of the sdfChoice quality, located at that alternative, and one that only the later revision’s choice has is an Added one. A removed alternative narrows the data and an added one widens it, so an alternative removed from Client-supplied data or added to Thing-supplied data is breaking with a value of that alternative as the witness, and the reverse changes are compatible. The candidates are the representative values of that alternative, from the earlier revision for a removed one and the later revision for an added one. A candidate that another alternative still admits is no witness, so the difference stays undetermined with comparison.unproven.

Each alternative inherits every shared quality that its branch does not replace. A changed shared quality is reported once, at the description that holds the choice, and it is judged on each corresponding alternative that inherits it in both revisions, beside that alternative’s own qualities. So a shared quality that every alternative replaces changes nothing and is compatible, and a raised shared exclusiveMinimum that a shared minimum makes redundant still narrows an alternative that replaces that minimum. A quality that an alternative’s branch states in either revision is compared at that alternative, located there, so a branch that comes to override a shared maximum is a changed maximum of that alternative. The meaning qualities unit, contentFormat and sdfType follow the same distribution. A shared one tells a Client how to read only the values of the alternatives that inherit it in both revisions, so a change between two meanings that every alternative replaces is compatible, and one that an alternative inherits keeps its own classification. Beside a choice whose alternatives either revision does not establish, a change that would be breaking is not classified.

A choice added to or removed from data as a whole may admit values the other revision rejects, and reject values it admits, so it neither narrows nor widens. Its candidates are the representative values of the earlier revision for Client-supplied data and of the later revision for Thing-supplied data. An enum beside an sdfChoice derives no alternatives, and a choice with an unavailable branch does not establish all of them. A changed choice whose alternatives either revision does not establish is therefore not classified, and a shared quality beside it neither narrows nor widens.

Type

Every integer is a number, and a description without a type admits values of every type. So integer data that becomes number data widens, number data that becomes integer data narrows, an added type narrows and a removed one widens. A fraction separates integer data from number data. The candidates are 0.5, then a fraction just inside each bound of the revision that admits fractions: an inclusive bound that is a fraction itself, and otherwise half a unit inside the bound, of 1 for an integer bound and of its last digit for another. So integer Thing-supplied data that becomes number data has the witness 0.5, or 10.5 with a minimum of 10, and integer Client-supplied data that becomes number data is compatible. Any other change between base types, such as string data that becomes boolean data, neither narrows nor widens. The candidates of every change of type other than one between integer and number are representative values: those of the earlier revision for Client-supplied data, when the type is added or changed, and those of the later revision for Thing-supplied data, when it is removed or changed. So string Client-supplied data that becomes boolean data has the witness "", the same change to Thing-supplied data the witness true, and a type added to Client-supplied data without one the witness 0. A type other than the six base types neither narrows nor widens and suggests no candidate, so it stays undetermined.

Nullable

The effective Nullable characteristic decides each revision, with its Specified default true where nullable is absent. Data that stops being Nullable narrows and data that becomes Nullable widens, and null is the candidate. So Client-supplied data that stops being Nullable and Thing-supplied data that becomes Nullable are breaking with the witness null, unless another constraint excludes null in both revisions, and the reverse changes are compatible. A nullable that is not a boolean neither narrows nor widens.

Required map entries

Map data’s required names compare as a set of decoded strings. A later revision that requires every entry the earlier one requires, and more, narrows, and one that requires only some of them widens. A requirement added to Thing-supplied data or dropped from Client-supplied data therefore loosens in the safe direction. A representative map holds exactly the entries its revision requires. So the representative values of the earlier revision lack every newly required entry, and are the candidates for Client-supplied data, and those of the later revision lack every dropped requirement, and are the candidates for Thing-supplied data. When the earlier revision requires flow and the later one flow and label, the Client-supplied witness is a map holding only flow, such as {"flow":5} for an integer flow with a minimum of 5. A requirement dropped from Thing-supplied data has a witness map that lacks it, such as {} when nothing else is required.

Map entries

Clients use only what the earlier revision describes or requires, following ADR 0039: Client-side revision comparison. A properties entry that only the later revision describes, and that the earlier revision does not require, is part of no Client’s interaction, so it is compatible in every Client direction, whatever else changes in its map and even when the Property’s directions are unavailable. So an optional note added to write-only or read-only map data is compatible. Beside a choice, the earlier revision also requires an entry that a corresponding alternative requires when that alternative inherits the entries in both revisions, as a changed shared quality is judged. So when an earlier scheduled alternative requires an undescribed start, a start of string data described beside the choice of write-only data is breaking with the witness {"start":0}. An earlier choice whose alternatives either revision does not establish, or that the later revision lacks, may require the entry too, so the entry is settled as a required one. When the later revision also comes to require such an entry, its changed required decides, as described under Required map entries. So when map data that requires zone comes to require zone and a newly described note, the change is compatible for Thing-supplied data, and breaking for Client-supplied data with a witness map lacking the note, such as {"zone":1} for an integer zone with a minimum of 1.

Maps are open, so an entry without a description admits every value. An entry whose description is removed therefore widens its map. An entry that the earlier revision requires without describing it narrows its map when the later revision describes it. A removed entry is compatible for Client-supplied data and breaking for Thing-supplied data with a Breaking witness. A newly described entry that the earlier revision requires is compatible for Thing-supplied data and breaking for Client-supplied data with a Breaking witness. The candidates are maps holding the entry with one value of each JSON kind, 0, "", true, {}, [] and null in that order, beside a representative value of every other entry that either revision requires there, as for a nested candidate. So when read-only map data requires such a zone, a removed flow entry of number data is breaking with the witness {"flow":"","zone":1}. When write-only map data requires such a zone and a note in both revisions, and only the later revision describes the note as string data, the note is breaking with the witness {"note":0,"zone":1}. A removed entry whose earlier description admits every candidate, such as one with only a description, stays undetermined with comparison.unproven.

A candidate is therefore placed only at an entry that the earlier revision describes or requires. A candidate for a change inside an entry stands at an entry that both revisions describe, and the candidate of an added or removed entry stands at that entry. The other entries around a candidate are filled as for any nested candidate, so they hold every entry that either revision requires, including one that only the later revision requires.

Array data

An array’s items is the nested description of its values. Its changes are compared like those of a map properties entry: they are settled together, apart from the array’s own qualities, and each is located inside items. An items description is a Direct items description, whose vocabulary is sdfRef, type, sdfChoice, enum, minimum, maximum, format, minLength, maxLength, description and $comment, with required and properties when its type is object, following ADR 0024: Effective alternatives and nullable characteristics. Sample-value checking establishes no meaning for one that carries any other quality, such as const, pattern, exclusiveMinimum, nullable or label. So when either revision’s items carries such a quality, every change inside it other than to description or $comment is undetermined with comparison.not_classified, including a narrowed bound beside it. A Direct items description has no Nullable characteristic, so an absent nullable there differs from an explicit one, and null is never a representative value of items.

An array without an items description admits items of every type, so an items description added to array data narrows it and a removed one widens it. The candidates are arrays of 0, "", true, {} and [], in that order, each repeated as often as the minItems of the revision that must admit them requires, and at least once. So an items description of integers added to Client-supplied data, or removed from Thing-supplied data, is breaking with the witness [""]. An items that is a description in one revision and something else in the other is not classified.

minItems and maxItems are inclusive counts that compare as exact numbers. An absent minimum reads as 0 and an absent maximum as unbounded, so an added minItems of 0 changes nothing. A raised minimum, a lowered maximum and an added maximum narrow, and the reverse changes widen. The candidate is an array of the count just across the tighter bound: one item short of the higher minimum, or one item over the lower maximum. Each item is a copy of the first representative value of the items of the revision that must admit the candidate, or null without an items description. So when write-only data’s items are integers with a minimum of 0, a minItems raised from 1 to 3 is breaking with the witness [0,0], and a maxItems lowered from 4 to 2 with the witness [0,0,0]. A count that is not a nonnegative integer neither narrows nor widens, and a candidate count beyond the value capabilities is never generated, so its change stays unproven.

uniqueItems reads as false where it is absent, so an explicit false is no change. Data that comes to require unique items narrows, and data that stops requiring them widens. The candidate repeats one representative item, twice or as often as the minItems of the revision that must admit it requires. So uniqueItems that becomes true on Client-supplied data is breaking with a witness such as [0,0], and the reverse change on Thing-supplied data with the same witness. Repeated items are never unique, so a count candidate of two or more items for an array that requires unique items stays unproven.

Constants

A const restricts a description to one value, unless it sits beside an enum, whose values each replace it. So an added const narrows and a removed one widens. A changed const neither narrows nor widens. The candidates for Client-supplied data are the representative values of the earlier revision, when the later revision has a const, and those for Thing-supplied data the representative values of the later revision, when the earlier revision has one. A changed const therefore has the earlier constant as its first Client-supplied candidate and the later constant as its first Thing-supplied candidate, each copied with its numbers in their authored spelling. So a constant added to write-only string data is breaking with the witness "", a constant "open" changed to "shut" there with the witness "open", and a removed constant is compatible there.

sdfType

byte-string and unix-time are the sdfType conventions of RFC 9880 Section 4.7.1 that Sample-value checking establishes. They tell a Client how to read a value, so a change between them is breaking in every Client direction the data carries, without a witness, following the meaning qualities of ADR 0039: Client-side revision comparison. A convention that is added or removed changes how values read as well, so the change neither narrows nor widens, and it is breaking only with a Breaking witness. The candidate is a value outside the convention’s JSON representation, which the revision with the convention rejects: "!", outside the base64url alphabet, for byte-string, and "", which is not a number, for unix-time. So byte-string added to Client-supplied string data, or removed from Thing-supplied string data, is breaking with the witness "!". The reverse changes, and a candidate that another constraint such as a pattern already excludes, stay undetermined with comparison.unproven. Any other sdfType value is not classified.

Requiredness

Each grouping’s mandatory declarations come from its Required declaration relationships, following ADR 0026: Required declaration relationships and source evidence. An sdfRequired entry of a grouping makes the declaration it selects mandatory in that grouping. An affordance’s sdfRequired and a true carrier belong to the grouping that encloses the definition carrying them, so a carrier makes its own affordance or grouping mandatory there. A declaration required from an enclosing grouping is represented only inside the groupings between them, so those groupings are mandatory there too, and the declaration is mandatory in each of them. Requiredness then closes through mandatory groupings: whatever is mandatory in a mandatory grouping is also mandatory in the grouping that requires it.

Corresponding groupings compare these closures at every depth, and declarations correspond by their position in the document. A declaration that both revisions have and that stops being mandatory in a grouping is breaking, because a Thing may now omit what a Client uses. A declaration that becomes mandatory only obliges Things to provide more, so it is compatible. A declaration that only one revision has is a removed or added definition of its own and does not count here. Each grouping whose mandatory declarations change has one changed sdfRequired quality, located at that grouping’s sdfRequired, present or absent, and it affects no data direction. It is breaking when any declaration stops being mandatory there, even when others become mandatory.

Since requiredness is compared after resolution, "temp", "#/sdfObject/Oven/sdfProperty/temp" and a true carrier in temp spell one requirement, and replacing one with another is no change. A requirement that a Thing moves to a required Object inside it, which then requires the declaration itself, is no change either. An Object that keeps requiring temp while its enclosing Thing stops requiring it is breaking at the Thing, because the Object may now be absent.

A revision’s resolution is partial or unavailable when a name selects no declaration, a reference is ambiguous, unavailable or malformed, a target has no effective declaration, or the traversal could not see every definition. Then a grouping whose known mandatory declarations differ, or whose own sdfRequired or that of a corresponding direct affordance changed, is undetermined with the code required.unavailable, and an unchanged requirement stays no change. sdfRequired in data-only descriptions selects no declaration of a grouping, so it is compared as a data quality and stays not classified.

Grouping instance counts

minItems and maxItems make an sdfObject or sdfThing a Grouping array and bound its instance count inclusively. Things decide how many instances they have, so the range behaves like Thing-supplied data, following ADR 0039: Client-side revision comparison. When both revisions are arrays, a raised minimum, a lowered maximum or an added maximum narrows the range and is compatible, and a lowered or removed minimum or a raised or removed maximum widens it and is breaking. An absent minimum reads as 0 and an absent maximum as unbounded, so an added minItems of 0 leaves the range as it is and is compatible. Counts compare as exact numbers, each change is judged at its own end of the range, and none has a witness or a data direction. A grouping that becomes or stops being an array changes how its instances are addressed, so its count changes are undetermined with comparison.not_classified, and so are counts that are not exact nonnegative integers or a minimum above the maximum.

Units

A changed unit in a data description follows the unit rule of ADR 0039: Client-side revision comparison and the recorded evidence of ADR 0027: Unit names and recorded registry guidance, described in the unit contract. A change between two different current names breaks every Client direction the data carries, because Clients would misread its values. A current name has a nonlegacy entry in the recorded SenML evidence, from either its SenML Units or its Secondary Units section. So Cel to K, ms to s and Wh to kWh are all breaking.

Any other unit change is undetermined, with the first reason that applies:

UnitReasonCodeApplies when
Addedcomparison.unit_addedOnly the later revision states a unit.
Removedcomparison.unit_removedOnly the earlier revision states a unit.
UriNamecomparison.unit_uri_nameEither name contains a colon, which makes it a URI name under RFC 9880 Section 4.7.
EvidenceWithheldregistry.caller_withheldThe request withholds the recorded evidence the change needs.
UnrecordedSpellingcomparison.unit_unrecordedEither name has no entry in the recorded evidence, such as cel or kwh. Lookup compares exact decoded text, without trimming or case folding.
LegacyNamecomparison.unit_legacyEither name is a legacy entry. Legacy names can give one unit several names, such as beat/min and 1/min.

A unit that is not text leaves the change undetermined with comparison.not_classified. A unit outside a data description is compared like any other unclassified quality. When a needed Property characteristic is unavailable, the change is undetermined with comparison.directions_unavailable, as for other data qualities.

Only names that need the recorded evidence are looked up, so added and removed units and URI names stay undetermined with their own reasons under either policy. With RecordedRegistryPolicy::WithholdRecorded, every other unit change is undetermined with registry.caller_withheld, and no recorded table is consulted. Each consulted row is charged to the one operation allowance. A lookup that exhausts it leaves its unit change undetermined with operation.limit.

Content formats

A changed contentFormat in a data description follows the meaning qualities of ADR 0039: Client-side revision comparison and the bounded model meaning of ADR 0033: Content-format model meaning, described in the content-format contract. A declaration’s established meaning is its media type and subtype compared without ASCII case, its parameter meaning, and its content codings in order:

  • A media name has established parameter meaning only under the supported rules: application/json without parameters or with one charset, which has no effect, application/cbor without parameters, and text/plain in its US-ASCII default or with one utf-8 or us-ascii charset. Parameter names and these charset values compare without ASCII case, and quoted and token spellings are equivalent.
  • Each coding needs a positive entry in the recorded HTTP content codings, compared without ASCII case. The reserved identity, an unrecorded token, and the deprecated x-gzip and x-compress, which RFC 9110 Section 8.4.1 makes equivalent to other codings, have no established meaning.
  • A numeric identifier means its complete recorded CoAP tuple, without a separate coding lookup. Its content type is read through the same media rules where they apply, so 50 means application/json and 0 means text/plain; charset=utf-8. A tuple outside those rules, such as 21 for image/gif, keeps its registered parameters, and distinct tuples are distinct registrations.

Two declarations with one meaning, such as 50 and application/json, Application/JSON and application/json, or text/plain and text/plain; charset=us-ascii, are no change and produce no difference. Two different established meanings make Clients misread values in every Client direction the data carries, so application/json to text/plain, application/json to application/json@gzip, @gzip@deflate to @deflate@gzip, and 21 to 22 are breaking. Sample-value checking never establishes a value beside a contentFormat, so no witness settles these changes.

Any other contentFormat change is undetermined, with the first reason that applies:

ContentFormatReasonCodeApplies when
Addedcomparison.content_format_addedOnly the later revision declares a content format.
Removedcomparison.content_format_removedOnly the earlier revision declares a content format.
Unestablishedcomparison.content_format_unestablishedA declaration has no established meaning: its spelling fails the RFC 9193 grammar, its identifier is out of range or unrecorded, its media name or parameters lie outside the supported rules, such as image/gif, or a coding has no established meaning. One media name with parameters both inside and outside those rules, which no recorded tuple has, is unestablished too.
EvidenceWithheldregistry.caller_withheldThe request withholds the recorded CoAP Content-Formats or HTTP content codings that a declaration needs.

Both spellings and their media rules are read before any recorded evidence, so a declaration without meaning on its own spelling is unestablished under either policy, and the supported media rules need no recorded evidence. Then the earlier declaration’s identifier or codings are looked up before the later one’s. With RecordedRegistryPolicy::WithholdRecorded, a change that needs a numeric identifier or a coding is undetermined with registry.caller_withheld, and the withheld registry is named in the report. A contentFormat that is not text leaves the change undetermined with comparison.not_classified, and a contentFormat outside a data description is compared like any other unclassified quality. When a needed Property characteristic is unavailable, a change that is not a respelling is undetermined with comparison.directions_unavailable.

Classification, the media rules, every compared row and the comparison itself are charged to the one operation allowance, and a comparison that exhausts it leaves its change undetermined with operation.limit. A comparison that consults the media rules or a recorded tuple names content-format-model-meaning/1 in baseline.interpretations.

Unavailable content

A revision with findings, unresolved references or other unavailable content is still compared, following ADR 0006: Scoped reference failures. Only the differences that depend on content an effective view could not establish are undetermined, each with a reason from that content. Content the view could not establish is an Unavailable difference whose reason carries the view’s code, and a change whose Client directions or requiredness depend on such content is undetermined with comparison.directions_unavailable or required.unavailable. Independent differences keep their classifications, so a breaking removal elsewhere still decides the outcome.

  • An unresolved reference, an effective reference cycle or an unavailable dependency leaves the affected definition, properties entry or quality undetermined, with a code such as reference.unavailable or reference.effective_cycle. Content hidden by an unavailable owner never reads as removed or added.
  • A document that could not be acquired or decoded keeps its acquisition result in its source row under its revision, and its revision’s scope lists it in unavailable_required. Each top-level grouping of the corresponding document in the other revision is an Unavailable definition with the acquisition reason, such as json.syntax, document.envelope or input.acquisition. Its side in the failed revision is that document, with presence unavailable, so no grouping reads as removed or added. When neither document has a grouping to name, the document itself is one Unavailable difference.
  • A document that declares an Extension feature is deferred as a whole, following ADR 0003: Check findings and completeness. It is compared like an undecodable document, with the code structure.feature_context_unavailable, and a definition importing content from it is undetermined with the same code.
  • Undeclared extension vocabulary leaves the base meaning of its definition intact, following ADR 0037: Undeclared extension vocabulary. Base qualities beside it keep their classifications, and a change to the vocabulary itself is undetermined as not classified. baseline.interpretations names undeclared-extensions-ignorable/1 when a breaking or compatible classification concerns a quality of a definition or data description carrying extension vocabulary, or rests on a witness whose checks set aside such vocabulary deeper in the description. Recorded extension vocabulary such as oma:id counts too, because the comparison does not consult its record, following ADR 0038: Recorded extension vocabulary.

One operation allowance

One operation allowance covers both revisions’ acquisition, composition and comparison, following ADR 0009: Bounded processing and reporting and ADR 0013: Shared workflow and report guarantees. No revision or phase refills it. Both revisions’ parsed nodes, parsed allocation, decoding work, numeric work and retained bytes together must fit the shared Limits. When the later revision’s acquisition exceeds what the earlier one left, every later document is unavailable with operation.limit. Composition and comparison then share one work, allocation, node and reference allowance, which also covers collecting each composed document’s Required declaration relationships and closing its requiredness. Corresponding documents are composed and compared one pair at a time in the earlier revision’s source order, followed by removed and then added documents. Monotone rules and witness checks charge the same allowance, and a witness check that runs out of it leaves its difference undetermined with operation.limit. When the allowance runs out, the rest of that document and every later one are undetermined with operation.limit. A document whose composition ran out is unavailable on that side, and a document whose comparison ran out gains one document difference with both sides present. Differences already found keep their classifications, and a difference whose details the allowance could not retain still counts. In the description where the allowance ran out, a changed quality without a monotone rule, in data that a common Client direction reaches, stays undetermined with comparison.not_classified. Every other change there that was still waiting to be settled is undetermined with operation.limit. Each revision keeps its own source-attempt ceiling, because source IDs are numbered within each revision.

Version warnings

A Client that watches a model’s info version misses a breaking revision that keeps or lowers it. RFC 9880 Section 3.1 recommends a version that is lexicographically increasing over a model’s life, so Esdieff warns about such a revision, following ADR 0044: Versions of breaking revisions. A compared document pair gets one Version warning with the code comparison.version_not_increased when all of these hold:

  1. The document’s bytes changed between the revisions.
  2. The comparison of the pair found at least one breaking difference, acknowledged or not. Every difference found while comparing a pair is located in its documents.
  3. The earlier revision’s info version is text, and the later revision’s is absent or is text that does not compare higher by Unicode code point order.

Comparison is plain code point order, without date parsing, so 2020-07-06 after 20200706 and 2019-11-14 after 2019-11-14 both warn, and 2019-11-15 after 2019-11-14 does not. A pair whose document is unchanged gets no warning, even when a document it imports changed. A breaking difference belongs to the pair in whose effective groupings it is located, so a changed document that holds only shared definitions, such as sdfData that other documents import, gets no warning of its own. Neither does a pair whose earlier version is absent or not text, or whose later version is present but not text, nor a removed or added document. A breaking difference whose details the operation allowance could not retain still counts.

The warning never changes a classification, the outcome, the disposition or the exit code, and strict_warnings stays false. Reading the two versions and comparing the document bytes is linear in content both Catalogues already admitted, so it charges nothing to the operation allowance.

Report 1.5

Operation diff uses the esdieff.report envelope with version 1.5, which adds Version warnings to version 1.4. Version 1.4 added the acknowledgement fields and the disposition they decide to version 1.3. Every diff report is emitted at 1.5, with or without acknowledgements or warnings. The shared source, outcome and diagnostic meanings of the report contract remain intact. Both Catalogues number their sources from 1, so each source names its revision, and every ID inside an earlier or later member selects a source of that revision.

ObjectRequired fields and typesMeaning
Diff requestassessment:null; inventory:null; comparison:"esdieff.revision-comparison/2"; scope:{earlier:Scope, later:Scope}Each revision has catalogue scope. assessed lists its model documents and unavailable_required those whose content is unavailable.
Diff sourceSource fields; revision:`“earlier”“later”`
Diff policy and baselinepolicy.recorded_registry:`“use_recorded”“withhold_recorded”`; policy.acknowledgements:Count; baseline.registry_knowledge:RegistryKnowledge[]
Diff outcomecomplete:boolean; errors:Count; warnings:Count; notices:0; incomplete_checks:Count; strict_warnings:false; dispositionerrors counts unacknowledged breaking differences. warnings counts Version warnings, including omitted ones, and changes neither completeness nor the disposition. complete is false and incomplete_checks is 1 when any unacknowledged difference is undetermined. The disposition is failed when any unacknowledged difference is breaking, otherwise undetermined when any unacknowledged difference is undetermined, otherwise passed. Without acknowledgements it is failed for a breaking comparison, undetermined for an undetermined one and passed for a compatible one.
Diff diagnosticsretained:Count; omitted:Count; truncated:boolean; reasons:string[]; omissions:Omission[]; items:VersionCondition[]Each item is one retained Version warning. omitted counts the Version warnings whose details did not fit, with the reason byte_limit.
VersionConditioncode:"comparison.version_not_increased"; severity:"warning"; basis:{kind:"advice", id:"comparison.version_not_increased", citation:"RFC 9880 Section 3.1"}; message:string; primary:RevisionSourceLocation; related:[RevisionSourceLocation]; arguments:{earlier_version:string, later_version?:string, breaking_differences:Count}The primary location is the later document’s /info/version, or its /info or root when that member is absent, and the related location is the earlier /info/version. later_version is absent exactly when the later document has no version.
RevisionSourceLocationSourceLocation fields; revision:`“earlier”“later”`
Diff requested coverageinventory:null; count_unit:"comparison"; total:1; assessed:Count; not_applicable:0; unassessed:0; undetermined:CountThe one comparison is assessed when no unacknowledged difference is undetermined. Broader coverage stays partial, because a comparison assesses no RFC requirements.
DiffResultkind:"diff"; outcome:`“breaking”“compatible”
Summarybreaking:Count; undetermined:Count; compatible:Count; acknowledged:{breaking:Count, undetermined:Count}; documents:{compared:Count, removed:Count, added:Count}Every difference, including omitted ones, the acknowledged differences among them, and the compared and unmatched documents.
Documentscompared:{earlier:Id, later:Id}[]; removed:Id[]; added:Id[]Removed IDs are earlier sources and added IDs later sources.
Differencekind:`“removed”“added”
Acknowledgementkind; subject; classification; earlier:{document:string, pointer:string}null; later:{document:string, pointer:string}
Witnessdirection:`“client_supplied”“thing_supplied”; raw_json:string; admission:{earlier:“admitted”
Sidepresence:`“present”“absent”

Version warnings, then differences, are optional detail within the report allowance left after the mandatory envelope. Warnings come first, in the earlier revision’s source order, and one that does not fit ends the list. Differences are listed unacknowledged breaking first, then unacknowledged undetermined, acknowledged breaking, acknowledged undetermined and compatible, so omission drops acknowledged details before unacknowledged ones. When they do not all fit, the leading ones are kept, differences_omitted counts the rest, and a result.differences omission record appears in result.omissions and diagnostics.omissions. A location whose pointer cannot be presented has a null pointer with its own omission record, and diagnostics.omissions counts such locations once per field and reason. diagnostics.truncated is true whenever anything was omitted. Omission never removes a source, a count, the warning count, the unused positions, the outcome or the disposition, and a report allowance too small for both revisions’ mandatory envelopes and the unused-position reserve fails the request before any comparison work. baseline.interpretations names content-format-model-meaning/1 when content-format comparison consulted it, the value interpretations that the checks of a Breaking witness relied on, copied-reference-relocation/1 when a composed revision relied on it, and undeclared-extensions-ignorable/1 under the rule for extension vocabulary above. The value interpretations are those a model report names for Sample-value checking: ADR0018-selected-representation for a civil-time representation, byte-string-json/1 and unix-time-posix-coordinate/1 for the sdfType conventions, and uuid-bare-json/1 and uuid-opaque-value/1 for UUIDs. Candidates that establish no witness name none.

The human report states the outcome and contract identity and, when acknowledgements were supplied, a Disposition: line with the acknowledged breaking and undetermined counts. It counts compared, removed and added documents, lists removed and added documents, counts each classification, and names consulted or withheld registry evidence and the content-format meaning interpretation as check does. A Warnings: list follows with each retained Version warning’s code, later document, both versions as JSON strings and breaking count, and the number of omitted warning details. It then lists unacknowledged breaking differences, then unacknowledged undetermined, then acknowledged differences, whose rows name their classification, then compatible, each with its witness and admissions, both effective locations and, where it differs from the location, the nearest content origin. An Unused acknowledgements: list follows, naming each unused entry’s position in the file, kind, subject, classification and locations. It uses the shared color controls and palette, and it reports omitted difference details. It renders the differences the JSON report kept, within the same report allowance. When they are too long as text, the JSON report is given in its place, as for model reports.

Offline device Catalogue

The thermostat, RGB lamp, door lock, metered power strip, irrigation controller and coffee machine examples provide authored models and conventional JSON Sample values for local development. Run the regression checks from the repository root.

cargo test --test device_catalogue

The private Rust runner invokes the existing Check plan CLI. Every case has an independent constraint or contract rationale and typed expectations for its native state, disposition, completion and Sample admission or comparison classification. Decisive diagnostics also require the expected source, effective and sample pointer relations. Every expected source acquisition remains visible, including deliberately failed acquisitions. Missing or unexpected source identities fail the runner. Case identities are checked once per plan. Missing, unused or duplicate expectations, unexpected or duplicate observed cases, host failures and malformed or unavailable reports fail the test with the device, variant and case identified where available.

An intentionally rejected Sample retains its native failed disposition and CLI exit 1. It passes the regression test when those results were expected. Completion is checked separately, including the limited thermostat’s known rejection alongside unavailable calibration meaning. Small controlled records exercise identity accounting, and altered admission, completion and diagnostic expectations demonstrate named failures.

These are supplied descriptions and values. They establish neither physical device behaviour nor network protocol interoperability. Each value is checked against its selected data description. No stateful device engine or interaction-sequence assertion is involved. The native meanings follow ADR 0003, Check findings and completeness, ADR 0004, Supplied catalogues and checking scope and ADR 0016, Selected samples with explicit admission and coverage.

Direct Check plans

cargo run -- check --plan examples/thermostat-check/minimal-plan.json --format json
cargo run -- check --plan examples/thermostat-check/rich-plan.json
cargo run -- check --plan examples/thermostat-check/limited-plan.json --format json
cargo run -- check --plan examples/rgb-lamp-check/rich-plan.json
cargo run -- check --plan examples/door-lock-check/rich-plan.json --format json
cargo run -- check --plan examples/power-strip-check/rich-plan.json --format json
cargo run -- check --plan examples/irrigation-check/rich-plan.json --format json
cargo run -- check --plan examples/coffee-machine-check/rich-plan.json

The minimal and rich variants of each family complete Initial Catalogue and Full selected-model checks. Their plans exit 1 because they contain intentional sample rejections. The rich lock plan also compares the minimal lock with the rich one. Both breaking changes are acknowledged, so that case passes with a breaking classification. The limited thermostat combines an invalid bound and missing dependency. Its model checks fail and remain incomplete. Its two undetermined samples and independently rejected sample also remain incomplete.

The limited lamp has only unavailable calibration meaning. Its model and sample cases are undetermined and incomplete, and its plan exits 3. The limited lock combines an invalid numeric bound with an unsupplied credential definition. Its plan exits 1, with failed incomplete model checks, an undetermined credential sample and an admitted complete state sample. Model findings remain distinct from selected-sample admission.

The power strip supplies three supported variants and one limited variant. Its rich model imports repeated outlets and shared meter definitions from an explicitly supplied second document. Its separate copied-requiredness plan imports an Object that requires its own declaration through an absolute pointer, and the copied requirement relocates to the importing outlet under ADR 0036, Copied reference relocation, so that plan exits 0. Its missing plan records the failed acquisition of a needed local dependency and exits 3 while preserving complete independent Sample admissions.

The limited irrigation and coffee models need unsupplied optional calibration meaning. Their model checks are undetermined and incomplete. Samples with absent optional calibration are admitted completely. Present calibration keeps applicable child work incomplete, while a missing required zone array or excessive servings still gives an independent rejection. Both plans exit 1.

All ordinary runs are offline and use existing finite allowances. The plans retrieve nothing and change no input bytes. Copy the complete directory for any family elsewhere, then pass the copied plan path to esdieff check --plan. All sources resolve relative to that plan. The Rust suite repeats every device plan from a temporary copy and checks that the original and copied bytes remain unchanged.

Device and constraint coverage

There are 19 model variants and 116 distinct Sample cases across 20 plans. The thermostat provides three variants and 20 cases, the lamp three variants and 16 cases, the lock three variants and 17 cases, and the power strip four variants and 22 cases. Irrigation adds three variants and 21 cases, and coffee adds three variants and 20 cases. The preserved thermostat entry plan shares the minimal model. The matrix lists actual cases rather than potential capabilities. Sample areas use the existing esdieff.sample/1 inventory from the Sample contract.

Family and variantNamed casesConstraint or contractRequested work
Thermostat, minimal entryComfortable target, Too hot targetFractional number within bounds, above maximumProperty, sample-type-null/1 and sample-numeric/1
Thermostat, minimalTarget lower boundary, Target upper boundary, Target below minimumInclusive exact bounds 5 and 30Property, sample-numeric/1
Thermostat, minimalTarget wrong type, Target unavailableString instead of number, explicit nonnullable targetProperty, sample-type-null/1
Thermostat, richFractional current reading, Current reading unavailableUnconstrained fractional step, nullable sensor readingProperty, sample-type-null/1 and sample-numeric/1
Thermostat, richTarget off half-degree stepExact multiple of 0.5Property, sample-numeric/1
Thermostat, richConfigure heatingRequired target and enumerated mode, absent optional label, exact target stepAction input, sample-map/1, sample-alternatives/1 and sample-numeric/1
Thermostat, richConfigure missing mode, Configure null modeAbsent required entry differs from present disallowed nullAction input, sample-map/1 and sample-type-null/1
Thermostat, richConfigure unknown mode, Configure wrong optional labelRejected enum value, present optional entry with wrong typeAction input, sample-alternatives/1 and sample-type-null/1
Thermostat, richOverheating alarm, Unknown alarm reasonStructured Event output and enumerated reasonEvent output, sample-map/1 and sample-alternatives/1
Thermostat, limitedCurrent reading needs dependency, Configure needs calibrationNeeded referenced meaning is not suppliedProperty and Action input, sample-context/1
Thermostat, limitedConfigure too hot despite missing calibrationIndependent bound rejection with unfinished sibling workAction input, sample-numeric/1, sample-map/1 and sample-context/1
Thermostat, minimal and richCatalogue and selected-model cases named by each planComplete supported model descriptionsInitial Catalogue and Full selected-model
Thermostat, limitedLimited Catalogue, Limited modelTextual numeric maximum is invalid, calibration dependency unavailableInitial Catalogue and Full selected-model, failed and incomplete
RGB lamp, minimalLamp on, Lamp off, Text is not on stateBoolean values and wrong-type rejectionProperty, sample-type-null/1 and sample-text-boolean/1
RGB lamp, minimalBrightness lower boundary, Brightness upper boundary, Brightness above maximumInclusive integer bounds 0 and 100Property, sample-numeric/1
RGB lamp, richRGB channel boundaries, RGB green above maximumRequired integer channels, inclusive bounds 0 and 255, invalid compound valueProperty, sample-map/1 and sample-numeric/1
RGB lamp, richSteady mode, Unknown modeAdmitted and rejected enum valuesProperty, sample-alternatives/1
RGB lamp, richDim red scene, Bright blue scene, Mixed scene has no Choice witnessOne whole Choice witness, exact branch boundaries and rejection of mixed branch constraintsAction input, sample-map/1, sample-alternatives/1, sample-const/1 and sample-numeric/1
RGB lamp, richScene applied output, Scene refused outputRequired Boolean result and const trueAction output, sample-map/1 and sample-const/1
RGB lamp, limitedBrightness needs calibrationUnsupplied selected brightness descriptionProperty, sample-context/1
Door lock, minimalLocked state, Unknown lock stateTwo-state text enumerationProperty, sample-alternatives/1
Door lock, minimalPIN lower length boundary, PIN upper length boundary, PIN too short, PIN has a letterInclusive scalar lengths 4 and 8, anchored digit patternProperty, sample-text-boolean/1
Door lock, richAuthorize Unicode credential, Authorize short Unicode credential, Authorize spaced credentialUnicode scalar length rather than UTF-8 bytes, anchored no-space patternAction input, sample-text-boolean/1 and sample-map/1
Door lock, richAuthorize missing operation, Authorize null credentialAbsent required entry differs from present disallowed nullAction input, sample-map/1 and sample-type-null/1
Door lock, richAuthorization result, Authorization result wrong typeStructured result with required Boolean and enumerated stateAction output, sample-map/1, sample-type-null/1 and sample-alternatives/1
Door lock, richTimestamped locked event, Impossible event dateEstablished date-time and definite calendar rejectionEvent output, sample-abstract-values/1
Door lock, limitedState survives unrelated model faults, Credential needs dependencyComplete selected state despite unrelated model errors, incomplete selected credentialProperty, sample-alternatives/1 and sample-context/1
RGB lamp and door lock, minimal and richCatalogue and selected-model cases named by each planComplete supported descriptionsInitial Catalogue and Full selected-model
RGB lamp, limitedLimited Catalogue, Limited modelUnsupplied calibration meaningInitial Catalogue and Full selected-model, undetermined and incomplete
Door lock, limitedLimited Catalogue, Limited modelInvalid textual maximum and unsupplied credential meaningInitial Catalogue and Full selected-model, failed and incomplete
Power strip, minimalOutlet on, Outlet off, Outlet text stateBoolean outlet state and wrong-type rejectionProperty, sample-type-null/1 and sample-text-boolean/1
Power strip, minimalOutlet power lower boundary, Outlet power upper boundary, Outlet power above maximumInclusive watt bounds 0 and 2400Property, sample-numeric/1
Power strip, richOutlet fractional powerImported repeated outlet with exact 12.345 watt readingProperty, sample-context/1 and sample-numeric/1
Power strip, richShared power above product bound, Total power rejects shared readingThe same 2400 reading is admitted by shared Power and rejected by its consuming overridesdfData and Property, sample-context/1 and sample-numeric/1
Power strip, richTotal power within override, Total power override boundary, Total power just above overrideExplicit maximum 1800 with source/effective override relationProperty, sample-numeric/1
Power strip, richOrdinary fractional energy, Large fractional energy, Large exact energy boundary, Energy above exact boundaryExact values beyond ordinary machine-float precision, inclusive model maximum 9007199254740994Property, sample-numeric/1
Power strip, richEnergy off eighth step, Shared energy lower boundaryRejected half-step 0.0625 and admitted zero under shared step 0.125Property and sdfData, sample-numeric/1
Power strip, minimal and richCatalogue and selected-model cases named by each planComplete supported models, repeated outlet components, supplied reusable definitions, W and Wh declarationsInitial Catalogue and Full selected-model, including full.special-type-unit/1 registry guidance separately from numeric admission
Power strip, missing dependencyMissing dependency Catalogue, Missing dependency model, Total power needs dependencyFailed acquisition of an explicitly named needed local file and unavailable imported meaningInitial Catalogue, Full selected-model and Property, incomplete model work and sample-context/1
Power strip, missing dependencyOutlet state survives missing dependencyIndependent complete Boolean admission despite the absent donorProperty, sample-type-null/1 and sample-text-boolean/1
Power strip, copied requirednessCopied requiredness Catalogue, Copied requiredness modelSurviving copied required pointer relocated to the importing outlet’s own declarationInitial Catalogue and Full selected-model, complete and passed
Power strip, copied requirednessCopied outlet state, Independent total powerInherited Boolean and locally authored numeric PropertiesProperty, sample-type-null/1, sample-text-boolean/1 and sample-numeric/1
Irrigation, minimalOne zone lower count boundary, Four zones upper count boundary, No zones, Five zonesInclusive identifier-array counts 1 and 4 and definite count failuresProperty, sample-array/1
Irrigation, minimalDuplicate zone identifier, Invalid zone identifierWhole-element text uniqueness with both sample locations, anchored zone-1 through zone-4 patternProperty, sample-array/1 and sample-text-boolean/1
Irrigation, richConfigure without optional feedback, Configure moisture lower boundary, Configure moisture upper boundary, Configure excessive nested moistureRecursive conjunction of arrays, zone records and optional nested moisture bounds 0 and 100Action input, sample-array/1, sample-map/1 and sample-numeric/1
Irrigation, richConfigure missing required zones, Configure null zonesMissing required array differs from supplied disallowed nullAction input, sample-map/1 and sample-type-null/1
Irrigation, richConfigure missing duration despite default, Configure invalid optional feedbackNo insertion of a documentary default, absent optional child differs from present wrong-type childAction input, sample-map/1 and sample-type-null/1
Irrigation, richConfigure empty zone array, Configure excessive zone arrayNested zone-record counts without projecting uniqueness onto id fieldsAction input, sample-array/1
Irrigation, richConfiguration applied output, Configuration output above maximumStructured Boolean result and bounded configured-zone countAction output, sample-map/1, sample-text-boolean/1 and sample-numeric/1
Irrigation, limitedAbsent optional calibration, Present calibration needs definition, Missing zones despite incomplete calibrationComplete admission with absent optional child, undetermined needed child and independent required-entry rejection with incomplete workAction input, sample-map/1 and sample-context/1
Coffee machine, minimalResources lower boundary, Resources upper boundary, Water above maximumRequired water and beans plus optional milk percentages with inclusive 0 and 100 boundsProperty, sample-map/1 and sample-numeric/1
Coffee machine, minimalMissing required beans, Present null beansMissing required entry differs from supplied disallowed nullProperty, sample-map/1 and sample-type-null/1
Coffee machine, minimalEspresso preparation, Unknown preparationAdmitted and rejected preparation enum valuesProperty, sample-alternatives/1
Coffee machine, richBrew espresso lower boundaries, Brew latte upper boundaries, Mixed recipe has no Choice witnessOne whole nested recipe alternative with const drink and matching size bounds, no witness assembled across alternativesAction input, sample-map/1, sample-alternatives/1, sample-const/1 and sample-numeric/1
Coffee machine, richRecipe witness cannot admit excessive servings, Missing servings despite defaultComplete child witness preserves outer conjunction, documentary default supplies no required valueAction input, sample-map/1 and sample-numeric/1
Coffee machine, richStructured brew result, Brew result wrong typeRequired Boolean result and nonempty text messageAction output, sample-map/1, sample-type-null/1 and sample-text-boolean/1
Coffee machine, richMaintenance clean event, Unknown maintenance reason, Maintenance nested resource above maximumEnumerated maintenance reason conjoined with nested bounded resource readingsEvent output, sample-map/1, sample-alternatives/1 and sample-numeric/1
Coffee machine, limitedBrew without optional calibration, Brew calibration needs definition, Excess servings despite incomplete calibrationComplete admission with absent optional child, undetermined needed child and independent bound rejection with incomplete workAction input, sample-map/1, sample-numeric/1 and sample-context/1
Irrigation and coffee machine, minimal and richCatalogue and selected-model cases named by each planComplete supported descriptionsInitial Catalogue and Full selected-model
Irrigation and coffee machine, limitedLimited Catalogue, Limited modelOptional model description needs an unsupplied calibration definitionInitial Catalogue and Full selected-model, undetermined and incomplete

These families exercise all five selectors through Property, sdfData, Action input, Action output and Event output. Irrigation exercises Sample-array counts, text-element uniqueness and authored zone identifier patterns. These patterns are ordinary text constraints, rather than URI or UUID format checks. Repeated outlet declarations are model components rather than Sample-array checks. Nullability, presence, enum, Choice and temporal cases here do not claim exhaustive combinations.

Sources and adaptations

All thermostat models and samples are authored for this repository and use its MIT or Apache-2.0 licence. No external device document, vendor data, simulator implementation or historical SDF dialect is imported.

The minimal Catalogue reuses the existing thermostat.sdf.json without changing it. The entry plan.json, comfortable.json and too-hot.json also remain unchanged. The rich variant adds a nullable current reading, half-degree target steps, a configuration Action and an alarm Event. The limited variant is newly authored to demonstrate a faulty bound and unsupplied calibration definitions. Its namespace uses the reserved example.test domain as an identifier and is never retrieved. The Count examples remain a separate entry workflow.

The lamp and lock adapt interface ideas from the same pinned One Data Model playground revision used by the external-model pilot. Their lamp source notes and lock source notes identify the original documents, metadata, copyright notices and unchanged BSD licence text alongside the newly authored constraints, models, plans and samples. Historical source documents and their absolute required declarations are not imported into the standalone examples.

The power-strip source notes record the RFC composition ideas and the pilot’s pinned Binary Switch source with its original notice and licence. The meter definitions, exact readings, product override and distinguishing limitation variants are newly authored. No original external corpus needs to be downloaded or rerun. Its failed-dependency source expectations are checked explicitly, including a regression check that rejects hidden failed or successful acquisition attempts or a fabricated acquisition success.

The irrigation source notes identify newly authored examples and the recorded RFC array, map and Choice rules. The coffee-machine source notes pin Eclipse Thingweb’s interface ideas and original licence notice. Coffee resource readings and brew results are re-expressed as SDF with authored presence constraints, recipes and maintenance data. No simulator code, protocol forms, scheduling behaviour or upstream defaults are imported.

Agreed deviations and acceptance restrictions

This document records explicitly agreed departures from RFC 9880 and narrower Esdieff acceptance policies. A policy rejection is distinguished from a definite violation of an RFC requirement.

Deviations from RFC requirements

No departures from RFC requirements have been agreed.

The selected T/t civil representation convention and conservative date-free exceptional-label interpretation are recorded in ADR 0018: Civil date and time sample conventions. A selected-representation error uses Interpretation basis; unavailable date-free or leap knowledge uses Operational incompleteness. Neither creates an additional acceptance restriction or an RFC-invalid diagnosis for an unestablished abstract value.

Acceptance restrictions

A001: Reject sdfRequiredInputData as an SDF quality. Esdieff reports an explicit error with guidance toward the current Action-input structure. This historical mechanism was removed, although the final RFC still registers its name and permits extension content. The restriction applies at assessed SDF vocabulary positions; it does not reject Given Names or arbitrary data keys with the same spelling. The reason and checking scope are recorded in ADR 0008: Reject the historical Action input quality.

A002: Refuse duplicate decoded JSON names. Model documents and conventional JSON samples cannot construct a usable map when an object repeats a decoded member name, including in nested or opaque content. Names compare exactly after escape decoding, without case folding or Unicode normalization; repeated identical values also fail. Esdieff retains the supplied source and identifies the repeated member, without choosing first or last precedence. This is an input acceptance policy, not a claim that duplicate names violate JSON syntax. The reason, finite limits, and independent-document behavior are recorded in ADR 0012: Exact numbers and JSON input policies.

Esdieff domain language

The vocabulary of SDF connected-device models, grounded in RFC 9880. Terms describe the modeling domain rather than software structure.

Documents and models

Terminology source: RFC 9880, Section 1.2.3.

SDF document: A JSON text representing a single map containing SDF definitions and optional document information. Avoid: Model when referring to one document.

SDF model: Definitions and declarations describing the network interactions of kinds of Things. A model can span multiple SDF documents through references. Avoid: File, document when referring to the model as a whole.

SDF specification: An SDF description when the distinction between its model and its documents is irrelevant.

Definition: A named semantic term with associated qualities. A definition does not necessarily introduce a component into its enclosing definition.

Declaration: A definition that introduces a component into its enclosing definition. It remains available for reuse as a definition.

Quality: A metadata entry describing a definition or declaration. Avoid: Property when referring to metadata.

Block: A set of SDF map entries described together because they serve one function, such as document information or namespace mappings.

Group: An entry whose Class Name Keyword selects the class of its named definitions.

Definition group: A collection of named definitions identified by a class name keyword.

Class: The category of model information identified by a Class Name Keyword.

Class name keyword: One of sdfThing, sdfObject, sdfProperty, sdfAction, sdfEvent, and sdfData.

Information block: Document metadata under info, describing the document and its included definitions.

Namespaces block: The namespace mappings and optional default namespace of an SDF document.

Definitions block: The definition groups contained in an SDF document.

Document and definition metadata

Terminology sources: RFC 9880, Section 3.1 and Section 4.6.

title: A short summary of a document and its definitions for display or discovery.

version: A string identifying the evolution of a document’s definitions, with no mandatory version-string format. Avoid: SDF format version.

modified: The latest revision time of the definitions, expressed as a full date or a UTC date-time.

copyright: Copyright information supplied as text or a link to text.

license: License terms supplied as text or a link, preferably an unambiguous license URI or SPDX identifier.

description: A long-form textual description of a definition or document.

label: A short textual description of a definition. An application may display its final name token when no label is supplied, without adding a model quality.

$comment: Source commentary whose presence does not change model meaning.

Things and interactions

Terminology sources: RFC 9880, Section 1.2.2, Section 1.2.3, and Section 2.2.5.

Thing: A physical item with network interaction opportunities. Avoid: sdfThing when referring to the physical item.

Affordance: A network interaction opportunity described by the model: a Property, Action, or Event.

Property: An affordance for reading, writing, or observing state. Avoid: JSON entry, quality.

Action: An affordance for invoking a named operation.

Event: An affordance for obtaining information about a happening.

Grouping: An sdfObject or sdfThing describing a collection of affordances, directly or through nested groupings.

sdfObject: A reusable grouping that can declare affordances but cannot contain other groupings. Avoid: JSON object.

sdfThing: A grouping that can also contain other groupings. Avoid: Thing as shorthand for this model element.

Grouping array: An sdfObject or sdfThing describing repeated groupings because minItems, maxItems, or both are present. Those qualities bound the number of repetitions inclusively. Avoid: Array data, which describes interaction values.

sdfData definition: A reusable description of data constraints and semantics that does not itself declare an affordance.

Names

Terminology source: RFC 9880, Section 2.3.1.

Given Name: A case-sensitive name chosen by the model author for a definition or another named entity. Embedded colons are reserved for a future extension and prohibited in base SDF.

Quality Name: A vocabulary name whose associated entry has semantics specified by SDF or an extension.

Terminology sources for namespace identity and references: RFC 9880, Section 3.2 and Section 4.

SDF namespace: A space of global names identified by a namespace URI. Multiple documents can contribute names to the same namespace. Avoid: Document location, download URL.

Namespace prefix: A document-local short name mapped to a namespace URI. Avoid: Quality Name Prefix, which has a separate extension-vocabulary role.

Default namespace: The namespace selected by defaultNamespace to receive a document’s contributed global names; also called its target namespace. A document without this setting contributes no global names.

Global name: A definition’s namespace URI followed by its JSON Pointer fragment identifier. Avoid: File path.

Same-document reference: A name reference consisting of # and a JSON Pointer fragment that selects an element in the current document.

CURIE reference: A name reference abbreviated using a namespace prefix from the document’s namespace mappings.

Referenceable name: An unprefixed affordance or grouping name used by sdfRequired to select directly contained declarations by name. It can select declarations of different classes carrying the same Given Name.

Quality Name Prefix: A registered prefix used to construct qualified Quality Names for extension vocabulary.

Qualified Quality Name: A Quality Name Prefix followed by a colon and an unqualified Quality Name. Avoid: CURIE reference, which selects a model definition using namespace mappings.

Composition

Terminology sources: RFC 9880, Section 4.4, Section 4.4.1, and Section 6.

Composition: The combination and refinement of definitions through references and containment to describe reusable capabilities and products. Avoid: File concatenation, arbitrary JSON merging.

sdfRef: A quality that reuses a referenced definition, with additions and overrides from the referencing definition applied through JSON Merge Patch.

Composition patch: The referencing definition’s map with its sdfRef entry removed, applied to a copy of the referenced definition through JSON Merge Patch.

Copied definition: The referenced definition as copied by sdfRef, before the composition patch applies.

Copied reference: A name reference that reaches an effective definition from a copied definition rather than from the composition patch. Avoid: Inherited reference.

Internal copied reference: A copied reference whose target is the copied definition or lies within it.

Reference relocation: The replacement of an internal copied reference’s target by the corresponding position in the importing definition. Avoid: Rebinding, rebasing.

Effective definition: A definition after the applicable reference composition and overrides have been processed. Avoid: Source patch, valid definition.

Content origin: The nearest source contribution establishing an effective quality, or removing it through a composition patch.

Importing consumer: The source sdfRef that establishes the composition boundary containing an effective quality. It is distinct from the quality’s content origin.

Default origin: An established implicit semantic value when a quality is absent, without an authored source contribution or inserted JSON member.

Restrictive refinement: The convention that an override narrows the possibilities described by a reused definition. RFC 9880 does not provide a general procedure for checking that convention.

Resolved model: An SDF model in which every sdfRef has been processed according to its composition semantics. Avoid: Valid model, since resolution alone does not establish validity.

sdfRequired: A quality identifying declarations whose corresponding data must be represented in the modeled grouping. Avoid: required, which constrains entries within map data.

Required declaration relationship: An sdfRequired occurrence’s relationship to the affordance or grouping declarations it selects, including all directly contained classes sharing a Given Name. An array entry true identifies its carrying affordance or grouping.

Declaration contribution: The authored definition contribution from which a surviving declaration originates, independently of later content refinements or reused data descriptions. Reinsertion after deletion introduces a new contribution.

Relationship completion: Establishment of the selected declaration identities and their relevant context. It does not establish the declarations’ effective capabilities or the validity of every relationship.

Data descriptions

Terminology sources: RFC 9880, Section 4.7, Section 5, and Appendix C.

Data description: Qualities describing the meaning and permitted values of interaction data at the information model level. Avoid: Wire format, protocol payload schema.

Data quality: A quality that describes data semantics or constrains data values.

Full data description: A Data description using the full data-quality vocabulary, including Property and sdfData definitions, Action input/output, Event output, properties entries and Choice alternatives. Nested descriptions retain their own vocabulary role, as described in RFC 9880, Appendix A and ADR 0020: Owned effective views and nearest origins.

Direct items description: The restricted description directly under items. Its established base vocabulary includes scalar bounds and lengths, format, enum and sdfChoice; explicit map data also permits required and properties. Those properties entries and Choice alternatives are Full data descriptions. Wider admitted content remains inspectable without gaining full data-quality meaning from its spelling. Avoid: Full data description, blanket prohibition of nested array data.

Data type: The kind of data selected by type: number, integer, string, boolean, array, or map (object).

Map data: Data selected by type: "object", with optional value constraints for named entries in properties and mandatory presence in required. An undescribed entry has no implicit value constraint, following ADR 0016: Selected samples with explicit admission and coverage. Avoid: sdfObject, Property affordances.

required: A data quality naming mandatory entries in map data. Avoid: sdfRequired, which concerns declarations in groupings.

properties: A map from data-entry names to descriptions of their values. A described entry is optional unless named by required; this quality does not close the map to other entries. Avoid: Property affordances.

sdfType: A quality naming additional information-level data semantics, such as a byte sequence or a point in civil time.

Civil date-time: An absolute point in civil time identified by format: "date-time", with conventional RFC 3339 text and its supplied offset annotation.

Civil date: A Gregorian calendar date identified by format: "date", without a time of day or timezone.

Civil time: A date-free clock coordinate with an offset annotation, identified by format: "time". It does not identify a unique dated instant.

Civil denotation: The established calendar or clock meaning of a selected conventional civil representation under ADR 0018: Civil date and time sample conventions. Recognized format names or identical invalid text do not establish it. An eligible date-free second 60 can have unavailable denotation without lacking a required field.

sdfChoice: A choice between named data alternatives, with shared data qualities except where an alternative overrides them.

Choice alternative: A named set of data qualities within sdfChoice. Its Given Name identifies the alternative without automatically constraining a data value to that name.

Effective alternative: A Full data description established after reference composition, shared-quality inheritance and whole-quality overrides. A named Choice alternative retains its Given Name; an Enum alternative retains its occurrence index and original text value as const. Its semantic coordinates can differ from authored source locations. Inherited qualities retain their donor’s established meaning and uncertainty, following ADR 0024: Effective alternatives and nullable characteristics.

enum: A nonempty list of string values abbreviating sdfChoice alternatives with corresponding const values. A definition uses either enum or sdfChoice.

const: A data quality restricting data to its stated value.

default: Documentary data that may be used when interaction data is absent. Base SDF defines no process that inserts this value.

Declared-value consistency: Advice about whether a stated const or documentary default is excluded by its final effective data description. It reuses selected-value checking without inserting defaults, changing source roles or proving general satisfiability, following ADR 0031: Bounded declared-value consistency.

Consistency candidate: One surviving effective const or default checked in its owning description. Final alternative constants and distinct importing consumers remain distinct candidates. An owner default requests one complete existential alternative witness; introduced or overridden branch defaults are separate candidates. One definite exclusion produces one advisory warning regardless of rejected leaf count.

contentFormat: A data quality naming the content format of a data value, using a string-form CoAP Content-Format identifier or a media type with parameters and content codings, as defined by RFC 9193, Section 3. Avoid: Protocol payload binding.

Content-format declaration: The complete authored contentFormat text, with decimal identifier spelling or a media name, optional parameters and ordered content-coding tokens. Its spelling follows RFC 9193 Section 6; decimal identifier range follows Section 3 separately. Spelling and registration do not establish parameter meaning, payload validity or a protocol binding.

Content coding: A transformation named by a Content-format declaration. Coding tokens apply in their stated order; repeated tokens denote repeated transformations. An absent coding sequence denotes no transformation, following RFC 9193 Section 3.

Dated positive registration: An entry in a specifically recorded relevant registry edition, with its canonical identifier and dated temporary, obsolete or deprecated flags. A missing positive leaves current registration unknown; it establishes no negative registration fact.

Unit name: The identifier of a measurement unit carried by unit, normally using a registered SenML unit name, with URI-based identification also available under the RFC’s conditions.

Nullable: A data characteristic admitting a null value beyond the effective type, with default true, while other applicable constraints still apply, according to ADR 0005: Nullability and presence. Avoid: Optional presence.

Byte string: An information-level sequence of bytes identified by sdfType: "byte-string".

Unix time: A point in civil time identified by sdfType: "unix-time", with a conventional numeric POSIX-time representation.

Abstract representation: A conventional JSON input channel for an information-level value. Usable representation input and established denotation are separate facts, following ADR 0007: Generated SDF and sample JSON.

Established denotation: The abstract value established under a known, applicable interpretation, beyond recognizing its name or retaining its representation.

Model meaning: The interpretation of an effective data description, independently of any supplied data value. Establishing it does not prove that an arbitrary representation denotes a value, that values can be compared, that a particular value is admitted, or that the description admits any value at all.

Sample meaning: The final supporting references and limitations for selected abstract values, const and admission. An alternative’s whole witness determines final proof, while independent unfinished areas remain visible.

Consulted sample interpretation: A conventional byte-string or POSIX interpretation actually attempted during the request. Consultation survives discarded alternatives and failed work without asserting final proof or completed denotation.

sdfInputData: The data description of an Action’s input.

sdfOutputData: The data description of an Action’s or Event’s output.

Readable: A Property characteristic indicating that its state can be read, with default true.

Writable: A Property characteristic indicating that its state can be written, with default true.

Observable: A Property characteristic indicating availability of asynchronous state notifications, with default true.

Property characteristic: A Boolean quality describing whether Property state is readable, writable, or observable.

Declared characteristic: A Property characteristic or Nullable characteristic supplied by an authored value, including one inherited from a reused definition. Its contributor origin is a separate question.

Specified default characteristic: A Property characteristic or Nullable characteristic supplied by the standard when its quality is absent in an established role. It describes the interface without adding a quality to the document or inserting interaction data.

Value constraints

Terminology source: RFC 9880, Appendix C. Grouping-array uses of minItems and maxItems are described separately above.

minimum / maximum: Inclusive lower and upper bounds for numeric values.

exclusiveMinimum / exclusiveMaximum: Numeric lower and upper bounds that exclude the bound itself. Avoid: Boolean exclusivity flags.

multipleOf: A positive numeric step requiring the value to be an integer multiple of that step.

Numeric lattice gap: A finite ordinary numeric interval containing no integer, or no integer multiple of an applicable positive step, after endpoint exclusion and established null exclusion. An integer description also intersects the step lattice with integers, following ADR 0030: Bounded numeric advice.

Numeric const-bound contradiction: A sole ordinary numeric const excluded by an applicable numeric bound. Established absence of type does not supply an authored type or type origin. Unavailable magnitude is distinct from an independently established nonnull const root kind.

minLength / maxLength: Inclusive bounds on text-string length measured in Unicode scalar values. Avoid: UTF-8 byte count, displayed-character count.

pattern: An ECMA-262 regular expression in Unicode mode constraining text strings. Matching is unanchored unless the expression supplies anchors. Supported syntax and matching capabilities are distinct; unavailable capability leaves affected conclusions incomplete, following ADR 0014: Bounded partial ECMAScript pattern capability. The explicit expanded pattern-syntax assessment checks surviving effective Full string patterns; Direct donor meaning remains unavailable until an establishing Full override. Full baseline assessment binds this rule to its model requirement and pattern/format area, following ADR 0028: Bounded effective model pattern syntax. Avoid: The I-Regexp conventions used for name patterns in the RFC text.

format: Additional abstract text-data meaning, such as a civil date or time, URI, URI reference, or UUID. Its meaning is separate from the conventional input representation.

URI value: A full resource identifier with a scheme, which may include a fragment. Identification does not imply resource retrieval, following RFC 3986 Sections 1.2.2 and 3. Avoid: Relative reference, fragment-free absolute-URI.

URI-reference value: A full URI or relative resource-reference expression, including empty, query-only and fragment-only forms. A relative expression’s target can depend on a base, following RFC 3986 Sections 4.1 and 4.2. Avoid: Model name reference, automatically retrieved resource.

UUID value: An opaque 128-bit identifier as defined by RFC 9562. Avoid: A required version-4 identifier, text spelling, proof of globally unique generation.

Array data: An ordered collection of interaction-data values selected by type: "array". Avoid: Grouping array.

items: The description that every element of array data must satisfy, subject to the item-description vocabulary defined by base SDF.

minItems / maxItems: Inclusive bounds on the element count of array data, or on grouping repetition when used as grouping qualities.

uniqueItems: A Boolean data quality requiring all array elements to differ when set to true.

Value equality: Comparison of data values in an applicable effective context, returning equal, different or undetermined. Equality is separate from sample admission, following ADR 0015: Bounded value equality in a resolved data context.

Model work

These terms distinguish the work performed on SDF specifications from the network interactions they describe.

Pinned document acquisition: Explicit retrieval of one selected source document at a complete revision identity, retaining its unchanged bytes only when their digest matches a separately supplied expectation. Avoid: Model checking, namespace resolution or dependency discovery.

Acquired snapshot: The unchanged local bytes retained by Pinned document acquisition. Its content identity does not establish JSON decoding, SDF validity or device behavior.

Acquisition receipt: Evidence of a Pinned document acquisition request and its actual transfer, content verification and output outcome. It is separate from a Model checking report.

Model checking: Assessment of an SDF specification against the applicable SDF requirements. Avoid: Sample-value checking when assessing the specification itself.

Model authoring: Creation or revision of SDF documents that express definitions, declarations, and their relationships.

Generated SDF document: A new SDF document expressing an authoring request’s selected definitions, Given Names, namespace choices and Composition patches. Its existence does not establish completion of the requested assembly or Model checking.

Authoring fidelity: Established preservation of the requested model meanings, Given Names, data values and permitted opaque content during Model authoring, following ADR 0017: Reference-preserving sdfThing authoring. Retained opaque structure alone does not establish its meaning after a context change.

Authored-quality edit: An explicit replacement or removal of a present quality on a selected authored named definition, preserving the other authored content and its context. Composition patches have a separate null meaning and are outside this operation, following ADR 0034: Authored-quality editing with source substitution.

Editing request: The selected original document and explicit authored owner, Quality Name and replacement or removal intent for each requested Authored-quality edit.

Edited SDF document: A generated revision expressing an Editing request. Candidate availability does not establish Editing fidelity or Model checking.

Editing fidelity: Established application of every requested Authored-quality edit and preservation of every other authored JSON value, Given Name, definition position, namespace mapping and reference spelling under esdieff.authored-quality-edit/1. It establishes source preservation, not before-and-after model equivalence or unknown extension meaning.

Source substitution: Replacement of exactly one original contributor by its Edited SDF document in the active result Catalogue. The original remains immutable Source evidence and cannot resolve names as a fallback.

Active result Catalogue: The Edited SDF document and all other active supplied contributors after Source substitution. Explicitly supplied aliases remain distinct contributors.

Model inspection: Examination of a model’s definitions, declarations, affordances, and data descriptions.

Catalogue: The SDF documents supplied together for model work, whether selected individually or from an explicitly supplied local collection. Avoid: Namespace, since a catalogue can cover multiple namespaces and several documents can contribute to one namespace.

Root document: A document selected as the starting point of an SDF model under examination.

Catalogue check: Model checking whose scope includes every document in the supplied catalogue, including unused definitions.

Selected-model check: Model checking whose scope starts from selected root documents and includes the dependencies needed for the checks.

Check plan: Saved model and sample source identities and ordered named checking and Revision comparison requests for a repeatable catalogue workflow. Avoid: SDF document or Assessment profile.

Check case: One named Model checking, Sample-value checking or Revision comparison request within a Check plan, retaining its own scope, selector or revisions and policy, and either its actual result or a request error. A Revision comparison names its own revisions’ documents, apart from the plan’s sources. Sample admission and a comparison’s classification remain separate from disposition and completeness. Avoid: SDF definition, Assessment area or expected-result assertion.

Check coverage: The model scope and SDF requirements that a check actually assessed.

Requested assessment: The predetermined requirements selected for a model check, independently of which checks a processor can currently complete.

Assessment profile: A named set of requirements defining a requested assessment. Avoid: Implemented checks when referring to the profile’s promised scope.

Assessment area: A named group of requirements in a requested assessment, counted once across its model scope.

Model requirement inventory: The immutable, cited model obligations selected by a requested assessment, independently of current implementation. rfc9880.model/1 contains 54 exclusive obligations from the normative body and Appendices A/C. The Full area inventory esdieff.full-model/1 groups them into 12 model areas plus the existing advisory area, following ADR 0011: Machine-readable report contracts. Initial retains its narrower eight areas. Sample, device, protocol, registry and operator duties have separate roles. Avoid: Implemented checks or user stories as a complete standards inventory.

Coverage owner: The requested Full area owning an actual recorded requirement. A condition retains its producing assessment-unit identity; optional coverage-owner detail relates it to Full without renaming its producer.

Assessment status: Whether a requested area is assessed, established not applicable, unassessed or undetermined because needed facts or capability are unavailable. Assessed includes established findings, rather than asserting that the model satisfies the area.

The same four states describe fine-grained model obligations. Repeated observations join undetermined before unassessed, assessed, then not applicable, so one completed occurrence cannot hide an unfinished sibling. Areas join their owned requirements once. Completion, error counts and optional presentation are independent.

Incomplete check: A check whose requested assessment could not be completed, for example because a needed definition or critical feature was unavailable.

Deferred model check: A model-checking capability deliberately left for later delivery. Deferral preserves the affected requirements and their actual assessment status; it does not establish that they are satisfied or not applicable.

Constraint contradiction: Applicable effective data constraints that together admit no values. Avoid: Definite RFC violation unless a violated requirement is established independently.

Sample value: Example interaction data whose meaning and constraints are described by an SDF data description. Avoid: Protocol payload without an applicable protocol binding.

Sample projection: Conventional JSON text generated from a typed sample value, retaining its exact numerical representation but carrying no original source-text provenance. Avoid: Original sample bytes when referring to generated text.

Sample-value checking: Assessment of one sample value against a selected effective data description, returning admitted, rejected, or undetermined. Admission is separate from model findings and requested-work completeness, following ADR 0016: Selected samples with explicit admission and coverage. Ordinary map entries and array elements conjoin with their containing value’s constraints. Array counts are inclusive and exact. An empty array requests no item value and establishes no meaning for a deferred item subtree. Repeated elements share descriptions while accumulating actual present interests; completed model conditions are observed once per final description. Avoid: Model checking when assessing example interaction data.

Generated value: A value Esdieff constructs for a selected effective data description, aimed at one Generation target and settled by Sample-value checking. Its admission, not its target, says whether the description admits it, following ADR 0041: Generated values settled by Sample-value checking. Avoid: Sample value, which a caller supplies; Representative value, which revision comparison tries as a Breaking witness.

Generation target: The named edge of a data description that a Generated value probes, such as minimum, below_minimum or missing_entry, fixed by the generation contract. A target that does not apply produces no value. Avoid: Expected result, since only Sample-value checking settles admission.

Simulation trace: The ordered record of one deterministic device demonstration: an initial state reading, then each command’s step, simulated time and invocation with its input, optional Action result and Event, and subsequent state reading in observed order. Sample-value checking assesses its individual values, while its sequence meaning comes only from the demonstration’s own authored rules and adds nothing to any Model requirement inventory. Avoid: Check case, protocol log, device state machine.

Authored behavior assertion: A named rule that a demonstration states for itself, relating its authored commands and independently tracked expected state to an observed Simulation trace, such as when a stateChanged Event must appear. It is never inferred from SDF descriptions, and it is separate from a Check case, the admission result of Sample-value checking and the Model requirement inventory. Avoid: SDF requirement, model obligation, admission result, device protocol rule.

Recorded trace: A JSON Lines file of Trace entries, observed from a Thing or Client or prepared as test vectors, whose entries are checked independently against one selected document. Line order carries no meaning beyond presentation, following ADR 0042: Recorded traces with independent entries. Avoid: Simulation trace, which has authored sequence rules; protocol log.

Trace entry: One line of a Recorded trace: a Sample selector, a value and optionally an Expected admission and a label. A malformed entry fails alone without stopping the others.

Expected admission: The admission a Trace entry states for its value, admitted or rejected. A definite admission that differs from it fails the entry, and an undetermined admission stays undetermined. Avoid: Generation target, which names the edge a Generated value probes.

Revision comparison

These terms describe how a later revision of a model affects the clients of the Things it describes.

Model revision: The documents of an SDF model at one point in their evolution, supplied together as one Catalogue. Avoid: version, which is an authored document quality with no mandatory format.

Corresponding definition: A grouping or affordance in a later Model revision with the same Given Name position, in the corresponding document, as one in the earlier revision. Documents correspond by the key the caller gives each one, which esdieff diff takes from the document’s location within its revision. A moved or renamed definition has no correspondent, so it reads as a removal and an addition. Avoid: Global name, which many device documents lack.

Revision comparison: Classification of each difference between the corresponding groupings of two Model revisions as breaking, compatible or undetermined, from the Client’s side. Changes to shared definitions appear through the effective groupings that use them. A difference Esdieff cannot classify remains undetermined, never compatible, following ADR 0039: Client-side revision comparison. Avoid: Model checking, which assesses one model against SDF requirements.

Client: The party that reads, writes and observes a Thing’s Properties, invokes its Actions and receives its Events. Avoid: Consumer, which names an Importing consumer in composition.

Client-supplied data: Interaction data a Client sends to a Thing: written Property values and Action input.

Thing-supplied data: Interaction data a Thing sends to a Client: read or observed Property values, Action output and Event output. A Property that is both readable and writable carries data in both directions.

Client direction: Whether data is Client-supplied or Thing-supplied. A Property’s effective characteristics decide which directions its data carries.

Breaking change: A difference between two Model revisions after which an interaction the earlier revision described can fail for a Client, or yield data the Client was not described to receive. Narrowed Client-supplied data, widened Thing-supplied data, a removed grouping or affordance, a Property characteristic that becomes false, input data added to or removed from an Action, output data removed from an Action or Event, a declaration that stops being mandatory, a widened grouping instance count and a change between two established meanings of a unit, Content-Format or sdfType are breaking. A difference that only obliges Things to accept or provide more is not, and neither is describing what no Client of the earlier revision uses, such as a map entry it neither describes nor requires or output data an affordance did not have. Avoid: Any difference; Restrictive refinement, which concerns overrides within one model.

Meaning quality: A data quality that tells a Client how to read a value: unit, contentFormat or sdfType.

Breaking witness: A value that one revision’s effective data description admits and the other’s rejects, in the direction that makes the difference breaking, as established by Sample-value checking against both revisions. A change to the values a data description admits is breaking only with a witness, compatible only with a proof that no witness exists, and otherwise undetermined.

Representative value: A simple value that an effective data description may admit, generated from its constant, enum values or documentary default, as one value of each type it admits or of each Effective alternative of its choice, or as null when it is Nullable. Revision comparison tries it as a candidate Breaking witness from the revision that must admit it, and value generation offers it as a Generated value. Sample-value checking settles each one, so a representative value its own description rejects establishes nothing. Avoid: Sample value, which a caller supplies.

Monotone rule: How a change to one data quality relates the values two Model revisions admit, with every other quality as it is: the later revision admits more, fewer or the same values, or none of these is established.

Compatibility proof: A demonstration that a data description’s changes admit no Breaking witness: every changed quality loosens in the safe direction for each Client direction, widening Client-supplied data and narrowing Thing-supplied data, and nothing else in the description changed except documentation or content no Client of the earlier revision uses. Avoid: Subset proof, which suggests general satisfiability solving.

Difference acknowledgement: A maintainer’s record that one difference between two Model revisions is intended, naming its kind, subject, quality, classification and its location in each revision, following ADR 0040: Acknowledged revision differences. Avoid: Acceptance, which names an Acceptance restriction, and baseline, which names the Standards baseline.

Acknowledged difference: A breaking or undetermined difference that matches a Difference acknowledgement. It keeps its classification but no longer decides the comparison’s disposition.

Version warning: Advice that a changed document with a Breaking change has a later info version that is absent or does not compare higher, although RFC 9880 recommends a version that compares higher in every later revision, following ADR 0044: Versions of breaking revisions. It never decides the comparison’s disposition. Avoid: Version check, which suggests a required format.

Base SDF and extensions

Terminology sources: RFC 9880, Section 1, Section 1.2.3, and Section 3.1.

Base SDF: The SDF specification defined by RFC 9880, including its extension mechanisms.

SDF extension: Additional SDF vocabulary or semantics defined beyond base SDF.

Extension feature: A named critical extension capability listed in a document’s features quality because correct processing requires understanding it.

features: The information-block quality listing critical extension features. A feature name is a registered name or a URI; a URI name does not imply retrieval.

Undeclared extension vocabulary: A Quality Name outside base SDF, used in a document that declares no Extension feature. It leaves the base meaning of its definition intact, following ADR 0037: Undeclared extension vocabulary. Avoid: Unknown critical feature, which defers the whole document.

Recorded extension vocabulary: A qualified Quality Name whose registered definition, positions and value domain Esdieff records as dated registry evidence, such as oma:id, following ADR 0038: Recorded extension vocabulary. Avoid: Registered prefix, which identifies only the defining organization.

Framework syntax: The normative SDF grammar with liberal extension points, defined in RFC 9880 Appendix A.

Formal admission: Membership of a supplied value in the applicable normative grammar alternative. A value admitted through a framework extension alternative can have unavailable extension meaning. Formal admission is separate from exact mathematical meaning and actual sample admission, following ADR 0032: Formal model admission.

Validation syntax: The stricter grammar derived by removing the framework syntax’s extension points to help detect vocabulary mistakes. Avoid: Complete semantic checking, which also requires prose requirements and composition processing.

Augmentation mechanism: Companion information that supplements an SDF model for an ecosystem or another specific use.

Protocol binding: An augmentation mechanism that maps abstract model concepts to a particular ecosystem’s network protocols.

Conformance

Standards baseline: The RFC, explicitly adopted verified corrections, and recorded external knowledge against which SDF requirements are assessed.

Temporal knowledge: Recorded facts about dated UTC leap adjustments and the interval in which adjustment or nonadjustment is established.

RFC interpretation: An agreed reading used to resolve an ambiguity or inconsistency in the RFC without intentionally departing from the standard.

Agreed deviation: An explicitly accepted departure from an RFC requirement. Avoid: RFC interpretation, incomplete check, or unimplemented requirement.

Acceptance restriction: An explicitly agreed Esdieff policy refusing particular supplied model or sample content without asserting that its presence necessarily violates the RFC. Avoid: Definite RFC violation, agreed deviation when no departed requirement has been identified.

Recorded registry evidence: A deliberately captured set of positive registry facts whose edition identifies its scope and date. A positive match establishes membership in that evidence; a miss leaves current registration unknown, following ADR 0027: Unit names and recorded registry guidance.

Recorded evidence policy: An embedding’s request-level choice to use or withhold the bundled dated registry evidence. Withholding makes needed evidence unavailable for that request without asserting that the recorded table is physically absent.

Registry consultation: Actual comparison against a recorded registry table, independent of whether a match or a completed lookup was established.

Unit source edition: The common raw registry source from which the unit sections were extracted. Its use identifies at least one consulted section, while each section retains its own extracted identity.

Consulted format fact: A static specification record actually consumed while a selected Sample request assesses a URI, URI-reference or UUID. Its immutable identity, RFC, sections and scope describe the consulted rule. Observations survive discarded alternatives and late limits; an unavailable initial owner differs from an established empty set. See ADR 0019: URI, URI-reference and UUID sample conventions.

Architecture decisions

Each record explains one decision behind Esdieff’s behaviour: the question, the options considered and the consequences accepted. Records are numbered in the order they were made and are never rewritten. A later record supersedes an earlier one when a decision changes.

The domain language defines the terms these records use.

0001: Base SDF as the semantic foundation

Esdieff’s core target is the abstract interaction and data model of base SDF in RFC 9880, including its extension mechanisms. Separately specified extensions, protocol bindings, and ecosystem conversions are additional scope rather than prerequisites for the core toolkit. This gives model authors a common semantic foundation without tying their models to one ecosystem’s wire representation.

Considered Options

Starting with one ecosystem’s integration could provide a concrete deployment path sooner, but would give that ecosystem’s requirements priority over the common SDF model. The core instead prioritizes model checking, composition, and inspection across base SDF.

0002: Recorded standards baseline

Esdieff uses a recorded standards baseline: RFC 9880, explicitly adopted verified corrections, and a dated snapshot of relevant registry knowledge. Normative RFC prose and Appendices A and C govern; informative schemas and examples provide supporting evidence. Corrections and registry updates enter the baseline deliberately so that a check’s standards basis remains reproducible.

RFC interpretations, agreed deviations, and unimplemented requirements remain distinct. Registry snapshots record available knowledge. A name missing from them is not proved unregistered, and its absence does not justify rejecting otherwise permitted extension content. A recorded extension definition can still establish that a value at one of its own positions is excluded, following ADR 0038: Recorded extension vocabulary.

Considered Options

Consulting changing online sources during every check could change conclusions without a corresponding toolkit change. Ignoring later corrections and registrations would instead discard relevant standards evidence. A recorded, deliberately updated baseline preserves both reproducibility and a path to updates.

0003: Check findings and completeness

Esdieff reports errors, warnings, incomplete checks, and check coverage separately. Missing definitions, unsupported checks, unresolved interpretations, or unknown critical features can leave conclusions undetermined; they do not by themselves establish a definite RFC violation. A definite error remains reportable alongside incomplete checks only when the missing information cannot change that conclusion.

This distinction supports phased implementation without presenting unassessed requirements as satisfied. In particular, RFC 9880, Section 3.1 requires understanding critical features for proper processing; a base-only interpretation cannot establish conclusions that depend on unknown critical semantics.

A successful requested assessment completes all explicitly requested checks without errors. Warnings are nonblocking by default, with an optional stricter policy. Requested unsupported requirements remain incomplete; Esdieff cannot silently narrow an assessment to implemented checks. Human and JSON reports carry equivalent conclusions, scope, coverage, and incompleteness, and distinguish effective-model paths from available source locations.

During phased delivery, the default is a named initial assessment profile with a predetermined requirement inventory. Every check summary identifies the broader RFC coverage, including when the requested initial assessment succeeds. A complete recorded-baseline assessment can be requested explicitly; unsupported requested requirements leave it incomplete. The initial inventory and exclusions are a product contract to settle before implementation, rather than a reflection of whichever checks happen to exist.

Coverage expansion aims at comprehensive base-SDF model checking while permitting explicit deferrals for uncommon cases. Each Deferred model check records the affected requirement, current assessment outcome, reason and condition for reconsideration. Deferred capabilities retain their coverage obligations; unresolved interpretations and requirements needing external knowledge remain distinct from missing implementation. Broadening capability does not silently redefine the Initial assessment or remove requirements from the Full inventory established by ADR 0011: Machine-readable report contracts.

Deferral reasons and reconsideration conditions belong to the documented capability boundaries. Scheduling work does not change its reported assessment status: deferral is planning information, not another runtime status or an additional report field. Reports retain their existing assessment states and explanations of unavailable conclusions.

An unfamiliar unqualified Quality Name receives a warning to help detect vocabulary mistakes. Recognized but unsupported optional extension vocabulary receives informational notices. Initial and expanded assessments summarize these observations. Full names and locates each inspected occurrence so the author can find unsupported content behind unfinished requirements. Composed observations retain the effective position and nearest source contribution. Existing diagnostic limits bound the retained details without changing coverage states. Permitted extension content is retained. Undeclared extension vocabulary leaves base conclusions intact under ADR 0037: Undeclared extension vocabulary, and only conclusions that need an extension’s own unsupported meaning remain incomplete. Explicitly rejected historical vocabulary follows ADR 0008: Reject the historical Action input quality.

Provably empty permitted value sets receive explanatory warnings rather than being classified automatically as RFC violations. These checks begin with simple proved cases and report the contradiction classes assessed; they do not promise general satisfiability analysis. Applicable null and choice semantics follow ADR 0005: Nullability and presence.

Considered Options

A single pass/fail result would conflate invalid models with models whose checking could not finish. A simple report may summarize the outcome, but it must preserve findings, incompleteness, and the scope actually assessed.

0004: Supplied catalogues and checking scope

Esdieff initially works with explicitly supplied SDF documents. A catalogue check covers every supplied document, including unused definitions; a selected-model check starts from chosen root documents and covers the dependencies needed for its checks. Reports identify their scope so that success for one model cannot be mistaken for success across a catalogue.

Catalogue checking is the default. Selected-model checking requires explicit supplied root documents; other supplied documents remain available for dependency lookup. The CLI accepts explicit file paths, one standard-input document and explicitly supplied local directories, while library callers supply document content and source identities directly. Input order does not assign a document’s role, and acquisition failures remain visible.

Directory discovery prepares ordinary Source inputs privately in the CLI. It selects immediate regular .sdf.json files by default, with explicit recursion and literal relative file or subtree exclusions. Descendant links and special files are skipped. Each directory must select a nonempty set, and discovery overlap with another discovered or explicit file is refused by native filesystem identity. Explicitly repeated file inputs remain separate attempts. Sorting gives repeatable source presentation, never namespace precedence or an implied Root document.

The entire finite selection, identity checks, root selection and source-metadata preflight complete before content acquisition. A preparation failure is an invocation error without a partial model report. After preparation, unavailable or malformed selected files remain ordinary acquisition results. Discovery observes the local filesystem without promising an atomic snapshot. These limits follow ADR 0009: Bounded processing and reporting, while reports retain ADR 0013: Shared workflow and report guarantees. Saved Check plans retain literal version-1 sources.

No automatic document retrieval is required for this initial model workflow. Namespace URIs identify names rather than document acquisition locations, and multiple documents can contribute to one namespace (RFC 9880, Sections 3.2 and 4). Additional acquisition workflows can be considered separately.

Considered Options

Implicit retrieval would couple semantic processing to network availability and an acquisition convention that base SDF does not require. Checking only reachable content would also miss mistakes in unused documents during a catalogue check. Explicit document supply and scope make those differences visible.

0005: Nullability and presence

Esdieff interprets nullable as admitting a null value, with the default true specified by RFC 9880, Section 4.7, Table 4. This is separate from mandatory presence: required constrains entries in map data, and sdfRequired constrains declared components. The registry description in Section 7.5.1 instead refers to omission, which conflicts with the data-quality definition.

The original specification source already describes null availability with default true. The later registry addition introduces the conflicting description without changing that meaning. This history supports the data-quality definition as the intended semantics.

Null admission extends the effective type; other applicable constraints still apply, including const. Thus a plain string description admits null by default, while const: "on" excludes it. For sdfChoice, Esdieff evaluates each effective alternative after inherited qualities and explicit overrides; a value is admitted when an effective alternative admits it, and an alternative may explicitly admit null. enum follows its RFC expansion into const alternatives.

The inspectable alternative and characteristic states are specified in ADR 0024: Effective alternatives and nullable characteristics. Inherited authored values retain their donor’s established meaning and uncertainty. A Full alternative defaults nullable to true only after its final inherited/overridden quality set establishes absence. These views expose the interpretation without performing sample admission or general consistency proofs.

Appendix C restricts const to one value, and Section 4.7.2 defines choice inheritance and enum expansion. These support this constraint interpretation without explicitly settling null precedence. Dependent conclusions remain incomplete when an effective alternative cannot be established; stronger adopted standards evidence can change the interpretation.

Considered Options

Treating nullability as optional presence would conflate distinct constraints and leave null values without the meaning explicitly given in Table 4. Esdieff records the interpretation separately from agreed deviations.

Allowing null to bypass every constraint would contradict the single-value meaning of const and the explicit enum expansion. Leaving every interaction unresolved would postpone useful definite checks despite the available supporting evidence.

0006: Scoped reference failures

Esdieff reports a cycle in effective reference expansion as an inability to complete the affected resolution, with its reference path. RFC 9880, Section 4.4 supplies no general recursive-model contract, so a syntactic cycle alone is not classified as a definite RFC violation. A reference eliminated by an override does not block the selected model’s resolution; a catalogue check still assesses the supplied definitions independently.

Multiple contributors to the same addressed global definition make that lookup ambiguous. Esdieff applies no input-order precedence or automatic deduplication, and reports which contributions conflict. Same-document references, separately addressed unambiguous definitions, and independent checks remain assessable; sharing a namespace is permitted by Section 3.2.

A definite reference error, such as malformed reference syntax or a prefix the writing document never mapped, follows from the written reference alone. It is one finding at the reference as written, however many copies, root chains or checked documents reach it. An unavailable target instead leaves each effective position it reaches unfinished, so it is reported at each of them.

Considered Options

Treating every cycle as an invalid model would impose a prohibition not stated in base SDF. Eagerly expanding content later deleted by a consumer’s override could also turn an irrelevant reference into a selected-model failure. Choosing the first or last contributor, or deduplicating identical text, would make meaning depend on input ordering or disregard different reference contexts. Reporting a definite reference error once per reach would count one authored mistake several times.

0007: Generated SDF and sample JSON

Generated SDF prioritizes readable JSON and faithful known semantics, names, and numeric values. Permitted opaque extension content is retained, but retaining its structure cannot establish preservation of unknown semantics when definitions or reference contexts move. Exact reproduction of source whitespace and key ordering is a separate presentation-preservation capability.

Sample inputs use conventional JSON representations, including unpadded base64url for byte strings and numeric POSIX time for unix-time, as described in RFC 9880, Section 4.7.1, Table 5. These representations are input conventions for abstract information-level data, rather than protocol payload bindings.

FullBaseline establishes the two known model interpretations without supplying or searching for a value. M026 and M027 therefore do not depend on decoding a byte sequence or assigning a particular POSIX coordinate. Actual constant denotation and contextual equality still use the same conventional operands and limits below. Model interpretation does not settle decoded-byte length or the unavailable negative-coordinate and leap-instant meanings.

For byte-string, the decoded JSON text must use the URL-safe alphabet without padding or ignored whitespace. Empty text denotes an empty byte sequence. A final two-character group has zero low four bits; a three-character group has zero low two bits. These canonical images follow the base64url convention in RFC 8949 Section 3.4.5.2 and RFC 4648 Sections 3.5 and 5. JSON escapes are decoded before this check. Invalid text is rejected without repair, alternate-alphabet conversion or padding removal. Byte-sequence meaning does not establish a Unicode length or a decoded-byte-length constraint from an authored text quality.

For unix-time, available exact JSON numbers are usable representation inputs, including fractions, large coefficients and exponents, negative values and mathematical zero written -0. A nonnegative number establishes its exact POSIX coordinate; no machine-width, binary floating-point or host calendar conversion is needed. Negative nonzero inputs retain exact representation and consultation, but their abstract denotation remains undetermined under this convention. This limitation does not itself reject the sample. An independent integer, null or other applicable constraint can still reject it. Information-level numeric coordinates do not certify the separate formal CDDL or any protocol binding.

Equality requires both operands’ denotations in a common compatible context, following ADR 0015: Bounded value equality in a resolved data context. Canonical byte text has one image per sequence, so comparing two established images establishes equality or difference without allocating decoded bytes. Established POSIX coordinates use exact numeric equality and the original remaining numeric allowance. Representation failure, unknown denotation and exhausted work retain distinct causes.

Considered Options

Requiring exact source presentation for every generated document would couple initial authoring to existing-document editing needs. Supporting multiple sample encodings from the outset would add representation choices before establishing the conventional SDF workflow.

Accepting noncanonical tails or repairing input would add alternate images beyond the selected channel. Rejecting all negative numeric input would confuse representation with unresolved denotation; assigning it a signed civil-time meaning would settle an additional convention. Limiting coordinates to host dates, fixed-width integers or floating point would reject or merge exact inputs that remain usable under the existing numeric capabilities.

0008: Reject the historical Action input quality

Esdieff rejects sdfRequiredInputData at assessed SDF vocabulary positions with an explicit, helpful error. The pre-standard Action-input mechanism was removed from the specification, and its legacy grammar production was subsequently removed. Supporting its historical semantics would introduce compatibility behavior outside the current Action model.

The diagnostic identifies the unsupported historical quality and points to sdfInputData. Where input has multiple named fields, it explains the current type: "object", properties, and required structure described in RFC 9880, Section 5.3. Migration requires reviewing the input description rather than renaming a keyword.

The final RFC still lists the name in its registry, and its framework syntax has liberal extension points. Consequently, this is an explicit acceptance restriction, recorded in the agreed restrictions list, rather than a claim that every occurrence is a mandatory RFC violation. Esdieff’s selective restriction does not imply use of the entire closed validation syntax from Appendix A.

The restriction applies to assessed vocabulary positions, including document and information-block qualities, and to effective definitions after JSON Merge Patch. Catalogue checking still assesses supplied definitions independently. Given Names, sample-data entries, and arbitrary keys within opaque extension content are not vocabulary positions. Raw inspection and independent checks remain available when this error occurs.

Considered Options

Preserving this historical quality as ordinary optional content would conceal a removed mechanism behind extension handling. Automatic conversion would require assuming the old model’s intended input structure. Explicit rejection provides an actionable path to the current Action model.

0009: Bounded processing and reporting

The library and CLI use explicit, configurable finite processing budgets for input size and depth, reference expansion, checking, numeric work, patterns, and diagnostics. A processing limit produces an explicit operational limitation and leaves affected requested checks incomplete, rather than establishing an RFC violation. This bounds work on supplied input while preserving the distinction in ADR 0003: Check findings and completeness.

Diagnostic truncation is reported separately from unfinished semantic checking. The aggregate outcome is retained even when individual diagnostics cannot all be displayed, so report limits cannot conceal errors behind earlier warnings. Numerical limitations are explicit; processing never silently rounds model values, overflows, or substitutes an incorrect verdict. Exact budgets, numerical representation, and dependencies remain implementation decisions requiring suitable evidence.

Considered Options

Unbounded processing would allow small reference graphs, extreme exponents, or patterns to consume disproportionate resources. Treating every limit as invalid input would misstate a toolkit limitation as a standards rule. Equating report truncation with incomplete checking would likewise confuse presentation limits with assessment coverage.

0010: Domain-oriented library and caller simplicity

Esdieff exposes typed access to SDF definitions, groupings, affordances, data descriptions, and structured findings, backed by the shared domain model. The library carries the burden of interpreting references, composition, and checking rules so that callers can use SDF concepts without reconstructing their meaning from generic JSON maps. Source and permitted extension JSON remain accessible.

Simplicity, correctness, and efficient normal use guide the library’s design. Interfaces should express the guarantees actually available and make incomplete results clear. Internal complexity should produce a concrete benefit for callers rather than requiring them to manage SDF processing details. Performance choices must preserve the standards baseline and semantic fidelity in ADR 0002: Recorded standards baseline and ADR 0007: Generated SDF and sample JSON.

Concrete public types, fields, identity, ownership, serialization contracts, and editing interfaces remain subsequent design decisions. This principle does not choose a graph representation, allocation strategy, or numeric dependency.

Public interfaces should accommodate future capabilities without transferring avoidable migration work to callers. This applies to typed Rust access and machine-readable reports alike. Compatibility rules and extension points must serve concrete expected uses while preserving precise meanings; the principle does not require speculative general-purpose mechanisms.

Considered Options

Making generic JSON the sole interface would push traversal and RFC interpretation onto every library consumer. Exposing mutable internals as the main interface would likewise make callers responsible for preserving invariants. Domain-oriented operations allow Esdieff to carry those responsibilities while retaining access to the underlying content.

0011: Machine-readable report contracts

Esdieff provides versioned JSON reports and stable diagnostic codes from the first useful checking milestone. Callers can read outcomes, requested assessments, model scope, coverage, incompleteness, truncation, standards baseline, and the distinction between RFC findings and acceptance-policy findings structurally. Human wording can improve without becoming an automation interface.

Before implementation, the concrete report schema and compatibility rules must cover changes to assessment inventories and diagnostic meanings as well as field evolution. An unchanged assessment identity or condition code must not silently acquire a different meaning. The design should accommodate intended future capabilities while keeping the report’s current guarantees precise, following ADR 0010: Domain-oriented library and caller simplicity.

Full retains assessment and baseline rfc9880/base-1. The existing mandatory request.inventory esdieff.full-model/1 binds its immutable13-area membership and54-member rfc9880.model/1 relation, documented in the model inventory. Known membership replaces unavailable membership without implying completed capability. Historical null inventories still mean unavailable membership, never an empty set. New membership needs a new identity; Initial and other profiles retain their meanings.

Borrowed requirement descriptors and fixed semantic statuses remain available independently of rendering. New optional aliases, summaries, rows and coverage owners may be wholly omitted. Area aggregates retain their existing count unit; requirement aggregates explicitly count requirements. Conditions preserve producing assessment_unit IDs, while optional coverage_owner and the immutable relation identify their actual requested Full owner. Generic rules use actual field/role context. Semantic states, aggregate errors and incompleteness never depend on retained diagnostics. The report contract pins exact fields and omission accounting.

Full broader.state follows the54 model obligations named by its inventory, while requested completion follows13 areas including independent advice. Completed model work can contain errors or coexist with unfinished advice. The optional Full omitted-areas list is absent; mandatory state is authoritative. Human and JSON share this calculation. Other operations retain their broader partial meaning.

Considered Options

Treating initial JSON as debugging output would postpone interface design, but require consumers to parse prose and migrate their integrations later. A supported report contract places that burden in Esdieff. It does not require serializing internal Rust structures or freezing every future diagnostic in advance.

Renaming assessment_unit according to the selected profile would silently change a published field’s meaning. A separate optional owner preserves its producer. Requiring a new inventory alias would break mandatory-only consumers; the existing inventory binding carries membership when optional detail is absent. Treating historical null membership as empty would invent completion. Counting supporting citations again, or replacing complete model obligations with a smaller implemented subset, would inflate coverage.

Deriving broader model completion from all13 areas is conservative but couples the named54-member model inventory to separate advice. Permanent partial cannot express established completion. An unconditional unimplemented-requirements list would falsely describe both completed model work and partial work caused by acquisition or processing limits.

Sample 1.1 adds mandatory final meaning sets and actual consulted-interpretation observations within the existing Sample result and baseline envelope, following ADR 0025: Selected numeric samples. The current nine-area identity, authoritative outcome, admission, counts and older operations are unchanged. Reference sets use complete kind/ID/citation identity: RFC views omit IDs; operational views preserve existing precise citations when present. Clients reading older additive 1.x reports treat absent meaning fields as an unavailable capability, never as an established empty set or not-applicable status.

0012: Exact numbers and JSON input policies

Esdieff distinguishes JSON decoding, framework syntax, information-level numeric meaning, and implementation capability. RFC 9880 Appendix C.1 makes integrality a value property, including fractional or exponential notation with integral values. RFC 8259 Sections 6 and 9 admit decimal tokens while permitting explicit implementation limits. RFC 8610 Appendix E explains the JSON mapping of CDDL numerical types; successful exact decoding establishes a number but does not prove every uint requirement in the normative SDF grammar.

Numeric input retains its original JSON token and is represented as a bounded signed decimal coefficient with a base-10 exponent. Mathematical comparison and integrality preserve exact values without binary floating-point conversion or exponent-sized expansion. Affected numeric work that exceeds capability or a finite work budget remains incomplete with its source value available, following ADR 0009: Bounded processing and reporting. Independent conclusions remain available. Unchanged generated numbers preserve an accepted raw lexeme, including at lexical exponent boundaries; normalization is an internal representation rather than a mandatory output syntax. Future computed-number output must meet the same-default acceptance/capability contract or identify an explicit limitation. This preserves usable JSON numbers with unchanged mathematical values, following ADR 0007: Generated SDF and sample JSON.

The initial assessment’s numeric contract covers JSON number shape, exact sign and positivity of multipleOf, nonnegative integral count/length values, and guarded mathematical proofs enumerated by its inventory. FullBaseline separately checks the normative CDDL number and uint domains under ADR 0032: Formal model admission: number admits every JSON number, while uint is the integral interval 0 through 2^64-1. Exact decoding of a count such as 18446744073709551616 does not establish uint admission; an available exact predicate establishes its exclusion when the grammar requires uint. Framework extension alternatives remain distinct from definite grammar errors. Initial, expanded and selected-sample behavior stays unchanged. Neither decoding capability nor a machine-type failure silently widens normative syntax or establishes a definite violation.

JSON input is one UTF-8 text. Decoding accepts JSON whitespace and rejects comments, trailing commas, concatenated texts, and quoted-number coercion. A leading BOM is not accepted. Syntactically admitted non-scalar escaped strings or keys are unsupported decoding capabilities, rather than a blanket acceptance restriction or JSON syntax violation. Preserve raw source and scope incomplete work to the affected conclusions. An unsupported key can prevent usable map construction; an unsupported value leaf does not erase independent numeric conclusions. Paired surrogate escapes decode normally.

Acceptance restriction A002 refuses duplicate decoded names in any JSON object, including nested and opaque content. Repeated identical values also fail. Names compare exactly after escape decoding, without case folding or Unicode normalization. No first/last precedence is established. The input-policy result identifies the repeated member and preserves supplied source. Independent documents remain usable. RFC 8259 Section 4 gives the interoperability basis; duplicate names are not rejected as JSON syntax errors.

Finite configurable defaults are 4 MiB per document, 32 MiB per catalogue, 256 documents, 64 nested containers, 100,000 JSON value nodes per document, 1,024 bytes per number token, 512 normalized coefficient digits, explicit exponent magnitude 1,000,000, and 2,000,000 numeric work units per request. Input and numeric caps are implementation capability, not standards limits. Configuration must remain finite and satisfy internal checked-arithmetic and stack bounds. Numeric work charges token characters and compared digits before operations; future arithmetic debits a documented finite work model before large allocation. Operational limits never erase retained aggregate findings.

Input, depth, and node caps do not alone control location/report amplification. Production storage uses shared or compact ancestry and source spans, with finite path/report materialization and work budgets checked before allocation. Full ancestor-pointer strings repeated per node or finding are not an adopted architecture. Public workflow and source-document implementation must settle and test these budgets before relying on the numerical/input contract. Report byte truncation preserves aggregate errors and is distinct from unfinished semantic work, following ADR 0009. A path or semantic-work limit leaves affected requested conclusions incomplete; presentation truncation alone does not imply semantic incompleteness.

Source inspection retains supplied content and number tokens. Generated output preserves known numeric and JSON value semantics; exact whitespace, escape spelling, and key ordering are separate presentation capabilities. Opaque content remains structurally available, without proving fidelity when its semantic context changes.

Considered Options

Fixed-width integer/float representations and fixed-scale decimal types can round, overflow, or underflow values before the model is assessed. Unbounded arbitrary-precision arithmetic and exponent expansion can spend disproportionate work on short tokens. Bounded arbitrary precision may support later operations, but exact parse/order/integrality do not require a large-integer dependency. Mandatory normalized output can cross the accepted lexical exponent budget, so unchanged values preserve accepted lexemes. A stock JSON map decoder can discard duplicate evidence and choose undocumented precedence. Externally converting numbers to strings changes JSON types. Full ancestor pointers repeated at every node can amplify small inputs despite ordinary input caps. Treating every numerical or decoding limitation as an RFC violation, or adding a blanket non-scalar-string restriction, confuses toolkit capability, input policy, and standards meaning.

0013: Shared workflow and report guarantees

Esdieff’s public boundary is document-supplied domain work with owned immutable source content, borrowed typed source/effective views, and scoped results that preserve independent findings. The public workflow and report contract gives checking, inspection, future sample-value checking and authored-document consumers one source/location/outcome foundation while keeping internal parser, graph and numeric types replaceable. This follows ADR 0010: Domain-oriented library and caller simplicity.

The immutable default assessment esdieff.initial/1 retains its predetermined structure/composition inventory and four guarded advisory proof classes. Broader recorded-baseline requests keep their own immutable baseline/inventory identities and cannot complete without all applicable requested work. Mathematical number capability remains separate from normative CDDL admission, following ADR 0012: Exact numbers and JSON input policies. New membership or meaning receives a new identity; implementation progress cannot redefine success.

Initial completes its eight areas through the existing traversal, composition and required-declaration resolver on the original cumulative allowance. Removing placeholder diagnostics follows completed work. Full knows 54 exclusive model obligations grouped into 13 requested areas, while genuinely unfinished applicable model meaning remains unassessed or undetermined. Sample admission, conversion, protocol/device behavior, registry administration and operator duties do not earn model completion. General satisfiability and optional refinement analyses are separate.

The shared requiredness seam retains copied declaration identity, original resolution policy, independent definite errors and unavailable needed targets. It does not build a parallel graph or replenish work. Fixed states are updated before optional finding retention; producing inspection conditions keep their identities and receive a Full owner only in the applicable recording context.

Report JSON 1.0 is a supported explicit wire contract, independent of Rust layout. It separates completion, aggregate findings, strict-warning disposition, requested/broader coverage, basis and omitted diagnostic detail. Stable condition codes retain their meanings; additive fields cannot change them. Source/effective/sample locations and available inheritance/override/deletion explanations remain distinct. No exhaustive provenance history is promised. This makes report consumers independent of human wording, following ADR 0011: Machine-readable report contracts.

The shared contract pins nested field types, absence/null states, compact source IDs, count bounds and units, and fixed acquisition/decode/basis values. Initial checks count eight immutable assessment areas. Standalone inspection requests no model assessment: it counts one declared view-establishment operation and discloses broader partial coverage. Future sample/author payloads remain their dedicated contract decisions, with unknown-operation guards protecting existing check/inspect readers.

Finite catalogue-wide parsed nodes/allocation, effective nodes/allocation/byte work, reference/checking work, compact ancestry and pointer/report budgets complement the input/number limits in ADR 0012. Storage and work are charged before derived allocation or traversal. Count/byte/pointer presentation truncation preserves aggregate errors and semantic completion; a required semantic capability limit leaves affected work incomplete, following ADR 0009: Bounded processing and reporting. Ordinary caller exercises guide simplicity and avoidable allocation without inventing a performance target.

Before copying, metadata preflight bounds keys, labels, acquisition URIs, content-version tokens, digests, exact raw filesystem identities and repeated references across all source roles. Semantic identities are never clipped. Only presentation labels can be shortened/omitted with reasons. Whole-request caller metadata and library-owned baseline/inventory metadata have separate finite caps. A worst-escaping mandatory report reserve preserves every source attempt and aggregate outcome; too-small report configurations fail before processing.

The CLI accepts explicit paths and one stdin document, defaults to catalogue checking, requires explicit supplied roots for selected-model checking, and emits one human or JSON report with exits distinguishing passed, failed, invocation error, undetermined and host-output failure. Direct checking can additionally prepare supplied files through bounded directory discovery, following ADR 0004: Supplied catalogues and checking scope. Preparation errors occur before acquisition and emit no model report. Future sample/author operations share these guarantees; their specific request/write decisions precede their implementation. No implicit acquisition, input precedence or generic mutable checked JSON is introduced.

Saved Check plans group named Check cases through the existing Catalogue operations. Explicit source keys and roles preserve acquisition attempts, and local paths are resolved beside the supplied plan path without canonicalizing a symlink to its target. Cases run sequentially with independent native allowances and continue after failed or incomplete work. The CLI owns this workflow rather than exposing a second semantic interpreter or a public batch API.

A Revision comparison case names each revision’s documents literally by source key and acquires them only when it runs, into two Catalogues of its own, as direct comparison does under ADR 0039: Client-side revision comparison. Earlier revisions therefore never join the plan’s sources, where they would become dependency candidates of its checks and could make references ambiguous. Its optional acknowledgement file is decoded with the plan, before any acquisition, and its case counts by the disposition its acknowledgements decide under ADR 0040: Acknowledged revision differences. The plan stays at version 1, since older releases refuse the new operation as a configuration error.

The separate esdieff.check-run envelope counts cases rather than combined RFC obligations. Its mandatory source/case summaries are reserved before acquisition or execution, including each comparison case’s classification and a share for each of its documents. Optional whole native reports use only the remaining allowance, preserving exact numerical serialization. Run-level detail omission cannot change authoritative outcomes, completion or exit precedence. Version 1.1 adds comparison cases, and every run report is emitted at that version. See the Check plan contract and runnable example.

Considered Options

A pass/fail-only report hides unfinished work and can let omitted later errors disappear behind retained warnings. Implicit source labels or namespace URIs as identity confuse acquisition, content and model names. Public parser/decimal types or mutable JSON graphs require caller migrations and semantic bookkeeping. Expanding every reference into copied content without byte/work charging permits allocation amplification despite input caps. Full ancestor pointers stored at every node amplify path memory. Freezing sample/author request details now adds decisions without their concrete acceptance cases; only their shared foundation is settled here.

Naming plan sources as a comparison’s revisions would put earlier revisions into every check’s Catalogue, or need a new source role to keep them out. Discovering revision directories inside a plan would make its results depend on the current directory contents, against ADR 0004: Supplied catalogues and checking scope. Deleting unfinished diagnostics alone would misrepresent requested work. Resetting an allowance for requiredness, or adding a second resolver, would bypass cumulative operation limits. Dummy samples and successful supplied-value checks cannot prove model-side capability. A mandatory heap inventory or 54-row DTO would impose unrelated Full storage on Initial/source-only callers. Fixed producer states and wholly optional detail retain bounded admission and the existing result’s fallback lifetime.

0014: Bounded partial ECMAScript pattern capability

Esdieff interprets the pattern data quality using ECMA-262 2025 Unicode u syntax and unanchored matching, as required by RFC 9880 Appendix C.2. Its suggested portable subset does not restrict otherwise permitted syntax.

An initially partial capability uses pinned regress 0.12.0 with optimizations disabled for syntax, and pinned rquickjs 0.14.0 with bundled QuickJS-ng 0.16.2 for matching. Matching guards, parsing, engine initialization, helper evaluation, compilation, matching and destruction occur on one private Rust worker with a 4 MiB stack per operation allowance. The worker starts lazily, reuses its runtime and context, and joins when the allowance is dropped. Syntax checks share the worker without initializing an engine. Supplied patterns and subjects are values passed to fixed internal functions, and the toolkit owns the runtime and allocator choice.

All duplicate decoded capture names, including otherwise valid disjunction duplicates, are unsupported. Capture-name escapes the guard cannot decode reliably are also unsupported. Active Unicode escapes are independently checked for the hexadecimal spelling required by the standard, including inside character classes, capture names and named backreferences. This excludes signed forms erroneously admitted by the pinned parser’s integer conversion while preserving escaped literal backslashes and valid Unicode spellings. An escaped greater-than sign inside a name is independently invalid under the identifier early errors, even though the pinned parser treats it as a delimiter; ordinary and class escapes for that character remain valid. Decimal quantifier endpoints are compared without machine-integer conversion: reversed bounds establish invalid syntax; endpoints at or above 1,000,000 exceed the capability. Unknown parser or engine rejection does not automatically establish invalid syntax.

Maximum supplied sizes are 4 KiB of pattern text and 1 MiB of subject text, measured in UTF-8 bytes. Maximum group nesting is 64 and maximum total alternatives is 512. The engine’s configured allocation limit is 16 MiB and its stack limit is 256 KiB, with the remainder of the 4 MiB worker stack reserved for Rust and engine frames. The allocation limit checks requested growth before allocator rounding and bookkeeping, so it is not an exact ceiling on the engine’s reported allocation counter. Configuration may only reduce supported size, structural, allocation and stack settings. Zero cannot disable these bounds.

Matching initially supports decoded capture names of at most 124 UTF-8 bytes. This conservative engine capacity is applied after syntax admission, so a valid longer name can remain syntactically valid while matching is incomplete. Escape spellings are charged by their decoded UTF-8 bytes. The engine permits at most 254 explicit capturing groups because its 255 capture slots include the whole match. Its named-group scope counter has a maximum of 255 and can be exhausted by ordinary alternatives when any named capture is present. Those known capacities are engine compile limits, not syntax violations. Other invalid group name exceptions retain their distinct unsupported classification.

Regexp work uses a request-wide default allowance of 100 polls, with a maximum configurable allowance of 10,000. Each engine call spends one entry poll, and interrupt callbacks spend the remainder. The next poll interrupts execution. Entry polling keeps short matches bounded even when the reused runtime does not reach its internal callback interval. Its accumulated cooperative engine duration defaults to 25 milliseconds and may be configured up to one second. Zero allowance or duration returns a work limit. Alternatives, array elements and declared-value candidates receive no fresh allowance. These count engine polling and cooperative elapsed time, not exact instructions or a hard wall-time deadline across parsing and compilation.

A minimal-limit runtime probe at engine startup and engine allocation source checks establish gross enforcement of the configured allocation setting for this dependency pin, including feature-unified embeddings. If the linked runtime cannot establish enforcement, matching is unsupported. The toolkit accepts no caller runtime or custom allocator. The promise excludes allocator rounding, bookkeeping overhead, total resident memory, arena reserve overhead and Rust allocations. Parsing and regexp compilation have finite supplied sizes and structures but lack externally enforced cancellation.

Selected text samples, choices and declared-value consistency use the same matching implementation through the library’s ordinary operations. Syntax and matching share one paid sequential worker stack slot from the original operation allocation. Matching reserves its configured engine allowance from that same allocation before engine work. The allowance owns the worker, which owns every engine object. Copied request text is admitted against the original allocation allowance before transfer. Each match compiles its own expression, clears pending exceptions and collects garbage before the context is reused. No runtime, compiled expression or source string escapes to callers. Successful matching fills the fixed text obligation of the existing sample inventory without establishing model-wide pattern meaning or general satisfiability.

FullBaseline establishes available model matching meaning through compilation with that same implementation and its qualified guards. No subject or match is needed: the obligation concerns the adopted Unicode, unanchored interpretation and available capability, rather than existence of a satisfying value. This compile-only operation retains the original work, allocation, worker-stack, engine-stack, interrupt and cooperative-duration allowances. Matching-only capacities can therefore leave M048 unfinished independently of M047 syntax. Successful compilation does not guarantee completion for every future subject or add external cancellation to compilation.

Resource exhaustion during worker startup, joining, engine initialization, helper evaluation, compilation or matching leaves affected conclusions incomplete under ADR 0009: Bounded processing and reporting. Independently established syntax errors remain RFC findings; unsupported capabilities and operational limits are neither syntax violations nor acceptance restrictions. Updates require renewed capability evidence rather than silently changing the standards baseline or claiming complete conformance from a finite fixture set.

The toolkit owns thread and runtime lifecycle so callers receive pattern conclusions without executable discovery, JavaScript or resource bookkeeping, following ADR 0010: Domain-oriented library and caller simplicity. Reusing one worker and runtime avoids repeated startup for sequential pattern checks. Expressions remain uncached so retained state and cache policy do not grow with model size. Broader support and expression caching require separate evidence.

Considered Options

Rust regex and fancy-regex directly change Unicode class and backreference semantics. Their finite matching controls do not establish ECMAScript fidelity. OXC exhibited relevant false-invalid and false-valid syntax outcomes, so it is not a syntax authority for this capability.

Regress in a supervised Rust process can avoid a C matcher and enforce external termination across syntax, compilation and matching. It requires worker packaging/discovery, IPC and platform-specific memory controls for library callers. It becomes the preferred alternative if excluding C or strict external process containment becomes a requirement.

The selected QuickJS-ng path adds C compilation and a C/FFI safety boundary while providing real regexp interruption and common tracked allocation limits within an ordinary Rust operation. Those controls are narrower than process isolation, and do not establish C memory safety or a complete ECMAScript conformance guarantee.

0015: Bounded value equality in a resolved data context

const restricts data to one value, and uniqueItems requires array elements to differ. RFC 9880 Appendix C defines those constraints at the information model level. It associates ordinary numbers, text, arrays, and maps with their JSON values, while Appendix C.2 and Section 4.7.1 give additional abstract meanings to format and sdfType. Equality must identify which of these meanings it established. This is an RFC interpretation for the supported ordinary-value scope, not an adoption of every JSON Schema rule.

Esdieff compares supplied conventional JSON values in an established shared effective data context. The result is equal, different, or undetermined, with its basis, available source identities and locations, and any operational or semantic limitation. The original JSON and numeric tokens remain available. Equality is separate from admission: equal values need not satisfy the effective type, null admission, bounds, format syntax, or other applicable constraints. No default is inserted, following ADR 0005: Nullability and presence.

Ordinary values

When the effective context establishes ordinary JSON value semantics without an additional meaning that could change equality:

  • Null equals null. Booleans compare by their Boolean value. Different JSON value kinds differ; no string-to-number or Boolean-to-number coercion occurs.
  • Numbers compare their exact mathematical decimal values using ADR 0012: Exact numbers and JSON input policies. For example, 10, 10.0, and 1e1 are equal; -0 equals 0; 0.1 differs from 0.10000000000000001; 9007199254740992 differs from 9007199254740993. Integer versus number is a constraint distinction, not a second JSON number kind. A number capability failure does not justify equality even for identical retained tokens.
  • Text compares the decoded sequence of Unicode scalar values. JSON escape spelling is irrelevant. Case folding, Unicode normalization, and locale collation are absent: "on" equals "\u006fn", while composed "é" differs from "e\u0301".
  • Arrays are ordered. Equal arrays have equal lengths and equal corresponding elements in their established item contexts. [1,2] differs from [2,1]; [10] equals [1e1] in an ordinary numeric item context.
  • Maps are unordered collections of decoded, case-sensitive string keys. Equal maps have the same key set and equal corresponding values in their established entry contexts. A missing entry differs from a present null entry. JSON member ordering has no equality meaning. Acceptance restriction A002 applies before usable map comparison at every depth, including opaque content; duplicate decoded keys do not choose a first or last value.

Compound equality requires every necessary comparison to establish equality. One definite difference establishes difference if unresolved information elsewhere cannot alter it. A different ordinary map key set or array length is decisive in an established ordinary structural context. An unavailable leaf does not erase an independent definite difference. If neither equality nor a decisive difference is established, the compound result is undetermined.

Additional meanings and unavailable contexts

A JSON representation comparison is a separately identified result. It cannot by itself establish that differing representations denote different abstract values. For example, differently offset date-time strings may denote the same instant, differently cased UUID text may name the same UUID, and alternative encodings may describe the same byte sequence. Meaning-specific comparators follow the separately adopted civil-time, resource and conventional JSON decisions; equality does not introduce additional normalization.

For a base format or sdfType, equality of supplied representations can establish abstract equality only when both operands’ denotations and a common compatible deterministic interpretation have been established. Recognizing a format name does not establish that interpretation or make an invalid or uninterpreted representation denote a value. Identical "not-a-date" strings therefore remain undetermined in a date-time context, even though their separately requested JSON representation comparison is equal. A meaningful interpretation may establish abstract equality without proving admission under all other constraints. Differing representations remain undetermined until an adopted meaning-specific comparator establishes equality or difference. Conventional byte-string and unix-time input remain those in ADR 0007: Generated SDF and sample JSON; those conventions alone do not provide all equality, representability, or normalization rules.

The comparison scope includes null in established compatible date, date-time, time, uri, uri-reference and uuid contexts. Null equals null; null and an established nonnull formatted value differ. An invalid nonnull representation, unavailable denotation, unknown equality-changing extension or incompatible alternative does not establish that difference. Null equality remains separate from admission, including when nullable:false excludes null. Restricted Direct meanings retain their existing boundaries. Null/null records no unperformed nonnull representation scan or knowledge query; mixed pairs retain the nonnull meaning actually established. Byte-string and Unix-time null handling follows the same separation.

Under ADR 0018: Civil date and time sample conventions, two established Gregorian dates compare by their calendar date. Equal decoded full-date text denotes the same date; different validated full-date text denotes different dates under the fixed-width convention. Both operands must establish denotation before a calendar conclusion, even when their text differs. JSON escape spelling is irrelevant. This adds no date ordering, epoch conversion, timezone or leap-knowledge requirement.

Two established dated date-times compare by their UTC instant. Numeric offsets adjust the Gregorian date and minute, exact fractional seconds ignore trailing zeros, and an inserted second retains its distinct slot. Offset annotations, letter case and JSON escape spelling do not distinguish instants; Z, +00:00 and -00:00 can therefore denote equal values under the recorded convention. Both denotations and a common compatible meaning are required before either equality or difference. Missing needed adjustment knowledge cannot supply a mismatch proof. This supplies no ordering, epoch coordinate, timezone database or date-free time comparator; differing nonnull time representations retain their unavailable comparison meaning.

Under that conventional channel, two established canonical byte strings compare by decoded JSON text, with complete canonical validation charged for each operand before comparison. Two established nonnegative POSIX coordinates compare by exact mathematical value, sharing the catalogue’s remaining numeric allowance. A malformed byte operand or unresolved negative POSIX denotation prevents abstract equality, including identical tokens. One established operand can supply truthful partial abstract support while the pair remains undetermined. Different conventional JSON domains may exclude a potential alternative only when its established context proves that exclusion; an unknown potentially matching alternative remains relevant.

Each pair carries its own supporting references and actual limitations. Const and enum reduction preserve only the decisive complete witness or necessary universal-exclusion proof. An earlier unknown or rejected enum candidate cannot leave limitations or discarded proof after a later definite match. Request consultation remains cumulative across these attempts. Unknown potentially matching candidates prevent an unjustified universal rejection without erasing independent established areas.

A decisive compound difference retains its actual leaf or structural rule and the established enclosing arrays and maps on that path. Completed siblings do not supply that proof, even if they established another ordinary or abstract meaning. Equal and undetermined pairs retain their complete or partial aggregate support. Independent abstract-value assessment and request consultation remain visible separately from the decisive const proof.

RFC 9880 Section 4.7.2 gives choices inherited qualities and explicit overrides, with alternatives that can overlap. Choice admission does not select an equality interpretation. Neither alternative ordering nor a first successful admission result establishes a common meaning for two operands. When alternatives introduce incompatible or unresolved interpretations, affected equality remains undetermined unless the library can establish a common compatible interpretation for both values. It may retain surrounding ordinary map or array structure and independent siblings where that meaning is unaffected. An equality consumer must not select whichever alternative produces its preferred verdict.

An unknown critical feature, unresolved effective context, unknown equality-changing extension, or unsupported abstract meaning gives undetermined for affected comparisons, including identical input when its common interpretation cannot be established. Established surrounding ordinary structure can still supply independent differences. Unsupported decoded string values remain scoped unavailable according to ADR 0012; unsupported decoded keys can prevent usable map construction. The library derives the resolved context from the effective description. Callers do not rebuild reference, item, property, choice, or extension meaning from generic JSON maps, following ADR 0010: Domain-oriented library and caller simplicity.

Known data-description roles remain distinct. In particular, the restricted items vocabulary in RFC 9880 Appendix A does not turn framework-admitted wider direct-item content into an ordinary full data description. A needed unsupported item interpretation remains undetermined. Appendix A permits items independently of an optional type. When items is present but context derivation has not established its applicable array structure, comparison remains undetermined instead of discarding the item meaning. Thus identical ["not-a-date"] representations under {"items":{"format":"date-time"}} do not establish abstract equality.

Object property meaning likewise requires an established applicable object structure: Appendix A’s compound-type requires type: "object". In full descriptions and restricted direct-item descriptions, properties without an established object structure gives an unavailable context instead of being discarded as an annotation. For example, identical [{"stamp":"not-a-date"}] values under {"type":"array","items":{"properties":{"stamp":{"format":"date-time"}}}} remain undetermined. With an established object structure, object-item properties contain full descriptions, so ordinary nested structure there can be compared in its established context. These guards preserve independently definite differences in surrounding ordinary siblings. Unknown qualities are retained with their source and are never guessed to be harmless equality annotations.

Null equality and primitive representation comparison are not a substitute for the chosen alternative’s null and type constraints. A format or sdfType is never ignored just because a string or number can be decoded. Unknown alternatives do not become a definite const rejection solely because one representation differs.

Finite work and constraint consumers

Comparison shares request-wide finite numeric, decoding, structural comparison, pair-count, parsed-node, and location-materialization budgets. Input size, container depth, per-source node count, numerical coefficient and exponent capability remain those in ADR 0012. Work is charged before traversal, string/key comparison, exact numeric comparison, repeated pair comparisons, or derived pointer allocation; arithmetic remains checked. Production ancestry is compact or shared, and pointers are materialized only as needed within finite budgets. Raising one budget does not silently remove another bound. A semantic-work or required-location-handle capability limit leaves the affected conclusion undetermined. Available source identities and spans remain usable when a rendered pointer cannot be materialized. Pointer presentation omission preserves the established verdict and is reported separately, following ADR 0009: Bounded processing and reporting.

A scalar or compound const comparison uses this one equality contract: equal establishes the equality part of matching, different establishes a mismatch only on its stated semantic basis, and undetermined leaves that part incomplete. Other constraints continue to contribute their independent results.

For uniqueItems: true, one established equal pair disproves uniqueness. All required pairs established different prove uniqueness. An undetermined necessary pair prevents a positive uniqueness conclusion unless another equal pair independently disproves uniqueness. Exhausting pair or comparison work is undetermined, never evidence that items differ. An empty or singleton array is vacuously unique without comparing values; decoding, item checks, and other constraints remain separate. False or absent uniqueItems requires no uniqueness comparison. A consumer may use indexing or fingerprints for candidate selection, but those cannot replace exact equality or introduce a different semantic policy.

Initial comparison investigation defaults retain ADR 0012 and align with the shared workflow defaults in ADR 0013: Shared workflow and report guarantees: 500,000 parsed nodes per request, 10,000,000 shared context/structural/string/key work units, 8 KiB per rendered pointer and 8 MiB cumulative pointer presentation output/work. Numeric work retains 2,000,000 units. Comparison-specific additional caps are 32 MiB of decoding work and 100,000 operand-pair comparisons per request. Nonzero finite configuration and supported stack limits are validated before work; these are implementation capability, not RFC limits or a performance claim. Product implementations may improve algorithms while keeping the same three-result semantics and supplying bounded evidence for changed finite-work accounting.

Considered Options

Raw-text equality would incorrectly distinguish escape spellings, numeric notation, and map member ordering. Machine floats or default numeric JSON decoding could silently merge distinct numbers before a const or uniqueness conclusion. Unconditional deep JSON equality would invent abstract meaning for formats and sdfType; treating every different representation as an unknown would unnecessarily defer ordinary scalar and compound constraints. Normalizing dates, URIs, UUIDs, or byte strings here would settle separate semantic decisions without their evidence. Keeping equality logic in each constraint consumer would allow const and uniqueness to disagree. Unlimited pairwise work or ancestor-pointer copying would violate the finite-work contract.

0016: Selected samples with explicit admission and coverage

A sample checks one supplied value against one selected effective data description. The selected description can be a Property, an sdfData definition, an Action input or output, or an Event output. The library owns acquisition, reference composition, applicable constraint interpretation, and scoped limitations; callers do not rebuild these from JSON maps. This follows ADR 0010: Domain-oriented library and caller simplicity.

The result distinguishes admitted, rejected, and undetermined from model findings, requested-work completeness, and the shared report disposition. Admitted establishes that this value satisfies every applicable constraint in the selected effective description under the recorded baseline. Rejected requires an established violated constraint whose meaning is unaffected by outstanding uncertainty. Unavailable needed context, unsupported applicable semantics, and exhausted work do not establish rejection. A definite rejection can coexist with incomplete other requested checks. A sample never establishes that the whole model is valid or that the description admits some other value.

Requests select the declaring effective document and a typed description kind plus its effective definition pointer. They supply conventional JSON bytes or an Esdieff typed JSON value, preserving exact numeric tokens and separate sample identity. Source, effective, and sample locations retain their different meanings. Missing sample input is an invocation error; JSON null is a supplied value. No default is inserted, following ADR 0005: Nullability and presence and ADR 0007: Generated SDF and sample JSON.

The immutable esdieff.sample/1 inventory covers the nine admission areas specified in the selected-sample contract, including recursively applicable constraints, alternatives, and abstract meanings. Its requested unit is a sample area, not a diagnostic, branch, path, or model-assessment area. Applicable unsupported work remains unfinished under that identity; supporting more of it does not redefine the request. Inapplicable work is established as such, rather than inferred from missing implementation. A new semantic scope requires a new inventory identity.

Effective alternatives inherit shared qualities with their explicit overrides, as RFC 9880 Section 4.7.2 specifies. One completely established matching effective alternative supplies an existential admission witness. Checking different constraints in different branches is insufficient. Unresolved potentially matching alternatives prevent rejection unless an independent proof applies to every possible admitting alternative. Admission never chooses an equality interpretation, following ADR 0015: Bounded value equality in a resolved data context.

Ordinary map admission follows RFC 9880 Appendix C.5. An established type: "object" checks the whole required list for presence and checks each described present value. Entries without a description remain unconstrained, and required can name such an entry. An absent optional description requests no value, reference or unsupported child constraint. Null is present and retains its own admission rules. Unknown enclosing map meaning or unavailable member identities cannot prove absence. A missing required entry has the actual containing sample map as its location and the authored required token as its related model location.

Map constraints conjoin their own presence requirements and needed children. A child choice returns its result to that containing map; its witness does not admit the whole map. A potentially admitting unknown choice clears its own tentative rejections while preserving independent outer or sibling findings. A definite missing entry can therefore reject a map whose other applicable child work remains unfinished. The original work and numeric allowances remain shared across all children and branches.

Ordinary arrays follow RFC 9880 Appendix C.4, combining inclusive exact counts with every actual element’s established item description. Direct-item vocabulary retains its restricted role; Full properties and alternatives can describe nested arrays. Element choices conjoin with the containing array, while a whole-array choice needs one whole-array witness. Shared description roots and alternatives retain their identity and origins as actual present interests accumulate. Completed common and applicable family checks are reused even when they found malformed model conditions. An empty outer array requests no item value and grants no capability to its deferred item subtree. Compound const and uniqueness use the common equality contract in ADR0015. Unknown needed item or equality meanings and finite work limits remain explicit, without erasing independent established violations.

Absent authored type alone does not create an unfinished admission obligation. A Full ordinary supplied array or map with established absence of items, properties and required may complete its structural family without a const or active uniqueness quality. Authored child descriptions still need their applicable structure; an unavailable count remains unfinished even when uniqueness establishes an independent result. This fills existing sample areas under the same nine-area inventory rather than changing their membership.

Sample reports use the distinct sample operation in report version 1.1 and retain existing check/inspect meanings and unknown-operation guards. Model conditions, sample constraint conditions, and operation conditions remain distinguishable. Strict warnings can fail shared disposition while sample admission remains admitted. Needed model errors can fail disposition while sample admission is undetermined. No whole-model assessment is requested implicitly.

Selection, ownership, limits, locations, counters, report fields, compatibility, command acquisition, and concrete cases are pinned in the selected-sample contract, extending ADR 0013: Shared workflow and report guarantees. These are toolkit interface decisions; they do not adopt missing format, item, copied-reference, or other standards interpretations.

Considered Options

A Boolean validation result would collapse unavailable semantics into acceptance or rejection. Reusing model-check disposition as admission would make strict warnings and unrelated model failures change the meaning of the sample. An inventory defined as implemented checks would silently turn unfinished constraints into success. Selecting only a JSON pointer without a description kind would confuse map entries, affordances, and Action input/output roles. Inserting defaults or converting numeric values through a machine float would change the supplied sample. Requiring whole-catalogue success would obstruct usable selected descriptions when an unrelated supplied definition is faulty.

Treating properties as a closed list would add an exclusion rule absent from the adopted map semantics. Combining different branch witnesses per entry would fabricate a matching whole alternative. Resolving raw property descriptions before whole branch overrides would activate discarded references and irrelevant constraints.

0017: Reference-preserving sdfThing authoring

The first Model authoring operation creates a new sdfThing from explicitly selected reusable sdfObject definitions, caller-chosen Given Names, namespace intent and Composition patches. Its authoring contract fixes ownership, generated-content access, fidelity, optional checking and explicit CLI output behavior. It builds on ADR 0013: Shared workflow and report guarantees and ADR 0007: Generated SDF and sample JSON.

Generated SDF retains an authored sdfRef to each selected sdfObject’s established global name and the caller’s patch, rather than silently flattening or transplanting reusable definitions. The generated catalogue contains the immutable supplied documents and the new document. Namespace mappings are explicit; source namespace prefixes are not copied as if they were global identities. Global contributor ambiguity and missing required dependencies leave affected work incomplete. Copied references inside the selected definitions follow ADR 0036: Copied reference relocation. A local-only sdfObject is a scoped unsupported authoring capability in this first reference-preserving operation, not invalid SDF. No namespace is assigned to its source without a request.

Explicit declaration requiredness uses an abbreviated Referenceable name only when that Given Name is valid in the abbreviated form. A Given Name containing # is preserved and selected by an encoded same-document SDF pointer reference instead, following RFC 9880 Section 4.5. Decoded JSON Pointer tokens and URI-fragment encoding remain distinct. This rule authors new declaration references. Inherited requiredness needs no rewriting, because copied pointers relocate to the new sdfThing’s coordinates.

Generation and fidelity are distinct from requested Model checking. Complete generated bytes can coexist with undetermined fidelity or a failed assessment, and remain available as a clearly tagged candidate for library inspection. A faithful result requires established composition and preservation of known semantics, Given Names, accepted number lexemes and permitted opaque structure; uncertainty about context-dependent opaque meaning leaves fidelity undetermined. Restrictive refinement is the RFC’s convention, not a general subset proof promised by authoring. An initial check can establish its own narrower result without establishing full RFC coverage.

The CLI emits a generated document only when generation and fidelity are complete and any requested check passes under the selected warning policy. Report and document destinations are separate, with one stdout user at most. Existing outputs require an explicit replacement option; input aliases and report/document collisions are always refused. Files are committed individually through bounded staging, without promising a transaction across two files or stdout. Inputs are immutable and never output targets.

Generated bytes and request-plan parsing are finite and charged before allocation or emission. Shared source, metadata, parsed/derived content, work, path and report limits apply across authoring and its optional checking; phases do not reset them. This follows ADR 0009: Bounded processing and reporting and ADR 0012: Exact numbers and JSON input policies.

Considered Options

Automatically copying local-only sdfObject definitions into the new document or flattening effective content can move opaque semantics out of the context that gives them meaning. Inventing a namespace for a supplied document changes its contributed identities. Automatically choosing prefix spellings or collision winners hides caller intent. Requiring all sample support or specialized checking would postpone ordinary established composition without improving its fidelity. Treating candidate availability as fidelity or completed checking hides independent limitations. Implicit overwrite or combined report/document stdout makes authoring unreliable in command-line workflows.

0018: Civil date and time sample conventions

The civil-time contract selects conventional representations and a bounded interpretation of exceptional labels.

FullBaseline recognizes the corresponding model interpretations without a test value. M049 model meaning is independent of denotation for any particular constant or selected value, so recognizing a format never records an adjustment knowledge consultation. Constants continue to use the actual borrowed operand and its established temporal denotation under this decision.

Civil date-time, date, and time samples use decoded JSON strings representing RFC 3339 date-time, full-date, and full-time, respectively, following RFC 9880 Appendix C.2. Their abstract meanings remain distinct from the conventional text representation and from document metadata modified, whose date-time convention requires Z. The grammar, exact fractional seconds, Gregorian calendar, case and numeric offsets follow RFC 3339 Sections 4 and 5, without additional limits imported from a calendar library.

The selected sample convention uses T/t between date and time and Z/z or a signed HH:MM offset. It preserves -00:00 as known UTC time with an unknown local offset under the recorded RFC 3339 baseline. RFC 9557’s changed Z annotation and its timestamp suffix grammar are separate baseline and representation decisions. Invalid conventional forms give a sample representation rejection; unsupported interpretation, needed absent leap knowledge and exhausted capability give an affected undetermined conclusion. No such limitation becomes an invented RFC-invalid diagnosis.

Dated leap-second meaning uses deliberately recorded IERS knowledge after offset adjustment. A positive inserted second is admitted only on an established insertion date; a known noninsertion or impossible UTC slot rejects it. A possible leap boundary outside recorded knowledge remains undetermined, including second 59 when an unestablished negative adjustment could remove it. Date-free time admits ordinary clock seconds 00..59 without assigning a date; a possible inserted-second label 60 remains undetermined because its eligible leap-label interpretation is unestablished. RFC 3339 full-time intentionally has no date, so this is not a missing required field or proof of invalidity. This date-free convention does not assert that the coordinate exists on every day.

Locations, admission areas, finite controls and aggregate outcomes follow ADR 0016: Selected samples with explicit admission and coverage. Temporal denotation and comparison remain separate under ADR 0015: Bounded value equality in a resolved data context. The adopted comparator scope includes Gregorian dates under the existing full-date convention: both operands must establish valid calendar dates; the same calendar date is equal and different calendar dates differ. JSON escape spelling does not alter the decoded date. This requires neither a timezone nor leap-second knowledge and introduces no ordering operation, epoch conversion or additional date representation. The civil-time contract pins concrete forms, knowledge scope and representative observations.

Dated date-time equality compares established UTC instants, excluding offset annotations from value identity. Subtract the numeric offset with Gregorian day/year rollover, including UTC dates beyond the four-digit source range. T/t, Z/z, +00:00 and -00:00 retain their admitted meanings. Fractions compare as exact decimal digit sequences with trailing zeros ignored; absent and all-zero fractions coincide. An inserted second remains a separate slot from the preceding ordinary second and the next day’s first second. Both operands must establish denotation, including any needed recorded adjustment knowledge, before the comparator can conclude equality or difference. Date-free time equality beyond identical denoting representations remains unavailable.

The shared evaluator establishes civil denotation for selected samples and declared-value consistency. It retains ordinary text-length checks and compares Gregorian dates or dated instants after both denotations and their common format are established across every relevant alternative. The fixed-width full-date convention permits validated decoded text to establish calendar equality or difference without retaining a normalized temporal value. Full date-time comparator capability includes established compatible nullable contexts and recursive projections; model capability recognition alone makes no claim about an actual operand’s denotation or adjustment knowledge. Formatted-null comparison follows ADR 0015; null/null requires no nonnull scan, and a mixed pair requires the nonnull denotation. One admitting alternative supplies no equality interpretation; unknown or incompatible interpretations, restricted Direct meanings and exhausted work remain scoped limitations.

Reports identify consumed representation convention as ADR0018-selected-representation and record C72 knowledge only when an actual slot query uses it. Request-level use survives discarded branch findings and optional presentation omission. A temporal unknown contributes one specialized incomplete detail for its cause while independent unfinished work keeps its own details and the existing area counts. Original counters, owner shares and first-result lifetime remain shared and unchanged.

Implementation rationale

The private borrowed capability shares Gregorian arithmetic and recorded leap facts with metadata modified; each consumer keeps its own representation grammar. Instant comparison temporarily borrows exact fractional text alongside a UTC Gregorian date, minute and distinct second slot. It retains no epoch coordinate or normalized value after comparison. Two text passes and bounded calendar work are precharged, and temporary comparison storage is included in the existing allocation accounting. This avoids a second facts table, a public parsing API, rounding or an implicit comparison convention.

Considered Options

UTC-only parsing would conflate model metadata with data formats. A library’s year range, nanosecond precision, timezone plausibility filter or automatic leap normalization could silently narrow the RFC’s representation and erase exceptional forms. Identical-representation-only date-time comparison leaves routine offset-equivalent event timestamps unfinished; including offset annotations in identity would distinguish established representations of the same instant. Automatically refreshing IERS data would change a conclusion without a recorded baseline change. Treating the absence of a future insertion announcement as a universal no-leap proof would mishandle future positive and negative adjustments. Assigning a host date would invent an absent input. An existential some-valid-date interpretation could admit a date-free inserted-second label, but SDF and RFC 3339 do not select that quantifier; it remains a deliberately deferred alternative. Admitting a space separator is an available application convention under the RFC’s note; this contract selects the named T/t production and diagnoses other selected-representation forms without denying their possible abstract meaning.

0019: URI, URI-reference and UUID sample conventions

RFC 9880 Appendix C.2 gives format an abstract information-level meaning. uri and uri-reference refer to RFC 3986; uuid refers to RFC 9562. The URI and UUID sample contract supplies conventional JSON inputs and the scope of established conclusions, following ADR 0007: Generated SDF and sample JSON, ADR 0015: Bounded value equality in a resolved data context and ADR 0016: Selected samples with explicit admission and coverage.

FullBaseline establishes these named model interpretations independently of actual operands. This M049 assessment does not establish scheme-specific admission, target identity or general comparator capability. A constant still needs its actual contextual denotation and adopted equality. Recognizing a model selector alone does not consult the sample representation facts.

The URI representation check assesses generic RFC 3986 syntax: URI requires a scheme and permits a fragment, while URI-reference also permits relative and empty forms. Fragment-free absolute-URI is a separate production. A successful generic check establishes its stated representation conclusion, not full abstract-format admission when needed scheme validity is unavailable. Scheme-bearing positive admission requires an established compatible meaning including applicable scheme-specific requirements; unsupported needed scheme meaning stays undetermined rather than being rejected by an allowlist. Relative-reference expression admission requires no target resolution, while any needed base or inherited scheme meaning stays explicit. No implicit IRI conversion changes the conventional channel. RFC 3986 Sections 1.1.1 and 4.1 distinguish generic and scheme-specific scopes. RFC 9110 Sections 4.2.1 and 4.2.2 require HTTP(S) authority form and a nonempty host: https:device and https:// both match generic grammar but fail those scheme requirements. A finite HTTP/HTTPS identity-syntax capability can establish ordinary cases without promising an exhaustive scheme inventory. Scheme validity supplies no claim of resource existence, DNS lookup or retrieval.

The conventional UUID input is a bare JSON string in the 8-4-4-4-12 hex-and-dash form, including upper, lower and mixed-case hex. Decode it to 16 bytes in text/network order. Esdieff adopts an opaque 128-bit value interpretation for the base UUID format, without a version or variant allowlist. Nil, Max, modern versions and reserved layouts remain representable without certifying their finer structure, interoperability or generation. This does not claim that every finer layout is defined. Any requested layout-specific meaning must retain the applicable variant requirements of RFC 9562 Section 4.1 and the corresponding version/layout requirements; unavailable needed meaning stays undetermined. UUID URNs, braces, unhyphenated text, numbers and binary arrays are other representations outside this conventional channel. Their failure here is an input-convention finding, not a universal claim that their abstract UUID is invalid. The bare-text convention and opaque interpretation follow RFC 9562 Sections 4 and 6.12.

With a common established UUID interpretation, equal decoded bytes establish value equality and differing bytes establish difference. Additional admission constraints remain separate. URI equality retains the conservative guarantee of ADR 0015: Bounded value equality in a resolved data context: compatible established identical denotations can establish equality; differing representations remain undetermined without an adopted purpose-specific comparator. No URI normalization or target-identity policy is introduced. A URI-reference denotes a reference expression; interpreting its target can require an explicit base and compatible meaning. A model namespace, source path or acquisition URI never supplies that base implicitly. Sample checking performs no network acquisition, as identification does not imply retrieval under RFC 3986 Section 1.2.2.

The scope also includes the formatted-null comparisons in ADR 0015. Complete UUID comparison therefore includes nullable values rather than requiring explicit nullable:false for model comparator capability. Known absent, true and false Full nullability are supported; unavailable or restricted Direct nullability retains its limitation. Recognizing URI or URI-reference null comparisons does not establish their still-unavailable general nonnull comparator capability. The model meaning contract describes these coverage limits.

Considered Options

Treating every generic URI success as abstract-format admission would admit known scheme-invalid identifiers. Deferring unsupported needed scheme meaning preserves that distinction without promising an exhaustive evolving scheme inventory. A URL parser that repairs input, insists on an HTTP host for every scheme, normalizes paths or accepts Unicode can change RFC 3986 inputs silently. Requiring fragment-free absolute-URI for data would confuse a distinct grammar with URI. Restricting UUID versions/variants beyond its text grammar changes opaque admission without proving generation provenance. Accepting UUID URNs as the same conventional channel is plausible but leaves format input less distinct; URNs remain URI input. Raw UUID text equality would incorrectly distinguish hex case. URI string inequality and automatic normalization would settle separate equivalence questions without a chosen purpose or base.

0020: Owned effective views and nearest origins

An effective result borrows immutable catalogue sources and owns compact derived records; its typed and generic views borrow that result. Exact scalars retain original lexemes and source locations, while effective locations identify the consuming document and path without fabricated source spans. Additive effective types share the source class and data-role rules, following ADR 0010: Domain-oriented library and caller simplicity and ADR 0013: Shared workflow and report guarantees.

Content explanations identify the nearest source, inheritance, override or deletion contributors. A separate default explanation identifies an established implicit semantic value without inserting JSON or inventing a source. Deleting inherited writable:false therefore retains the deletion explanation and the effective true default explanation at the same absent quality. Known named entries retain their own available or unavailable result, and an unavailable descendant leaves independently established subviews accessible.

Same-document references require established definition or full-data roles. The target’s root-reference chain is composed before the consumer’s RFC 7396 Merge Patch, excluding its sdfRef; surviving nested references are processed afterwards. Missing targets, cycles and unknown needed roles remain scoped limitations, following ADR 0006: Scoped reference failures. Internal copied references relocate to the importing definition, and name references select in the resolved model, following ADR 0036: Copied reference relocation. Ordinary source maps retain literal nulls; only actual consumer patches apply null deletion.

Derived composition, capability establishment, evaluation and generation use precharged explicit frames because derived nesting can exceed original input depth. Source evaluation retains its admitted depth and established traversal order. Aggregate node, allocation, reference and work allowances cover all requested models. The shared evaluator counts distinct observations in composed contexts; unchanged local rules can be skipped only when completed source evaluation, the same role and feature context, and unchanged premises establish that replay would repeat the same observation. Completion evidence is retained for actual local map, named-entry and quality evaluation independently of later descendant failures. Presentation limits do not supply that proof.

Object-dependent map-data required shape checking needs a reliable explicit object type in Full data descriptions and Direct items descriptions. An unchanged required array alone does not prove that containing premise survived composition; conservative changed-context invalidation retains the check when a consumer establishes or removes an object type. Borrowed required_entries() presents nonempty authored syntax, not proof of an applicable object constraint or sample-entry presence. Full descriptions retain documentary syntax access independently of applicability; Direct items descriptions preserve their established object guard. This follows the compound-type and jso-items roles in RFC 9880 Appendix A, without resolving wider direct-item defaults or imports.

Considered Options

Reparsing generated JSON as a source invents source spans and duplicates exact-value storage. Replacing source handles with a composite backing would change their location guarantees. A single provenance accessor cannot preserve both deletion and implicit-default explanations. Skipping unavailable collection entries hides known uncertainty. Eager target-descendant resolution makes deleted references block their consumers. Origin kind alone cannot establish unchanged evaluation context.

0021: Explicit modified metadata assessment

Revision metadata needs calendar and UTC-label checking without changing existing callers’ promised assessment scope. The immutable esdieff.expanded.modified/1 inventory combines the unchanged eight-area initial inventory and one modified-date-time/1 area. The modified metadata contract fixes its meaning independently of implementation progress, following ADR 0013: Shared workflow and report guarantees.

The normative RFC 9880 Appendix A modified production is separate from sample format conventions. It admits full Gregorian dates and optional T/t clock labels ending Z/z with exact fractions. Applicable exceptional-slot rules and finite recorded IERS facts reuse ADR 0018: Civil date and time sample conventions; metadata retains its own UTC-only grammar. Checking depends on reliable source Information context without a reference-composition prerequisite, live knowledge update or version/license convention.

One semantic status per requested area survives detail omission and distinguishes established absence of applicable metadata, unrequested work and unavailable inventory membership. The early shared Information pass preserves independent shape errors before unrelated traversal while unknown critical/member meaning defers dependent conclusions. Actual-use temporal knowledge remains visible when presentation is omitted and identifies the finite evidence supporting a conclusion.

Considered Options

Expanding the initial identity would change existing callers’ contract. A modified-only operation would make ordinary callers combine assessments themselves. Freezing future expanded meanings now would add unrelated decisions; arbitrary requirement combinations would add a selection interface with no current consumer need. Reusing a sample parser without constraining its grammar could admit prohibited numeric offsets or import date-free conventions. Host calendars, fixed precision and automatic IERS refresh would narrow accepted representations or change the evidence without a recorded decision. Retained coverage rows alone cannot provide semantic area status because presentation is optional.

0022: Scalar constraints and characteristic states

Borrowed source and Effective data descriptions expose named scalar constraints with exact numeric values, nonnegative mathematical counts and positive steps. Property characteristics separately identify authored values, including inheritance, and specified defaults; existing Boolean access remains compatible. Contributor origins stay separate, following ADR 0020: Owned effective views and nearest origins, and no value is inserted into composed JSON or interaction data.

Named access keeps ordinary callers from selecting raw Quality Names or reconstructing shape checks, following ADR 0010: Domain-oriented library and caller simplicity. Exact numbers and unavailable capability retain ADR 0012: Exact numbers and JSON input policies. Effective inspection’s existing default explanation carries its established Boolean value in human output and an optional JSON default_value field; finite presentation omission preserves the independent typed characteristic. This additive report field follows ADR 0011: Machine-readable report contracts.

FullBaseline also establishes ordinary scalar model meaning in the owning effective description, including final alternatives, without a sample or a general satisfiability proof. Mathematical scalar interpretation and exact const equality remain separate from formal numeric and literal admission. Restricted donor roles, unknown extensions and finite capability retain scoped unfinished observations. The model meaning contract gives the finite completion rules for M042, scalar M043, M045 and M046.

Considered Options

Changing existing Boolean methods to return characteristic states would impose an unnecessary migration. An owned scalar summary would duplicate values and add retained allocation without a demonstrated caller need. A typed numeric-selector argument could enforce the same rules, but named accessors fit the established domain interface and cover text and flags as well. Calling an inherited authored value a specified default would lose the distinction between reuse and absence; treating documentary default data as the source of Property capabilities would conflate two different SDF concepts.

0023: Supplied global composition and dependency scope

Reusable device definitions can span supplied documents. Input order must not choose a definition, erase ambiguity or broaden selected-model work into a catalogue check. The existing effective owner and shared evaluator establish composition, following ADR 0006: Scoped reference failures, ADR 0013: Shared workflow and report guarantees, and ADR 0020: Owned effective views and nearest origins.

RFC 9880 Sections 3.2 and 4 establish namespace contributions and name references. CURIE Syntax Section 3 assembles a prefix binding and reference tail by literal concatenation. Esdieff’s supported supplied lookup compares exact decoded namespace text and percent-decoded RFC 6901 target pointers. It supports ASCII NCName prefixes [A-Za-z_][A-Za-z0-9_.-]*; wider valid prefix characters or unsupported assembled forms produce capability limitations. URI normalization, relative-URL resolution and retrieval are not part of that relation. A binding with path or fragment content retains that content during assembly.

Each candidate’s contribution identity requires reliable source context. Clear-context absence of defaultNamespace establishes no contribution; literal absence with unknown critical features does not. Present mappings always require that context, even when their text appears unrelated. Unavailable acquisitions, envelopes, keys or bounded work remain possible contributors. This conservative limitation can obstruct a unique import in a heterogeneous catalogue, without establishing those candidates as dependencies or assessing their unrelated content.

Several sources can contribute distinct addresses to one namespace. Multiple established contributors to one address remain ambiguous even when their bytes are identical. Source identity plus local node identity distinguishes target-root patches and replay proofs; coincident local node numbers never establish sameness. Established malformed reference syntax or an original unmapped prefix is a definite finding at its original source reference, counted before optional diagnostic retention. Missing mapped targets, unavailable identity and ambiguity retain scoped incompleteness. Repeated observations are not suppressed without complete identical rule, reference and context proof.

Mandatory target-root references keep their original binding contexts and precede consumer patches. Deleted nested references need no expansion. Surviving copied references keep the binding context of their authoring document even when the visible mappings agree, and internal ones relocate under ADR 0036: Copied reference relocation. A copied sdfRequired in a full Data description keeps the separate data-only limitation, preserving raw syntax and independent constraints without adding direct-item semantics.

Catalogue checks independently assess all supplied sources. Selected-model checks independently assess roots and evaluate surviving imported content through the same effective rules, with only the contributor context needed to establish that content. They do not independently assess unused contributor definitions or ordinary Information metadata. Explicit expanded modified assessment additionally checks each distinct actually needed source once with the shared scanner and preflight, preserving ADR 0021: Explicit modified metadata assessment. Unknown contribution or dependency closure keeps the aggregate area undetermined. Cumulative work, derived storage and report limits cover discovery, target selection, composition and scope reporting together; omitted presentation cannot change established findings or completion.

An explanation keeps nearest content origins and carries an optional importing consumer directly through copy, merge, replacement and deletion. Mandatory root chains keep their outer importing sdfRef; a separately composed nested reference establishes a new boundary. Ordinary source content has no consumer, and implicit defaults have no fabricated authored source. The public accessor and optional report location expose the same immutable source handle rather than a fallible ancestor search.

Considered Options

First/last contributor selection and identical-content coalescing would erase ambiguity. URI normalization or URL resolution would silently broaden the equality relation and alter literal CURIE assembly. A full public global index or another resolver would duplicate the existing effective boundary without a caller need. Treating raw absent defaults as semantic exclusion before critical-feature preflight would claim contribution absence without the needed context. Independently checking every contributor subtree would change selected scope into unrelated catalogue work. Choosing copied prefix identity from equal-looking maps would make meaning depend on coincidental spelling rather than authorship. Reconstructing consumers by walking effective ancestors would make an established explanation depend on a second bounded lookup.

0024: Effective alternatives and nullable characteristics

Effective alternatives are ordinary Full data description views derived after established reference composition. They inherit the containing description’s surviving data/common qualities, excluding enum, sdfChoice and Property-only readable/writable/observable characteristics. Each surviving explicit branch quality replaces the shared quality as a whole, including map qualities. Nested alternatives derive after their final inherited context. These meanings follow RFC 9880 Section 4.7.2 and ADR 0005: Nullability and presence.

Reference composition applies its actual Merge Patch deletions first. A branch-local tombstone supplies no explicit override, so a surviving shared quality applies again. The composed branch retains its deletion explanation, while the derived active quality identifies the shared contribution. Ordinary const:null remains an authored value. enum derives text const alternatives with occurrence indices, preserving order, duplicate occurrences, original lexemes and source spans. An enum occurrence is not an invented Given Name or an authored const member.

Inherited qualities retain their donor’s established meaning. Wider Direct items description qualities such as array type, nullable, default, counts and nested items remain opaque and typed-unavailable when inherited; the receiving Full role does not settle them. Established independent bounds and object structure stay accessible. A surviving explicit Full override replaces uncertainty for that quality. Absent direct-item nullable contributes no authored quality, allowing an otherwise established Full alternative’s specified default true. Unsupported optional opaque content does not hide independent base meanings.

EffectiveDataDescription::alternatives() returns an absent, known or unavailable collection. Known collections preserve Choice names or Enum occurrence indices and Field-valued branch handles. Empty, unavailable-container and individually unavailable-branch states remain distinct. A known branch can expose established qualities while other needed meanings or capabilities remain unavailable. nullable_characteristic() shares Declared/SpecifiedDefault states with Property characteristics, retaining source absence and separate contributor origins. Documentary default, required, sdfRequired, null admission and const remain independent; no value is inserted into source, composed JSON or interaction data.

Derived alternatives use a bounded eager arena and dedicated complete-state copying. Copying preserves source/node identity, scalar content, nearest/deleted origins, failure and required-reference evidence, donor meaning and importing consumer/conflict records where applicable. Placement roles, completion and replay eligibility are recomputed after inheritance and overrides. Source observation replay requires its completed source role, source identity, clear feature context and unchanged rule premises. Shared inheritance invalidates whole-map replay and the containing-type premise for required/properties while independent explicit scalar premises can remain unchanged. These guarantees extend ADR 0020: Owned effective views and nearest origins within ADR 0009: Bounded processing and reporting.

Selected samples use that same arena with deferred property work. Root references and raw branch roots settle before final shared qualities and whole explicit replacements; only then do described present entries request child expansion and parameter checks. Copies preserve genuine failures, donor meaning and reference ancestry while resetting interest-dependent completion, exclusion and alternative groups. An absent optional description remains outside the sampled interest, without supplying whole-model capability credit. An unexpected change to a finalized sampled owner fails closed instead of reusing a stale alternative group. One persistent parameter finding store retains its charged capacity across direct checks. Private checking borrows the original operation budget and that separate parameter finding allowance, charging work, derived allocation and pattern resources directly without replenishment. Ordinary finding storage retains its workflow-local policy; effective node and reference allowances remain resolver-owned. Model meaning and Declared-value consistency borrow the same budget, while numeric and equality allowances remain shared across effective model iteration.

Imported alternatives retain the directly captured outer mandatory-root consumer and separate nested importing boundaries from ADR 0023: Supplied global composition and dependency scope. Enum-derived roots carry the donor’s applicable boundary; their const scalars retain the original enum occurrence source. An implicit nullable explanation can carry this consumer context while retaining no authored default source. Conflict storage is precharged when copied, and unavailable nonmap branches prevent complete collection establishment while preserving known identities and independent siblings.

Composed JSON and existing pointer selectors retain their original meaning. Derived alternatives are reached through their collection and direct explanation handles, with semantic coordinates separate from authored source locations. Optional inspection detail reports collection and branch availability, raw derived JSON, per-quality unavailable meanings and nearest/default/consumer explanations. Partial raw JSON preserves opaque values without establishing their meaning. Bounded omission preserves aggregate outcomes and does not imply absence or validity. Check and inspect emit report 1.0 with additive optional fields under ADR 0011: Machine-readable report contracts. This establishes inspection and existing parameter rules, not sample admission, satisfiability or the unfinished full baseline.

Considered Options

A compact overlay could preserve the same public handles with different internal storage. Eager derivation fits the current owned arena and bounds the present implementation; no performance superiority is claimed. Exposing merged parser values would force callers to rebuild donor meanings, origins and unavailable states. Synthesizing pointer-selectable members would change composed JSON and confuse semantic coordinates with authored content. Applying branch tombstones to shared qualities would discard the required shared fallback. Treating every inherited quality as Full would incorrectly settle restricted donor semantics. Copying historical completion or suppressing diagnostics by origin alone would overlook changed rule premises.

0025: Selected numeric samples

Selected samples use the existing supplied catalogue, effective composition and shared reports under ADR 0016: Selected samples with explicit admission and coverage. Model and Sample sources have distinct roles and identities while sharing input admission, acquisition, decoding and exact-number limits. Sample sources never become model roots or namespace contributors, even when their JSON resembles SDF.

A typed JSON value has an owned conventional projection preserving checked number lexemes. Consuming catalogue construction moves eligible projection storage; borrowed construction makes a bounded copy. Dedicated sample views expose optional original spans: original byte samples retain their spans, while typed projections and all their descendants have none. The existing original-source JSON view cannot expose a typed projection as original source text. This preserves the distinction in ADR 0007: Generated SDF and sample JSON.

Each typed constructor meters aggregate metadata, duplicate-name comparisons, text/key scans, projection and decoding against one remaining work allowance. Traversals are charged before they run, so separate affordable phases cannot collectively exceed the constructor allowance.

Sample context includes only facts needed by the selected value. Shared composition and parameter rules select relevant work before scheduling it. Mandatory reference chains and references affecting needed qualities remain required. Descriptive metadata, Property interaction flags, documentary default, declaration sdfRequired and unused descendants do not trigger a model assessment. Skipped descendants have unestablished effective meaning; selected context availability is independent of whole-view completeness. Needed model findings, sample constraint findings and operation limitations keep separate domains and authoritative counts.

Alternative traversal excludes those skipped descendants before scheduling, and copying carries that unavailable state alongside donor meanings and contributor origins. Established alternatives retain their own views under ADR 0024: Effective alternatives and nullable characteristics. Scalar const, enum and nested choices use those final alternatives for whole-branch sample witnesses under ADR 0015: Bounded value equality in a resolved data context and ADR 0016: Selected samples with explicit admission and coverage; needed unavailable equality or compound meaning remains unfinished.

Exact comparisons and positive-step membership use normalized decimal coefficients and powers under ADR 0012: Exact numbers and JSON input policies. They do not round through floating point or expand buffers according to exponent magnitude. A sample operation begins with the numeric allowance remaining after all model and sample parsing and shares that remainder across its comparisons and divisibility work. Independent operations on the immutable catalogue begin with the same remainder. Parsed storage and decoding work remain acquisition dimensions; derived storage and semantic work remain operation dimensions.

The fixed nine areas of esdieff.sample/1 retain their membership while numeric support is added. Unknown type or abstract meaning, unresolved alternatives and exhausted needed work suppress affected proofs. An established independent bound rejection can coexist with unfinished const or other obligations; unsupported applicable meaning never becomes success. Ordinary numeric descriptions can complete the sample profile without certifying model grammar or conformance.

The borrowed Sample result exposes a mandatory meaning view for abstract values, const and final admission. The two area statuses agree with the existing nine-area profile. Each part has a finite set of supporting references and actual limitations; not-applicable areas have empty sets. General Appendix C supports a complete ordinary admission without asserting that const was applicable. A whole alternative witness replaces tentative sample proof and limitations. Undetermined admission has no admission proof, while a necessary independent rejection retains its own support even when another area is unfinished.

Consulted interpretations are a separate request-level observation. Byte-string or POSIX consultation occurs when that operation actually attempts the corresponding denotation or comparison, including an unsuccessful attempt and an attempt later discarded by a complete witness. A recognized name, null-only sample, unknown context or refused preflight supplies no consultation by itself. Mandatory meaning and consultation remain present when optional conditions, locations, witnesses and coverage rows are omitted.

The declaring selector is mandatory identity metadata, independent of displayed-location limits and an older effective result’s remaining storage. One bounded constructor validates source roles, handle ownership and supported roles, measures at most 8192 declaring pointer bytes and precharges exact requested string and ancestry capacities. It has 65664 metadata work units shared across identity lookup, measurement, syntax and copying. Before scanning a key it checks the remaining pointer ceiling; escaped growth stops at that ceiling. This allowance does not resolve references or establish model or sample meaning. Action/Event suffixes can produce an internal description pointer of 8206 bytes. Composition, parameter checks, dependency scope and arithmetic still share one semantic operation budget.

Each sample registration pre-admits an additional 163930 wire bytes: two quoted declaring pointers of 8192 bytes and one quoted description pointer of 8206 bytes cost 147546 at worst JSON escaping, with 16384 for fixed sample fields. The fixed inventory bounds 128 member/scalar slots at 64 wire bytes each (8192), three 256-ID scope arrays plus the single root (3076), nine optional coverage rows (2304) and eight boundary omission records (2048), totaling 15620. Common source records and caller metadata retain their existing reserve. Dynamic conditions, witnesses and explanations draw only from optional detail allowances.

Wire size and owned storage are distinct. The sample allowance uses the existing four-times ownership/DTO reserve, 655720 bytes, plus its share of the existing four-times output/growth reserve. It adds no second output allowance. Within ownership, the two strings request at most 16398 bytes, ancestry at most 8192 machine-word entries, and model/scope vectors exactly one slot each. Fixed state/result records are included. All requested capacities are charged before allocation, and registration checks their combined bound with the mandatory DTO allowance against 655720. A limited model can occupy that slot without an effective arena; derived exhaustion does not prevent reporting the retained selector, causes or known findings.

The mandatory DTO group is precharged before construction, from ownership rather than optional scratch. Its 506140-byte bound covers 512 staged fixed slots at 512 bytes each, two simultaneous sets of up to 769 scope-array values at 128 bytes each, 40988 bytes of simultaneous pointer payload copies, and six 256-entry numeric identity vectors. The supported JSON metadata layouts and bounded literal keys are accounted separately from optional condition storage. At an exact mandatory wire cap, optional scratch is zero; the mandatory identity, minimum result and DTO still fit their pre-admitted ownership group. These are conservative capacity bounds rather than measurements of process memory.

The Sample encoder appends the actual result DTO directly to the shared output after the base envelope. It avoids a simultaneous temporary serialization string while preserving field order, escaping, exact numbers and the existing output-growth allowance. Human fallback retains its real first result while generating replacement metadata. Both result graphs, source records and complete emitted bytes remain charged to their original ownership groups; direct serialization adds no allowance or relaxed growth debit.

Considered Options

Reacquiring a sample through a second catalogue would obscure joint limits and source identity. Reusing original-source views for generated projections would invent byte provenance. Broad selected-model validation followed by diagnostic filtering would spend work and create findings for unrequested context. Resetting numeric work for each constraint would ignore input parsing and allow repeated obligations to evade the limit. Converting numbers to a machine float or appending exponent-sized zero buffers would change exactness or resource guarantees. A separate sample report would duplicate the shared outcome, scope and presentation contracts without a needed domain boundary.

Required declaration relationships and source evidence

Required declaration relationship inspection is an explicit addition to source or effective inspection. It resolves established sdfRequired references, all directly contained affordance/grouping classes sharing a Given Name, and carrying true markers under RFC 9880 Section 4.5; pointer targets require a declaration position under Section 1.2.3, while standalone carrier markers do not instantiate definitions. Relationship completion remains separate from validity and target capability. Outside authored identities have source evidence and capability not_requested; callers request their effective content separately. Copied pointers relocate by coordinate under ADR 0036: Copied reference relocation. Data-only applicability remains a needed, scoped limitation rather than guessed optionality, following ADR 0006: Scoped reference failures and ADR 0023: Supplied global composition and dependency scope.

Effective nodes retain their initial Declaration contribution before ancestor refinements or content donor substitution. Surviving coordinates retain it; genuinely new or reinserted members use their introducing contribution. Source position is independently established before exposing a source Definition. Current effective coordinates, nearest content origins and importing consumer remain separate, including alternative branch copies, following ADR 0020: Owned effective views and nearest origins and ADR 0024: Effective alternatives and nullable characteristics.

One original work, storage, node and reference allowance covers opted-in selection, preflight, composition, relationship lookup and dependency scope. A collection summary survives semantic retention failure and presentation omission; exactly one inspection unit is counted. A request-specific 1024-byte mandatory report reserve covers direct fixed-field emission with no summary JSON map. Seven exact Counts, bounded printable reasons and one first-failure suffix omission fit a 768-byte wire bound and a 512-byte early human prefix. The incremental borrowed diagnostic reason ownership is bounded by 272 bytes within the reserved 4096-byte ownership share; optional owner DTOs and location omission reasons have separate precharges. The concrete inventory is in the Public workflow and report contract, following ADR 0009: Bounded processing and reporting and ADR 0011: Machine-readable report contracts.

Required relationship inspection examines Model definitions and rejects a Sample root before selection in both views, following ADR 0025: Selected numeric samples. Ordinary raw source inspection of a Sample remains available. Sample sources neither contribute declaration identities nor gain model meaning from SDF-shaped JSON.

Considered Options

Composing every referenced target would introduce hidden capability work and make a known relationship depend on unused descendant failures. Reconstructing declaration evidence from final content origins loses contributions overwritten during ancestor refinement. Omitting an exhausted or completed-empty collection would make absence indistinguishable from unavailable traversal. A general summary JSON map or redundant wire request flag would add avoidable backend capacity and cloning obligations.

0027: Unit names and recorded registry guidance

An explicit esdieff.expanded.units/1 assessment adds unit-spelling/1 and unit-registry-guidance/1 to the immutable eight initial areas. It examines final effective Full data descriptions, including distinct consuming coordinates after inheritance and refinement. Source preflight and retained diagnostics do not define the observation population. Independent findings survive unresolved composition, critical features and operational limits, following ADR 0020: Owned effective views and nearest origins and ADR 0023: Supplied global composition and dependency scope. Direct items do not acquire Full unit meaning through an opaque donor; independently explicit Full alternatives retain their established meaning.

RFC 9880 Section 4.7 distinguishes ordinary SenML names from URI names by a colon, and prohibits the unit-subnamespace URN except for a unit name containing a colon. Esdieff inverts Section 7.3’s index encoding once to establish the represented-symbol guard. This interpretation is unit-index-mapping/1, not URN equivalence or assignment. Valid optional RFC 8141 r/q/f components remain separate from that guard. A literal slash violates the Section 7.3 pchar mapping; an encoded pchar has no invented overencoding error. Unestablished nonempty UTF-8 meaning leaves the unit-specific conclusion unfinished. Located replacement advice preserves exact case and scale and is conditional on the intended unit; it never rewrites the declaration or discards suffix meaning.

Literal urn and ietf recognition ignores ASCII case. Noncanonical params or unit marker case is deferred under unit-marker-identity/1: RFC 2648’s template says the whole ietf URN is case insensitive, while RFC 3553 requires exact case-sensitive params comparisons. Encoded markers are separately unestablished identity. Neither case ambiguity nor encoded-marker recognition authorizes normalization. RFC 8141 Section 3.1 forbids decoding NSS escapes for general URN equivalence.

Recognized unit URNs distinguish index defects from optional-component grammar. Empty or non-pchar-first r/q components receive unit.urn_components_syntax, an error grounded in RFC 8141 Section 2. An ordinary top-level question mark receives unit.urn_delimiter_advice, preserving that section’s qualified SHOULD processor recommendation as advice. Question marks within valid r/q/f components remain data. Rejected components and ordinary query delimiters establish no represented symbol, replacement or registry query; a completed classification leaves definition and assignment knowledge unestablished.

Registry guidance uses all 67 SenML and 39 Secondary Units positives from the recorded IANA XML edition, with all nine legacy flags retained. Exact direct symbols are neither trimmed, case folded nor percent decoded. A dated positive is scoped membership evidence; a completed miss finishes qualified guidance while current registration remains unknown. A represented-symbol match does not certify a URN assignment. The request’s RecordedRegistryPolicy permits recorded evidence by default or honestly withholds it according to an embedding’s evidence policy. Withholding preserves independent spelling findings and reports needed evidence as request-unavailable with caller_withheld, rather than pretending the compiled table is physically absent. This follows ADR 0002: Recorded standards baseline.

The borrowed unit summary counts final effective observations once. The four lookup outcomes are disjoint; legacy is a positive subset and URI names are orthogonal. Actual consultation, query completion and admitted evidence remain distinct. Section-specific metadata identifies each extracted table; source_edition identifies their common raw XML without claiming both sections were consulted. No observation means Absent, interrupted work before a comparison fabricates no record, and fixed owner failure reports unavailable/null counts. Finite report admission and one precharged operation allowance preserve these meanings even when every optional detail is omitted, following ADR 0009: Bounded processing and reporting and ADR 0011: Machine-readable report contracts. See the unit contract for bounds and callers.

Considered Options

A symbol whitelist would reject permitted URI names and turn dated misses into false current-negative registration claims. Normalizing every URN would conflate represented-index interpretation with identity and hide the namespace case conflict. An arbitrary caller snapshot would broaden ownership, update and trust contracts without the need served by explicit withholding. Per-name mandatory summaries would amplify storage; one fixed owner retains trustworthy aggregate observations while located findings and replacements remain optional. Smaller admission tied to renderer placement would couple semantic truth to fallback lifetimes; two complete extension DTO generations keep the independently charged mandatory boundary stable.

One combined index/component diagnosis would give slash-encoding instructions for a correct index with a malformed suffix. Treating the ordinary question-mark recommendation as a mandatory component error would also hide its SHOULD qualification; separate grammar errors and delimiter advice preserve those bases.

0028: Bounded effective model pattern syntax

Model authors need syntax findings at the description they use, including imported and overridden patterns. Integrate the syntax portion of ADR 0014: Bounded partial ECMAScript pattern capability through the shared effective evaluator, following ADR 0020: Owned effective views and nearest origins and ADR 0024: Effective alternatives and nullable characteristics. Normative syntax is RFC 9880 Appendix C.2 and ECMA-262 2025 Section 22.2.1.

Provide the immutable esdieff.expanded.pattern-syntax/1 assessment with the initial eight areas and pattern-syntax/1. Full invokes the same syntax rule as M047 in its fixed pattern/format area, while unfinished matching or other applicable meaning remains incomplete. Other profiles, inspection and Sample keep their meanings. The private dependency is exact regress 0.12.0 with its qualified default std/backend-pikevm features, Unicode mode and disabled optimization. Matching and its runtime remain separate work.

Assess established Full string patterns after composition, independently of explicit string type and source shape replay. Direct patterns remain opaque; receiving a Direct donor in a Full branch does not settle its unavailable meaning. Explicit Full overrides can establish it. Deleted/overridden imports are not separately assessed in selected scope. Effective findings point to the consumer path and nearest authored token, and unavailable needed contexts leave the area undetermined without hiding independent errors.

Preserve the independent Unicode spelling/name-terminator and decimal endpoint guards. Duplicate decoded capture names, unverified name decoding and unverified parser rejection remain unsupported. Known malformed syntax is an RFC finding; finite capability and operational exhaustion are incomplete. Matching-only name/capture capacities do not restrict syntax.

The only reducers are 4096 UTF-8 pattern bytes, 64 group levels and 512 alternatives. All traversal, secondary scans, name decoding/comparison/growth and finding growth debit the original operation counters before work or allocation. Pattern findings count before optional retention, and their shared finding vector admits its full new requested capacity from the original allocation owner before growth. Failed retention alone preserves the established conclusion.

Reserve one logical 4 MiB stack slot from the original operation allocation for its lazy joined worker, shared with matching under ADR 0014: Bounded partial ECMAScript pattern capability. All guards, parse/emission and destruction occur inside that worker. Logical dependency invocation/input accounting and finite admission do not provide parser-heap, resident-memory, exact-instruction, cancellation or wall-time guarantees. Callers supply ordinary model work and receive domain results without runtime ownership.

Add a uniform 171 report bytes above each invoking request’s existing mandatory allowance, at both request admission and metadata production. Keep four mandatory-owner buffers, four optional-owner residual buffers and four encoding/output buffers, totaling the existing eight times report ceiling. Fixed owners, literal DTOs, collection growth and simultaneous fallback generations must fit those original partitions for the supported backends. No pattern phase can borrow a fresh budget.

Considered Options

Checking source patterns before composition would assess overwritten/deleted imports and could misstate Direct donor meaning. Reusing source structural replay for syntax would suppress the first actual syntax check. Checking only an explicit string type would miss a present model constraint whose spelling must still be valid.

Leaving known syntax out of Full would conflict with its request for all applicable baseline requirements. Publishing a nine-area Full inventory would confuse partial implementation with complete membership. A separate pattern work/allocation allowance would replenish the original operation; a guessed parser allocation slab would not prove containment. A larger report reserve is unnecessary when the complete producer fits the original owners and this derived additive reserve.

The supervised process and alternative regex dependencies remain the separately considered options in ADR 0014. They are not introduced by this syntax integration. The pattern contract states the current public behavior and limitations.

0029: Content-format declarations and recorded registry guidance

Context

Authors need to distinguish a malformed complete declaration from valid spelling whose registration or meaning is unknown. RFC 9880 Appendix A note 2 references RFC 9193 Section 6, whose decimal grammar has no digit ceiling; Section 3 separately gives the Content-Format identifier range. A small convenient registry subset would turn known dated positives into misleading unfamiliar results. Parameter and payload meaning require work beyond declaration checking.

Decision

An explicit fixed ten-area content-format assessment adds complete grammar and dated registry guidance to the immutable initial inventory, following ADR 0003: Check findings and completeness and ADR 0013: Shared workflow and report guarantees. FullBaseline joins both declaration dimensions into M024 and its pattern/format area while preserving producing condition identities. Final effective Full coordinates define the observation population, following ADR 0020: Owned effective views and nearest origins and ADR 0024: Effective alternatives and nullable characteristics. Overrides, deletions, critical-feature gates and Direct donor uncertainty retain their established meanings.

Whole borrowed grammar classification precedes decimal range checking under recorded interpretation I-CF-RANGE-1. Dated guidance uses all relevant positives from pinned CoAP, media-type and HTTP-coding editions, with canonical identities and temporary, obsolete and deprecated flags preserved. A positive-table miss leaves current registration unknown; actual table use does not imply completed lookup or current status. This follows ADR 0002: Recorded standards baseline.

UseRecorded and WithholdRecorded share the existing evidence-policy and borrowed metadata seam established by ADR 0027: Unit names and recorded registry guidance. Withholding is an embedding’s evidence trust choice. It reports needed unavailable evidence without pretending the compiled table is physically absent. Parameters have explicit excluded-meaning Notices in ExpandedContentFormat. FullBaseline additionally uses ADR 0033: Content-format model meaning for bounded parameter, registered tuple and ordered coding meaning; reserved identity remains interpretation unknown. No AST, payload decoder, protocol binding or refresh machinery is added.

The content-format contract records the exact grammar, extracted identities, dates, digests, status distinctions and conditions. Mandatory aggregates and actual-use evidence survive complete optional omission. Shared source-bound ownership, two complete DTO generations, old-result fallback and independent output growth fit the unchanged admission reserves. Every new semantic visit uses the original finite operation allowance, following ADR 0009: Bounded processing and reporting.

A complete grammar/range traversal precedes registry replay over the same borrowed derived coordinates. Operational completion remains separate from unknown semantic premises; replay never clears earlier uncertainty or duplicates findings and observations. A finished population with no reliable query needs omits replay. This preserves later independent declaration errors when lookup exhausts work, while deliberately spending additional traversal/classification credit and moving first consultation later under a tight capability. The unit module’s ordering and the original allocation/work allowances remain unchanged.

Considered options

A short popular-format allowlist was rejected because unfamiliar misses would omit available dated positive knowledge. Runtime XML or registry refresh was rejected because it would change reproducibility, evidence trust and capability. A public parser AST or payload validation was rejected because callers need declaration conclusions and preserved effective locations, not decoder machinery. Giving declaration checking its own ad hoc Full membership was rejected because it cannot establish a complete model inventory. The separate immutable model inventory now supplies that relation. Parameter semantics within the expanded inventory was rejected because syntax and registry evidence cannot establish parameter-specific rules or payload compatibility.

Interleaving classification and lookup was rejected because a lookup stop can leave later declarations unvisited behind a false completed syntax area. Marking both areas unfinished on every lookup stop is a truthful smaller alternative, but loses useful independent syntax completion and later spelling/range findings. Retaining classifications for later lookup was rejected because it introduces a growing population owner where charged borrowed replay suffices.

Consequences

Callers opt into added checking without altering the initial meaning of scalar getters or the old inventory. Reliable syntax errors remain blocking errors, while missing registration evidence and unsupported meaning are incomplete. Recorded positives and dated flags are Notices, with no current-status claim. Tight finite capabilities can leave requested work unfinished; detail omission alone cannot change semantic status. Table, backend, header or reporting graph changes require renewed source-bound qualification.

0030: Bounded numeric advice

Model authors benefit from local contradictions that ordinary interval comparison does not find, including fractional bounds with no integer and intervals with no multiple of a positive step. Provide an explicitly selected assessment, using the effective Full data descriptions established by ADR 0020: Owned effective views and nearest origins and ADR 0024: Effective alternatives and nullable characteristics. Numeric constraints follow RFC 9880 Appendix C.1.

esdieff.expanded.numeric/1 contains the unchanged Initial eight areas and advisory-numeric-three/1. Its three Warning/Advice classes are an integer interval gap, a sole numeric const excluded by each applicable bound, and a positive-step interval gap. These are local sufficient contradictions, without a general satisfiability, restrictive-refinement or sample-admission conclusion. Full keeps its fixed model obligations and existing advisory area; it does not implicitly request these new classes.

Proofs require final ordinary meaning and the applicable Full role. An established absent type permits the numeric const comparison only. A malformed or unavailable type is not absence. Interval proofs require established integer/number type as appropriate and null exclusion, supplied by nullable false or the independently known nonnull root kind of the sole ordinary const. Unavailable const magnitude does not erase an established root kind. Documentary default supplies no guard. Donor interpretation, unsupported qualities and unestablished structural meanings cannot be inferred from source JSON kinds or spelling. Derived Choice alternatives are checked separately; no union proof is added. The numeric advice contract states all applicability and support boundaries.

Evaluate every surviving const bound independently. Select the strongest known lower and upper bounds for interval work, with exclusion winning exact ties. A bound with established restrictive meaning but unavailable magnitude leaves the affected work undetermined while a contradiction using independent known bounds can survive. Unknown denotation cannot be presumed restrictive.

Use borrowed normalized decimals and bounded virtual long division, without floating point, a large-integer dependency, generated public number tokens or exponent-sized storage. Divide each endpoint by the positive lattice step, round the lower quotient upwards and upper quotient downwards, then adjust integral exclusive endpoints by one. No lattice value exists when the lower integer index exceeds the upper. For integer type with rational decimal step p/q in lowest terms, use the common integer lattice pZ; finite coefficient factor removal cancels powers of two and five.

Keep class outcomes independent: an unavailable positive step can leave its attempt unfinished while a supported integer interval contradiction remains a warning. The one numeric area’s status is undetermined until every applicable class is completed; absence of a warning supplies no satisfiability conclusion.

Virtual numerator and denominator lengths are at most 1024 digits; adjusted quotients have at most 1025 digits. Factor storage has at most 513 digits. A magnitude-first shortcut handles a quotient smaller than one before virtual-width admission. Successful factor removals are bounded by the finite coefficient, without a loop counting to the exponent. Capability limits leave work undetermined and never establish a gap.

All traversal, comparisons, digit scans, carry/borrow, factor trials, buffer acquisition and finding growth debit the original remaining operation and numeric counters before work or allocation. Sequential classes and descriptions share those counters. No refill, refund or allowance increase is introduced. Existing mandatory report owners contain the added area and aggregates with zero additional numeric reserve. Optional conditions retain at most four original operand identities, their final effective coordinates, nearest authored contributions and consumer origin. Absent type contributes no invented argument or location. Numeric human fallback destroys the first result before constructing its replacement; retained model and finding owners remain accounted for.

Considered Options

A general constraint solver would expand the public claim and the supported language considerably. Reusing supplied-candidate divisibility cannot establish interval existence. Floating point would lose exact endpoints and decimal steps. Expanding powers into strings would make accepted exponents select unbounded allocation. Per-class budgets or a larger report reserve would conceal failures of the original shared owner contract. Treating every familiar quality as harmless would miss its role, interpretation and structural premises.

0031: Bounded declared-value consistency

Model authors need advice when a stated const or documentary default is excluded by its effective data description. Select esdieff.expanded.consistency/1 explicitly, containing the unchanged Initial eight areas and const-consistency/1 and default-consistency/1. Exclusion is Warning/Advice, separate from normative parameter errors and existing advisory producers. The consistency contract sets the exact scope, following RFC 9880 Section 4.7.2 and Appendix C.

Reuse the selected-value evaluator and contextual equality of ADR 0015: Bounded value equality in a resolved data context and ADR 0016: Selected samples with explicit admission and coverage. An internal borrowed value distinguishes a role-checked Sample source from a current effective Model value. One immutable context carries the effective description and candidate root through nested evaluation and equality projection. Projection validates arena, ancestry and that boundary; it starts at the candidate, without interpreting model document containers as data. Public sample handles retain their source-role guarantees.

Check each final alternative’s local const independently. Check the owner’s documentary default once against the complete existential Choice or Enum; separately check an alternative’s introduced or overridden default. A private construction marker records that boundary. Origin kind alone cannot identify it: a branch sdfRef can introduce inherited donor default 1 with branch minimum 2 when the owner has no default. Actual deletion and fallback follow ADR 0024: Effective alternatives and nullable characteristics. Distinct final alternatives and importing consumers remain distinct candidates.

One definitive exclusion yields one new warning per candidate, even when several leaf constraints reject it. Existing warnings remain independent. An unknown possibly admitting alternative prevents exclusion; unrelated unfinished work does not erase an established restriction’s finding. Unsupported needed meaning remains visible in the two area statuses. Completed work and absence of a warning do not establish that the description admits any value, restrictive refinement or general satisfiability. Documentary defaults are assessed without inserting them.

Distinguish aggregate unfinished branch meaning from a local owner failure within the existing failure state. Only successful alternative membership can set this aggregate cause, preserving an existing local cause. Consistency evaluation may use it only on that collection’s exact owner with no group establishment failure. Copied nodes lose the group association and must establish their own membership; the cause alone grants no eligibility. Keep ordinary-context, child-meaning, feature, donor and candidate guards. The existing all-branch evaluator can then retain one independent exclusion while the overall operation stays incomplete.

All candidates, descriptions and alternatives share one request equality counter and the original remaining numeric, semantic and allocation counters. Charge loops, scans, copies, retained capacities and retries before work; no phase refill or refund is introduced. Preserve a real decisive candidate leaf or container as the source primary, with effective operands, relevant origins and consumer locations. If evidence cannot be retained, keep the single aggregate warning and mark its detail omitted. Never substitute a donor’s whole compound token for a derived candidate. This preserves ADR 0009: Bounded processing and reporting and ADR 0013: Shared workflow and report guarantees.

Considered Options

A separate model validator would duplicate selected-value semantics and resource rules. Turning model source JSON into a Sample handle would break source roles and composed coordinates. Storing the description and root in every nested value would enlarge repeated frames. Counting every rejected leaf would make advice totals depend on evaluation detail. A general constraint solver would promise broader reasoning than checking these declared values.

0032: Formal model admission

FullBaseline checks the formal numeric and literal domains imported by RFC 9880 Appendix A. These grammar obligations are separate from the exact information-level meaning of numbers in Appendix C.1, following ADR 0012: Exact numbers and JSON input policies. Initial, expanded assessments, source inspection and selected-sample admission retain their existing scope and exact-decimal behavior. The formal admission contract records the boundaries.

Imported number admits every JSON number, read as an exact decimal without a precision or range limit. RFC 8610 Appendix E maps CDDL onto JSON and describes JSON numbers as decimal, without limits to their precision or range. It also calls a floating-point precision restriction unlikely to be useful for JSON. RFC 9880 itself uses a decimal that binary64 cannot express: Figure 5 in Section 6.2.1 overrides a length with "minimum": 5e-2. This is Esdieff’s RFC interpretation. Later guidance from the RFC authors would be evidence for revisiting it, not a precondition for applying it.

Imported uint admits integral values from 0 through 2^64-1, following the prelude. Fractional or exponential notation does not change an integral value’s membership. No supplied decimal is rounded to establish admission. For example, 0.1, 5e-2 and 1e400 are numbers, 10.0 is a uint, and 2^64 is a number but not a uint.

Full and Direct numeric parameters, lengths and Full array counts use colon entries in Appendix A. An established value outside their imported domain is a formal grammar error: a colon entry cuts off fallback to map extension entries, as specified in RFC 8610 Section 3.5.4. Every JSON number satisfies a numeric parameter, so only lengths and counts can be excluded. Grouping repetition counts instead use =>. Their non-uint values, including negative, fractional and nonnumeric values, can fall through to the framework’s extension entries. Full records known grammar admission and unavailable base repetition and extension meaning. It does not retain the narrower grouping-count error for those fallback values. No independent normative prohibition has been adopted for them.

The allowed-types union for Full const and default includes the feature alternative any. Known content outside the base alternatives is therefore framework-admitted, with extension meaning and applicable final const meaning left undetermined. Homogeneous number, text or Boolean arrays are base alternatives; nested, mixed or null-element arrays use the extension alternative. Text-key maps have unrestricted values, so their nested numbers and arrays do not inherit the scalar number or array restrictions. The feature annotation describes an extension alternative without itself requiring a named critical feature, following RFC 9165 Section 4.

number membership needs no arithmetic once a number is decoded. One private exact predicate compares a decoded count with virtual decimal digits for uint, which avoids a large-integer dependency, rounding and exponent-sized expansion. The role-aware literal classifier stays beside the existing effective traversal, without a second JSON model or public interface.

Use the original request’s remaining semantic and numeric counters, and charge scans and comparisons before performing them. Decoding limits, unknown critical context, unavailable donor meaning and exhausted work leave the affected obligation undetermined; they never become domain exclusions. Source composition patches do not impose deleted operands on the effective model. Selected and catalogue scopes retain their existing boundaries, and inherited findings retain both their effective locations and original source operands. Optional detail omission preserves aggregate errors and completed work, following ADR 0009: Bounded processing and reporting.

Considered Options

Restricting number to integers from -2^64 through 2^64-1 and values exactly expressible in binary64 follows RFC 8610’s float types literally and was the earlier decision. It made RFC 9880’s own Figure 5 a grammar error, and it rejected ordinary decimal steps in real models, such as multipleOf: 0.1 with unit s and multipleOf: 0.005 for a 5 ms delay step. Sample checking already treated those values exactly. Rounding through binary64 would change the supplied value and accept rounded large integers. Rejecting every extended literal or grouping fallback would replace the normative framework grammar with stricter validation syntax. Leaving known extension admission unfinished would confuse grammar membership with unavailable semantics. Extending these checks to every workflow would change the narrower Initial, expanded and sample contracts. A general CDDL interpreter or arbitrary-precision dependency would add unnecessary surface for these fixed domains and shallow literal alternatives.

0033: Content-format model meaning

Context

A Full model assessment must establish the content-format declaration’s modeled meaning independently of a sample. Grammar and positive registry membership do not establish arbitrary media parameters, their absence or ordered coding meaning. For example, a registered multipart name cannot conceal missing knowledge about its required boundary parameter. The existing expanded assessment in ADR 0029: Content-format declarations and recorded registry guidance intentionally advertises only grammar and recorded guidance.

Decision

Keep ExpandedContentFormat unchanged. FullBaseline M024 additionally establishes complete recorded numeric CoAP tuples and a small explicit media-rule set: parameterless JSON and CBOR, one no-effect JSON charset, and the plain-text US-ASCII default or one UTF-8/US-ASCII charset. Other media-specific rules, parameters and duplicate parameters remain Unassessed. Missing or withheld registration evidence remains Undetermined. The content-format contract pins these distinctions and their primary RFC sources.

Positive explicit coding tokens identify transformations applied in their stated order, including repeated occurrences, under RFC 9193 Section 3. Absent coding means no transformation. Explicit reserved identity remains unavailable; do not import HTTP negotiation semantics as an SDF error. Numeric declarations designate complete registered content-type/coding tuples, without a second unrelated registry query or payload interpretation.

Use the existing charged borrowed grammar/registry replay, with a private meaning module and no public syntax tree. Preserve every authored string and origin. Record actual admitted consultation as content-format-model-meaning/1, even when optional findings are omitted. Unsupported semantic observations occur before finding-retention decisions. All scans, tuple accesses and parameter comparisons consume the original shared work allowance.

The complete Full report can carry ten interpretation IDs, beyond the registry module’s four, including copied-reference-relocation/1 from ADR 0036: Copied reference relocation. Requalify both complete report generations, interpretation Vec growth, registry records, retained-result fallback and optional omission against the original reserves. The compiled backend fits those reserves; qualification checks the combined graph rather than assuming a free fourth array slot. This follows ADR 0009: Bounded processing and reporting.

Considered Options

Completing every registered parameterless media name would conceal required parameters outside the known rules. Inferring arbitrary media semantics from recorded CoAP tuple spellings would need additional normalization and matching rules. Acquiring every registry template would broaden dependencies and trust without delivering a proportional general interpreter. A public parser tree would force callers to rebuild conclusions. Payload decoding and protocol bindings are outside model declaration meaning. Increasing reserves before qualifying the compiled maximum graph would hide an avoidable ownership cost.

0034: Authored-quality editing with source substitution

Existing-document maintenance uses a distinct Authored-quality edit and Editing fidelity contract. Explicit owners select ordinary authored named definitions, and replacement or removal requires a present quality. Every target is established against original content before application. Owners inside any authored sdfRef context are excluded because Composition patch null has a different meaning from a literal JSON null replacement. The editing contract fixes source preservation, identity, limits and report meanings without changing ADR 0017: Reference-preserving sdfThing authoring.

The original retains exact bytes and acquisition metadata as evidence. Source substitution replaces exactly that active contributor with a distinct generated source, preserving other contributor identities and genuine ambiguity. Untouched references resolve through the active result Catalogue. Local-only documents need no invented namespace. Candidate generation, Editing fidelity and any requested Model checking remain independent conclusions.

Editing fidelity under esdieff.authored-quality-edit/1 verifies requested changes and preservation of every other authored JSON value and context. Numbers retain accepted lexemes, and opaque JSON remains in place. This does not prove before-and-after model equivalence or unknown extension meaning. It follows ADR 0007: Generated SDF and sample JSON, ADR 0012: Exact numbers and JSON input policies, and the finite cumulative budgets in ADR 0009: Bounded processing and reporting.

The additive report operation edit uses version 1.2 and counts one editing operation. Model assessment identity and counts remain separate, following ADR 0011: Machine-readable report contracts and ADR 0013: Shared workflow and report guarantees. Mandatory substitution, source attempts, aggregate outcomes and candidate completeness survive omission of optional detail.

The one editing unit includes any requested Model checking. Generation and Editing fidelity remain independent when that assessment fails or remains unfinished. Checking uses the generated root and ordinary needed dependencies under the same cumulative operation allowances. Hard plan ceilings that prevent complete request admission are distinct from an admitted unfinished operation, which retains its exact edit count and report.

The CLI reuses authoring destination identity protection, explicit replacement and individually committed bounded staging. Ordinary document delivery requires complete generation, established Editing fidelity and a passing requested check. Abandoned staging receives explicit cleanup. Cleanup or later report failure retains the primary error, identifies any retained staging and states whether the document was delivered. Two destinations and stdout do not provide transaction or rollback guarantees.

Considered Options

Adding editing to new-Thing authoring would merge different preservation claims. A generic JSON patch or upsert could add stale targets or edit opaque occurrences without an established definition role. Keeping old and edited sources simultaneously active manufactures global-name collisions, while coalescing byte-identical aliases would hide real ambiguity. Extending literal-null editing into Composition patches would silently adopt different semantics.

0035: Explicit pinned document acquisition

Pinned document acquisition is an explicit CLI operation for one public GitHub file at a complete commit identity and a separately reviewed expected SHA-256. It preserves unchanged bytes in a new native file and produces a bounded Acquisition receipt. Keeping retrieval separate makes the resulting Acquired snapshot an ordinary offline input and preserves ADR 0004: Supplied catalogues and checking scope and ADR 0006: Scoped reference failures.

The acquisition contract fixes origin, verified TLS, identity content encoding, no redirects or retries, byte ceilings and transfer deadlines under ADR 0009: Bounded processing and reporting. Native destination preflight and no-replacement commits protect prior evidence. The document and optional named receipt are independent outputs. A committed document can remain after receipt delivery or staging cleanup fails, and the outcome must disclose that state. Neither transport success nor a matching digest establishes Model checking, licensing or real-device acceptance.

Considered Options

Implicit namespace retrieval would make model meaning and completeness depend on network availability and an acquisition convention SDF does not require. Following branches, learning the expected digest from the same transfer, replacing snapshots or coalescing identical contributors would weaken explicit source selection and offline replay. Receipts therefore remain separate evidence that callers may deliberately translate into existing Source metadata, rather than new remote inputs or automatically loaded plans.

0036: Copied reference relocation

Context

RFC 9880 Section 4.4 copies a referenced definition and applies the composition patch through JSON Merge Patch. It does not say what name references inside the copy mean afterwards. Sections 4.3 and 4.4.1 also leave open whether a name reference selects an element of the document as written or of its resolved model. Reusable Objects commonly require their own declarations through absolute pointers such as #/sdfObject/alarm/sdfProperty/status, so reusing one through sdfRef copies a pointer to the source’s coordinates.

Decision

Esdieff adopts this RFC interpretation as copied-reference-relocation/1, following ADR 0002: Recorded standards baseline.

A copied reference keeps the document and namespace mappings of the definition that authored it. When its target, read in that context, is the copied definition or lies beneath it by decoded JSON Pointer tokens, it is an internal copied reference. It relocates to the corresponding position in the importing definition. This applies to same-document and CURIE forms alike and at every copy boundary, including a target’s root chain and nested copies. Other copied references keep their original target. Relocation starts from the target the reference has in its authoring context, so a copied reference whose target is missing there stays missing in every copy, even when the importer declares something at the corresponding position.

A reference written in a composition patch belongs to the importing author and uses that author’s context, even when its text equals the inherited one. Only the sdfRef member or sdfRequired array actually written in the patch counts. Patching sibling qualities leaves a copied reference copied.

Every name reference selects the element at its pointer in the target document’s resolved model. An importer can therefore reference and require declarations that exist only through a copy. A relocated target that a patch deleted is missing, as for any other reference, under ADR 0006: Scoped reference failures and ADR 0020: Owned effective views and nearest origins. Nothing falls back to the source definition. Cycles created by relocation or by composing a pointer’s path are scoped failures.

Composing a pointer’s path is an exception to the explicit frames of ADR 0020: Owned effective views and nearest origins. A lookup composes a definition on its path, and that composition can need another lookup through another composed definition, so nested path compositions recurse. Each nested composition is reused for the rest of the operation, and the nesting stops at a fixed bound of 32 levels, or at the reference depth when that is lower. Exceeding the bound leaves the affected result undetermined with operation.limit, following ADR 0009: Bounded processing and reporting. The bound is a supported stack limit rather than an allowance, and raising the reference depth does not raise it. Recursion keeps lookup on the existing composition steps, while explicit frames would need a resumable lookup inside every expansion. Ordinary models nest only a few levels, and 256 levels of recursion can exhaust a 2 MiB thread stack.

Copied sdfRequired pointers relocate by coordinate. A relocated pointer selects the declaration at that coordinate in the resolved model, with its own Declaration contribution under ADR 0026: Required declaration relationships and source evidence. A deleted declaration leaves the relationship missing, and a reinserted one is selected as a new contribution. Referenceable names and true entries keep their carrier-relative meaning. Boolean and short-name sdfRef keep no processing meaning.

baseline.interpretations lists the identifier whenever a result relied on this interpretation. That is when requested work relocated a copied reference, read a copied CURIE reference with its authoring document’s namespace mappings, or found that a name reference target in the resolved model differs from the document as written, including a target that composition removed. Reports that did none of these omit it.

Considered Options

Binding a copied reference to its source target keeps the source’s constraints and ignores the importer’s refinement of the very data its copy uses. Reading inherited pointers literally in the importing document selects unrelated lookalike definitions, or nothing. Requiring authors to restate every inherited reference breaks reuse of ordinary models that require their own declarations by pointer. Keeping copied references undetermined left that common reuse incomplete, and an opt-in switch would keep that default while doubling the tested behaviour. String prefix matching would treat a sibling such as BaseExtra as inside Base. Limiting resolved-model lookup to sdfRequired or to same-document pointers would let two spellings of one global name disagree. Classifying a reference by the map that holds it would let an unrelated sibling patch silently rebind it. Relocating by pointer structure alone, even when the source lacks the target, would make one copied reference broken in its source yet valid in each importer that happens to declare the missing element. Recording the identifier only for relocation and composed-only targets left passing results that read a copied CURIE in its authoring context, and missing targets that composition removed, without naming the reading they rely on.

0037: Undeclared extension vocabulary

Context

RFC 9880 Section 2.3.3 makes Quality Names an extension point, and Section 3.1 gives the features quality for listing critical extension features that cannot be safely ignored. Esdieff previously let any quality outside base SDF stop the base meaning of the definition carrying it. One oma:id on a Property left its type, constraints and Sample admission undetermined. Every model converted from OMA LwM2M carries such a quality, and working-group extensions such as protocol mapping add unqualified qualities like sdfProtocolMap.

Decision

Esdieff adopts this RFC interpretation as undeclared-extensions-ignorable/1, following ADR 0002: Recorded standards baseline.

Undeclared extension vocabulary is a Quality Name outside base SDF, used in a document whose features declares no Extension feature. It leaves the base meaning of its definition intact. Base conclusions, including types, constraints, requiredness, composition and Sample admission, proceed as if it were absent. Its own meaning stays unsupported unless it is Recorded extension vocabulary under ADR 0038: Recorded extension vocabulary. Its notices stay as they are. A qualified name keeps extension.optional_unsupported, and an unqualified name keeps its quality.unfamiliar warning, so a misspelled base quality is still reported. Composition copies and merges these qualities like any other, and inspection shows them.

The rule covers qualified and unqualified names alike. Working-group extensions use unqualified names, and the RFC reserves the cannot-ignore treatment for declared features.

A base Quality Name in a position whose role does not support it is not extension vocabulary. Wider Direct item descriptions and other role questions keep their existing outcomes. A document that declares any Extension feature is still deferred as a whole under ADR 0003: Check findings and completeness, and so is any result whose composition depends on such a document.

baseline.interpretations lists the identifier whenever a reported conclusion was established for a description carrying undeclared extension vocabulary. Reports that relied on no such description omit it.

Considered Options

Keeping every unknown quality blocking was safe, but it left every OMA-derived model and every protocol-mapping model without base meaning, although the RFC already offers features for extensions that do change it. Ignoring only qualified names would guard against misspelled base qualities, but it would keep working-group extensions blocked. A misspelling already receives a warning, and a strict warning policy turns that warning into a failure.

0038: Recorded extension vocabulary

Context

RFC 9880 Section 7.5.2 lets organizations register a Quality Name Prefix and define qualified Quality Names under it. The IANA SDF Quality Name Prefixes registry recorded its first prefix, oma, on 12 May 2026. The Open Mobile Alliance defines one quality with it in its OMNA SDF Quality Names registry. oma:id is the LwM2M Object or Resource ID of a definition, and its CDDL adds "oma:id" => uint to the RFC 9880 sockets $$SDF-EXTENSION-OBJECT, $$SDF-EXTENSION-DATA and $$SDF-EXTENSION-ACTION. The oma2sdf converter emits it on every converted Object and Property, and its output for object 3303 writes the Object ID as a string.

Decision

Recorded extension vocabulary is a qualified Quality Name whose definition Esdieff records as dated Recorded registry evidence, following ADR 0002: Recorded standards baseline and ADR 0027: Unit names and recorded registry guidance. The first entry is oma:id, recorded from the IANA prefix registry and the OMNA registry page as accessed on 16 October 2026.

oma:id belongs where its registered CDDL sockets apply. That is an sdfObject definition, an sdfAction definition and every full data description: sdfData, sdfProperty, Action input and output data, Event output data, object property entries and choice alternatives. Its value must be a CDDL uint under the formal admission rules of ADR 0032: Formal model admission, so 3303 and 3303.0 are admitted while "3303", -1 and 3303.5 are not. An excluded value at one of these positions is an error whose basis is the OMNA registration rather than RFC 9880. Reports give it a new registration basis kind, with the registration’s citation and the Quality Name as its identifier. The kind joins report version 1.0 in place, because no report reader predates the first release. Full assesses it as M028 in its critical-extension area, so the 54-obligation inventory stays unchanged and the Initial assessment is unaffected.

At any other position, such as an sdfEvent or sdfThing definition or a Direct item, oma:id is undeclared extension vocabulary under ADR 0037: Undeclared extension vocabulary, with its usual notice. So is any other oma: name. A dated record establishes what it contains, not that nothing else has been registered since.

The recorded meaning covers value admission only. Esdieff does not check that an ID names a real LwM2M object, or that IDs are unique within an Object, because the registration states neither. A caller that withholds recorded registry evidence leaves the oma:id conclusions unavailable, as it does for units. Base conclusions still proceed past oma:id at its positions in every assessment. Where a report did not consult the recorded evidence, as in a Sample report, an assessment other than Full or a Full check that withholds it, those conclusions rely on ADR 0037 and name undeclared-extensions-ignorable/1. Further recorded extensions take the same shape: a registered or published definition, the positions its CDDL names and its value domain.

Considered Options

A warning for an excluded value would let a catalogue with broken IDs pass unless strict warnings were requested, although the registered type makes the defect definite. Following the four classes in the OMNA table instead of its CDDL would leave placements its own grammar admits, such as Action input data, unchecked. Treating other oma: names or other positions as errors would turn a dated record into a claim that nothing else was registered. Reusing the rfc basis kind would avoid a report change but name RFC 9880 as the reason, and a report version 2.0 would protect no existing reader.

0039: Client-side revision comparison

Context

A manufacturer that changes a shared definition needs to know which device interfaces now break their clients. RFC 9880 gives version no mandatory format and defines no compatibility rules, and the Restrictive refinement convention has no general checking procedure. Esdieff already establishes effective groupings with their content origins, exact numbers and Sample-value checking, so a Revision comparison can reuse them. The rules below are Esdieff’s own.

Decision

esdieff diff compares two Model revisions from the Client’s side and classifies each difference between their corresponding groupings as breaking, compatible or undetermined.

Direction. Narrowed Client-supplied data, widened Thing-supplied data, a removed grouping or affordance, and a Property characteristic that becomes false are Breaking changes. So is input data added to an Action that had none, since existing invocations send none, and so are input data removed from an Action and output data removed from an Action or Event. These changes are to the affordance as a whole rather than to a data description, so they need no Breaking witness. A declaration that stops being mandatory in a grouping is breaking, and one that becomes mandatory is compatible. Requiredness is compared as the closure of mandatory declarations in each corresponding grouping, through its required groupings, and an affordance’s sdfRequired belongs to its enclosing grouping. A declaration required from an enclosing grouping can only be represented inside the groupings between them, so each of those is mandatory there too, and the declaration is mandatory in each of them. Things decide how many instances a Grouping array has, so its instance count range behaves like Thing-supplied data: a narrower range is compatible and any other change is breaking. An absent minimum count reads as 0 and an absent maximum as unbounded, and a grouping that becomes or stops being an array stays undetermined. A Property that is both readable and writable carries data both ways, so any change to its value set breaks one direction or the other. Data that the two revisions carry in no common Client direction reaches no Client in both, so its changes are compatible and its characteristic changes decide. Clients use only what the earlier revision describes or requires. A map entry that the earlier revision neither describes nor requires, or output data an affordance did not have, is part of no Client’s interaction, so describing it later is compatible in either direction. A described entry whose description is removed from Client-supplied data stays admitted, since maps are open, so that removal is compatible too. Removing a described entry’s description from Thing-supplied data is breaking with a witness map holding a value that the earlier description rejects. Candidate witnesses for map data are therefore placed only at entries the earlier revision describes or requires, while the other required entries around them are filled as for any nested candidate, described under Proof. A difference that only obliges Things to accept or provide more is compatible. Compatibility for Thing implementers is not assessed.

Proof. A change to the values a data description admits is breaking only with a Breaking witness: a value that Sample-value checking establishes as admitted by one revision’s effective description and rejected by the other’s, in the breaking direction, following ADR 0016: Selected samples with explicit admission and coverage. It is compatible only with a proof that no witness exists, such as every changed quality loosening in the safe direction. Candidate witnesses come from the changed quality itself and from representative values of the revision that must admit them, such as its const, its enum values, its documentary default or a simple value of each type it admits. A witness belongs to the change it was made for, so a candidate inside nested data stands beside representative values of the enclosing entries that either revision requires, and only where both revisions describe that enclosing content alike. Everything else, including a quality the comparison cannot yet classify, is undetermined, following ADR 0003: Check findings and completeness. A witness check that runs out of the operation allowance stays undetermined, even when it has already established a rejection that ADR 0016 keeps for a supplied sample. Exact numbers and Value equality decide whether an effective quality changed at all, so 10 and 1e1 are the same bound, following ADR 0012: Exact numbers and JSON input policies and ADR 0015: Bounded value equality in a resolved data context. An absent uniqueItems reads as false. No general subset solver is involved.

Correspondence. Each revision is one supplied Catalogue. Documents correspond by source key, which esdieff diff derives from each document’s location within its revision, groupings by their position in the corresponding document, and nested groupings and affordances by Given Name. Enum values correspond by value, so reordering an enum changes nothing. Choice alternatives correspond by Given Name and are compared as the effective alternatives they derive, and an array’s items is compared as the nested description of its values. Moves and renames read as a removal and an addition. Shared definitions are compared through the effective groupings that use them, with their content origins, following ADR 0020: Owned effective views and nearest origins.

Meaning qualities. unit, contentFormat and sdfType tell a Client how to read a value, so a change between two established, different meanings is breaking in every Client direction the data carries. For units, that is a change between two different current names in the recorded SenML evidence, from either its SenML Units or its Secondary Units section. A legacy name, a URI name, an unrecorded spelling, an added or removed unit, or withheld evidence leaves the change undetermined, following ADR 0027: Unit names and recorded registry guidance. Legacy names can give one unit several names, such as beat/min and 1/min. For contentFormat, two declarations with established meaning that differ are breaking, and two spellings of one meaning, such as 50 and application/json, are no change, following ADR 0033: Content-format model meaning. For sdfType, a change between byte-string and unix-time is breaking. An added or removed meaning quality, or one without established meaning, is undetermined unless a Breaking witness settles its data change. Beside a choice, a shared meaning quality tells Clients how to read only the values of the alternatives that inherit it, so a change that every alternative replaces is compatible.

Other qualities. Changes to description, label, $comment and documentary default are compatible, since none affects an interaction. An items description that carries a quality outside the vocabulary of a Direct items description has no established meaning, following ADR 0024: Effective alternatives and nullable characteristics, so inside it only changes to description and $comment are compatible and every other change is undetermined. A revision with findings or unresolved references is still compared, and the affected parts are undetermined, following ADR 0006: Scoped reference failures. The result is breaking when any difference is breaking, otherwise undetermined when any is undetermined, and it uses the exit codes of check.

Considered Options

Flagging every tightened quality is simpler, but it raises false alarms when another constraint, such as a const, already excluded the value the change removes. Checking only narrowed inputs misses a widened reading that clients never handled. Keeping a rejection that a witness check established before its allowance ran out would classify a difference whose checking was cut short. Treating unclassified differences as compatible would hide breakage behind missing capability. Pairing by Global name survives file moves, but device documents commonly declare no default namespace and would stay unpaired. Guessing renames from similarity would invent identity. Counting any change of unit text as breaking would flag legacy-name replacements and typo fixes. Treating only SenML Units names as current would leave a change such as ms to s undetermined, although Clients misread every value. Classifying the data of a Property whose revisions share no Client direction by each quality’s own rule would call a unit change there breaking, although no Client exchanges that data in both revisions. Comparing authored sdfChoice branches rather than derived alternatives would read a branch that overrides a shared bound as the opposite change. Filling the entries around a nested candidate from the admitting revision alone would let the other revision reject it for a change elsewhere in the enclosing map, and pin that witness on the wrong difference. Comparing raw sdfRequired arrays would miss a requirement spelled another way or moved between nested groupings. Reading open maps literally would make every added optional entry in Client-supplied data breaking, although no Client built from the earlier revision sends it. Letting a requirement of a nested declaration reach only the requiring grouping would report a requirement moved into a required nested grouping as a change, although Things must provide the same data.

0040: Acknowledged revision differences

Context

A Revision comparison fails a CI job on every Breaking change, following ADR 0039: Client-side revision comparison. A deliberate major revision breaks Clients on purpose, and so does a change the maintainer has reviewed but Esdieff leaves undetermined, such as a changed pattern. Without a way to record that intent, the maintainer must disable the comparison for the release that needs it most. The words “accepted” and “baseline” already name Acceptance restrictions and the Standards baseline.

Decision

A maintainer can supply Difference acknowledgements. Each one names one intended difference by its kind, subject, quality, classification and, for each revision, the document’s source key and the difference’s effective pointer. A difference that matches one is an Acknowledged difference. It keeps its classification, and only unacknowledged differences decide the disposition and exit code, so an acknowledged breaking comparison exits 0 while its report still says it breaks Clients.

The identity leaves out request-local source IDs, which shift when documents are added, and content origins, which move when content is refactored into a shared definition. It also leaves out witnesses and quality values, so an acknowledgement covers later changes to the same quality at the same place in the same classification. Because classification is part of the identity, a rules change that turns an acknowledged undetermined difference into a breaking one brings it back for review.

Breaking differences and undetermined differences of kind removed, added or changed can be acknowledged. Unavailable content, differences left undetermined because content they depend on is unavailable or by the operation limit, and differences whose details the report could not retain cannot be, since nobody examined that content. An acknowledgement that matches nothing is reported and leaves the disposition unchanged. The diff report gains a new version for the changed disposition fields, while the comparison contract identity stays the same because no classification changes. Acknowledgements follow ADR 0009: Bounded processing and reporting.

Considered Options

A new accepted classification would hide the real classification and change a fixed value set. Acknowledging breaking differences only would still fail CI on a reviewed undetermined change, such as an added unit. Failing on unused acknowledgements would force cleanup, but reverting an intended change or upgrading the comparison rules would then turn CI red. Including witnesses or quality values in the identity would pin exact values, so entries would break whenever the witness rules improve.

0041: Generated values settled by Sample-value checking

Context

Firmware and app teams test their code against a model with example interaction data, and today they write every value by hand. Esdieff already builds Representative values for ADR 0039: Client-side revision comparison and checks values it builds itself against an effective data description. A generator that guesses whether a value is valid would hand testers wrong expectations whenever a constraint interacts with another, such as a pattern beside a minLength.

Decision

Esdieff generates Generated values for a selected effective data description. Each value aims at one named Generation target, such as a minimum, a value just below it, a missing required entry or a wrong type. The fixed target list, order and value rules form the contract esdieff.generation/1, so a changed rule is a new contract identity.

Sample-value checking settles every Generated value, and its admission is the only statement Esdieff makes about whether the description admits it. A target called below_minimum that another constraint also rejects is still just rejected, and a value the checker cannot settle is undetermined, never listed as valid or invalid. Generation is deterministic, with no randomness or seed, so the same model and request give the same values in the same order.

A target that does not apply produces no value, and so does one whose value would exceed the value capabilities. Constraints that Esdieff cannot construct values for, such as an arbitrary pattern, get no target rather than a guess. Each Generated value is settled with the allowance one Sample-value checking request would receive, and building each description’s values is charged to that description’s own allowance, so one heavy description cannot leave the others undetermined. Fixed ceilings on values per description and descriptions per request, and a request-wide limit on retained value bytes that keeps every output within the report byte limit, keep the operation finite under ADR 0009: Bounded processing and reporting. A value whose check runs out is undetermined, and its description is partial. Generation reports no model findings, so its disposition is passed or undetermined, never failed.

Considered Options

Random or seeded generation, as in json-schema-faker, finds unexpected interactions but gives different values across tool versions and needs a seed contract to stay reproducible. Labelling values valid or invalid by their target alone would be wrong whenever constraints combine. Synthesizing strings for a pattern would need a regular-expression generator whose results the bounded pattern capability of ADR 0014 might not settle. One allowance shared by the whole request, as revision comparison uses for its witnesses, would let a single large enum leave every description in a document undetermined.

0042: Recorded traces with independent entries

Context

Teams collect interaction values from devices, apps and test runs, and want to know which ones a model rejects. esdieff sample checks one value per run, composes the model each time and spends one of the 256 source attempts per value. The door-lock demonstration’s Simulation trace has authored sequence rules, which recorded data lacks.

Decision

A Recorded trace is a JSON Lines file of Trace entries. Each entry names a Sample selector within one selected document, carries a value and may carry an Expected admission and a label. Esdieff composes the model once, resolves each distinct selector once and checks every entry independently, with the allowance one Sample request would receive, so one heavy entry cannot starve the rest.

Line order is presentation only. A Recorded trace adds no sequence meaning, no timing and no protocol binding, and its checks add nothing to any Model requirement inventory.

An entry passes when its value is admitted with nothing else expected, or when its definite admission equals its Expected admission. It fails when its value is rejected with nothing expected, when its definite admission differs from the expectation, or when the entry itself is malformed or selects nothing. An undetermined admission stays undetermined whatever was expected, and so does a line the JSON decoder cannot read, such as one that is not UTF-8, following the input policies of ADR 0012: Exact numbers and JSON input policies. One bad line never stops the run. The trace’s disposition is failed for any failed entry, otherwise undetermined for any undetermined entry, otherwise passed, so exit codes follow check.

The trace file is a source with role sample, and conditions locate their entry by byte spans in that file. Generated values written as Trace entries, with their settled admission as the expectation, replay through the same check, which turns them into regression vectors for later Model revisions.

Considered Options

One JSON array of samples would need the whole file decoded before the first check and would hide which line failed. Accepting each line as a separate Sample source would spend the source-attempt ceiling and recompose the model per value. Treating an undetermined entry as passing when a rejection was expected would claim a conclusion the check did not establish. A sequence-aware trace would need authored behavior rules, which belong to demonstrations such as the door-lock simulation.

0043: SARIF and Markdown report projections

Context

CI systems display code-scanning results from SARIF 2.1.0 logs as inline annotations, and release notes are usually Markdown. Esdieff’s JSON and human reports carry findings with source byte spans and effective pointers, and revision comparison differences with their classifications and acknowledgements, but CI users must read them from job logs.

Decision

check and diff can emit SARIF, and diff can emit a Markdown changelog. Both are projections of the result the operation already produces. They change no conclusion, disposition or exit code, and they render only the findings and differences the operation retained, within the same byte limit, with omitted items counted in the output. Each projection fits its own output to that limit, so it can list a detail the JSON report dropped for space, or the reverse.

In SARIF, a check result is a retained error, warning or notice condition, and a diff result is a retained difference: breaking as error, undetermined as warning and compatible as note. A Version warning from ADR 0044: Versions of breaking revisions is a diff result at warning too. Incomplete work is a tool execution notification rather than a result, since it is not a finding about the model. Regions come from the retained source spans, with lines and columns counted in Unicode code points and the byte range alongside. An effective pointer is a logical location because it has no source position. An acknowledged difference is a result with an external suppression, so reviewers still see the break while CI treats it as intended.

The Markdown changelog groups differences by classification, puts acknowledged differences in their own section and renders model text inertly.

Considered Options

A separate SARIF-only analysis would duplicate the checking rules and drift from the JSON report. Reporting incomplete work as warning results would let a dismissed annotation hide unfinished checking. Hiding acknowledged differences from SARIF would remove intended breaking changes from review entirely.

0044: Versions of breaking revisions

Context

A Client that watches a model’s info version to notice incompatible changes misses a breaking revision that keeps or lowers its version. RFC 9880 Section 3.1 gives version no mandatory format but RECOMMENDS one that is lexicographically increasing over a model’s life, so a newer model’s version compares higher than every earlier one. A Revision comparison already finds the Breaking changes of each document pair, following ADR 0039: Client-side revision comparison. In the OneDM playground and exploratory histories, 14 of the 25 first-parent revisions with a breaking difference did not raise their version, and every version there is a date written as 2019-11-14 or 20200706.

Decision

A Revision comparison warns once for each compared document pair when the document’s bytes changed, at least one Breaking change was found in that pair, acknowledged or not, and the earlier revision’s info version is text while the later revision’s is absent or is text that does not compare higher by Unicode code point order. The warning is a Version warning with code comparison.version_not_increased, located at the later version, or at the nearest member that would hold an absent one, with the earlier version as related evidence. It carries both versions and the pair’s breaking count.

Because the RFC only recommends the order, the warning never changes a classification, the disposition or the exit status, and strict_warnings stays false for diff. An acknowledged Breaking change still counts, since an intended break is exactly when a higher version is expected, following ADR 0040: Acknowledged revision differences. An unchanged document earns no warning, even when a document it imports changed. A breaking difference belongs to the document pair in whose effective groupings it is located, so a changed document that holds only shared definitions, such as sdfData that other documents import, earns no warning of its own. Neither does a pair whose earlier version is absent or not text, nor an added or removed document. The diff report gains a new version for its warnings, while the comparison contract identity stays the same because no classification changes.

Considered Options

Warning on every change without a higher version would flag about 63% of the measured revisions, including many with no classified difference at all, so only the Client-relevant breaking case warns. Parsing dates would accept 2020-07-06 after 20200706, but it would adopt a format the RFC deliberately leaves open, so plain code point comparison applies and the warning shows both strings to make the reason visible. Failing the comparison on the warning would turn a recommendation into a requirement. Assigning each breaking difference to the document holding its content origin would warn for a changed shared-definition document, but a change that only points a reference at other content would then belong to the unchanged target and warn nowhere. Leaving acknowledged differences out would silence the warning for the releases that most need a higher version.