Concept: Receipts and proofs
Status: shape-only for cryptographic verification; fixture-rehearsed for shape and outcomes. Receipts are present on every membrane crossing. Today they are not signatures over canonical bytes — they are SHA256 hashes of
(ref|subject|outcome)(see 022 gap report item 17). Proof bundles are fixture IDs.
What a receipt is
Section titled “What a receipt is”A receipt is the artifact every membrane crossing leaves behind. It exists so that any party with a legitimate interest in what happened — the actor, the subject company, an advisor, an auditor, a counterparty, a regulator — can confirm that the act crossed the membrane in the shape claimed.
The shape:
interface MembraneReceipt { ref: GestaltRef; // a stable id for this receipt outcome: MembraneOutcome; // admitted | refused | pending | ... reasons: string[]; // structured reason codes / human notes signature?: string; // signature over canonical bytes (future) fixture?: boolean; // true today on every receipt}Every operation in the membrane contract returns a receipt in its
response, in the receipt field of MembraneResponse.
Why receipts everywhere
Section titled “Why receipts everywhere”In conventional software, a successful response is its own proof: the call returned 200 OK, the row exists. This breaks for everything Gestalt is trying to do:
- An auditor years later cannot verify “the row existed” — the row may have changed.
- A counterparty cannot independently verify what was admitted on the other Geist.
- A refusal disappears into a log line; nobody can prove that an attempt was made and refused for a specific reason.
- A Steuerberater cannot rely on “the system accepted my opinion” — she needs proof of what she signed under, what version of the capability, what authority epoch.
Receipts are the discipline that makes “what happened” survive every
participant. Even refusals get receipts. Even Zeitgestalt queries get
receipts (receipt-backed inquiry).
What outcome means
Section titled “What outcome means”The outcome enum:
admitted serious atom committedrefused structured refusalpending awaiting signing / evidence / advisorprojected admitted into a projected reality onlyverified a non-mutating call (probe, query, verify) succeededqueued accepted into a durable outbox (effect.intent)executed dispatched (effect.dispatch)failed dispatched but failed (idempotent record)What reasons carries
Section titled “What reasons carries”A short list of structured reason codes plus human-readable notes. Examples:
[ "fixture precheck requires invoice_payload" ][ "shop commit fixture admitted" ][ "tenant self resolved through fixture SDK fetch" ][ "proof disclosure requires explicit scoped entitlement" ]For refusals, the body of the response carries the structured refusal
fields (failedGate, requiredEvidence, etc.). The receipt’s
reasons is a complementary view, not a substitute.
Verifying a receipt
Section titled “Verifying a receipt”Today the SDK exposes a shape-check verifier:
import { verifyFixtureReceipt } from "@gestalt/sdk";
const result = verifyFixtureReceipt(receipt);// { verified: true, fixture: true, reasons: ["receipt shape accepted"] }This checks:
receipt.refis present (orreceipt.fixtureis true),receipt.outcomeis one of the known enum values.
It does not check a cryptographic signature against canonical
bytes. The membrane endpoint POST /v1/receipts/verify exists but
returns { verified: true, fixture: true } regardless.
When the runtime signer lands (see 022 item 17), receipts will:
- be signed over canonical bytes including the operation, the request envelope hash, the response body hash, the timestamp, and the runtime signer’s identity,
- be verifiable against the runtime signer’s published key without contacting the cloud,
- support key rotation: old receipts verify against historical keys, new ones verify against current.
The SDK shape will not change. Today’s verifyFixtureReceipt(receipt)
will become a real verification call.
Fixture honesty
Section titled “Fixture honesty”Every receipt today carries fixture: true. This is intentional:
- It means “no real consequence was bound by this crossing.”
- It means “do not rely on this for any external claim.”
- It means “do not present this to a third party as a proof of fact.”
A doc, an SDK, or a Koerper that strips the fixture: true marker is
violating the discipline. Don’t do that.
Proof bundles
Section titled “Proof bundles”A proof bundle is a scoped, signed collection of receipts, packages, evidence, and signer provenance, suitable for disclosure to a counterparty, advisor, or regulator.
Proof bundle requests:
const proof = await client.requestProof({ tenant: "tenant_node:rheinwerk_calibration", subjectCompany: "company_geist:rheinwerk_calibration", scope: "advisor_review", // or "self_audit" | "external_counterparty" fields: ["invoice", "payment_observation", "advisor_opinion"], purpose: "Q1 2026 Steuerberater review of receivable settlement",});If no entitlement is cited, the request is refused with
missing_entitlement. Disclosure is always entitlement-scoped.
There is no global “give me a proof” path.
The fuller M6 proof bundle:
const bundle = await client.requestProofBundle({ tenant: "tenant_node:rheinwerk_calibration", entitlement: "entitlement:fixture_proof_bundle",});Today this returns a fixture bundle ID. Real proof issuance is in
closed_runtime_boundary (see
022
item 5).
What a real proof bundle will contain
Section titled “What a real proof bundle will contain”When proof issuance becomes operational, a bundle will carry:
- the receipts for the relevant atoms,
- the capability atoms they cited (with their authority sources),
- the authority package versions in force at admission time,
- the evidence bundles referenced,
- the signer provenance chain (which runtime signer produced the receipts, and which key version),
- the lens or entitlement under which the bundle was disclosed,
- the disclosure scope (what fields the relying party may display, retain, forward),
- the validity window (until when the disclosure is current),
- the revocation path (how the disclosing tenant can revoke reliance).
A relying party will be able to verify a bundle entirely offline against the published runtime signer key and the published authority package hashes. No need to call back to Gestalt.
Disclosure discipline
Section titled “Disclosure discipline”Proof bundles are not “exports.” They are not bulk dumps of company truth. They are entitlement-scoped, signed assertions about specific facts.
Constraints:
- A Steuerberater receives a bundle scoped to their lens — visible facts, retention, fee period.
- A counterparty company receives a bundle scoped to the bilateral edge between them.
- A regulator receives a bundle scoped to a specific filing or inquiry, not universal telemetry.
- An auditor receives a bundle scoped to the audit’s bounds.
The forbidden surface explicitly includes
unscoped_proof_bundle_disclosure. There is no path through any SDK
or any tool to a “give me everything” bundle. By design.
Receipts vs proofs vs evidence
Section titled “Receipts vs proofs vs evidence”| What it is | Who produces | Who relies | |
|---|---|---|---|
| Receipt | Artifact of a single membrane crossing | Cloud Geist (runtime signer) | Anyone who saw the crossing |
| Proof bundle | Scoped, signed collection of receipts + supporting data | Cloud Geist on entitled request | The party named in the entitlement |
| Evidence bundle | Raw signed material backing a claim before admission | Connectors, witnesses, the actor | Gravity, capabilities, downstream atoms |
Evidence flows into atoms. Receipts come out of membrane crossings. Proofs are assembled from receipts and supporting evidence on demand.
Receipts in your code
Section titled “Receipts in your code”const response = await client.precheckIntent({...});
// every response carries a receipt (when the operation produces one)console.log(response.receipt?.ref);console.log(response.receipt?.outcome);console.log(response.receipt?.reasons);
// shape-verifyconst verified = verifyFixtureReceipt(response.receipt!);A Koerper should treat receipts as opaque blobs to store and forward — not to interpret. The Geist owns interpretation.
What receipts are not
Section titled “What receipts are not”- Not logs. Logs are observability. Receipts are claims.
- Not transaction IDs. A transaction ID identifies a row. A receipt asserts what crossed the membrane and why.
- Not API keys. Receipts are public artifacts of public crossings. They are safe to share with the parties named in the operation.
- Not invoices. Receipts are about the membrane crossing, not about money. An invoice is its own atom; the act of admitting that invoice atom produces a receipt.