ERC-8299: WYRIWE - What You Read Is What You Execute

Following post #18, the appendix @babyblueviper1 asked for. This documents the GenericCommitRevealSettler integration pattern for judgment attestations as a reference for any producer implementing the L4 composition.


Contract

GenericCommitRevealSettler on Sepolia: 0xFe7Ab6d95f7567a311B98D029373d0fc1511aCCe

Bytes-opaque commit/reveal primitive. No bond, no NodeType gate, those are ERC-8275-specific concerns handled by CommitRevealSettlerV2. This contract only verifies the preimage binding, making it usable for any record schema: contribution snapshots, judgment attestations, OCP observations, or any future type.


Hash construction

commitmentHash = keccak256(abi.encode(record, periodId, committer))


record is bytes, the abi-encoded judgment attestation core (see encoding convention below). Binding to periodId + committer prevents cross-period and cross-sender replay without the contract knowing anything about the record schema.


Encoding convention for judgment attestations

The bytes record parameter should encode the attestation fields that determine the judgment identity:

bytes memory record = abi.encode(
    rawProposalHash,     // bytes32 — what was proposed
    verdictHash,         // bytes32 — the judgment, binding to rawProposalHash
    executedActionHash,  // bytes32 — what was actually executed
    verdictTimestamp     // uint256 — verdict issuance, strictly pre-execution
);


This is the minimal set that closes the reviewed→executed gap. agentId, registry, validatorId, and recordPointer are attestation metadata and do not need to be in the committed record, they are carried in the full JudgmentExecutionAttestation struct resolved at settlement time.


Recommended preflight

Before calling submitCommit, verify the hash binding off-chain at zero gas cost:

// eth_call — no gas spent
bytes32 expected = computeCommitmentHash(record, periodId, committerAddress);


computeCommitmentHash(bytes calldata record, uint256 periodId, address committer) is a view function on the contract. Verify expected byte-exact against your locally computed hash before submitting the transaction. If they don’t match, something in the encoding is wrong — fix it before spending gas.

This is the pattern from post #18 (computeCommitmentHash via eth_call before any gas was spent). Recommend treating this as a required preflight, not an optional check.


periodId convention

Use the ledger entry number as periodId. This creates a 1:1 binding between ledger entries and settlement periods and makes getCommit(periodId, committer) directly queryable from the entry index. The periodId + committer binding in the hash construction means two producers can commit in the same period without collision.


Workflow

1. Compute record = abi.encode(rawProposalHash, verdictHash, executedActionHash, verdictTimestamp)
2. Compute commitmentHash = keccak256(abi.encode(record, periodId, committerAddress))
3. Preflight: eth_call computeCommitmentHash(record, periodId, committerAddress) → verify match
4. submitCommit(periodId, commitmentHash)        // stores CommitRecord on-chain
5. Execute the governed action
6. submitReveal(periodId, record)                 // verifies preimage, stores recordHash


submitReveal reverts on mismatch (safe to revert — no bond). The reveal window is 48 hours from commit. Challenge period is 7 days from reveal.


Invariant check after reveal

CommitRecord memory c = getCommit(periodId, committer);
// c.committedAt > 0          — committed
// c.revealedAt  > 0          — revealed
// c.committedAt < c.revealedAt  — temporal ordering holds
// c.recordHash == keccak256(record)  — preimage binding holds


The Revealed event emits (periodId, committer, recordHash, record) — the full bytes record is in the event log, so any observer can independently verify the preimage without a separate storage read.


recordPointer sub-paths

The recordPointer in the full attestation struct MUST expose:

  • {recordPointer}/commitment — pre-settlement: signed verdict, relay anchor, commitmentHash, block number of submitCommit

  • {recordPointer}/outcome — post-settlement: recordHash from getCommit, transaction hash of submitReveal, settlement account

These are separately resolvable. A dispute verifier MUST be able to confirm commitment integrity (pre-settlement question) without accessing outcome evidence (post-settlement question). /ledger/19/commitment and /ledger/19/outcome from post #18 are the live reference implementation of this shape.


Reference implementation

  • Ledger entry: https://api.babyblueviper.com/ledger/19

    • /ledger/19/commitment pre-settlement evidence

    • /ledger/19/outcome post-settlement evidence

  • Commit tx: 0x735ad616bf988a5879440ff31b8d091a60e19afbbc6ad596d62f4041e7a7870f (block 11030402)

  • Reveal tx: 0x299a3f5152e767aa2aa344ef5942210707609ded2da8a02b5f3c37071b22dd8b (block 11030403)

  • Contract: GenericCommitRevealSettler 0xFe7Ab6d95f7567a311B98D029373d0fc1511aCCe (Sepolia)

Two production systems, one settlement primitive. Both reference implementations live.

1 Like

@TMerlini Section 7 + the RecordPointer schema + the explicit three-layer boundary all read right from the implementer’s seat — and “verdict weight lives in the accountability record, not in the bool” is the sentence I’d put on the spec’s tombstone if it could only keep one. @JimmyShi22 glad to have you in this thread too — the settler appendix below is exactly the piece that connects this composition back to the 8274 variant section.

The appendix (#21**) is verified against the deployed implementation — and the reference now conforms to its sub-path requirements exactly.** The encoding convention, hash construction, periodId binding, and workflow match what entry 19 settled with, byte for byte. Reading your MUST-contents for the sub-paths, I found our own reference serving was one revision behind the appendix: the commitmentHash + submitCommit block weren’t exposed on /commitment, the recordHash + submitReveal tx weren’t on /outcome — and reveal-side evidence was riding the commitment path, which violates the separation. Fixed and live as of this post: /ledger/19/commitment now carries {commitment_hash, commit_tx, commit_block 11030402, committed_at} and /ledger/19/outcome carries {record_keccak, reveal_tx, reveal_block 11030403, revealed_at} — each side only its own question. Block numbers RPC-verified against the receipts.

One detail worth a line in the appendix, since “verdictHash — the judgment, binding to rawProposalHash” leaves the construction unspecified: ours is verdictHash = keccak256(verdict_event_id || rawProposalHash) — binding the verdict to the specific signed artifact, not just to the proposal. Without the artifact id in the preimage, a validator that issued multiple verdicts over the same proposal could pick which one to reveal after seeing the outcome; with it, the commit pins exactly one. And +1 on preflight-as-required: entry 19’s executed-action policy already encodes it (“abort on any binding mismatch vs computeCommitmentHash”) — it should be normative, a producer that skips it just burns gas discovering encoding bugs on-chain.

On the open question — keep string recordPointer as the URI locator, with RecordPointer as the resolved payload schema. Not for convenience; the inline version is structurally wrong for this claim type:

The attestation is frozen; the record is alive — by design. Your own schema says it: outcomeEvidence MAY be empty before settlement. The attestation is signed at verdict time, which for a judgment claim is before the outcome exists (that’s the entire commit-reveal point). Inline the struct and every attestation signs a snapshot in which outcomeEvidence is empty by definition — a post-settlement consumer still has to resolve the living record to get the outcome, so inlining buys nothing for the half that matters later, while freezing the half-empty state into the type. A locator is the correct binding between a frozen attestation and an evolving record.

The integrity inlining seems to offer is already supplied where it belongs. The half that must never change (commitment evidence) is anchored independently of the URI — relay copies at issue time, and the on-chain commit itself. The half that must change (outcome) shouldn’t sit under the signature at all. That’s exactly the work the /commitment vs /outcome separability does: /commitment content is stable from issue, /outcome evolves pending → settled.

The honest cost of the locator is availability, and we’ve already paid that tuition. A hardening audit on our side found that relay copies for 9 of 18 entries had been silently replaced (NIP-33 parameterized-replaceable overwrite on duplicate d-tags). The fix was redundancy plus a live retention audit — every entry now serves a relay_anchor status — not inlining. Suggested spec language: locators MAY be non-HTTP (your registryType/registryRef already allows this); commitment evidence SHOULD be replicated to systems the validator does not control; implementations SHOULD audit retention and surface it. Note the failure mode is bounded: URI rot degrades auditability, never the commitment binding — the on-chain commit hash survives any URI’s death.

Secondary but real: the current 9-field type string is serving in production and sits verbatim in the L4 section; changing it right before review invalidates issued attestations including entry 19. And EIP-712 hashes dynamic bytes by content anyway — a verifier of the inlined struct still needs the payload from somewhere, so you inherit the locator’s availability problem while paying the type-complexity cost on top.

1 Like

Before the spec update reply, wanted to ask directly:

The entire L4 section of this spec is yours. The JudgmentExecutionAttestation struct, the triple-hash construction and slot-for-slot WYRIWE mapping, claimType and verify() semantics, recordPointer and the commitment/outcome separability invariant, Nostr relay anchoring as the commitment primitive, the production reference implementation running against real capital, and now Appendix A verification and closing the string-vs-struct question. That’s not acknowledgement-level work, that’s co-author work.

We’d like to add you to the author field if you’re open to it. Pseudonym is completely fine, babyblueviper1 (@babyblueviper1) works in the ERC header. If you’d rather stay as an acknowledged contributor that’s equally fine, no pressure either way. Just felt wrong to keep shipping spec revisions built on your design without making the offer.

1 Like

Appendix matched and /commitment + /outcome separation confirmed, that closes Appendix A.

Two spec updates from this post (commit 9464f32):

verdictHash construction, updated verdict_artifact_cid to verdict_artifact_ref throughout, with a note that the format is storage-backend dependent: IPFS CID for content-addressed storage, Nostr event ID for relay-anchored verdicts. The anti-equivocation property is identical either way, the specific signed artifact is bound in the commitment, so swapping between multiple verdicts post-reveal is not possible regardless of which anchor format the producer uses.

string recordPointer — closed. Design note 5 now states this explicitly: the attestation is signed once and frozen at verdict time; the record it points to is alive by design. outcomeEvidence does not exist when the verdict attestation is signed, inlining RecordPointer into the EIP-712 type would require signing a permanently incomplete field. On-chain anchoring via verdictHash already secures commitment integrity independently of the pointer. The 9-field type string is stable.

RecordPointer stays as the resolved payload schema in Appendix B, not in the signed type.

1 Like

@TMerlini accepted, and honored — babyblueviper1 (@babyblueviper1) in the header is exactly right (that’s the live GitHub handle, same identity the reference implementation runs under).

What you can expect from a co-author seat, since the offer deserves more than a yes: the reference implementation stays conformant with every spec revision (today’s same-hour sub-path fix is the standing service level, not a one-off); I’ll review each revision against what production actually does and flag any spec-vs-deployed drift in either direction; and I’ll keep the L4 composition coherent with the attestation/judgment variant section heading into the ERC-8274 v0.2 PR, so the two specs compose instead of fork. The design authority on WYRIWE’s core — L1 through L3, the provenance scheme itself — remains yours; my lane is the judgment composition and the accountability mechanics, and I’ll stay in it.

On #24: both closures read right. verdict_artifact_ref with the storage-backend note is the correct generalization — the anti-equivocation property lives in binding the specific signed artifact, not in which content-addressing scheme names it, and the spec now says so. And design note 5 states the frozen-attestation/living-record argument more cleanly than my post did. The 9-field type string being declared stable matters practically too: every attestation issued to date remains valid through review.

Appendix A closed, Appendix B holding the resolved payload schema, type string frozen — from the implementer’s seat this spec is converging fast. Ready for the next revision whenever it ships.

1 Like

Thank you, and the same-hour sub-path fix is exactly the kind of conformance signal that makes a co-author credit mean something rather than just look good in a header.

The WYRIWE/ERC-8274 v0.2 coherence commitment is the piece that matters most long term. Having the judgment variant land consistently in both specs, rather than drifting into parallel implementations that compose on paper but fork in practice, is what makes this stack actually usable. Looking forward to the section PR when @JimmyShi22 opens v0.2.

Mirroring this from the L2 side: gateway.gen-plasma.com tracks spec revisions. Each revision is reviewed against the deployed node before the commit goes in, drift found in review gets fixed first. CommitRevealSettlerV2 and GenericCommitRevealSettler on Sepolia are the settlement layer; the npm package version is the conformance marker.

Both reference nodes are now in the spec’s Reference Implementation section (commit 4b93efe) — L2 and L4 with explicit conformance commitments. Two layers, two operators, both tracking.

1 Like

Quick update, the spec is now filed as a PR on ethereum/ERCs:

Add ERC: WYRIWE — What You Read Is What You Execute by TMerlini · Pull Request #1810 · ethereum/ERCs · GitHub

All CI checks passing (EIP Walidator, HTMLProofer, Markdown Linter, CodeSpell). Awaiting editor review and number assignment.

The discussion thread here will remain the primary place for feedback. If you have questions on the triple-hash construction, attestation profile, or the live reference implementation, drop them here.

1 Like

Congrats on getting it filed — green across eipw and the linters on a spec this dense is no accident.

One note from the anchor-layer side, since the abstract seats TruthAnchorV1 as the on-chain proof-commitment / anchor surface alongside the identity and verification layers.

Worth stating the composition explicitly for implementers. WYRIWE answers what input was actually fed — the triple-hash chain of custody. The anchor layer answers a different question: this commitment existed at block T and hasn’t moved. It takes a WYRIWE commitment — the input_hash, or a root over the triple, integrator’s choice — as an opaque 32-byte proofHash and emits it with an immutable on-chain record id + timestamp. It never interprets the bytes, so it nests under WYRIWE without touching any provenance semantics — the same AttestationIndex / event-layer boundary noted in the acknowledgements.

A forward item on referencing: the draft names TruthAnchorV1 in prose rather than linking ERC-8263, which is the right call today — eipw won’t let you requires: or relative-link an ERC that isn’t merged yet, and 8263 is still in review (#1748). Once it lands I’ll wire the explicit requires: 8263 and a reciprocal reference both ways, so the input-provenance and anchor layers point at each other by number — same coherence discipline you and @JimmyShi22 are holding on the 8274 side.

And if a third reference node is useful next to the L2 and L4 implementations, I can add an anchor-layer one: a WYRIWE triple-hash anchored through TruthAnchorV1 on-chain, with the contract/package version as the conformance marker. Happy to prep it on a word.

1 Like

@VincentWu thanks, and that framing is exactly right. The two questions are orthogonal: WYRIWE closes “what was fed in and when in the pipeline”; the anchor layer closes “this commitment existed no later than block N.” Neither absorbs the other’s semantics, the anchor takes the 32-byte proofHash opaquely, which is what keeps the composition clean.

Explicit composition language for implementers is worth adding. I’ll draft a short “Composition with ERC-8263” subsection in the spec, covering the handoff point (proofHash construction → anchor input), the two independent timestamp authorities (relay-attested via Nostr + block-attested via TruthAnchorV1), and what verify() == true guarantees at each layer. That framing is already live in Fede’s ledger entries; formalizing it in the spec gives implementers a checkable model.

On the anchor-layer reference node: agreed, once 8263 merges I’ll add it alongside the L2 and L4 entries. The PGA #307 end-to-end trail you’re wiring now (dinamic identity in aux field) would be the natural first entry for that section.

Really appreciate the support on the ERC-8275 thread @babyblueviper1. Your WYRIWE standard fills a critical gap — input provenance is the foundation everything else builds on.

I think the natural composition is 8299 handling input integrity at L4, with 8275 providing the discovery + escrow + reputation layer above it. The triple-hash commitment scheme in 8299 gives us exactly the kind of verifiable input chain that a reputation system needs to make trust decisions.

Would love to explore the concrete integration points between the two standards — especially how 8299 attestations could feed into 8275’s reputation scoring.

2 Likes

@Panini glad to compose here — you’ve put your finger on the exact seam. 8299 at L4 establishes input integrity + verdict authenticity: what was actually read, and that a named validator’s judgment over exactly that input was committed before the outcome was known. That’s the raw material a reputation system needs; it isn’t itself the reputation.

One design line worth holding so 8275’s reputation layer stays trustless: the score should be derived from the attestation record, not maintained as a separate mutable number. A reputation weight any party can recompute from (a) the 8299/L4 attestations, (b) their commit-before-outcome anchor (the 8263 leg), and (c) the settled outcomes beats an updater-controlled score that has to be trusted. If reputation is recomputable from chain/relay state, no one has to trust the scorer — which is the point of putting it on top of WYRIWE rather than beside it.

Two guards that follow:

  • Usage weight counts distinct at-stake counterparties, not call volume, capped relative to outcome-derived weight — otherwise a busy or self-dealing agent out-scores an accurate one (the Sybil/wash surface).
  • Losses stay in the record, not just wins — a reputation feed that only sees successes is marketing; publishing the misses is what makes the score mean anything.

Not theoretical on our side: the L4 reference impl (api.babyblueviper.com/ledger) already serves this shape — signed verdicts, each anchored before its outcome, outcomes settled where the validator can’t edit them, wins and losses both, recomputable per entry. So it’s a live feed 8275’s reputation scoring could read today. Happy to write up the concrete attestation→reputation-input mapping (fields + recompute path) as a short integration note for the 8275 draft.

1 Like

@babyblueviper1 is the answer, @Panini , and the key move is his: derived-not-stored, so the score is recomputable from the attestation record with no scorer to trust, with “losses stay in the record” and “distinct at-stake counterparties, not call volume” as the anti-gaming guards. That’s the reputation input done right.

The one thing I’d pin from the WYRIWE side, since it’s the leg I own: his “input-verified outcomes” rests on a specific guarantee. Aggregating outcomes only means something if you can prove the model was scored on the input it actually processed, not the one that was requested, which is exactly what 8299’s commitmentHash binds (rawInputHash → sanitization → inputHash). So the two legs feeding the score are separable: WYRIWE proves the input the outcome was about; the verifier proves the verdict on it is authentic. Fede’s recomputable score needs both, and keeping them distinct is what stops either being assumed.

His offer to document the concrete attestation → reputation-input mapping for the 8275 draft is the right next artifact, happy to slot the WYRIWE input-binding leg into it so the mapping carries both.

@babyblueviper1 This is exactly the integration model I was hoping for — thank you for laying it out so clearly.

Three points really land:

  1. Recomputable reputation — 100% agreed. If the score is derivable from (8299 attestation + 8263 anchor + settled outcome), there is no scorer to trust. The 8275 reputation weight should be a view function, not mutable state.

  2. Usage weight capped by outcome weight — sharp insight. A high-volume agent should not out-score an accurate one. I will bake this into the spec: reputation = f(attestationCount, counterpartyDiversity, winRate, volumeCap) where volume-derived weight is ceilinged by outcome-derived weight.

  3. Losses stay in the record — yes. A reputation feed that only shows wins is marketing. The 8275 escrow contract already records all outcomes (disputes included), so the raw data is there.

Would love that integration note — a concrete attestation-to-reputation field mapping with the recompute path would be the exact artifact to anchor the cross-standard reference. In the meantime, adding a note to the 8275 spec pointing to api.babyblueviper.com/ledger as a live feed for reputation scoring.

One additional integration point: @TMerlini just verified the fraud proof mechanism on Sepolia (CommitRevealSettlerV2, self-incriminating reveal with same-tx slash). An 8299 attestation that includes the Settler commitmentHash as a linked field would close the loop — input integrity (8299) + execution proof (8274) + economic settlement (8275) all anchored to the same cryptographic root.

2 Likes

@Panini that’s the shape exactly — and reputation = f(attestationCount, counterpartyDiversity, winRate, volumeCap) with volume ceilinged by outcome-weight is the right function. Here’s the concrete field mapping + recompute path, grounded in the L4 reference impl (api.babyblueviper.com/ledger) so it isn’t hypothetical.

Attestation → reputation-input mapping (each input recomputable from public data, none self-attestable):

reputation input source on the 8299/L4 attestation how it’s recomputed (trustless)
attestationCount the signed Nostr event_id of each type=pre_action_verdict entry, signed by verifier_pubkey count distinct event_ids whose schnorr sig verifies (NIP-01) against the published key — can’t be forged or self-inflated
winRate outcome_evidence.settled_digests[] → settled outcome entries on outcome_evidence.account (public Hyperliquid acct, on-chain, non-editable) per verdict, follow its settled digests and read win/loss off the public account; only count outcomes whose settlement postdates committed_at
committed_at (gates winRate) commitment_proof: signed_at/published_at + relays (tier-1 relay attestation), and timing.available.tier2_onchain_committed_at (tier-2 ERC-8263 anchor) third-party relay copies + an on-chain block timestamp prove the verdict predates the outcome — no trust in the issuer
counterpartyDiversity the principal/subject the verdict was issued for (the inputHash’s at-stake party) count distinct at-stake counterparties, not call volume
volumeCap derived: ceiling the attestationCount/volume weight by (winRate × settled-count) a busy verifier with few settled outcomes can’t out-score a proven one

Recompute path (any party, public data only):

  1. Pull the verifier’s ledger (or the attestations handed to you).
  2. Per entry: verify schnorr(event_id, verifier_pubkey) → authentic verdict.
  3. Read commitment_proof → establish committed_at (relay tier-1, or on-chain tier-2) without trusting the issuer.
  4. Follow outcome_evidence.settled_digests → settled win/loss on the public account; confirm each settlement timestamp > committed_at.
  5. Apply f(...) deterministically. Same inputs → same score. There is no scorer to trust — your point exactly.

On cross-standard anchoring (your settler-commitment-hash idea — yes, and it’s already wired): the 8299 attestation’s event_id IS the ERC-8263 proofHash leg, which is the settler’s commitment hash. One identifier threads 8299 attestation ↔ 8263 on-chain commit ↔ 8275 settlement, so reputation, anchor, and settlement all key off the same bytes (entry 23 on the reference impl demos the full identity → judgment → execution chain this way).

One honesty note, because it’s the whole point of a reputation feed: on the live record today counterpartyDiversity is 1 — every verdict so far is our own earner dogfooding /review, a single counterparty. The mapping supports diversity (distinct subject identities); our record just doesn’t exercise it yet, and volumeCap is exactly what stops a single-counterparty or high-volume feed from looking more reputable than it is. Wins AND losses are both in there (currently 10W/9L across 19 settled) — a feed that hid the losses would be marketing, not reputation.

Happy to drop this into the 8275 draft as the reputation-input appendix, or keep it here as the integration reference — your call on where it lives.

1 Like

All three land, Panini, recomputable-as-a-view, the volume-capped f(attestationCount, counterpartyDiversity, winRate, volumeCap), losses-in-the-feed. Same shape Fede’s running, and his ledger (api.babyblueviper.com/ledger) is the right reference feed to cite. His attestation→reputation field mapping is the artifact; I’ll slot the WYRIWE input-binding leg into it.

One disentangle before we wire it, because it keeps the merged 8275 coherent: there are two different commitmentHashes, and they shouldn’t be linked into one.

  • WYRIWE’s (8299) is per-action — binds agentId · modelHash · inputHash · outputHash · timestamp. This is the one that feeds agent reputation: it proves a scored outcome was about the input the model actually processed.

  • The Settler’s (8275 L3) is per-period — binds snapshotRoot · periodId · nodeAddress. That’s node-infrastructure compensation (who produced/relayed how many records) — a separate axis.

So the converged 8275 carries two economic axes keyed off different commitments: node-contribution compensation (the settler) and agent reputation (WYRIWE attestations + outcomes). The reputation loop closes via the WYRIWE attestation, not by embedding the settler’s snapshot hash into it, keeping them separate is what stops infra-economics and agent-scoring from getting conflated.

The real cross-standard link is the inputHash thread: inputHash → WYRIWE (input integrity) → 8274 verify (execution proof) → settled outcome → 8275 reputation. Same pivot the rest of the stack already turns on. Happy to draw that exact path in the mapping doc with @babyblueviper1 .

1 Like

That separation makes sense.

Keeping the per-action commitment separate from the per-period settler commitment avoids mixing agent reputation with node infrastructure compensation.

One possible next boundary to make explicit is the receipt layer between them:

- the per-action attestation proves what the agent processed and produced;

- the per-period settler proves what the network relayed or included;

- the receipt should bind the scored action to the evidence that made it eligible for reputation.

So the reputation path depends on the action-level proof, while the compensation path depends on the period-level settlement root. Different commitments, different economic meaning.

2 Likes

@TMerlini yes — that separation is the right call, and I’d rather state it precisely than let my “shared identifier” shorthand above stand, because it over-collapsed two different commitments:

  • Per-action (WYRIWE / 8299): the attestation binding agentId · modelHash · inputHash · outputHash · timestamp, fixed at the verdict. This is what reputation derives from, and the per-action leg is what the 8263 proofHash anchors. Per-action lifecycle.
  • Per-period (the Settler / 8275): the node-compensation commitment aggregating settled outcomes over an epoch. Different scope, different lifecycle.

Keeping them separate is right: reputation is per-action and recomputable from the attestation record; infrastructure economics is per-period. Sharing one hash would let compensation cadence leak into agent scoring — exactly what we don’t want.

So the cross-standard relationship isn’t “same bytes everywhere,” it’s the pathway you laid out: inputHash → WYRIWE attestation (per-action) → execution proof → settled outcome → reputation, with the settler’s per-period hash consuming those settled outcomes downstream rather than reusing the attestation’s bytes.

@pipavlo82 — your receipt layer is the clean way to make that boundary explicit: the receipt binds a scored action to its eligibility proof, so the reputation path stays on the action-level attestation and the compensation path on the period-level settlement root — the same separation, enforced at the seam rather than assumed. Worth pulling into the mapping as the explicit binding between the two paths.

And yes — happy to co-author the formal mapping doc. I’ll take the reputation-input side (the field map + recompute path above, corrected to this per-action/per-period split, with the receipt layer as the binding seam); you take the settler/compensation side. That hands Panini one document with the whole pathway end to end.

1 Like

Yes, that split is the right boundary.

I agree the receipt layer should not collapse the per-action reputation path and the per-period compensation path into the same commitment.

The useful role of the receipt is to bind a scored action to the evidence that made it eligible for reputation, while keeping node compensation anchored to the settlement root.

So the mapping becomes:

input → attestation → execution proof → receipt → settled outcome → reputation

The receipt is the seam: it makes the transition from “this action was processed” to “this action is eligible to affect reputation” explicit and later verifiable.

1 Like

Yes, that earlier message was my first framing of the boundary.

After your clarification, I agree the next useful step is the formal mapping doc.

I can take the ReceiptOS / execution-receipt side of the mapping:

- receipt schema

- receiptRoot

- Merkle root / proof

- anchor result

- final anchored receipt JSON

- the eligibility rule: an action must have an independently verifiable receipt before it can affect reputation

I would keep the split explicit:

- WYRIWE / 8299: per-action input/model/output attestation

- ReceiptOS: execution receipt and eligibility proof seam

- Settler / 8275: per-period settlement and compensation root

So the receipt does not score by itself. It makes the action eligible to be scored.

Happy to draft the receipt-side field map first, then align it with the reputation-input and settler-side paths.

2 Likes

@pipavlo82 “the receipt gates, it doesn’t score” is exactly the right boundary — that’s the A.5 seam stated cleanly, and a distinct receipt component owning it (rather than smuggling eligibility into either the attestation or the settler) keeps the axes clean. I’m for it.

One load-bearing constraint to carry into the receipt-side mapping, because it’s the whole foundation the reputation axis rests on: the receipt has to stay a recomputable view, not a signed artifact from a trusted service. Eligibility must be checkable by any party from public data — the same conditions A.3.2/A.3.3 already define: authentic verdict (schnorr vs the published key) ∧ committed_at provably predates settlement (the 8263 leg) ∧ outcome settled on the non-editable account. If “ReceiptOS” is a recompute/verification layer that derives the receipt (and its receiptRoot/Merkle proofs) from those public facts, we’re fully aligned. If it ever becomes an issuer that signs eligibility, it reintroduces exactly the trusted party A.5 forbids — and a consumer would then have to trust the receipt issuer to trust the score, which defeats derived-not-stored.

So the interface contract I’d hold: a reputation consumer must be able to verify a receipt’s eligibility WITHOUT trusting whoever produced the receipt — recompute it themselves from the attestation + the commitment proof + the settled outcome. Get that and the receipt is purely additive: it names and structures the gate A.3 already enforces, with no new trust.

On optional-vs-required (Tiago’s opened that to you): either works for us under one condition — that the receipt IS the recomputable eligibility predicate, not a new condition layered on top. If “required receipt” just names the gate A.3 already enforces (authentic verdict ∧ committed_at < settlement ∧ settled outcome), making it first-class is fine — it’s the same public facts, so our reputation recompute stays self-contained and adds no new dependency. The only version I’d resist is one where the receipt introduces a new trusted/signed condition beyond those facts, because then eligibility (and the score that depends on it) would require trusting the receipt issuer. So it’s your call on scoping; our hard line is just recomputable-not-signed. Happy to align the receipt → reputation-input interface from our side — which receipt fields the reputation recompute reads, and the guarantee none of them require trusting the receipt producer — once your draft is up.

2 Likes