Agent Action Capsule · build your own evidence layer
b7 / 11

Agent work for someone else

Seam ② Contract. Build: both sides' records of a deal between a principal's agent and a counterparty. Conform to: draft-mih-agent-evidence-request-00 and draft-mih-agent-settlement-records-00.

When an agent acts for a principal and deals with a counterparty, three parties hold records, and the evidence layer has to let each one check the others without trusting them.

A principal, an agent and a counterparty, each sealing its own records Top row: three parties, the principal on the left, the agent in the middle, the counterparty on the right. Step 1: an arrow from the principal to the agent labelled acts for, and under the principal a WHO record: who authorized this action, signed on the principal's side. Step 2: a two-way exchange arrow between the agent and the counterparty, and under each a sealed half of the exchange, key A for the agent and key B for the counterparty, each citing the other's half by digest. Step 3: a row of four settlement legs, terms, payer_observed sealed by the agent, payee_observed sealed by the counterparty, and delivered with a content digest; on the left a verifier that trusts neither derives the state, such as agreed, mismatch or payer_stated, from the legs present. Step 4: an evidence request whose subject is the asker's own exchange half and whose coverage is a pinned anchor, and three possible outcomes: the artifact, identical bytes for the same subject and anchor; a signed refusal with a reason token; or a recorded absence, the asker's own record. Step 5: four slots, CAN, WHO, WHAT and AUDIT, joined by a subject digest whose construction each profile defines (here SHA-256 over the JCS form of the action), each checked on its own. Step 6: status badges: exchange halves live; settlement legs built; evidence request built; WHAT joined to WHO built as a vector set; CAN and AUDIT designed; on the acts-for arrow, the principal-to-agent flow in one host designed, not built. Principal Agent Counterparty acts for WHO record who authorized this action signed on the principal's side exchange agent's half · key A cites B's half by digest their half · key B cites A's half by digest settlement legs (each one an Agent Action Capsule) terms what, how much payer_observed key A: sent payee_observed key B: received delivered content digest verifier (trusts neither) derives the state from the legs present: agreed · mismatch · … evidence request subject {exchange: my half} coverage {expected_pin} artifact identical bytes per subject and anchor signed refusal no_such_subject, policy_declined, … recorded absence the asker's own record that nothing came CAN was it permitted WHO who authorized it WHAT what the agent did AUDIT did the runtime enforce subject_digest = HASH(subject_preimage), per profile here SHA-256(JCS(action)); a join key only: each record is checked with its own verifier flow: designed live built built designed vectors vectors designed

1What it is

Agent work for someone else is an exchange with three parties: a principal who authorizes the work, an agent that does it, and a counterparty the agent deals with, often with a payment between them.

Each party seals only what its own side observed, under its own key, and asks the others for evidence with a request whose answer is exactly one of three things: the artifact, a signed refusal with a reason, or the asker's own record that nothing came.

Separate records answer separate questions (was it permitted, who authorized it, what was done, did the runtime enforce), and they are joined by one digest of the action rather than merged into one format.

2Design choices

Chosen: each party seals its own side only, under its own key, and may cite the other side's record as something it holds, never as its own observation.
Rejected: the agent, or the platform it runs on, recording both sides; that is one party's account of a two-party event. (settlement-records §3; bilateral-attestation-02)
Chosen: whether a payment's two sides agree is derived by a verifier from the legs present.
Rejected: a leg that asserts the settlement state (agreed, mismatch); one sealer would then state a fact only both sides' records can establish. (settlement-records §1 item 7, §9)
Chosen: an evidence request ends in exactly one of three outcomes, and none is ever recorded as another: a timeout is never written up as a refusal, and a signed refusal is never written up as silence.
Rejected: treating silence, a transport error and a stale cache as one "failed" result; they carry different weight, and only a refusal is the responder's signed act. (evidence-request §4.5)
Chosen: the same subject under the same coverage anchor yields byte-identical evidence for every requester; a responder may refuse someone, but may not answer two askers differently.
Rejected: per-audience answers, a fuller history for an auditor and a curated one for a counterparty in a dispute (the draft's "flattering version"). (evidence-request §1.1, §5)
Chosen: the ask is symmetric: either party to an exchange may ask the other, naming its own sealed half as the subject.
Rejected: a one-way audit channel where only the original requester asks; the side holding a signed reply is the one that can show the other side's log left something out. (evidence-request §3.1, §6)
Chosen: CAN, WHO, WHAT and AUDIT records join on a shared digest of the action, or an explicit signed cross-reference (§4); digest equality is a join key and nothing more.
Rejected: growing one format to contain the others, or letting one slot's verifier vouch for another slot's content. (accountability-composition-01 §4, §5, §6.3.4)
Chosen (Mesh-LLM worked example): the provider seals its payee_observed leg only from what its own wallet reported crediting and deducting.
Rejected: filling the payee leg from the invoice amount; the invoice is not what the wallet credited, and a missing fee never reconciles. On a host that does not pass those numbers, no payee leg is sealed. (Mesh-LLM/capsules crates/evidence-plugin/src/settlement_legs.rs)

3What it shows / what it does not

Shows

  • That two records sealed under two distinct keys report the same payment reference, amount (after the receive fee) and status, or which of those differ.
  • That a responder answered, refused with a stated reason under its signature, or that the asker recorded no answer inside its waiting window.
  • That a responder gave two askers different bytes for the same subject and anchor: they compare artifact digests, without trusting each other (not for exchange subjects, which only one asker holds; there the responder's own recorded ask is the second copy, evidence-request §5).
  • An omission: a party holding the other side's signed reply citing its half, when that side now answers no_such_subject (evidence-request §3.1, §6).
  • That a WHO record and a WHAT record name the same action, by recomputing the digest each one binds.

Does not show

  • That either side's observation is true; agreement on a digest attests to the digest, not to what it stands for.
  • Who holds a key in the real world; that is the verifier's own key policy.
  • Why nothing came back: a partition, a crash and a deliberate silence look the same (evidence-request §4.4).
  • That evidence stays available; a responder's signed retention commitment makes a later absence attributable, not impossible (evidence-request §9).
  • That the action was authorized, or that the record set is complete, just because digests match (accountability-composition-01 §6.2).
  • Who is right when the two sides disagree; neither record is preferred.

4Example

Two conformance cases for the symmetric ask. The responder's declared holdings include one record that cites the asker's exchange half e2c78557…. Asking about that half is served; asking about a half no record cites is refused no_such_subject, never matched loosely.

"responder": {
  "evidence_stream": "stream-a",
  "log_size": 42,
  …
  "exchange_citations": {
    "e2c78557e239cd93cf344c2e435158367deac1d3b525deb6e09c23d1a8139227": [
      "ef53392288cd922e52ce6d54c30196a2f33af60ba87885b89cd34ed3d17a35d1"
    ]
  },
  …
},
…
{
  "id": "res-exchange-cited",
  "section": ["§3.1 Subject", "§6 The Symmetric Ask"],
  "request_json": "{\"coverage\":{\"expected_pin\":\"e2c78557e239cd93cf344c2e435158367deac1d3b525deb6e09c23d1a8139227\"},\"nonce\":\"n-0107\",\"subject\":{\"exchange\":\"e2c78557e239cd93cf344c2e435158367deac1d3b525deb6e09c23d1a8139227\"}}",
  "request_json_digest": "61a78ad010f8eee326f2bd696f21821c4bbf6731bb3e9dbdda257dcb0320ca42",
  …
  "expect": { "answer": "artifact" }
},
{
  "id": "res-exchange-not-cited",
  "section": ["§3.1 Subject", "§6 The Symmetric Ask"],
  "request_json": "{\"coverage\":{\"expected_pin\":\"a2ad745b1e5290793135b8c1fb20887d6e8de485cccb6c14e63dfc8337038846\"},\"nonce\":\"n-0108\",\"subject\":{\"exchange\":\"a2ad745b1e5290793135b8c1fb20887d6e8de485cccb6c14e63dfc8337038846\"}}",
  "request_json_digest": "0d60ed530c450e0d3521d9d4bc11aaa76ca3858d471779f30ef9ab280252a580",
  …
  "expect": { "answer": "refusal", "reason": "no_such_subject" }
}
FieldTypeMeaning
responder.exchange_citationsobjectThe responder's holdings for this case: exchange-half digest → the records that cite it.
subject.exchangehexThe asker's own sealed half of the exchange, by digest: what it wants evidence about.
coverage.expected_pinhexThe anchor the answer must verify against; a requester's own exchange half is a valid pin for an exchange subject (§3.2).
noncestringRequester-supplied; recommended, so a recorded refusal cannot be replayed against a fresh request.
request_json_digesthexSHA-256 over the request bytes as received (RFC 8785 text); a refusal names the request by this digest.
expect.answerstringartifact or refusal, written by hand from the draft text.
expect.reasonstringThe most specific registered reason; here the half resolves to no record.

The vectors are derived from the -00 text, not from any implementation; where -00 leaves a wire shape open (here, a subject as a one-member map), the file records the reading it used.

Source: action-state-group/agent-action-capsule:vectors/evidence-request/resolution.json @ 2ef8aeb49e2334e24c404bd62d3fdb161770873c

5Status

6Specs

7What you need before the next step