{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://revl.dev/schema/revl-interchange-v1.schema.json", "title": "revl composition interchange (manifest + G8 audit)", "description": "The versioned, tool-consumable verdict a revl gate produces for a composition: what each component provides, requires, and reaches (its G8 boundary surface), plus the declared host-code externs and the per-service distributability verdict. A consumer can read provides/requires/reaches from this document WITHOUT running revl. See docs/interchange-format.md for the compatibility promise.", "type": "object", "required": ["schema_version", "kind", "manifest", "boundary"], "properties": { "schema_version": { "description": "MAJOR.MINOR of this interchange format. Same MAJOR is backward compatible: a consumer written for X.m keeps reading X.n (n>m); new MINOR versions only add optional members. A MAJOR bump may remove or re-shape members.", "type": "string", "pattern": "^[0-9]+\\.[0-9]+$" }, "kind": { "description": "Self-identifying tag so a consumer can tell an interchange document apart from any other JSON. Always the constant below for this format.", "type": "string", "enum": ["revl.interchange"] }, "manifest": { "$ref": "#/$defs/manifest" }, "boundary": { "description": "Per-component G8 boundary surface, keyed by component name. This is the 'reaches' half of provides/requires/reaches.", "type": "object", "additionalProperties": { "$ref": "#/$defs/boundaryEntry" } }, "externs": { "description": "Every declared host-code extern in the composition (the trust surface a proof cannot cover).", "type": "array", "items": { "$ref": "#/$defs/extern" } }, "distributability": { "description": "Per-service verdict on whether the service may cross a process seam (interop-bridge §4), keyed by service name.", "type": "object", "additionalProperties": { "$ref": "#/$defs/distributabilityVerdict" } }, "cardinality": { "description": "Optional (item 260). Per-component per-capability crossing-count ceiling per activation, keyed by component name. Present only for components that cross an emission boundary, so a crossing-free composition carries an empty object. A capability whose multiplicity is not statically provable (a loop, any recursion, a first-class emitting arrow, a crossing behind a host extern) is `unbounded` with `bound: null` and a `reason`; the component `verdict` rolls the tokens up with `unbounded` dominating.", "type": "object", "additionalProperties": { "$ref": "#/$defs/cardinalityEntry" } }, "gauntlet": { "description": "Optional. A gauntlet dossier (docs/gauntlet.md) carried in the same envelope. Its proved/tested/claimed/pending sections reuse the manifest+boundary vocabulary defined here, so item 31's dossier composes into this format without a schema change. Left open (additionalProperties) so the dossier can evolve independently.", "type": "object" }, "function_specs": { "description": "Optional (issue #2705). One row per function that states an `ensures` spec, present only when a function states one. `last_result` is the result of the last recorded `revl test --report json` run supplied with `revl audit --spec-results`, or `unrun` when none was recorded (docs/function-specs.md).", "type": "array", "items": { "type": "object", "required": ["function", "spec", "last_result"], "additionalProperties": true } } }, "additionalProperties": true, "$defs": { "manifest": { "description": "The linker's composition manifest: the static membership, load order, and each component's provide/require/isolate/intercept surface.", "type": "object", "required": ["components", "loadOrder"], "properties": { "components": { "type": "array", "items": { "$ref": "#/$defs/component" } }, "loadOrder": { "description": "Component names in dependency order (providers first). Teardown is the exact reverse (LIFO).", "type": "array", "items": { "type": "string" } }, "templates": { "description": "Optional. Instance-parametric components: spawn targets instantiated at runtime, each in its own local realm, excluded from the static composition.", "type": "array", "items": { "type": "string" } } }, "additionalProperties": true }, "component": { "type": "object", "required": ["name", "inject", "provides"], "properties": { "name": { "type": "string" }, "file": { "type": "string" }, "inject": { "description": "Provision keys this component requires (its 'requires').", "type": "array", "items": { "type": "string" } }, "provides": { "description": "Provision keys this component provides.", "type": "array", "items": { "type": "string" } }, "isolate": { "description": "Optional. provision-key -> realm name, when a key is bound in a named local realm.", "type": "object", "additionalProperties": { "type": "string" } }, "intercept": { "description": "Optional. provision-key -> interception metadata for keys this component intercepts.", "type": "object", "additionalProperties": { "type": "object" } } }, "additionalProperties": true }, "boundaryEntry": { "type": "object", "required": ["emissions", "capabilities", "compensated", "awaits", "externs"], "properties": { "emissions": { "description": "Emission call sites (irreversible boundary crossings) this component performs, as `key.method` labels.", "type": "array", "items": { "type": "string" } }, "capabilities": { "description": "emission-label -> the capability scopes its declaration carries. A single-element list of \"*\" is a bare emission that promises nothing about where it goes.", "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" } } }, "compensated": { "description": "How many of the `emissions` labels above carry a compensating undo. Counted over distinct labels, never over emit steps, so it can never exceed the number of `emissions` and a label compensated at more than one site counts once. Compensation reached through an emitting host extern has no `key.method` label and is therefore absent from this count; it is named in `compensatedHostEmissions` instead.", "type": "integer", "minimum": 0 }, "compensatedHostEmissions": { "description": "Names of emitting host externs this component compensates. They cross the boundary but carry no `key.method` label, so they are absent from both `emissions` and `compensated`. Present only when there is one, so a boundary entry with no host-extern compensation is byte-identical to before this field existed.", "type": "array", "items": { "type": "string" } }, "awaits": { "description": "Iteration/await boundaries in this component's body.", "type": "integer", "minimum": 0 }, "externs": { "description": "Host-code externs this component reaches, transitively through functions. A first-class dispatch appears as name \"*\" with class \"first-class dispatch\".", "type": "array", "items": { "$ref": "#/$defs/extern" } } }, "additionalProperties": true }, "extern": { "type": "object", "required": ["name", "backends"], "properties": { "name": { "type": "string" }, "class": { "description": "The extern's classification, one of the four G4 boundary classes: \"pure\" (no observable effect), \"acquire\" (takes a resource that must be released), \"emission\" (an irreversible crossing out of the system), or \"witnessed\" (a reversible host mutation that names its inverse). The pseudo-class \"first-class dispatch\" appears (with name \"*\") for a reach through a value whose target is not statically nameable. May be null when unknown.", "type": ["string", "null"] }, "inverse": { "description": "Issue #2692: the single derived inverse-provenance class of this crossing, one value of the closed vocabulary. \"declared\" is an exact inverse the author declared (`undo ...`); \"generated\" is an exact inverse derived from trusted metadata (reserved: no current declaration produces one); \"compensation\" is a best-effort offset (`compensate ...`), not a restoration; \"forward\" is irreversible but recoverable forward by a re-issue the declaration's idempotency register covers (a deferred emission with `idempotent` or `idempotent(key: ...)`; the register says whether the re-issue is free or fenced); \"irreversible\" is an emission with no inverse, offset or forward claim; \"unknown\" is no provenance fact at all. This version emits it on every entry, `unknown` included, and it is never inferred from a name or a shape. Optional in the schema so a document captured before the field existed still validates; absence there is not `unknown`. See docs/interchange-format.md.", "type": "string", "enum": ["declared", "generated", "compensation", "forward", "irreversible", "unknown"] }, "capabilities": { "description": "The declared capability scope of a scoped `emission[...]`/`witnessed[...]` extern, as a sorted list of tokens (e.g. [\"fs\"]). This token — not the extern name — is what a `capability ` policy rule and the register floor key on. Absent for an unscoped extern, whose token is its own name. This is the machine-readable form of the ` [fs]` clause on the human render's `host code:` line.", "type": "array", "items": { "type": "string" } }, "backends": { "description": "Backend tiers this extern has a body for (sorted), e.g. [\"py\"]. This is the machine-readable form of the tier the human render prints after the class, as in `(witnessed, py)`.", "type": "array", "items": { "type": "string" } } }, "additionalProperties": true }, "distributabilityVerdict": { "type": "object", "required": ["verdict", "reasons"], "properties": { "verdict": { "type": "string", "enum": ["transport-safe", "address-space-bound"] }, "reasons": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": true }, "cardinalityEntry": { "description": "One component's crossing-count ceiling (item 260).", "type": "object", "required": ["per_capability", "verdict"], "properties": { "per_capability": { "description": "Capability token -> its per-activation crossing ceiling.", "type": "object", "additionalProperties": { "type": "object", "required": ["bound", "kind"], "properties": { "bound": { "description": "The proved per-activation maximum, or null when unbounded.", "type": ["integer", "null"] }, "kind": { "type": "string", "enum": ["bounded", "bounded-symbolic", "unbounded"] }, "reason": { "description": "Present when kind is unbounded: why the multiplicity is not statically provable.", "type": "string" } }, "additionalProperties": true } }, "verdict": { "type": "string", "enum": ["bounded", "bounded-symbolic", "unbounded"] } }, "additionalProperties": true } } }