Package format

How an ODS package holds a document, the inputs of each run and a manifest that lets anyone check the files are unchanged.

Draft

The launch format is written down, and the viewer reads it. A producer does not yet write every field of the manifest. The format can change until the first release.

Status: draft. This is format 1; it is fixed when ODS launches. Reference implementation: @opencycle/ods-package (writePackage, readPackage).

An ODS package holds one ODS document and the files that let a reader check it: the full inputs of each run, the terrain those inputs refer to, and a manifest that lists every file with its SHA-256. A reader can prove that the files are the ones the manifest lists, unchanged since the package was written. A package does not prove who wrote it: packages are not signed yet.

The words MUST, MUST NOT, SHOULD and MAY are used as in RFC 2119.

1. Container

  • A package is a ZIP archive. Paths use / and are relative to the archive root.
  • File name: <name>.odspkg. A reader MUST NOT depend on the name.
  • A media type will be registered with IANA (proposed: application/vnd.ods.package+zip).

2. Encodings

  • Text. Every JSON file is UTF-8.
  • JSON values. A writer serializes each value as JSON first: a date becomes its ISO 8601 UTC string, an id becomes its string. The package holds only JSON values (objects, arrays, strings, numbers, true, false, null).
  • Canonical JSON is RFC 8785, as canonical-json.md sets out, with shared test vectors.
  • Hash. SHA-256 of the file's bytes, as 64 lowercase hex characters.

3. Files

Path Required Holds
manifest.json yes The manifest (§4). Not listed in its own files.
ods.json yes The ODS document (§6), as canonical JSON.
snapshots/<hash>.json no A run's full inputs. <hash> is the hash the run recorded.
bundles/<hash>.json no The context a run was given. <hash> as above.
terrain/<hash>.json no A terrain grid that a snapshot or bundle refers to as {"$terrain": "<hash>"}.
outputs/<name> no A run output kept as a file, for example one CSV of 1-minute rows per monitor.
any other path no A file the document names by a File record (files[].path), such as an open grid grids/<sha256>.json or a large value values/<sha256>.json. The manifest lists it under outputs.

A file under snapshots/, bundles/ or terrain/ is content-addressed: its hash MUST equal its name. A writer that has a file whose content does not match the recorded hash still includes it, and the manifest says so (§4).

4. Manifest

Field Type Holds
format string "ods-package".
formatVersion string "1".
odsVersion string The ODS release the document follows, for example "1.0.0". Each schema is named by its $id on opendevelopmentstandards.org under that release.
created string When the package was written (ISO 8601).
producer object name, and optional engine: the versions that ran.
subject object What the package is about: type, id and optional name. type is "Trace" for a run, with optional flowVersion and flowUpdatedAt (flowChangedSinceRun is true when both times are present and differ), or "Document" for a document with no run, such as a layout export: its id is the document's, and it has no snapshots.
sharing string Where the contents may go (§7): open, approved or local.
personalData array The personal information classes the document holds (§7). Empty when it holds none.
snapshots array One entry per run snapshot (below). Empty for a Document package.
terrain array Present only when a snapshot or bundle refers to terrain.
bundles array Present only when the package holds context bundles.
outputs array Present only when the package holds output files: their paths.
files array Every file except manifest.json: path, bytes, sha256.
integrity object algorithm ("sha256") and a description.
packageHash string The hash of the canonical JSON of this manifest without packageHash.

An entry in snapshots, bundles or terrain has hash, included and, when included, verified (the content matched the hash when written). Entries in snapshots and bundles also name the run: traceId.

An optional array or object is left out when it is empty, except personalData, which is always present.

5. Verification

A reader MUST run these checks before it shows the content:

  1. Each file in files is present, with the listed bytes and sha256.
  2. packageHash equals the hash of the manifest's canonical JSON without packageHash.
  3. Each included content-addressed file hashes to its name.
  4. A file that files does not list is a warning.

Result:

  • verified: every check passed.
  • incomplete: no check failed, but at least one warned (an unlisted file, a blob not included, an unknown formatVersion).
  • failed: a file is missing, changed or has the wrong size, the manifest changed, the package hash is missing, or a blob does not match its name.

Notes about the content never change the result. Examples: a run whose snapshot the manifest does not list; a flow that changed after the run.

A reader SHOULD refuse an archive above a size limit it states, before it unzips it (the reference reader refuses 1 GiB unzipped).

6. Document

ods.json is one ODS Document:

Key Holds
odsVersion As in the manifest.
generatedAt When the document was made.
producer The software that made the document.
sharing As in the manifest.
risk frameworks: the frameworks the runs judged against, with the controls the runs had to meet.
context What the runs evaluated, and who took part (stakeholders).
environment The conditions. Left out when not filled.
methodology flows: each flow the runs used, once. traces: the subject trace first, then the runs its flow steps started. algorithms, evidence, assumptions: the methods the runs used, the evidence for them and the readings the producer chose.
files The files that records point at. A trace names its snapshot as one of them, at snapshots/<hash>.json.

The schema is core/Document.json. A document with no odsVersion at its root was written before ODS had releases: a reader checks its hashes and does not read its records as ODS records.

Sealed steps

A step that runs a closed engine is sealed. Its trace keeps the step's full inputs and outputs and names the method it claims to follow (an Algorithm, with version and publisher), but not how the engine works. A package MAY carry the Evidence that the Algorithm cites, such as a conformance report.

7. Sharing

A document can hold personal information, such as the address of a residence. The manifest's sharing says where the contents may go:

  • open: anywhere.
  • approved: only to services the reader approves.
  • local: nowhere; the contents stay on the reader's device.

A reader, and any agent or service connector it offers, MUST follow sharing, and MUST show what it will send before it sends anything. The writer fills personalData from the classes the schemas mark, so a writer cannot leave it out by mistake.

8. Conformance

  • A writer conforms when every package it writes passes §5 with the result verified, given complete inputs, and fills sharing and personalData.
  • A reader conforms when it runs §5 in full, reports the result and the failed checks, and follows §7.