# Enterprise Disclosure Review — semantic contract A bounded original companion for EM-XCT-05. Version 0.1.0 is a bounded reference; the publication manifest records its catalogue lifecycle. It provides metadata records and restricted applicability diagnostics, not a source-value delivery or policy-enforcement service. Publication status and reviewable-draft assurance are distinct. See review.md for actual audit scope and adoption-limits.md before integration. ## Contract Two immutable records are supported: a proposal containing 1–32 single-object metadata members, and a review referring to exactly one proposal identity/revision/digest. Members may describe the same or different objects; every member names exactly one, with one consistent revision/digest per referenced ID across the proposal. Different projections of the same object are explicitly separate members. A calculated source aggregate must already be owned/modelled by its domain. The review does not become that domain aggregate. Every proposal pins its audience, purpose, environment, known previous-release context and custody-instruction context. Every member pins source revision, source schema, output shape and 1–64 named top-level scalar fields. Every field has 1–8 exact classification-binding references. These are opaque external record pins: identity, revision and digest. This reference does not duplicate external scheme/term definitions, retrieve/interpret artifacts, validate source values or infer a classification order. The host snapshot must pin the current proposal itself, contain its complete current context/member declarations, and enumerate the complete active review-pin set. Retiring a proposal changes that current pin. Active and withdrawn review pins must be disjoint; supplied review records must equal the active set. The host attests that the selected fields are scalar leaves of a closed source schema and that its external pins actually resolve to their declared objects, classifications and current custody context. The reference checks exact agreement, not the truth or completeness of those assertions. Merely echoing the caller's proposal as the host snapshot defeats the integration contract. Examples are stamped host-internal synthetic fixtures and are not a source resolver or integration template. The whole snapshot is validated against a closed schema and exact identifier grammar before returning any record result. Active review IDs are unique; active/withdrawn overlap is rejected by identity/revision even if their digests differ. Withdrawn-pin existence and historical provenance remain host attestations. Snapshot `asOf` must equal the trusted host's supplied evaluation `now`; this binds the declared time but does not attest clock accuracy or that authority/source observations actually came from that instant. A current snapshot cannot be relabeled as historical evidence without a genuine preserved snapshot from that time. `inspect()` returns restricted internal applicability diagnostics. It requires a **trusted host assertion** for Dimension and inspect capability before inspecting record contents. This assertion is not an authentication token, signature or user request field. The host must authenticate and authorize the request separately. No result is suitable for forwarding verbatim to a recipient. Uniform HTTP refusal, timing/existence protection and actual serving are not implemented. Current author/reviewer authority, exact context/membership, the complete review set, withdrawal and the half-open review interval `[validFrom, validTo)` affect applicability. Assessment time cannot predate proposal capture, even for an unauthoritative review; future capture is stale. A cleared applicable review yields `applicable-review`. Every return carries `notServingAuthorization=true`, the proposal pin, snapshot digest, evaluation time, counted review pins, ignored pins/verdicts/reasons and the withdrawn-pin list. These are restricted diagnostics. All verdicts, including negative/inconclusive ones, cease to contribute outside their declared windows or current authority; expiration alone never grants clearance, and ignored negatives remain visible alongside any independently valid clearance. Hosts requiring persistent objections need a different explicitly reviewed profile. Rejection, inconclusive assessment, absent/expired review, stale context and conflicting eligible verdicts remain distinct. Only one active revision per review identity is accepted, and an active review cannot immediately supersede another still-active review. An explicit startup profile permits self-clearance; segregation profiles require a different reviewer for clearance. An authorized author's rejection or inconclusive assessment still counts under segregation and conflicts with another reviewer's clearance. Qualified ASCII actor strings are compared exactly; the host must bind them to actual distinct people where required, rather than aliases. These are governance choices, not a NIST conformance claim. Early stale/context results have `reviewsEvaluated=false`, with no verdict analysis; counted/ignored visibility applies after review evaluation. The `priorReleases` pin records the host's known relevant release context, not all knowledge held by every recipient. Human clearance and exact pins do not prove privacy, prevent subtraction/re-identification, or erase earlier releases. `custodyContext` is an opaque pin to separately owned instructions, including any unresolved hold/schedule conflict. Its equality establishes neither permission nor prohibition to retain, serve or destroy. No actual disposition-state calculation exists here. The host evaluator must return insufficient-context for unresolved custody or unsupported classification comparisons; inspect() does not perform these checks and can report applicable-review while a hold remains unresolved. The matrix example contains an explicit reviewer rejection of a synthetic subtraction risk; the code does not discover the risk itself. There is no structured source-value payload field, but free-text `residualRisk` and identifiers can themselves contain sensitive facts. The code neither detects nor redacts them. Authors must avoid copying source values into notes unless their actual record policy permits it. Actor identifiers, notes, diagnostic pins and past revisions need their own access and custody controls. Immutability means no silent in-place revision, not a universal obligation to retain personal data forever; disposal of records remains a separately governed host operation. ## Identity, time and changes The digest is SHA-256 over the entire record with only its top-level `digest` member removed. Format, type/version, Dimension, identity, revision and body are included. Encoding is a named local restricted JSON representation: UTF-8, sorted string keys, compact separators, no floats/nonfinite values or Unicode normalization; list order is significant. This is not RFC 8785/JCS. Identifiers use exact scheme-bearing printable ASCII syntax; revisions/member keys use nonempty ASCII letters/digits/dot/underscore/hyphen tokens, with no whitespace. Code uses full-string matching in addition to JSON Schema patterns. No URI equivalence or identifier-alias resolution is claimed. Encoding rules: keys sort by Unicode scalar/code-point order; quote and backslash use `\"` and `\\`; backspace/form-feed/newline/carriage-return/tab use `\b`, `\f`, `\n`, `\r`, `\t`; other U+0000–001F characters use lowercase four-digit `\u00xx`; slash, DEL, U+2028/U+2029 and other permitted scalar characters are emitted literally in UTF-8. Integers use ordinary base-10 without a plus sign or leading zeros; booleans/null are lowercase JSON tokens. Surrogates and Python container/string subclasses are rejected. The tests include a literal byte vector with C0 controls, U+2028, quote and backslash. No independently implemented cross-language/native digest compatibility is claimed. JSON input rejects duplicate keys, invalid UTF-8 and non-integer numeric syntax. Dictionary APIs are not wire parsers; the host must use `load()` for serialized input. No missing offset or leap-second support: timestamps are actual calendar instants in whole UTC seconds with `Z`. Calendar parsing avoids platform-dependent year formatting. Field `kind: number` describes external source metadata only; this format carries no numeric source payload. `seal()` computes content integrity and validates local structure. It does not approve content. `import_records()` performs a pure transactional immutable merge of the complete local master set: same revision+digest is idempotent; a conflicting revision fails; corrections use a new revision and preserve history. It requires both inspect and record host assertions. It does not persist, authenticate the writer's object-specific role, compare-and-swap a database, or enforce review authority at write time. The host must do those things. Imported unauthoritative reviews may be retained as evidence but cannot count as applicable under a different current authority snapshot. The import validates internal review→proposal and optional review→superseded-review pins against that full local set: exact existence/digest, correct type, same proposal identity for supersession, nondecreasing assessment times and acyclic supersession links. Self-supersession of the same identity/revision is invalid. Supersession does not automatically change authority or the host's active set. Same-second corrections can be ordered by the explicit link; opaque revision strings have no numeric/lexical ordering meaning. A snapshot inspection assumes those store-level invariants were enforced at import; it additionally rejects multiple active revisions and a still-active superseded target. The inspection check covers only immediate supersession edges in the supplied active records. The host must deactivate transitive superseded ancestors too; inspect cannot recover an omitted intermediate record. Supersession forks and replacement across revisions of the same proposal identity are permitted; current governance must resolve the active set without silently selecting a winner. Import's cycle traversal is defensive; constructing a digest-consistent cycle is not part of the executed fixture evidence. Reference coherence concerns nested reference pins; it does not reserve the envelope's own ID as an external-reference namespace. Historical answers need preserved snapshots and current permission to read those records; each returned answer pins its input snapshot. No past serving decision is reusable as a current grant. Prototype R1/R2/R3 records are refused by 0.1.0; preserve and inspect them with their original frozen schema/reference. The release version changes every record digest; do not relabel or automatically reseal old evidence. No automatic mixed-version import, upgrade or downgrade exists. A future release needs explicit migration mappings and separate version dispatch rather than reinterpretation of stored bytes. ## Execution and limits Run `python test_disclosure.py` with Python 3.11+ and `jsonschema==4.26.0`. This writes a test report and three synthetic fixtures. The reference has no network, data-serving or destruction operation. Input bounds (256 KiB, depth 20, at most 128 entries in a generic list/object, 32 members, 64 fields/member) are reference constraints, not a tested denial-of-service protection. The byte cap can bind before all cardinality maxima are reached. The report records code/schema/test/README hashes and Python/jsonschema versions. Additional bounds: at most 64 supplied active reviews, 64 active pins, 64 withdrawn pins and 64 entries per actor catalog; immutable merge requires the complete local master set, and `len(existing)+len(incoming)` cannot exceed 128 even for an idempotent replay. This reference cannot scale by silently partitioning away required internal references. A real rollover/partition/migration design is future work. The test report is written after fixtures and also hashes their exact generated bytes. The code version is checked against all three schema version constants (proposal, review and snapshot) on module load. The tests include three profiles, schema/classification/context drift, changed membership/fields/order, known prior-release/custody-context changes, withdrawn authority, reviewer segregation, half-open expiry, equal-authority conflict, incomplete review sets, immutable correction/import, internal supersession links, type preservation, rights assertions, malformed/unsupported JSON, identifier-alias edge cases, nested-field rejection and round-trip. They do not test a real source resolver, policy engine, schema compiler, reviewer judgment, custodian, database concurrency, recipient channel or native V3 engine in this unit suite. Native synthetic checks are recorded separately in acceptance-results.json. See the current test report for the executed count. The semantic tree is in spec.json. Native V3 binding stores each proposal/review identity as its own object and each immutable revision as a separate restricted fact. Native storage time is distinct from proposal capture and review validity. All revision facts coexist; native fact supersession does not select the active review. Validate native envelopes, validate_native(), the complete local register through import_records(), and inspect() under independently obtained current host state. The explicit companion calls are not automatically dispatched by V3. ## Release clarifications after the R3 prototype audits Host snapshots carry an exact format/version and every answer carries evaluatorVersion. Snapshot activeReviews is scoped to the exact proposal revision, not all revisions of that proposal identity. Inspection additionally refuses proposal/review identity collision and any active immediate supersession target by identity/revision, including conflicting digests. Assessment after the evaluation instant, not-yet-valid intervals and expired reviews have distinct ignored reasons. Earlier authority/segregation exclusions remain the first reason if several exclusions apply. Reference coherence enforces one revision/digest per referenced ID across all roles in a record, including evidence. It cannot cite an earlier revision of that same ID as a diff baseline in the same record; use a separately identified externally governed diff artifact, without pretending it is the earlier object itself. Ignored supplied reviews retain verdict/reason. Withdrawn reviews are represented by pins only; retrieve their historical records under current read authority for their verdict. Maximum string length is 4096 Unicode code points. The closed bounds remain operational limits, not a hostile-input protection claim. The 128 bound applies to the complete current local register plus incoming batch; repeated import also consumes the batch count. It is not a monotone lifetime counter. With indefinite historical retention it is effectively a 128-record growth ceiling. Partial disposal leaving an internal dangling proposal/supersession reference makes subsequent import invalid. This implementation offers no tombstone semantics or disposal/migration operation. Any separate host disposal must preserve internal reference closure; replacing records with fabricated tombstones or silently dropping required history is not supported. Retention constraints may forbid even a reference-closed removal, so obtain the actual custody decision. At-rest append-only storage and compare-and-swap are host duties. The pure merge detects immutable conflicts only against the supplied register. An independently trusted prior digest or snapshot is needed to detect replacement of an unreferenced stored leaf. Maximum review validity duration is host policy. The local format requires an end time but permits dates through year 9999; finite validity is not a short-expiry guarantee.