openOM

Requirement reference (0.1)

Every OM-* requirement ID cited by the schema, the code catalog, the samples, and the reference implementation resolves here to its normative clause. MUST/MUST‑NOT are binding; SHOULD/MAY are recommendations; INFO is advisory. Machine-readable: /spec/requirements.json.

OM-CANON-*

OM-CANON-001RFC 8785 JCS serialization
MUST · §C
An openOM payload MUST be serialized to canonical bytes using RFC 8785 JSON Canonicalization Scheme (JCS) - UTF-8 with no BOM, member keys sorted by UTF-16 code unit, no insignificant whitespace, and the ECMAScript number model - after the §C.1 preprocessing is applied.
OM-CANON-003Signature excluded from integrity preimage
MUST · §C
The integrity hash MUST be computed over the payload with meta.signature removed (not nulled) and MUST be expressed as "sha256:" followed by the lowercase hex SHA-256 digest, so that adding a signature in a later version does not disturb the hash.
OM-CANON-005Producer stores exact preimage bytes
MUST · §C
A Producer MUST embed as the om.json stream exactly the canonical preimage bytes (the JCS of the payload with meta.signature removed) that were hashed, so a Consumer's byte-recompute of the stored stream equals the stored payloadHash directly.
OM-CANON-007capRate is a decimal fraction
MUST · §C
The capRate value MUST be expressed as a decimal fraction (e.g. 0.0625 for 6.25%), not as a percentage number.
OM-CANON-008Consumer hashes bytes as received
MUST · §C
A Consumer verifying integrity MUST hash the stored payload bytes exactly as received and compare that digest to the marker hash; it MUST NOT re-canonicalize or re-normalize (NFC) the received payload before verifying.
OM-CANON-009Reject duplicate member names
MUST · §C.1
Canonicalization MUST reject a payload containing two object member names that collide after NFC normalization, raising OM-IO-DUPKEY.
OM-CANON-010Reject malformed Unicode and bad structure
MUST · §C.1
Canonicalization MUST reject strings or member names containing a lone/unpaired UTF-16 surrogate (OM-IO-BADUTF8) and MUST reject a payload whose top-level value is not a JSON object or that exceeds the nesting-depth guard (OM-IO-STRUCTURE).
OM-CANON-013Reject non-representable integers
MUST · §C
Canonicalization MUST reject any integer-valued number whose magnitude exceeds 2^53-1 (the ECMAScript safe-integer limit), raising OM-IO-NUMRANGE, since such values would be silently rounded by the number model.
OM-CANON-015JCS number formatting
MUST · §C
An in-range number MUST be serialized using the RFC 8785 / ECMAScript Number-to-string rules - negative zero as 0, exponent notation only outside the ES fixed-notation range, and safe integers with no exponent.
OM-CANON-016Integrity-hash preimage definition
MUST · §C.3
The integrity hash preimage MUST be the JCS canonical bytes of the payload with meta.signature removed, and the hash MUST be SHA-256 over those bytes.
OM-CANON-017Only signature excluded from preimage
MUST · §C.3
Only meta.signature may be excluded from the integrity preimage; every other field - including meta.sourceDocHash and meta.supersedes - MUST be part of the hashed preimage.

OM-CONS-*

OM-CONS-010Cap rate vs NOI/price
SHOULD · H.4
A validator SHOULD emit warning OMW-W010 when deal.capRate differs from deal.noi divided by deal.askingPrice by more than the absolute cap-rate tolerance (default 0.005).
OM-CONS-011Price per SF vs price/SF
SHOULD · H.4
A validator SHOULD emit warning OMW-W011 when deal.pricePerSF differs from deal.askingPrice divided by property.buildingSF by more than the relative monetary tolerance (default 0.01).
OM-CONS-012Pro-forma NOI without as-of
SHOULD · H.3
A validator SHOULD emit warning OMW-W012 when deal.noiType is 'pro-forma' but deal.noiAsOfDate is absent.
OM-CONS-013Cap rate plausibility band
SHOULD · H.4
A validator SHOULD emit warning OMW-W013 when deal.capRate falls outside the plausibility band (default [0.02, 0.20]).
OM-CONS-014Non-positive money/area
SHOULD · H.3
A validator SHOULD emit warning OMW-W014 when deal.askingPrice, deal.noi, or property.buildingSF is present and non-positive (<= 0).
OM-CONS-020Year-1 rent vs in-place NOI
SHOULD · H.4
A validator SHOULD emit warning OMW-W020 when noiType is 'in-place' and the first rent-schedule period's annualRent differs from deal.noi by more than the relative monetary tolerance (default 0.01).
OM-CONS-021Gap between rent periods
SHOULD · H.3
A validator SHOULD emit warning OMW-W021 when a rent-schedule period starts more than one day after the prior period's periodEnd (a gap between consecutive periods).
OM-CONS-022Overlapping rent periods
SHOULD · H.3
A validator SHOULD emit warning OMW-W022 when a rent-schedule period's periodStart is on or before the prior period's periodEnd (overlapping consecutive periods).
OM-CONS-023Escalation vs rent step
SHOULD · H.4
A validator SHOULD emit warning OMW-W023 when a period's escalationFromPrior differs from the implied annualRent step (annual/prevAnnual - 1) by more than the absolute rate tolerance (default 0.005).
OM-CONS-024rentPSF vs annualRent/SF
SHOULD · H.4
A validator SHOULD emit warning OMW-W024 when a period's rentPSF differs from its annualRent divided by property.buildingSF by more than the relative monetary tolerance (default 0.01).
OM-CONS-025monthlyRent vs annualRent/12
SHOULD · H.4
A validator SHOULD emit warning OMW-W025 when a period's monthlyRent differs from its annualRent divided by 12 by more than the relative monetary tolerance (default 0.01).
OM-CONS-026Rent period outside lease term
SHOULD · H.3
A validator SHOULD emit warning OMW-W026 when a rent period's periodStart is before lease.commencement or its periodEnd is after lease.expiration.
OM-CONS-030Remaining term vs dates
SHOULD · H.4
A validator SHOULD emit warning OMW-W030 when lease.remainingTermMonths disagrees with (expiration - as_of reference date) beyond the remaining-term-days tolerance (default 31 days), using 30.4375 days per month.
OM-CONS-031Total term vs dates
SHOULD · H.4
A validator SHOULD emit warning OMW-W031 when lease.termMonths disagrees with (expiration - commencement) beyond the lease-term-days tolerance (default 31 days), using 30.4375 days per month.
OM-CONS-032assertedDate in future
SHOULD · H.3
A validator SHOULD emit warning OMW-W032 when assertedDate is later than a caller-supplied processing date (never the system clock, so it is silent on the default path).
OM-CONS-033noiAsOfDate after assertedDate
SHOULD · H.3
A validator SHOULD emit warning OMW-W033 when deal.noiAsOfDate is later than assertedDate.
OM-CONS-034Expiration on/before commencement
SHOULD · H.3
A validator SHOULD emit warning OMW-W034 when lease.expiration is on or before lease.commencement.
OM-CONS-040Net lease vs pass-throughs
SHOULD · H.3
A validator SHOULD emit warning OMW-W040 when leaseTypeAsserted is a net type (NN, NNN, absolute-net) yet landlordResponsibilities marks taxes, insurance, or cam as landlord-borne.
OM-CONS-041Lease type vs responsibilities
SHOULD · H.3
A validator SHOULD emit warning OMW-W041 when a gross/modified-gross lease records no landlord responsibilities, or an absolute-net lease records structural/HVAC (roof, structure, parking, hvac) landlord responsibilities.
OM-CONS-050Self-supersede no-op
SHOULD · H.3
A validator SHOULD emit warning OMW-W050 when meta.supersedes equals the hash of this payload with the supersedes pointer removed (a no-op re-embed superseding content byte-identical to itself).
OM-CONS-051Re-embed assertedDate regression
SHOULD · H.3
During re-embed, an implementation SHOULD emit warning OMW-W051 when the new payload hash differs from the embedded prior payload's hash and the new assertedDate is earlier than the prior embedded assertedDate (a superseding assertion dated before the one it replaces).
OM-CONS-060Unverifiable 'verified' source
SHOULD · H.3
A validator SHOULD emit warning OMW-W060 when a rent period's source is 'verified' but the 0.1 payload carries no corroborating verification metadata.

OM-DD-*

OM-DD-001Payload conforms to openOM 0.1 JSON Schema
MUST · Part II §E / §H.1
An openOM payload MUST validate against the openOM 0.1 JSON Schema (2020-12) — including the required top-level members @context, @type (const RealEstateListing), specVersion (const 0.1), assertedBy, assertedDate, and meta — and any JSON Schema violation not specialized to another code is reported as the blocking schema error OMV-E001.
OM-DD-002Currency defaults to USD when absent
MAY · Part II §E / §H.1
The top-level `currency` member is OPTIONAL and, when present, MUST be a three-letter ISO 4217 code (pattern ^[A-Z]{3}$); when it is absent the payload is interpreted as USD, and validators emit the non-blocking info finding OMI-I001 recording that the USD default was assumed (with warning OMW-W061 also mapped to this requirement).
OM-DD-003noiType/noiAsOfDate required when noi present
MUST · Part II §E / §H
Whenever deal.noi is present, deal.noiType and deal.noiAsOfDate are REQUIRED; a payload carrying deal.noi but missing either member MUST be rejected as schema error OMV-E002.
OM-DD-004Per-field provenance via rentPeriod source; defaults to asserted
SHOULD · Part II §E / §H.1
In openOM 0.1 per-field provenance is carried ONLY by the OPTIONAL `source` member on each rentSchedule rentPeriod object, whose value MUST be one of `asserted`, `extracted`, or `verified`, and an absent `source` MUST be interpreted as `asserted`, with validators emitting the non-blocking info finding OMI-I002 when any rentPeriod omits it.

OM-EMB-*

OM-EMB-002Catalog /AF references the payload
MUST · §D
An embedding implementation MUST add the om.json payload's Filespec to the PDF catalog's /AF (associated-files) array, since populating only the /EmbeddedFiles name tree does not create the required /AF association.
OM-EMB-004Embedded stream /Subtype is application/ld+json
MUST · §D
The embedded-file stream(s) for om.json MUST carry /Subtype = application/ld+json (name-escaped as /application#2Fld+json) on each of their /EF /F and /EF /UF entries.
OM-EMB-007/EF /F and /UF share one stream
MUST · §D
The Filespec's /EF dictionary MUST provide both /F and /UF entries, and both MUST reference the same single embedded-file stream object.
OM-EMB-010Store exact JCS payload bytes verbatim
MUST · §D
The exact JCS-canonicalized payload bytes MUST be stored verbatim as the embedded-file content (the implementation must never let the PDF library re-serialize them), and the integrity hash is computed over those same bytes.
OM-EMB-011No timestamps written (determinism)
MUST-NOT · §D
The embed operation MUST NOT write any generation or modification timestamps (e.g. Filespec /CreationDate or /ModDate, or any wall-clock time-of-embed) into the output, so that output is deterministic and byte-reproducible. (The payload's assertedDate is an author-supplied assertion date, not a generation timestamp, and IS written to the XMP marker.)
OM-EMB-014Locate payload by decoded filename om.json
MUST · §D
A reader locating the payload MUST resolve the catalog /AF Filespec whose decoded filename (/UF preferred, else /F) equals "om.json", then read its /EF stream.
OM-EMB-020Incremental byte-preserving save
SHOULD · §D
An implementation SHOULD perform an incremental, byte-preserving PDF save on embed (appending an update rather than a full load→save re-serialization) so the original bytes are preserved; this matters chiefly for signed OMs and is currently a documented follow-up not yet implemented.

OM-ERR-*

OM-ERR-001Finding is the validation result unit
MUST · §H
Every result produced by validation MUST be expressed as a Finding record carrying a stable code, a severity of error, warning, or info, a payload path, and a human-readable message.
OM-ERR-002Configurable consistency tolerances
MUST · §H.4
Consistency-tier checks MUST compare values against numeric tolerances (cap-rate absolute, monetary relative, rate absolute, term-day, and cap-rate plausibility band) that are configurable by the caller and default to the spec-defined §H.4 values.
OM-ERR-004blocked equals errorCount > 0
MUST · §H
The validation report's `blocked` flag MUST equal `summary.errorCount > 0`, so that a payload is blocked from embed if and only if at least one error-tier finding is present.
OM-ERR-007Finding record shape
MUST · §H
A Finding MUST expose `code`, `severity`, `path`, and `message`, and MAY carry an optional `requirement` back-reference plus optional `expected`/`actual` values.
OM-ERR-008JSON Pointer path and requirement back-reference
MUST · §H.1
A Finding's `path` MUST be an RFC 6901 JSON Pointer into the payload, with the empty string denoting the whole document; a Finding MAY additionally carry a `requirement` back-reference to the spec requirement it enforces (populated for every currently-defined code).
OM-ERR-009Deterministic finding order
MUST · §H.1
Findings MUST be emitted in a deterministic order — by severity, then by code ascending, then by path as a byte string — identical across runs and across implementations.
OM-ERR-010om_validate report envelope
MUST · §H
The `om_validate` result MUST be a report envelope containing `specVersion`, `validatorVersion`, the `errors`/`warnings`/`info` finding arrays, a `summary` of error/warning/info counts, and the `blocked` flag.
OM-ERR-013meta.supersedes format (OMV-E010)
MUST · §H
A present `meta.supersedes` value MUST be either null or a string of the form `sha256:<64 hex chars>`; any other value MUST be reported as error OMV-E010.
OM-ERR-014Advisory info tier / skipped-check context
INFO · §H.4
The validator SHOULD emit advisory info-tier findings (e.g. OMI-I003 when a consistency cross-check is skipped because a required input is absent); info findings never block and MUST NOT mutate the payload.
OM-ERR-090meta.signature shape (OMV-E003)
MUST · §H
`meta.signature` MUST be either null or the reserved `{alg, keyId, value}` shape; any other value MUST be reported as error OMV-E003.

OM-HOOK-*

OM-HOOK-002Change-notification webhook envelope
MUST · §Y (spec Part II §5b)
A §Y change-notification delivery MUST carry a JSON envelope with envelopeVersion, event, id, publishedAt (RFC 3339 UTC 'Z'), sourceUrl, specVersion, payloadHash, verification, and payload, conforming to webhook-envelope-0.1.schema.json, that a consumer POSTs to a broker-configured receiver and the receiver validates on parse.
OM-HOOK-003HMAC signature over exact body with replay window
MUST · §Y
Each §Y delivery MUST be signed with an HMAC-SHA-256 'OpenOM-Signature: t=<unix>,v1=<hex>' header computed over the exact '<timestamp>.<rawBody>' preimage, and a receiver MUST verify it by recomputing that HMAC, comparing in constant time, and rejecting when |now - t| exceeds the tolerance window (default 300s).
OM-HOOK-006Sign/verify the exact transmitted bytes
MUST-NOT · §Y
The signature MUST be computed and verified over the exact raw body bytes as transmitted/received; the envelope MUST NOT be re-serialized on either the sending or receiving side.
OM-HOOK-011SSRF-safe webhook target
MUST · §Y (with [OM-SEC-001])
Before delivering to a webhook target the sender MUST reject an unsafe destination URL: the scheme MUST be https and the host MUST NOT be a loopback/private/link-local/CGNAT/metadata host or an IP literal in any encoding (dotted-quad, dword, octal, hex, short forms, and IPv4-mapped/compressed IPv6).

OM-IO-*

OM-IO-001Upstream fetch / DNS failure
MUST · MCP hosted transport — url fetch
When the hosted transport fetches a PDF from an https URL, a DNS resolution that yields no addresses, or a connection/read failure from the upstream host, MUST be reported as a retryable OM-IO-001 error rather than any partial or fabricated result.
OM-IO-002SSRF blocked address range
MUST · MCP hosted transport — SSRF hardening
The hosted url fetch MUST resolve the host first and refuse the request with OM-IO-002 when any resolved IP falls in a blocked (internal/loopback/private) address range, and this check MUST be re-applied on every redirect hop so a redirect cannot reach a blocked host.
OM-IO-003Operation / fetch timeout
MUST · MCP hosted transport — bounded execution
A fetch that exceeds the connect/read timeout, or a guarded parse operation that exceeds its wall-clock timeout, MUST be aborted and reported as a retryable OM-IO-003 timeout error rather than being allowed to hang.
OM-IO-005Size / page ceiling never silently truncated
MUST · MCP hosted transport — resource caps
An input that exceeds a resource cap — a fetched body larger than max_bytes, content lacking the %PDF- header, or a document whose page count exceeds the per-call page ceiling — MUST be rejected with OM-IO-005 and MUST NOT be silently truncated.
OM-IO-006Blob missing or expired
MUST · MCP hosted transport — blob store
A request referencing a blobId that does not exist, has expired past its TTL, or has been deleted MUST fail with OM-IO-006 (not found or expired).
OM-IO-007Blob authorization (anti-IDOR)
MUST · MCP hosted transport — blob store authz
A blobId that exists but is bound to a different principal MUST be rejected with OM-IO-007 (not authorized), so a principal can never read another principal's blob, and this ownership binding cannot be forged or omitted through the data PUT.
OM-IO-008Unsupported PDF reference for transport
MUST · MCP transport — PdfRef resolution (§6d)
A PDF reference that the active transport cannot serve MUST be rejected with OM-IO-008: the PdfRef must carry exactly one of path/url/blobId, on stdio url/blobId and request-upload are unavailable, on the hosted transport a local path is refused, and only https URLs are fetched.
OM-IO-009Redirect limit exceeded
MUST · MCP hosted transport — url fetch
The hosted url fetch MUST follow at most max_redirects redirect hops and, once that limit is exceeded, MUST stop and fail with OM-IO-009 rather than following further redirects.
OM-IO-010Malformed PDF / parser crash
MUST · MCP — untrusted-PDF parse isolation
A PDF that cannot be read or parsed — a malformed document, an unreadable path, or a guarded-subprocess crash or in-child exception (including a rejected memory limit) — MUST surface as OM-IO-010 and MUST NOT take down the server.
OM-IO-012Malformed / out-of-bounds page range
MUST · core text extraction — page range
A page-range argument that is malformed or refers to pages outside the document MUST be rejected with OM-IO-012 rather than silently clamped or ignored.
OM-IO-013Malformed / mismatched pagination cursor
MUST · core text extraction — pagination cursor
A pagination cursor that is malformed, or presented against a different input than the one that produced it, MUST be rejected with OM-IO-013.
OM-IO-014Rate limit / quota exceeded
MUST · MCP hosted transport — rate limiting
A principal exceeding its fixed-window call limit (in-memory, distributed, or per-API-key quota) MUST be denied with a retryable OM-IO-014 error carrying a retry_after hint, and a multi-instance deploy MUST enforce one global limit per principal via a shared counter store.
OM-IO-402Inference extraction is a separate paid service
MUST-NOT · MCP boundary — deterministic-only server
The open deterministic server MUST NOT perform hosted inference extraction; the InferenceExtractor seam is implemented only by the separate commercial service, and a hosted deployment representing an unentitled inference-extraction request MUST return the non-retryable OM-IO-402 payment-required seam, which the deterministic tools never raise.

OM-MCP-*

OM-MCP-004Tool error envelope
MUST · §I
Every openOM MCP tool MUST map any expected failure to the error envelope `{"error": {code, message, retryable, details?}}` (with optional `retryAfter`) and MUST NOT let an exception propagate out of the tool.
OM-MCP-005Cursor scoped to input
MUST · §I
An om_extract_text pagination cursor MUST be bound to the specific input document (a sha256-derived tag of the PDF bytes), and a cursor whose tag does not match the current input MUST be rejected as a CursorError rather than resumed against a different document.
OM-MCP-007No network, no inference in MCP
MUST-NOT · §I/§V
The openOM MCP tool layer MUST NOT perform any network access or any LLM/inference call — the deterministic cardinal boundary applies to every tool body.
OM-MCP-008Per-call page ceiling
MUST · §I
On the hosted (http) transport, a document whose page count exceeds the configured per-call page ceiling MUST be rejected with OM-IO-005 rather than silently truncated, and the page count MUST itself run inside the bounded subprocess so a malicious page tree cannot hang or OOM the host.
OM-MCP-010om_inspect classify and profile
MUST · §I
om_inspect MUST be a read-only tool that classifies and profiles the document, returning class, classConfidence, pages, payload summary, images, textCoverage and ocrOverlay without mutating the input.
OM-MCP-011om_read payload with hash guard
MUST · §I
om_read MUST return the broker-asserted openOM payload together with a verification block, and MUST surface a hash-mismatched payload as null (never as a trusted payload) so an altered payload is never presented as unaltered.
OM-MCP-012om_extract_text paginated
MUST · §I
om_extract_text MUST be a read-only tool that returns paginated text plus best-effort tables for the selected page range, honoring the max_chars budget and the input-scoped cursor for continuation.
OM-MCP-013om_extract_images manifest only
MUST · §I
om_extract_images MUST be read-only and MUST return an image manifest referencing local file paths (with xref, dimensions, colorspace, hasSMask, mime, byte size and contentHash) rather than inlining raw image bytes into the response.
OM-MCP-014om_validate two-tier report
MUST · §I
om_validate MUST return a two-tier report of errors, warnings and info plus the canonical payload hash, and the call itself MUST be treated as a success even when the payload contains errors (validity means well-formed and self-consistent, not market truth).
OM-MCP-015om_embed validate-then-embed
MUST · §I
om_embed is the only mutating tool and MUST validate the payload before embedding, refusing the embed with OMV-E001 when the payload has schema errors.

OM-PROF-*

OM-PROF-004Null verification is conformant
MUST-NOT · §10
A verification layer that could not be evaluated (originVerified for the §10 layer-3 domain-origin check, or signatureValid for the layer-4 reserved signature) MUST be reported as null and MUST NOT be reported as false, because null means the check was not run (no domain to check against, or not yet verifiable) whereas false would assert that the check ran and failed.

OM-REF-*

OM-REF-002Conformance suite reproduces published vectors
MUST · §T
A conforming implementation MUST provide a conformance suite that reproduces the published reference vectors and sample outcomes locally — for each vector, recomputing the JCS-canonicalized payload hash and matching it to the vector's expected `jcs_sha256`, and (where a vector PDF exists) confirming the embedded payload reads back present with a valid hash; and for each sample, validating it against the schema so that valid samples produce no errors and invalid samples both fail validation and produce (at least) all of their declared `errorCodes` — passing (exit 0) only if every check passes.

OM-SEC-*

OM-SEC-001SSRF-hardened URL fetch
MUST · § SSRF fetch (OM-SEC-001/011/014)
When fetching a PDF from a client-supplied URL, an implementation MUST accept only https, MUST resolve the host and reject the request if any resolved address falls in a private, loopback, link-local (including cloud-metadata 169.254.169.254), CGNAT, or IPv6 ULA/loopback range, and MUST connect to the pinned validated IP (resolve-then-pin, no re-resolution) to defeat DNS rebinding; the in-browser webhook/fetch path, unable to resolve DNS, MUST at minimum enforce https-only and reject every literal encoding of a blocked IP.
OM-SEC-002Decompressed payload size cap
MUST · §J
An implementation MUST cap the decompressed om.json payload at a fixed maximum and MUST abort with OM-IO-BOMB rather than inflating past the cap, on both the embed side and the read side, to prevent a decompression-bomb attack. The default cap is the Python core's MAX_PAYLOAD_BYTES = 5,000,000 bytes; the /js implementation's DEFAULT_MAX_PAYLOAD_BYTES = 5 x 1024 x 1024 = 5,242,880 bytes (5 MiB) and is overridable per call via maxBytes.
OM-SEC-006Single-use presigned upload target
MUST · §I / §K
On the hosted transport, an implementation MUST hand clients a reserved, single-use presigned upload target (blobId + presignedPut + expiresAt) for supplying PDF bytes rather than accepting arbitrary inbound uploads, and MUST refuse the request (OM-IO-008) where no blob store exists (e.g. stdio).
OM-SEC-010Bounded untrusted-PDF parse
MUST · § MCP guard (OM-SEC-010 / OM-MCP-008)
On a network-facing server, parsing of an untrusted PDF MUST run in a killable subprocess bounded by a wall-clock timeout and (on POSIX) an address-space memory cap, mapping a timeout to OM-IO-003 and any crash or in-child failure to OM-IO-010, so that a malicious PDF can never hang or exhaust the server; where an in-process memory cap is unavailable (non-POSIX), the deployment MUST bound memory externally and the tool warns once.
OM-SEC-012Per-principal rate limiting
MUST · § hosted rate limit (OM-SEC-012)
The hosted transport MUST enforce a per-principal fixed-window rate limit and, when a principal exceeds the allowed calls per window, MUST reject the call with OM-IO-014 and a retry_after value; rate limiting only bounds resource use and never weakens a correctness or verification guarantee.
OM-SEC-013Unguessable, owner-scoped blob IDs
MUST · §K
Every blob MUST be keyed by an unguessable id carrying at least 128 bits of entropy, and blob access MUST perform existence-then-authz (anti-IDOR): a blob is returned only to its recording principal, with a principal mismatch raising OM-IO-007 and a missing/expired blob raising OM-IO-006, ownership being server-written and never derived from client-supplied metadata.

OM-TRUST-*

OM-TRUST-001Badge strict-precedence state machine
MUST · §AA / §10
A consumer trust badge MUST derive its state deterministically by strict precedence over the four provenance layers - returning 'absent' when no payload is present, the terminal 'hash-mismatch' when the payload's hash is not valid (never evaluating higher layers), 'integrity-ok' when integrity passes but origin is unverified, and 'origin-verified' when the domain vouch also passes - so a higher trust state is never shown unless every lower check it depends on passed.
OM-TRUST-002Signature layer reserved, unreachable in 0.1
MUST-NOT · §10 layer 4
The layer-4 cryptographic-signature verification MUST remain reserved and unevaluated in spec 0.1 - signatureValid is null forever and the 'signature-verified' badge state is never returned - so no signature-based trust may be asserted in this version.
OM-TRUST-003UI honesty: forbidden overclaim words
MUST-NOT · §AA
Consumer UI copy MUST be honest by construction: an integrity-only pass MUST NOT use the words 'verified', 'authentic', 'signed', 'official', or 'genuine' (it proves 'unaltered since embed', not authorship or truth of figures), and every badge label/caption MUST come only from the shared honestLabel function.
OM-TRUST-005Cross-domain rehost degrades, never errors
MUST · §10.1 (L3 domain-origin)
Domain-origin (layer-3) verification proves that the entity controlling the source domain vouches for this exact payload - source and its JSON-LD mirror are HTTPS, share the same registrable domain (eTLD+1), and the mirror's canonical hash equals the embedded payloadHash - and a rehost to another domain or an unreachable/mismatched mirror MUST degrade gracefully to origin-unverified, never raise an error.
OM-TRUST-009Stale/superseded mirror warning
MUST · §AA (OMW-W051)
When the embedded payload's hash differs from the same-domain mirror's current hash AND the mirror is a genuine newer assertion - it either names the embedded payload's hash in meta.supersedes or carries a strictly later valid assertedDate - the consumer MUST classify the embedded copy as stale/superseded and surface warning OMW-W051 (keeping the badge), rather than treating it as tampering.
OM-TRUST-010Diverged same-domain mirror warning
MUST · §AA (OMW-W052)
When the same-domain mirror is reachable and integrity of the embedded payload passes but the mirror serves different, non-superseding content (edited/wrong figures, not a newer assertion), the consumer MUST surface warning OMW-W052 ('the source domain shows different data') instead of a clean integrity pass, and this MUST NOT override a hash-mismatch state.

OM-VAL-*

OM-VAL-002Cross-implementation schema-validation parity
MUST · VAL-01 / §H
Schema validation MUST be performed with full-mode format assertion enabled (Python jsonschema Draft202012Validator with FORMAT_CHECKER; ajv with ajv-formats mode:"full"), so that format-constrained fields such as date-typed assertedDate are asserted (not annotation-only) and every implementation — the Python core, the /js library, and the eval-free MV3 standalone validator — produces bit-for-bit identical validation results.
OM-VAL-006Consumer hash-mismatch handling
MUST · §C.4 / §X.4
A conformant consumer MUST recompute the SHA-256 hash over the payload bytes exactly as received and compare it to the expected omspec:payloadHash, reporting hashValid=false on mismatch; on a mismatch the payload is still returned but the consumer MUST NOT present or trust it as verified.

OM-VEC-*

OM-VEC-004Conformance sample matrix
MUST · §B
Both implementations MUST reproduce, for every sample in spec/samples/manifest.json, the recorded schema-tier and consistency-tier outcome: a sample marked valid MUST produce zero errors and not block, an invalid sample MUST block and surface each listed error code, and each listed warning code MUST be present.

OM-VER-*

OM-VER-003Forward-compatible unknown members
MUST · Spec Part II §E (schema description)
An openOM payload processor MUST accept a payload that carries unknown OPTIONAL members: the 0.1 schema leaves additionalProperties open across all objects, so unrecognized top-level or nested fields do not produce schema errors, preserving forward compatibility (non-standard/vendor fields nonetheless belong under the `ext` object to avoid colliding with future core terms).

OM-XMP-*

OM-XMP-002Required omspec XMP marker
MUST · §D.2.1
The embed operation MUST write the required omspec XMP marker properties (specName, specVersion, payloadFilename, payloadHash, assertedDate) into the PDF catalog /Metadata packet as a conformant, namespaced omspec: RDF block, with the PDF/A extension-schema description preceding it, and MUST replace any prior omspec block rather than stacking. (The Python core (xmp.py) injects the block alongside existing dc/pdf XMP, preserving it; the /js writer (embed.ts) emits a fresh XMP packet and does not preserve pre-existing XMP.)
OM-XMP-003Payload detection order
MUST · §D
The reader MUST locate the embedded om.json stream in a fixed detection order — authoritative path catalog /AF → Filespec whose /UF or /F equals om.json → /EF (preferring /UF over /F) — and MUST fall back to the /EmbeddedFiles name tree for producers that populate only that.
OM-XMP-004Idempotent re-embed (replace not stack)
MUST · §D
A re-embed MUST strip any existing om.json attachment (its catalog /AF reference and its /EmbeddedFiles name-tree entry) before attaching the new payload so it replaces rather than stacks a second copy, such that repeated embeds produce an output payload hash byte-equal to a single direct embed.
OM-XMP-005Read orchestration pipeline
MUST · §D.2.2
The deterministic read operation MUST orchestrate detect (XMP omspec:payloadHash) → extract (om.json via /AF → /Filespec → /EF) → decompress → recompute the §C hash and compare, returning a detection state of absent, present, hash-mismatch, or encrypted.
OM-XMP-006Parse object streams / compressed xref
MUST · §D.2.2
The reader MUST parse PDF structure that uses compressed object streams and compressed cross-reference streams (relied on via pdf-lib in the /js implementation) in order to locate the embedded payload.
OM-XMP-008Degraded producer: no reference hash
MUST-NOT · §D.2.2
When the om.json payload is present but the PDF carries no omspec:payloadHash reference hash (a degraded producer), the reader MUST NOT report hashValid as true — integrity stays unverified (hashValid null / payloadHash null).
OM-XMP-011Omit supersedes when null
MUST · §D.2.1
The omspec:supersedes XMP property MUST be omitted entirely from the marker when there is no prior payload (null), rather than written as an empty value.