🔒 All inputs are processed locally in your browser. No data is transmitted. Do not enter real personal data — use synthetic or anonymised inputs only.
The mapping table

Where every receipt member goes

The input is one receipt object under receipt. Every member maps into exactly one place in each envelope; nothing is invented, defaulted or dropped.

Receipt memberLineage RunEvent memberEvent envelope member
execution_hashrun.runId (derived ; see the derivation table below)id
tool_idjob.namedata.tool_id
namespacejob.namespace (and every input dataset's namespace)none (the caller source lands on the envelope instead)
parent_hashes[i]inputs[i] : one dataset named by the hash, {namespace, name, type: "table"}, the estate lineage-card facet dialectdata.parent_hashes (unchanged)
parent_tool_ids[i]none (paired to the parent hashes by position, never emitted)data.parent_tool_ids (unchanged)
chain_depthnonedata.chain_depth (unchanged)
policy_parameters_hashnonedata.policy_parameters_hash (unchanged)
event_time (caller-declared)eventTimetime
source (caller-declared URI-reference)nonesource
none (fixed by this node)eventType: "COMPLETE", outputs: [], producer and schemaURL pinned to the vendored 1.55.0 schemaspecversion: "1.0", type: "co.ainumbers.ocg.receipt.v1", datacontenttype: "application/json", data = the receipt fields unchanged

The required-field surface each envelope must carry is pinned: the RunEvent mapping validates against the vendored JSON Schema (every emitted event is schema-validated in the node's fixture test), and the envelope always carries the four required context attributes of its core spec, id, source, specversion, type , plus the structured-mode members time, datacontenttype and data.

The runId derivation

A pure function of the receipt

The RunEvent needs a run identifier. This node does not mint one at export time, because that would make the identifier a function of the moment, not of the receipt. Instead the runId is derived from the receipt's own execution_hash in three deterministic steps:

StepOperationResult
1Take the first 32 hex characters of execution_hash (its first 16 bytes)16 raw bytes
2Set byte 6's version nibble to 8: b[6] = (b[6] & 0x0f) | 0x80version bits 1000 in the high nibble; the receipt's own low nibble preserved
3Set byte 8's two variant bits to 10: b[8] = (b[8] & 0x3f) | 0x80variant bits 10x in the two high positions; the receipt's own six low bits preserved
4Format the 16 bytes as canonical lowercase 8-4-4-4-12 hexthe runId

Every other byte of the runId is byte-identical to the first 16 bytes of the receipt's hash. That makes the runId a commitment device: whoever reads the envelope can re-derive it from the receipt and detect a substituted receipt immediately. Example: hash 656e6fd6… yields runId 656e6fd6-3469-85d1-a93a-6dcffbebdb8d (bytes 6 and 8 carry the two bit-sets; nothing else moves).

Fail-closed refusals

Refused exports carry no envelopes

Any missing or malformed member refuses the export whole. A refusal emits no envelopes at all (both envelope members are null), so a downstream stack can never ingest a half-mapped receipt.

Refusal triggerRefused field
Any of the nine required members absentthe missing member's name
execution_hash or policy_parameters_hash not 64 lowercase hex charactersexecution_hash / policy_parameters_hash
event_time not a well-formed timestamp (calendar-checked: month, day, leap-year February, hour ≤ 23, minute ≤ 59, second ≤ 60, offset present)event_time
source empty, non-ASCII, whitespace or control characters, a forbidden raw delimiter, or a percent sign not followed by two hex digitssource
parent_hashes entries not 64-hex, or parent_tool_ids length differing from parent_hashes lengthparent_hashes / parent_tool_ids
chain_depth not a non-negative integerchain_depth

Hard fence: the receipt is caller-supplied and caller-asserted. This node performs no verification of the hash values themselves; this node is an exporter, not a verifier. Correctness of the underlying execution is scored by the estate's recompute nodes, never by this receipt's envelopes.

Try it

Export envelopes from a pasted receipt

Paste one receipt (the receipt object itself, or a wrapper {"receipt": ...}; both accepted). The page runs the same mapping the kernel runs, locally, with no network.

Manifest

Contract surface

Kernel: chaingraph/kernels/art-831-receipt-export-envelopes.kernel.mjs, a pure total mapping from a validated receipt to two JSON envelopes; no hashing inside the mapping path, no iteration bound from inputs beyond the parent arrays. Deferred proving (a new gpu:false node, §18 steady-state rule). Conformance fixtures carry pinned golden hashes; every emitted RunEvent validates against the vendored 1.55.0 schema in the property test. Adjacency: none (a terminal export view; the node consumes nothing and feeds nothing). the node consumes nothing and feeds nothing.

input  : {receipt: {tool_id, execution_hash, parent_hashes[], parent_tool_ids[], chain_depth,
         policy_parameters_hash, event_time, source, namespace}}
output : {status: exported|refused, event_time, lineage_event, event_envelope,
          refused_field?, reason?          <- refusal carries no envelopes (both null)}
flags  : RECEIPT_EXPORTED | RECEIPT_EXPORT_REFUSED (+ root/multi-parent mirror flags)

Clause authority: the two wire specs are pinned by the row (snapshots under the workspace research/clause-snapshots/receipt-export/ dir; excerpts registered in chaingraph/standard/clause-snapshot-registry.json). The RunEvent schema is vendored as test data with its Apache-2.0 license at chaingraph/kernels/fixtures/vendor/openlineage-1.55.0/.