Skip to content

Releases: holistis/tokenizen

v0.5.0

Choose a tag to compare

@holistis holistis released this 06 Sep 19:34

Cross-installation discovery, the answer to the second open question from x402-foundation/x402#3379: how does a buyer find a seller's claims that were recorded on a different installation?

The insight: because every claim is self-verifying (claimId is a content hash, the signature recovers to buyerAddress), findability needs no trusted index. Claims can be published anywhere, and whoever discovers them re-verifies each one locally.

What is new

discoverDeliveryHistory(seller, sources): aggregates a seller's claims from several independent, UNTRUSTED sources (the local ledger, and any host-independent substrate you choose to also read), de-duplicates by claimId, re-verifies every single claim regardless of source, filters out claims about other sellers, and runs the completeness analysis over the survivors, with per-source accounting. No source is trusted; the trust comes only from re-verifying each claim.

An EAS-on-Base source (src/eas.ts): publish a claim as an Ethereum Attestation Service attestation on Base (recipient = seller), then discover it straight back from the chain via eth_getLogs, decode, and re-verify locally. Plain ethers, no eas-sdk dependency; the package never bundles an RPC, a key, or gas.

Two public, runnable fixtures anyone can check: docs/DISCOVERY-FIXTURE.md (npm run discovery-fixture, 8 controls over two simulated installations) alongside the existing docs/COMPLETENESS-FIXTURE.md.

Proven live on Base mainnet

Not just documented. On 2026-09-06 the full round-trip ran for real on Base mainnet: a schema was registered, two claims (one positive, one negative) were published as attestations, and a separate read-only run discovered both back from the chain by recipient and re-verified them locally, trusting only Base. See DECISIONS.md D-005.

Hardened after adversarial review

An independent review confirmed the trust model holds (no verification bypass, no claimId shadowing) and this release addresses what it found: a source resolving to a non-array can no longer crash the aggregation and censor the other sources; cryptographic rejections are counted separately from valid-but-other-seller claims; per-source and total work are bounded against volume; and the schema-parsed claim is stored so no unverified field rides into the result.

Honest limits

Discovery solves findability, not completeness. A source can still omit claims, and no aggregation invents what no source reveals. Verification proves authorship of content, not that a payment or delivery happened, and not that buyers are distinct; volume and Sybil are not addressed by aggregation. The production substrate (EAS, ERC-8004) is wired as a reusable, offline-tested source, but bundling an RPC and gas is left to the integrator.

511 tests, typecheck and build green.

v0.4.0

Choose a tag to compare

@holistis holistis released this 06 Sep 17:29

This release answers, in code, the question goun7 raised on x402-foundation/x402#3379: can a dishonest host hide delivery claims?

The honest framing first. Fully preventing omission from a single answer is not achievable by anyone, and this release does not pretend otherwise. Even Certificate Transparency, the largest system built for this, saw its split-view gossip layer declared dead in 2018 and leans in practice on a handful of funded monitors, not on a proof inside the log. What is achievable for a small package is to make an omission leave a trace that a reader can find without trusting the host.

What is new

priorClaimId: a new optional, signed field. Each buyer links their successive claims about the same seller into a chain, where each claim carries the claimId of that buyer's previous claim about that seller. Because the link sits inside the signed content, a host cannot strip or alter it without breaking the signature, and the read path re-verifies every claim. Same optional and never-defaulted discipline as the measured and externalRefs fields, so no claim recorded before 0.4.0 changes its claimId. A buyer's first claim about a seller simply omits the field.

analyzeCompleteness, surfaced as a completeness field on get_delivery_history. It reads the per-buyer chains in a result and flags, in possibleOmissions, any shown claim whose priorClaimId points to a claim that is not in the result. That is the concrete signal that a host may be hiding a middle claim.

The one thing to understand before you rely on it

The completeness field is computed by the same server that returns the claims. If you do not run that server yourself, do not trust the field: a dishonest host can put a rosy report in it. The trust lives in the signed priorClaimId links inside the claims, which a host cannot forge, not in the derived report. A suspicious reader recomputes analyzeCompleteness locally over the returned, independently verified claims. This is stated in the tool description, the README (with a recompute recipe), the source, and DECISIONS.md D-006.

Prove it yourself

A public, reproducible fixture ships with the package: docs/COMPLETENESS-FIXTURE.md, runnable with npm run fixture. It builds one buyer's chained claims about one seller, simulates a host that hides the negative middle claim, and checks nine controls: five GREEN properties that must hold and four RED tamper negatives that must be rejected. The same controls run as a test on every push. It is modeled on the transparency discipline goun7 published for Tamga Protocol: deterministic from a fixed test key, every value labeled by source, and tamper cases you can run rather than take on faith.

Honest limits

This catches a hidden claim in the middle of a buyer's chain. It does not catch a hidden most-recent claim, nor a hidden entire buyer, and a dangling link can also just mean the prior claim was recorded on a different installation. For assurance beyond middle-claim detection, cross-check against the buyer's own retained copy of their claims and the on-chain payment the settlementRef points to. The separate question of finding claims across independent installations (D-005) is not solved here and stays open, pointed at existing infrastructure like EAS and ERC-8004, waiting for a real multi-installation case.

494 tests, typecheck and build green.

v0.3.0

Choose a tag to compare

@holistis holistis released this 06 Sep 16:09

capacity-attest is the delivery-receipt layer for x402 agent payments. After a buyer agent pays a seller for capacity (gpu-hours, storage, api-credits, bandwidth), it leaves a signed, factual claim of what was actually delivered, and other agents can read that history before they pay. No reputation score, no token, no lending, no yield.

This release makes capacity-attest a good citizen of the wider agent-economy stack instead of a standalone island. One rule guided the whole release: cite other systems, never re-implement them and never vouch for them.

What is new

externalRefs: an optional block on a claim that can point to other agent-economy infrastructure without capacity-attest verifying it. Six pointer fields: sellerAgentRef and buyerAgentRef (for example an ERC-8004 agent id or a DID), mandateRef and mandateIssuerDid (an externally issued mandate, for example a Google AP2 mandate), intentRef (an external AP2 intent mandate), and disputeContext (for example a Legal Context Protocol reference). These are citations, not verified facts. Same preimage discipline as the measured block in 0.2.0: exactly one optional, never-defaulted key, so every claim recorded before 0.3.0 still hashes bit for bit identically. Enforced by a frozen regression anchor test.

resolve_agent_identity: a new read-only MCP tool that looks up an agent's on-chain identity in an ERC-8004 Identity Registry, using only the standard ERC-721 reads ownerOf and tokenURI. It requires the caller to supply both the registry reference and an RPC endpoint, because ERC-8004 has independent deployments per chain and the spec names no canonical address. It never fetches or trusts what the tokenURI points to. Tested against an injectable fake contract in the suite, and live against the real registry on Base mainnet.

Why we did not build more

We researched whether capacity-attest should build its own identity, authority, intent, execution, settlement, discovery or liability layer. For every one of them the answer was no. Each layer is already covered by better-resourced production infrastructure (ERC-8004, Google AP2, Microsoft Entra Agent ID, the x402 Foundation, the Legal Context Protocol, and more). Building our own would be a worse copy of work that already exists at a scale we cannot match. The full reasoning, per layer, with sources, is in packages/capacity-attest/DECISIONS.md, sections D-007 through D-013.

Also in this release

get_delivery_history now re-verifies every claim's signature when it reads the ledger, not just the shape of the fields. A claim written straight into the ledger file by anything other than record_delivery can no longer be served back as genuine. The tool response and its description now also say plainly that completeness of the shown set rests on the host's honesty, not on cryptography, and the README shows how a buyer can share their own signed claim directly, bypassing any host. See DECISIONS.md D-006.

Two known limits are documented with explicit trigger criteria rather than built ahead of real need: unmetered claim creation (D-014) and unbounded response size (D-015).

474 tests, typecheck and build green.