Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

receipt.gno

7.89 Kb · 250 lines
  1// Package receipt is an append-only log of agent execution receipts.
  2//
  3// The thesis: provenance is not correctness. A chain can prove *who*
  4// committed to an output, *when*, that the bytes have not changed since,
  5// and *what* was staked or attested — but it cannot, by itself, prove the
  6// output was any good. Correctness comes from an external validation
  7// mechanism.
  8//
  9// So a receipt stores commitments (hashes) to the task, inputs, outputs,
 10// tool calls and runtime, never the raw data — that lives off-chain. The
 11// realm then lets independent validators attach attestations: "I re-ran
 12// this and it reproduced", "the tests pass", "the output matches the
 13// commitment", or "rejected". The receipt's trust level is exactly the sum
 14// of the attestations it has collected, and nothing more.
 15package receipt
 16
 17import (
 18	"chain"
 19	"chain/runtime"
 20	"strings"
 21
 22	"gno.land/p/nt/ufmt/v0"
 23)
 24
 25// Verdicts a validator can record against a receipt.
 26const (
 27	VerdictReproduced   = "reproduced"    // re-ran and got the same output commitment
 28	VerdictTestsPass    = "tests-pass"    // the referenced test suite passed
 29	VerdictOutputMatch  = "output-match"  // output matches its commitment
 30	VerdictPolicyOK     = "policy-ok"     // no forbidden tool / policy respected
 31	VerdictRejected     = "rejected"      // the work is wrong or invalid
 32)
 33
 34// Attestation is an independent validator's verdict on a receipt.
 35type Attestation struct {
 36	Validator address
 37	Verdict   string
 38	Note      string
 39	Height    int64
 40}
 41
 42// Receipt commits to one agent action. Every field except Attestations is
 43// immutable once recorded.
 44type Receipt struct {
 45	Seq              uint64
 46	Agent            string // agent id (e.g. a gno.land/r/nym-moultest123/agents/passport/v0 id)
 47	TaskHash         string // commitment to the task spec
 48	InputCommitment  string
 49	OutputCommitment string
 50	RuntimeID        string // which runtime/model produced it
 51	PolicyVersion    string // policy in force at execution time
 52	ToolCallsRoot    string // root hash over the tool-call trace
 53	HumanIntervened  bool
 54	Author           address
 55	Height           int64
 56	Attestations     []Attestation
 57}
 58
 59var receipts []*Receipt // index 0 => Seq 1
 60
 61// Record appends a new execution receipt and returns its sequence number.
 62// The caller commits to opaque hashes; the realm never sees raw payloads.
 63func Record(
 64	cur realm,
 65	agent, taskHash, inputCommitment, outputCommitment,
 66	runtimeID, policyVersion, toolCallsRoot string,
 67	humanIntervened bool,
 68) uint64 {
 69	assert(agent != "", "empty agent id")
 70	assert(taskHash != "", "empty task hash")
 71	assert(outputCommitment != "", "empty output commitment")
 72
 73	seq := uint64(len(receipts)) + 1
 74	r := &Receipt{
 75		Seq:              seq,
 76		Agent:            agent,
 77		TaskHash:         taskHash,
 78		InputCommitment:  inputCommitment,
 79		OutputCommitment: outputCommitment,
 80		RuntimeID:        runtimeID,
 81		PolicyVersion:    policyVersion,
 82		ToolCallsRoot:    toolCallsRoot,
 83		HumanIntervened:  humanIntervened,
 84		Author:           cur.Previous().Address(),
 85		Height:           runtime.ChainHeight(),
 86	}
 87	receipts = append(receipts, r)
 88	chain.Emit("ReceiptRecorded",
 89		"seq", ufmt.Sprintf("%d", seq),
 90		"agent", agent,
 91		"output", outputCommitment,
 92	)
 93	return seq
 94}
 95
 96// Attest attaches an independent validator's verdict to a receipt. The same
 97// validator cannot attest twice; the author of a receipt cannot attest to
 98// their own work (self-attestation proves nothing).
 99func Attest(cur realm, seq uint64, verdict, note string) {
100	r := mustGet(seq)
101	validator := cur.Previous().Address()
102	assert(validator != r.Author, "author cannot attest to their own receipt")
103	assertVerdict(verdict)
104	for _, a := range r.Attestations {
105		assert(a.Validator != validator, "validator already attested")
106	}
107	r.Attestations = append(r.Attestations, Attestation{
108		Validator: validator,
109		Verdict:   verdict,
110		Note:      note,
111		Height:    runtime.ChainHeight(),
112	})
113	chain.Emit("ReceiptAttested",
114		"seq", ufmt.Sprintf("%d", seq),
115		"validator", validator.String(),
116		"verdict", verdict,
117	)
118}
119
120// ---- read-only API ----
121
122// Get returns a copy of a receipt by sequence number.
123func Get(seq uint64) Receipt { return *mustGet(seq) }
124
125// Count returns the number of receipts recorded.
126func Count() int { return len(receipts) }
127
128// Confirmations returns (positive, rejections) attestation counts. It is a
129// count of independent verdicts, deliberately NOT a truth value: a caller
130// decides what threshold it trusts.
131func Confirmations(seq uint64) (positive, rejections int) {
132	for _, a := range mustGet(seq).Attestations {
133		if a.Verdict == VerdictRejected {
134			rejections++
135		} else {
136			positive++
137		}
138	}
139	return positive, rejections
140}
141
142// ---- internal ----
143
144func mustGet(seq uint64) *Receipt {
145	assert(seq >= 1 && seq <= uint64(len(receipts)), "unknown receipt")
146	return receipts[seq-1]
147}
148
149func assertVerdict(v string) {
150	switch v {
151	case VerdictReproduced, VerdictTestsPass, VerdictOutputMatch, VerdictPolicyOK, VerdictRejected:
152		return
153	}
154	panic("unknown verdict: " + v)
155}
156
157func assert(cond bool, msg string) {
158	if !cond {
159		panic(msg)
160	}
161}
162
163// Render shows the receipt log, or a single receipt at :<seq>.
164func Render(path string) string {
165	if path == "" {
166		return renderIndex()
167	}
168	seq := parseSeq(path)
169	return renderReceipt(seq)
170}
171
172func renderIndex() string {
173	var sb strings.Builder
174	sb.WriteString("# Agent Execution Receipts\n\n")
175	sb.WriteString("_Provenance is not correctness._ Each row commits to an agent action; ")
176	sb.WriteString("trust comes only from independent attestations.\n\n")
177	if len(receipts) == 0 {
178		sb.WriteString("_No receipts recorded yet._\n")
179		return sb.String()
180	}
181	sb.WriteString("| # | Agent | Output commitment | Human? | ✅ | ❌ |\n")
182	sb.WriteString("|---|---|---|---|---|---|\n")
183	for _, r := range receipts {
184		pos, rej := 0, 0
185		for _, a := range r.Attestations {
186			if a.Verdict == VerdictRejected {
187				rej++
188			} else {
189				pos++
190			}
191		}
192		human := "no"
193		if r.HumanIntervened {
194			human = "yes"
195		}
196		sb.WriteString(ufmt.Sprintf("| [%d](/r/nym-moultest123/agents/receipt/v0:%d) | %s | `%s` | %s | %d | %d |\n",
197			r.Seq, r.Seq, r.Agent, shortHash(r.OutputCommitment), human, pos, rej))
198	}
199	return sb.String()
200}
201
202func renderReceipt(seq uint64) string {
203	r := mustGet(seq)
204	var sb strings.Builder
205	sb.WriteString(ufmt.Sprintf("# Receipt #%d\n\n", r.Seq))
206	sb.WriteString(ufmt.Sprintf("- **Agent:** %s\n", r.Agent))
207	sb.WriteString(ufmt.Sprintf("- **Author:** %s\n", r.Author.String()))
208	sb.WriteString(ufmt.Sprintf("- **Recorded at height:** %d\n", r.Height))
209	sb.WriteString(ufmt.Sprintf("- **Runtime:** %s\n", r.RuntimeID))
210	sb.WriteString(ufmt.Sprintf("- **Policy version:** %s\n", r.PolicyVersion))
211	sb.WriteString(ufmt.Sprintf("- **Human intervened:** %t\n\n", r.HumanIntervened))
212
213	sb.WriteString("## Commitments\n\n")
214	sb.WriteString("The realm stores only these hashes; the payloads live off-chain.\n\n")
215	sb.WriteString(ufmt.Sprintf("- **Task:** `%s`\n", r.TaskHash))
216	sb.WriteString(ufmt.Sprintf("- **Input:** `%s`\n", r.InputCommitment))
217	sb.WriteString(ufmt.Sprintf("- **Output:** `%s`\n", r.OutputCommitment))
218	sb.WriteString(ufmt.Sprintf("- **Tool-calls root:** `%s`\n\n", r.ToolCallsRoot))
219
220	pos, rej := Confirmations(seq)
221	sb.WriteString(ufmt.Sprintf("## Attestations (%d ✅ / %d ❌)\n\n", pos, rej))
222	if len(r.Attestations) == 0 {
223		sb.WriteString("> Unverified. This receipt proves the commitment above was made, nothing more.\n")
224		return sb.String()
225	}
226	sb.WriteString("| Validator | Verdict | Note | Height |\n")
227	sb.WriteString("|---|---|---|---|\n")
228	for _, a := range r.Attestations {
229		sb.WriteString(ufmt.Sprintf("| %s | %s | %s | %d |\n",
230			shortHash(a.Validator.String()), a.Verdict, a.Note, a.Height))
231	}
232	return sb.String()
233}
234
235func parseSeq(s string) uint64 {
236	var n uint64
237	for i := 0; i < len(s); i++ {
238		c := s[i]
239		assert(c >= '0' && c <= '9', "invalid receipt path: "+s)
240		n = n*10 + uint64(c-'0')
241	}
242	return n
243}
244
245func shortHash(s string) string {
246	if len(s) <= 12 {
247		return s
248	}
249	return s[:6] + "…" + s[len(s)-4:]
250}