RFC 0014: The lineage record and the action binding — how a decision cites what it read, and an action cites what it decided
On this page
- Summary
- Problem
- Evidence
- Specification (sketch) — the join as built
- 1. The lineage record: a receipt names its source
- 2. The citation: one grammar, owned by the gateway
- 3. The decision record cites, and is cited by digest
- 4. The action binds a decision to what was done
- 5. The join, in both directions, by a verifier that reads one record member and no more
- 6. Identity: who asked
- 7. Where each part lands
- Alternatives
- Compatibility
- Security and privacy
- Conformance
- Implementation
- Unresolved questions
- Status: Draft
- Type: Exploratory (research line — a cross-project artifact: the gateway's version 3 receipt and its verifier's join, the reference runtime's citation members; outside JPS)
- Created: 2026-09-14
This is an open proposal, not part of the specification. See RFC 0000 for the process and evidence bar.
Scope note, load-bearing. Nothing this RFC proposes lands in JPS Core, a profile, a conformance class, or any other RFC's specification-track surface. Every part it records lives in another repository of the project and is governed there: the receipt members, the citation grammar and the verifier's join in the reference gateway's
SPEC.md(§1.2a, §4, §6) and its frozen corpus; the record members in the reference runtime's architecture decision records (ADR-0033, ADR-0034); the worked examples in the demo's acts. It is recorded under RFC 0000's cross-project exploratory provision: a disposition here endorses (or declines) the design record as written and confers no authority over any of those repositories, each of which decides by its own process. Unusually for a record in this directory, the parts already exist: this record is written after the fact, as the runtime's decision records are, so that a binding that spans three repositories can be read, reviewed and objected to as one design rather than reconstructed from three. RFC 0000 describes the provision for a design question that deserves visibility before any implementation exists, and RFCs 0010 and 0011 were filed prospectively; this record therefore seeks the provision's application to retrospective documentation and lists whether it covers that case as an unresolved process question (Unresolved 8).
Summary
When a decision is challenged, three questions get asked: what information did we have, which
rule did we apply, what did we then do. The project answers them from three ledgers that, until
this line, only a person could reconcile. The gateway's receipts bind retained bytes to its
attestation under operator-configured source and authority labels — byte-lineage, never that
the genuinely named source returned them; the runtime's decision record says what was judged
and decided; a write to a target system was the application's own log. This record describes the join as built: a receipt that
names its source — which system, which statement, which snapshot, through what, for whom — and
a citation, one grammar owned by the gateway, by which a decision record names the receipts
it relied on and an action receipt names the decision record and the receipts it rests on. A
verifier that reads the gateway's store and the runtime's decision-record directory side by side
then resolves the join in both directions, by digest and by exact name, and interprets no
decision semantics beyond reading and validating a record's cites member.
The claim is deliberately small. A citation is the caller's assertion, recorded as given by a runtime that holds no key and reads no store. The verifier's finding is that what a citation names is there: a receipt at exactly that session, index and signature, whose own verification under the gateway's key is reported as its own finding; a record with exactly the claimed digest under the directory the operator named. Never that it was the right receipt, never that the record is true, and never that a person approved the action the receipt records.
Problem
The interoperability problem is that three artifacts made by three programs must agree on one way of naming each other, or the reconciliation stays manual.
- A version 2 receipt (gateway
SPEC.md§1.2) binds the bytes, the position in a session, the chain, and two labels the operator chose. It does not say which system was asked, which statement ran, which snapshot was read, or through what; its arguments digest is a keyed equality oracle to every caller; and it has no form for an action a person asked for. - A decision record (runtime ADR-0018) holds the pack's digest, the facts as evaluated and the disposition. It does not hold where the facts came from, and it must not verify anything to say so: the runtime is stateless, keyless and offline by decision.
- A write-back is performed by whatever the application uses, and nothing ties it to the judgment that proposed it.
The affected users are whoever must answer the challenge — an auditor who trusts none of the parties, a policy owner ruling on a disagreement between a draft and history (ADR-0034), an operator asked why a ticket changed state — and any second implementation of a receipt verifier or a record writer, which needs the grammar written down rather than inferred from the reference implementations.
Evidence
Implementation, release and demonstration status are stated separately for each item below; none of it is a sketch, and not all of it is released.
- Receipt version 3 — gateway
SPEC.md§1.2a, corpuscorpus/v3/. A receipt carries akind(acquisitionoraction), a saltedargumentsCommitmentin place of the keyed digest, acallerfrom a verified token ornull, and either anacquisitionrecord (adapter by name and digest, shape, endpoint, a commitment to the statement, snapshot, peer identity, schema digest, an upstream integrity token ornull, page item digests,observedAt) or anactionrecord (requester, decision claim, citations, tool, request commitment, adapter,observedAt). The gateway's own statement of what a version 3 receipt adds and does not change is that section's opening paragraph; this record does not restate it. Merged on the gateway'smain; the gateway has cut no release containing it (its tags stop atv0.2.0, which predates every part named here), and the demo builds it from a pinned commit. - The verifier's join — gateway
SPEC.md§4 steps 5–7 and the statusescitation-unresolved,decision-record-mismatch,record-citation-unresolved,record-citation-malformed, held by twenty version 3 store vectors in the frozen corpus (among themv3-action-valid,v3-citation-unresolved,v3-citation-case-differs,v3-decision-record-mismatch,v3-decision-records-absent,v3-record-cites-resolved,v3-record-cites-twice,v3-record-citation-member-by-another-case,v3-requester-null). - The executor — gateway
POST /act(design notedocs/design/executor.md): before any executor runs, the engine holds an authenticated requester, an open session of its own, a platform whose configuration allows writes, a tool the binding names, the decision claim's shape, each citation resolved in its own store and verified under its own key, and a record with the stated digest under its decision-record directory; then it performs the write through the platform's MCP tool and mints the action receipt. Seven cross-vendor review rounds and twenty-seven findings are recorded on the gateway's pull request 114. - The record's citation — runtime ADR-0033:
citeson every record a run leaves, held to the gateway's structural grammar and the runtime's one-MiB document limit, without resolving or verifying citations, recorded as given, omitted when none was supplied; a rehearsal accepts a citations document of the grammar and within the limit and writes no record, citations included. Runtime ADR-0034: a matrix row may carry the samecitesundermatrixVersion "3", so a row transcribed under a receipted page can name that receipt. ADR-0033 shipped in runtime 0.20.0; ADR-0034 is merged and tagged for 0.21.0, whose release was in progress at the time of writing. Each carries cross-vendor review records on its pull request: 145, eight rounds and thirty-one findings; 147, seven rounds, whose closing summary counts nineteen findings where its round tables itemize seventeen — the discrepancy is the source's and is left as found. - Worked examples — the demo's Act 7
(pull request 70, open at the
time of writing): a draft pack replayed against thirteen fixture rows standing for past
decisions, initially without citations; an optional helper then copies the newest receipt of
the store's last session onto every row as a caller-asserted citation — it does not establish
that the receipt covers those rows, which is exactly what a citation does not establish. Act 8
(branch
act8/approved-write, pushed to the demo repository and not yet a pull request, since it builds on Act 7): a receipted read, a judgment citing it, an action minted under a person's token, the three ledgers verified together, and the judgment rewritten after the fact to show the action receipt outliving it. These are demonstrations, not conformance evidence, and their standing is as stated, not merged.
What the evidence does not include, said here so the Implementation section is not misread: no second, independent implementation of the version 3 verifier exists; the runtime is the only writer of records that cite; and the golden-record agreement test the gateway's ADR-0001 names — one record fetched through both adapter shapes deriving to byte-identical facts — is a stated design and has not been built.
Specification (sketch) — the join as built
Field names and canonical forms are not fixed here; the gateway's SPEC.md governs every form a
verifier checks and the runtime's decision records govern what its records carry, exactly as
RFC 0010 and RFC 0011
defer. What this section fixes is the shape of the agreement between the parts: who writes
what, who checks what, and what a check means.
1. The lineage record: a receipt names its source
An acquisition receipt records, under the gateway's signature, what the adapter reported about
how it got the bytes: the adapter by name, version and digest; the operator-declared shape; the
endpoint; a commitment to the statement (query, resource path or tool call) whose salt the
gateway returns to the caller and does not retain — exclusive possession of it depends on the
transport and on the caller's custody, which the gateway's SECURITY.md says and this record
does not improve on; the source's own word about currency (a bookmark, a transaction id, an
ETag) or null; the transport's peer identity or null; the discovered schema by digest or
null; an integrity token the upstream itself produced, carried verbatim, or null; for a page,
the gateway-computed digest of each item's canonical bytes, in order; and the adapter-reported
observation time — except for the command shape, which reports nothing, where it is the
gateway's own stamp of the moment it had read the command's output in full. Two of these are the honest
bounds: upstreamToken never lets a source that vouches for itself and one that vouches for
nothing read the same, and shape never lets bytes attested through a bare operator command
read as bytes whose acquisition was recorded.
The property this buys, and its bound: a reader can take through what — the adapter by name
and digest, the shape, the endpoint — and which snapshot, when the source reported one, off
the receipt offline; which query is a commitment, checkable offline when the statement and its
salt are available to the reader, and null when the adapter reported none. The
acquisition record is the adapter's testimony under the gateway's signature — a compromised
adapter can misreport its acquisition as it can misreport its bytes, and is attributable by the
source it was configured as; what it cannot do is sign, provided the isolation the operator
established keeps it from reading the signing seed, since an adapter run as the signer's own
identity can read what the signer can.
2. The citation: one grammar, owned by the gateway
A citation is {sessionId, callIndex, signature}: a flat session token, an integer from 0 to
2^53−1, and a version 3 signature of exactly 128 lowercase hexadecimal characters. The required
members and their value forms are the gateway's (§1.1, §1.2a, §3a); the runtime adopts those
forms and requires exactly the three members on input, as the executor does of a request's
citations, while the gateway's verifier tolerates additional signed members at any depth of a
receipt it verifies — so the accepted input sets differ at the edge, and one verifier still
resolves every citation any of them wrote. A citation resolves when its sessionId is exactly a
session directory name the verifier enumerated, its callIndex exactly a receipt file stem in
it, and its signature the same string as that receipt's — exact strings, never normalized, so
a citation that differs by case or by a leading zero names nothing.
3. The decision record cites, and is cited by digest
The runtime writes cites on every record a run leaves when the caller supplied citations,
holds the supplied document to the structural grammar above and to its document limit of one
MiB, resolving and verifying nothing, and records it as given. It does not check that a session exists, that a receipt verifies, or that the
cited receipts bear on the facts; a document not of the shape is refused as a bad invocation
before the project is read, as is one over the limit; a rehearsal accepts a document of the
shape and within the limit and records nothing, citations included.
A decision record is cited by the digest of its bytes, as the verifier enumerates
candidates (§4 step 6): every regular file under the directory whole, a .jsonl file included,
and for a .jsonl file additionally each line — the bytes split on 0x0A, one trailing 0x0D
removed, an empty piece not a candidate, a non-empty unterminated final piece a candidate.
Nothing inside a record is read to compute its digest, and recordVersion stays "1": the
member is additive.
4. The action binds a decision to what was done
An action receipt carries the requester the gateway authenticated (never null), the
requester's claim of the decision — the record's digest and the pack's digest — and the
requester's citations, together with the tool, a commitment to the request sent, the executor's
identity and when the target answered; its resultDigest is over the target's response bytes,
retained like any artifact. The executor refuses before anything runs unless the citations
resolve in its own store under its own key and a record with the stated digest is under its
decision-record directory; it compares nothing inside the record and reads nothing of the
pack. A target's refusal of the write is a response like any other and is receipted.
5. The join, in both directions, by a verifier that reads one record member and no more
Given the store, the registry and the decision-record directory, the verifier resolves:
- from the action's side (§4 step 6): the action's
decision.recordDigestequals the SHA-256 of some candidate anywhere under the directory, ordecision-record-mismatch; - from the record's side (§4 step 7): each candidate step 6 enumerated — a regular file whole,
or for a
.jsonlfile each line and not the file whole — that is one JSON object with a top-levelcitesmember is a record that cites, and each of its citations resolves as an action's do, orrecord-citation-unresolved; acitesof another shape isrecord-citation-malformed. The finding is keyed by the candidate's digest — the same digest an action would name it by. This is the one member of a record the verifier reads — and the reference reads it only in a record its scanner recognizes: a record nested deeper than ten thousand levels is passed over in this step with no citation finding at all, while its bytes remain a candidate for step 6, so an action's digest match does not establish that such a record's citations were checked; - from the action to its receipts (§4 step 5): each citation resolves by three exact string
comparisons — session directory name, receipt file stem, signature — or
citation-unresolved. Whether the cited receipt itself verifies is that receipt's own finding, reported independently: a citation can resolve to a receipt the ladder reportsmalformedorsignature-mismatch, and the store's verdict then fails on that finding, not on the citation. (The executor holds more before it runs: each cited receipt must also pass the ladder under the engine's key, which is its requirement and not the verifier's.)
What "verifying" means here, exactly: that what a citation names is there, by exact name,
and that a record with the claimed digest is somewhere under the directory the operator named;
what the named receipt is worth is its own finding. A stricter reading — that the cited receipts
were the right ones, that the record's facts match their artifacts, that the pack digest names
the pack the record was made under — would have the verifier interpret a record, and beyond
the cites member nothing in this design does. packDigest is recorded as given and checked
against nothing.
6. Identity: who asked
A non-null caller on a version 3 receipt, and requester on an action receipt, are the
issuer, subject and token digest of a token the gateway verified against a configured issuer,
with a local copy of its keys and nothing fetched on the request path. A gateway configured
with no issuer records caller: null on every acquisition receipt and refuses every action,
since a requester is never null; a version 2 receipt has no caller member. What a verified
token proves is who asked,
at the gateway's boundary. It does not prove that they approved what was asked for. The token
is never stored and never signed into a receipt.
7. Where each part lands
| Part | Repository | Where |
|---|---|---|
Receipt version 3: kind, caller, commitments, acquisition, action |
gateway | SPEC.md §1.2a; corpus/v3 |
| Citation grammar and resolution; decision-record candidates; the join statuses | gateway | SPEC.md §3a, §4 steps 5–7, §1.4 |
| The executor and its refusal ladder | gateway | docs/design/executor.md, POST /act |
| Identity verification and its bound | gateway | docs/design/engine-config.md (identity) |
cites on decision records; nothing written on a rehearsal |
runtime | ADR-0033; experimental evaluate --cites, the graph surface, the MCP tool |
cites on matrix rows; the history profile that reads them |
runtime | ADR-0034; matrixVersion "3" |
| Worked examples | demo | projects/enterprise-demo/DEMO.md, Acts 7 and 8 (standing as in Evidence) |
Alternatives
- No join. Three ledgers reconciled by hand. This was the state before the line and remains what a deployment gets if it supplies no citations; nothing here is required.
- The runtime verifies what it cites. Rejected: the runtime is a stateless oracle that holds no key, opens no connection and reads no store, by its own decisions (ADR-0006, ADR-0012, as ADR-0033 restates them), and a record that carried a verified reference would claim what the runtime cannot know.
- The record embeds the receipt. Rejected: a copied receipt verifies no better than a named one, and the record would then carry bytes the runtime cannot check for shape.
- A citation member in JPS Core. Not proposed. Nothing here is part of a pack: a pack names the evidence it needs (RFC 0003); a record names what was used. The question of a JPS-level member arises only if two independent runtimes write records that cite, which no one has done.
- An outside lineage format — OpenLineage, in-toto attestations. Not chosen for the binding itself, since neither carries a session chain, a seal, or a commitment scheme; whether a receipt and an action receipt can be bound to such a format, so that a consumer of either reads the other, is a study question the plan names and this record leaves open.
- Digest the record's canonical form rather than its bytes. Rejected: the verifier would then interpret a record to name it, and a book re-serialized by a tool that reorders members would silently keep verifying under a digest the bytes no longer have. Digesting the bytes means that changing a cited candidate's bytes breaks that match unless a candidate with the same bytes remains anywhere under the directory; it does not establish an append-only history of the book — step 6 binds neither a line's position nor the book's sequence, so lines can be reordered, and a copy kept elsewhere keeps a rewritten line's join alive.
Compatibility
- Readers. A version 3 verifier verifies a version 2 store unchanged; a version 2 receipt
means afterwards exactly what it meant before. A verifier that does not know
citesreads a record with one as it always did — the member is additive andrecordVersionis unchanged. - Writers. A record without citations is byte for byte what it was. A matrix without
matrixVersion "3"is unchanged. - Semantics. A citation is an assertion; its presence changes no disposition, no trace, no
payload. An action receipt is a new
kind, not a change to acquisition receipts. - Migration. None. A deployment adopts citations by supplying them.
Security and privacy
- Assertion, not finding. Every citation and the decision claim are the caller's or the requester's word until the verifier resolves them. A record that cites receipts that do not exist is written as it was given; the finding that they do not resolve is the verifier's, and only when the store and the book are read together.
- Disclosure. The statement and the request sent to a target are commitments; the salts are
returned to the caller and never stored, so a party holding the store learns nothing about
them from their commitments alone. Every other member is in the clear —
endpoint,snapshot,peerIdentity,upstreamToken, the tool's name — and can disclose what an adapter put there; what the retained artifact discloses is the source's affair, and a source that echoes its arguments has disclosed them. The token is never stored; its digest is. - Tampering is observable, not prevented. The book is the runtime's file, writable by
whoever can write the project; the store is the gateway's, writable by whoever can reach it.
Rewriting a cited record is caught as
decision-record-mismatchfrom the action's side when no candidate with the original bytes remains under the directory, and removing a cited receipt ascitation-unresolved, with the seal's count missing it besides; nothing stops either edit, and neither finding says anything about the book's order or history. - Confusion. Exact-string resolution: a citation that differs by case, by a leading zero, or
by a look-alike character names nothing. A record's
citesthat is not exactly the grammar isrecord-citation-malformed, never partially read — in a record the reference's scanner recognizes; a record beyond its nesting limit yields no citation finding and stays a digest candidate (§5), so a match from the action's side says nothing about its citations. - Resource. The verifier's walk of the decision-record directory is not bounded in bytes, entries or time; the gateway states availability as a limit of the reference, and an operator who mounts an archive has made the walk as long as the archive. The executor's walk is the same one.
- Two engines on one store is outside the executor's ownership claim, stated in its note.
- What identity does not establish. A token proves who asked. Approval of a specific action is not evidenced by anything here, and the receipt does not say it (Unresolved 1).
Conformance
The conformance surface is the gateway's frozen corpus, not this record. Positive: a valid
action receipt with resolving citations and a record whose digest matches
(v3-action-valid, v3-record-cites-resolved). Negative: an unresolved citation, a mismatched
record, an absent record directory, a null requester, a cites member given twice
(v3-citation-unresolved, v3-decision-record-mismatch, v3-decision-records-absent,
v3-requester-null, v3-record-cites-twice). Boundary: a citation that differs by case
(v3-citation-case-differs), a record member spelled in another case
(v3-record-citation-member-by-another-case), a version 2 receipt relabelled as version 3, a
version 3 receipt signed under the version 2 prefix. Adversarial: a member appended inside the
acquisition record (v3-appended-member-inside-acquisition), a malformed kind.
On the runtime's side the conformance is shape refusal: a citation document not of the grammar is refused on every surface before the project is read, as is one over the one-MiB limit, and a rehearsal accepts a document of the grammar and within the limit and writes no record. These are the runtime's tests, not corpus vectors, and this record does not promote them.
Implementation
Two implementations exist and are not independent: the gateway's Go verifier and executor, and
the runtime's Go record writer, both by this project. A clean-room second implementation of the
verifier was built for receipt version 2 from the corpus alone — which is what exposed that the
format had never been written down and produced SPEC.md §1 — and none has been built for
version 3's join. The two-independent-implementations bar of RFC 0000
is therefore not met for anything here, and this record asks for endorsement of a design
record, not for acceptance of a stable feature. A plausible second implementation is the same
exercise again: a verifier written from SPEC.md §1.2a and §4 and the version 3 corpus alone,
by someone with no access to the Go code, whose disagreements would be the finding.
Unresolved questions
- Approval evidence. A token proves who asked. What would evidence that a person approved this action — a signed statement over the request commitment and the decision claim, under a key the person holds — and where would it live? The plan names this open; nothing here answers it.
- A row's citation of a page. A matrix row cites the page receipt it was transcribed under;
the page receipt names each item by digest in
pageItems, and the verifier checks the form of that list and nothing about its correspondence to the artifact. Which item a row came from is therefore a consumer's check by re-digest, not the verifier's finding. Whether a row should cite an item as well as its page is open. - Binding to an outside format. Whether a receipt, a record and an action receipt can be bound to OpenLineage or in-toto so that a consumer of either format reads the other, without weakening what the gateway's own verifier holds — a study, preregistered, with intervals.
- A JPS-level member. Only if two independent runtimes write records that cite. Until then the grammar is the gateway's and the record member is the runtime's.
- The both-paths agreement. The golden-record test ADR-0001 names is unbuilt, and RFC 0003's two-back-end bar — two runtimes with different back ends resolving the same references — is not what the gateway's two adapters are: they acquire bytes for operator-named sources and resolve no pack reference. This record does not claim that bar met, and a later amendment to RFC 0003 must not cite it as if it did.
- Two engines on one store. Stated as outside the executor's claim; whether it should be served, and by what (a store lock, a per-engine session prefix), is open.
- The bytes-of-a-line rule. Digesting a
.jsonlline by its bytes ties a citation to those bytes and to nothing about the book's order or history (step 6 searches every candidate under the directory). Whether a book should be allowed to be re-serialized under a recorded canonical form, at the cost of the verifier interpreting records, and whether a citation should bind position or sequence at all, are questions this record leaves open; for now the join is by bytes alone, and says so. - Retrospective records under RFC 0000. The cross-project provision speaks of visibility before an implementation exists. Whether it covers a record filed after the parts were built, as this one is, is a process question for the maintainer's disposition of this record.