aere-quantum/agents
2026-10-21 23:20:15 +03:00
..
dovezi-ancora-28001 agents: the chain as the witness of an agent's ledger - a notarized head, read through the AIP-23 verifier under a post-quantum certified anchor, bounds entry times from below; run on testnet 28001 with its evidence 2026-09-30 09:43:10 +03:00
dovezi-martor-agenti-28001 agents: the hosted witness for agent ledgers (sandbox on testnet 28001), its probe and negative control; crypto-inventory 0.4.1 resolves a minimum TLS version given through a constant or a ternary; proof-kinds and conformance gain the agent-witness-checkpoint kind; the reproduction scripts of the Shield recipes no longer carry a workstation path 2026-10-20 01:04:12 +03:00
x402 Stranger pass of 21 Oct: x402 verify-payments reads all wallet transfers in windows under the endpoint range limit (was UNMEASURED on the live testnet; now VALID), device-operation reputation is byte-identical in JS --canonical and Python, module README figures as measured, .gitignore for the keys the examples write, temporary directories removed by the probes 2026-10-21 23:20:15 +03:00
agent-ancora.mjs ai-trust, proof-of-ai, verifiable-data: the trust chain of an AI result, the AIP-23 envelope of an agent action, and a dataset whose answers are checkable without the data 2026-10-02 11:28:14 +03:00
agent-aprobare.mjs Add agents: a post-quantum identity, a policy and a signed action ledger for AI agents, with human approval and revocation 2026-09-29 21:59:41 +03:00
agent-cli.mjs agents: the hosted witness for agent ledgers (sandbox on testnet 28001), its probe and negative control; crypto-inventory 0.4.1 resolves a minimum TLS version given through a constant or a ternary; proof-kinds and conformance gain the agent-witness-checkpoint kind; the reproduction scripts of the Shield recipes no longer carry a workstation path 2026-10-20 01:04:12 +03:00
agent-ledger.mjs identity: the SD-JWT form of an AERE hybrid identity is judged on its ML-DSA-65 half by default, the Ed25519 half only on explicit request, and every verdict says postQuantum (rule sdjwt.hybrid-half); pq-pki: the signature algorithm a certificate or a revocation list declares must be its issuer key's (ALG_KEY, CRL_ALG_KEY); agents: an equivocation proof requires the agent's ML-DSA-65 key; pq-gateway: the status names the path to the backend and hybrid-only refuses a plain-HTTP backend; conformance 241 rules, 631 vectors 2026-10-19 05:19:21 +03:00
agent-policy.mjs agents/x402: an agent wallet that pays over x402 only what the agent's ledger records and its policy allows, run on the public testnet 2026-09-30 00:01:34 +03:00
control-negativ-ancora.mjs agents: the chain as the witness of an agent's ledger - a notarized head, read through the AIP-23 verifier under a post-quantum certified anchor, bounds entry times from below; run on testnet 28001 with its evidence 2026-09-30 09:43:10 +03:00
control-negativ-aprobare.mjs identity: the SD-JWT form of an AERE hybrid identity is judged on its ML-DSA-65 half by default, the Ed25519 half only on explicit request, and every verdict says postQuantum (rule sdjwt.hybrid-half); pq-pki: the signature algorithm a certificate or a revocation list declares must be its issuer key's (ALG_KEY, CRL_ALG_KEY); agents: an equivocation proof requires the agent's ML-DSA-65 key; pq-gateway: the status names the path to the backend and hybrid-only refuses a plain-HTTP backend; conformance 241 rules, 631 vectors 2026-10-19 05:19:21 +03:00
control-negativ-martor-agenti.mjs agents: the hosted witness for agent ledgers (sandbox on testnet 28001), its probe and negative control; crypto-inventory 0.4.1 resolves a minimum TLS version given through a constant or a ternary; proof-kinds and conformance gain the agent-witness-checkpoint kind; the reproduction scripts of the Shield recipes no longer carry a workstation path 2026-10-20 01:04:12 +03:00
martor-agenti-serviciu.mjs agents: the hosted witness for agent ledgers (sandbox on testnet 28001), its probe and negative control; crypto-inventory 0.4.1 resolves a minimum TLS version given through a constant or a ternary; proof-kinds and conformance gain the agent-witness-checkpoint kind; the reproduction scripts of the Shield recipes no longer carry a workstation path 2026-10-20 01:04:12 +03:00
martor-agenti.mjs agents: the hosted witness for agent ledgers (sandbox on testnet 28001), its probe and negative control; crypto-inventory 0.4.1 resolves a minimum TLS version given through a constant or a ternary; proof-kinds and conformance gain the agent-witness-checkpoint kind; the reproduction scripts of the Shield recipes no longer carry a workstation path 2026-10-20 01:04:12 +03:00
proba-agent-ancora-testnet.mjs agents: the chain as the witness of an agent's ledger - a notarized head, read through the AIP-23 verifier under a post-quantum certified anchor, bounds entry times from below; run on testnet 28001 with its evidence 2026-09-30 09:43:10 +03:00
proba-agent-ancora.mjs agents: the chain as the witness of an agent's ledger - a notarized head, read through the AIP-23 verifier under a post-quantum certified anchor, bounds entry times from below; run on testnet 28001 with its evidence 2026-09-30 09:43:10 +03:00
proba-agent-aprobare.mjs Add agents: a post-quantum identity, a policy and a signed action ledger for AI agents, with human approval and revocation 2026-09-29 21:59:41 +03:00
proba-agent-cli.mjs Add agents: a post-quantum identity, a policy and a signed action ledger for AI agents, with human approval and revocation 2026-09-29 21:59:41 +03:00
proba-agent-ledger.mjs identity: the SD-JWT form of an AERE hybrid identity is judged on its ML-DSA-65 half by default, the Ed25519 half only on explicit request, and every verdict says postQuantum (rule sdjwt.hybrid-half); pq-pki: the signature algorithm a certificate or a revocation list declares must be its issuer key's (ALG_KEY, CRL_ALG_KEY); agents: an equivocation proof requires the agent's ML-DSA-65 key; pq-gateway: the status names the path to the backend and hybrid-only refuses a plain-HTTP backend; conformance 241 rules, 631 vectors 2026-10-19 05:19:21 +03:00
proba-agent-policy.mjs agents/x402: an agent wallet that pays over x402 only what the agent's ledger records and its policy allows, run on the public testnet 2026-09-30 00:01:34 +03:00
proba-martor-agenti.mjs agents: the hosted witness for agent ledgers (sandbox on testnet 28001), its probe and negative control; crypto-inventory 0.4.1 resolves a minimum TLS version given through a constant or a ternary; proof-kinds and conformance gain the agent-witness-checkpoint kind; the reproduction scripts of the Shield recipes no longer carry a workstation path 2026-10-20 01:04:12 +03:00
README.md agents: the hosted witness for agent ledgers (sandbox on testnet 28001), its probe and negative control; crypto-inventory 0.4.1 resolves a minimum TLS version given through a constant or a ternary; proof-kinds and conformance gain the agent-witness-checkpoint kind; the reproduction scripts of the Shield recipes no longer carry a workstation path 2026-10-20 01:04:12 +03:00

Agents: policy, post-quantum identity, a signed action ledger, human approval and revocation

An AI agent that can pay or call tools needs limits that someone other than the agent can check. This component gives an agent a post-quantum identity (an ML-DSA-65 key), a policy (a spending limit per time window, allowed tools, allowed recipients, which actions need human approval, who may revoke the agent), and a ledger in which every action the agent proposes is judged against the policy, signed by the agent and chained. A verifier that does not trust the agent re-runs the policy over the whole ledger and says whether any allowed action broke it. Humans approve and revoke with their own ML-DSA-65 keys.

Node.js 24 only (node:crypto with ML-DSA), no dependencies, no network (except the chain witnesses below, which read a chain, and the hosted witness, which is a service). It moves no money: amount is the unit the policy names; moving value is the job of a payment layer, which can ask for this ledger as evidence that an action was allowed.

Quick start (command line)

node agent-cli.mjs id --out agent/                  # prints aere-agent:<40 hex>; writes agent.key.pem and agent.pub.pem
node agent-cli.mjs human --out alice/               # an approver or an owner: aere-human:<40 hex>
node agent-cli.mjs policy --spec spec.json --out policy.json
node agent-cli.mjs record --key agent/agent.key.pem --policy policy.json --ledger ledger.json --action pay.json
node agent-cli.mjs approve --key alice/human.key.pem --policy policy.json --action pay.json --out approval.json
node agent-cli.mjs record ... --approvals approval.json,approval2.json
node agent-cli.mjs verify --ledger ledger.json --policy policy.json [--revocations r.json] [--anchors a.json] [--not-before <unix>] [--witness <id>]
node agent-cli.mjs revoke --key owner/human.key.pem --policy policy.json --out revocation.json
node agent-cli.mjs equivocation --a ledger-a.json --b ledger-b.json --out proof.json
node agent-cli.mjs verify-equivocation --proof proof.json

A spec is { agentId, spend: { amount, windowSeconds, asset? }, tools: [...], recipients: [...], approval: { approvers: [humanId...], threshold, above?, tools? }, owner: humanId, wallet: 0x<EVM address> }; every field but agentId is optional. When wallet is named, a payment must say from and be from it. An action is { kind: "payment", to, amount, asset? } or { kind: "tool", tool, args? }; the ledger sets its time. Exit codes: 0 yes (allowed, valid, found), 1 no (invalid, not found, refused by a check), 3 an action refused by the policy, 2 wrong usage. Private keys stay in their files and are never printed; the tool creates them with mode 0600, which has no effect on Windows (protect the folder there).

What each part does

  • Policy (agent-policy.mjs): definePolicy returns the policy in a normal form and its hash. hashPolicy recomputes the hash of a policy received from anyone and refuses unknown fields, so a relying party that pinned a hash cannot be handed a looser policy under it. checkAction is pure: a payment must be a strictly positive decimal integer, to an allowed recipient, in the policy's asset, and within the limit over the window; a tool must be on the list. Approval is a requirement in addition to the limits, never an exemption. decisionEnvelope writes a decision as an AIP-23 envelope (aere-proof-of-agent-decision) whose actionHash is the SHA-256 of the action's canonical JSON (keys sorted), so anyone can recompute it.
  • Identity and ledger (agent-ledger.mjs): agentId is derived from the public key (nobody can claim another agent's id). Each entry carries the action, the decision, the approvals it used and optionally the hash of its provenance (for example a Proof of AI envelope); it is signed by the agent and chained by hash. The spending in the window is derived from the ledger's own allowed entries, so the limit holds over the whole ledger, across restarts (resumeLedger verifies the saved ledger, then continues it).
  • Verifier (verifyLedger): recomputes the policy hash, the identity, every signature and the chain, and re-runs the policy from the first entry: an "allowed" written over a refusal is caught even when the agent re-signs its whole ledger. Revocations are given to it separately, by the owner, because an agent can leave its own revocation out of its ledger; the result says which set of revocations it judged against (revocations.setHash).
  • Approval and revocation (agent-aprobare.mjs): an approval signs exactly the action (kind, recipient, amount, asset, tool, and the hash of the tool arguments, so an approval to deploy to staging does not approve production), the agent and the policy; it has a validity window of at most seven days and a nonce that counts once per ledger. Only approvers named in the policy count, each once. A revocation is signed by the owner named in the policy; from its time on every action is refused.

Paying over x402

x402/ holds the agent wallet: a service that keeps the payment key for the owner and signs an x402 payment only when the agent's ledger records it and the policy allows it, with the wallet as the witness of the ledger's heads and time. With a 2-of-2 contract wallet (AereAgentWallet2of2, ERC-1271) the money leaves only with the agent's signature and the wallet service's together, so neither the agent nor the owner can spend alone. Both were run end to end on the public testnet 28001 on 2026-09-29, and the evidence is there with a verifier anyone can run. See x402/README.md.

The chain as the witness of the ledger (2026-09-30)

Without a witness, an entry's time is only the statement of whoever holds the agent key. agent-ancora.mjs makes the chain that witness: the ledger's head (sequence number and hash) becomes an AIP-23 envelope, its hash is notarized on AereNotary, and the first-seen time the contract records, read through the AIP-23 reference verifier under a post-quantum certified anchor (a Merkle proof in the certified state), becomes an anchor {seq, hash, at} for verify --anchors.

node agent-ancora.mjs head --ledger ledger.json --out head.json                                  # no network
node agent-ancora.mjs notarize --head head.json --rpc <url> --key-file <key> --out notarized.json # needs ethers (x402/)
node agent-ancora.mjs anchors --ledger ledger.json --head notarized.json --rpc <url> \
     --chain 2800 --verify-proof <verify-proof.mjs from aere.network/tools> --out anchors.json   # --chain: the chain whose time you accept
node agent-cli.mjs verify --ledger ledger.json --policy policy.json --anchors anchors.json

With the anchor, an entry after the notarized head cannot claim a time before its first-seen time (minus the 300 s tolerance), an entry up to the head cannot claim a time after it, and a branch that does not contain the head does not verify. The time is the chain's, not the agent's and not the notarizer's: whoever notarizes can only notarize late, which weakens the bound, not move it earlier. Only the hash of the head's statement goes on chain, nothing of the ledger. The anchors file is the output of the verifier's own run, with the RPC endpoint and the AIP-23 verifier it chose; an anchors file handed over by the party being verified proves nothing. anchors answers not measured (exit 2) while the finality is pending or when the verifier cannot be run, never an anchor it did not certify. notarize reads the chain id from the endpoint and refuses chain 2800 (a real transaction paid by the key's account) unless AERE_CONFIRM_MAINNET=yes.

A hosted witness (2026-10-19)

Sandbox: testnet 28001; mainnet: at activation. Every answer of the service says so in its sandbox field.

The section above asks the agent's owner to run a notary transaction, a funded wallet and the AIP-23 verifier. The hosted witness takes the first two off the owner: the agent sends its ledger head, signed with its ML-DSA-65 key, and gets back a receipt that anyone can check without the witness. martor-agenti.mjs is the format, the judge and the client; martor-agenti-serviciu.mjs is the service.

The form is the one transparency logs already use:

  • The head is a checkpoint of the agent's log, accepted the way a C2SP tlog-witness accepts a log's checkpoint (add-checkpoint): it must be signed by the log's key (here the agent's ML-DSA-65 key, from which the agent id is derived), it must name as its predecessor exactly the last head the witness holds for that agent and policy (previous, null for the first; otherwise 409 with that head, as C2SP answers 409 with its latest size), and it is written to disk before the answer. The ledger is a hash chain, not a Merkle tree, so a consistency proof between two heads would need the entries, that is the actions, which the witness never sees. The agent signs its predecessor instead, and the descent itself is checked by whoever holds the ledger: every witnessed head must be an entry of the ledger shown.
  • Two heads signed by the agent that give one position two hashes (the same seq, or a previous against a head already witnessed, also when the new head repeats a head the witness holds) are a proof of equivocation (aere-agent-head-equivocation): the witness refuses the head and returns the proof in the 409. It keeps one proof per agent and policy (one proof is enough to show the equivocation; a further one is returned, kept: false, not stored). A kept proof belongs to the shard of the head it contradicts and leaves with it, so every kept proof has a session of its own with a head in a kept shard: there are at most as many as heads kept (40,000), and that bound is the cap, so nobody can fill the store to push out, or keep out, another agent's proof. Until the second review (2026-10-19, R2-02) the cap was 2,000 in all, and anyone could fill it with sessions of their own (two requests per session), after which a real equivocation of another agent was returned but not kept, and verify --witness-url showed that agent clean. The one proof of a session is the one that lives longest: a new proof whose contradicted head sits in a NEWER shard than the head of the kept proof takes its place (replaced names the proof it took the place of, which then answers 404); until the third review (R3-02) an agent could fill the place of its session with an equivocation against a head of the old shard, so that the equivocation that mattered was returned not kept, and after the next rotation the session had no proof left. /health counts the proofs returned and not kept (equivocationsNotKept: onePerSession, cap). GET .../heads names the kept proofs by id, and GET .../equivocation/<id> returns one. Anyone checks a proof with the public key inside (verify-equivocation).
  • The accepted heads are the leaves of an RFC 9162 log, as in Certificate Transparency and Sigstore Rekor. On receipt the witness returns a promise signed with its ML-DSA-65 key that it saw the head at the receive time (the role of an SCT, or of Rekor's signed entry timestamp; an AIP-23 time envelope). Within the maximum merge delay (RFC 9162's MMD; 1800 s here, checkpoints every 10 minutes) it signs a checkpoint (the log's name, its size and root, as in C2SP tlog-checkpoint; an AIP-23 envelope of kind aere-proof-of-agent-witness-checkpoint, registered in proof-kinds/ with a vocabulary for each field) and notarizes it on AereNotary, so the checkpoint's time is the chain's, certified post-quantum through the AIP-23 verifier, not the witness's word. Consecutive checkpoints name each other and come with RFC 9162 consistency proofs.
  • The log is sharded, the way Rekor and Certificate Transparency shard theirs: a shard holds at most 20,000 heads; when it is full the witness signs its final checkpoint and starts the next shard, under a new log name (aere-agent-witness/28001/<k>, the first shard keeps the plain name), whose first checkpoint names the final checkpoint of the shard before. The witness keeps the current shard and the one before; an older shard is removed from its disk and memory, but only once its final checkpoint is notarized: while it is not, a head that would make the log rotate gets 503 log_busy with code: notarization_behind (and Retry-After), and the heads of that shard stay served (until the second review, R2-07, the shard was removed anyway, and heads answered 202 with a mergeBy were left without a certified time). A new shard is made whole under a temporary name and then renamed (R2-08: a write that failed between the folder and its ciob.json, then a restart, used to lose the link between the shards for good). A shard to remove is first renamed (.sters-<k>-*, an atomic rename) and only then deleted, in the background; the next open deletes whatever carries that name, and a shard older than the two kept that lacks its ciob.json or its frunze.ndjson is taken as the rest of a removal, not as a shard (third review, R3-01: a stop during the background deletion used to leave a rest that the opening kept as an unnotarized shard, empty, which no notarization could ever settle, so every new head got 503 notarization_behind for good, or, with checkpoints left in it, the witness refused to start). Until 2026-10-19 a full log answered 503 to everyone, for good, and anyone could fill it.
  • The receipt is that checkpoint, with the head received, its position, the receive time and the RFC 9162 inclusion proof (the role of Rekor's verification.inclusionProof). It is VALID for the AIP-23 reference verifier: form, integrity, the witness's ML-DSA-65 signature and, once a post-quantum anchor covers the notarization, finality.
route (behind the gateway; the service listens on 127.0.0.1) what it does
POST /v1/agents/witness a signed head (martor-agenti.mjs request). 202 accepted, with the signed promise; 200 already seen; 409 equivocation (the proof, and whether it was kept), stale_head (older than the last head witnessed) or not_successor (with the last head); 400, 403, 422 a refusal that names its rule (continut: any field besides the head and its signature, so a ledger's content is never taken; semnatura, cheie, identitate, sesiune, integritate, timp: a head declared more than 300 s from the witness clock); 413 above 16 KB; 429 above 60 heads per client (an IPv6 client counts by its /64) or 30 changes per agent in 10 minutes (the per-agent count takes only requests whose signature verifies AND that change the state, a new head or a newly kept proof: neither a forged request, nor a replay of the agent's public head, nor a head refused with 503 uses up its quota); 503 log_busy above 833 new heads per hour from everyone (20,000 / 24, so a shard never fills in less than a day), or with code: notarization_behind while a rotation would remove a shard whose final checkpoint is not notarized, both with Retry-After (also through the gateway). The gateway refuses a POST that carries an Origin header (a web page, through the open CORS of /v1/): a head is sent by the agent, not by a browser
GET /v1/agents/witness/<id> the state of a head (its id is the statementHash of the head): pending, checkpointed (with an unnotarized receipt) or notarized (with the receipt); 404 for a head the witness does not hold, also one of a shard it no longer keeps
GET /v1/agents/witness/<agentId>/heads?session=<s>[&from=<seq>&limit=<1..100>] one page of the witnessed heads of an agent under one policy, in order, with next (the seq to ask from, or null), the latest head and the ids of the kept equivocation proofs, and signedPage: the same page (each head {seq, hash, id}, next, count, latest, the kept proofs) with its time, signed by the witness with its ML-DSA-65 key; nothing is read from disk
GET /v1/agents/witness/<agentId>/heads[?after=<session>] the sessions (policies) of an agent, at most 100 per page, each with its number of heads, its latest head and its number of kept proofs (not signed)
GET /v1/agents/witness/equivocation/<id> one kept proof of equivocation
GET /v1/agents/witness/checkpoint[?shard=<k>][&from=<size>] the latest checkpoint of the current shard, or of the kept shard k (for a frozen shard: its final checkpoint), and the latest notarized one, with a consistency proof in that shard from from, and the shards kept; a monitor that held a checkpoint of a shard that has since been frozen asks ?shard=<k>&from=<its size> (until the second review, R2-09, only the current shard was served)
GET /v1/agents/witness/health the witness id, the log and the current shard, leaves and maxLeaves, the counts (also the proofs not kept, and whether the rotation waits for a notarization), the last checkpoint and the last notarization (a failed notarization shows a code, such as unfunded, never its message), and the rate limiters (limiters: keys held, the cap, keys dropped at the cap)

The Aere Cloud route /v1/agents/witness is not open yet; until it is, a witness can be run by anyone (below), and the commands are the same with its address. The id of the hosted witness is published when the route opens; a verifier pins it.

node martor-agenti.mjs submit --key agent/agent.key.pem --ledger ledger.json --url <witness>     # previous = the witness's last head of this agent
                                                                                                 # nothing new to send: exit 0, no request (2 if the
                                                                                                 # witness then does not give the state of that head);
                                                                                                 # a 200 or 202 that is not the state of the head sent: 2
node martor-agenti.mjs receipt --url <witness> --id 0x<head id> --ledger ledger.json [--witness aere-witness:<id>] --out receipt.json
                                                                                                 # exit 0 once notarized, 2 before (and on 503,
                                                                                                 # 429, or a 200 that is not JSON); writes the
                                                                                                 # answer ONLY if it is the receipt of that head of
                                                                                                 # that ledger and the witness signature verifies:
                                                                                                 # else 2, the reason named, nothing written
node agent-cli.mjs verify --ledger ledger.json --policy policy.json --anchors receipt.json \
     --rpc https://testnet-rpc.aere.network --chain 28001 --verify-proof <verify-proof.mjs from aere.network/tools> \
     --witness aere-witness:<id of the witness you trust> [--witness-url <witness>]
node martor-agenti.mjs verify-receipt --receipt receipt.json --ledger ledger.json [--witness <id>]   # the local checks alone, no network;
                                                                                                 # a pending answer: 2; an empty --witness: wrong usage, 2
node martor-agenti.mjs verify-equivocation --proof proof.json
node martor-agenti.mjs request --key agent/agent.key.pem --ledger ledger.json --previous <seq>|none --out head.json   # the signed head, to POST yourself

receipt writes what the agent will hand over in --anchors, and what the agent hands over is its own responsibility: a receipt it hands over that is tied to another ledger, or whose witness signature does not verify, is a fault of the ledger (below). So receipt writes the answer (to --out, or to the standard output) only once it has checked it here: the receipt of the head asked (--id), a head of the ledger given (--ledger: the same agent, policy, seq and hash, and its predecessor), the witness signature verified with the witness pinned by --witness when it is given, otherwise with the key the receipt names (and the message then says the witness is not pinned), and the other local checks of verify-receipt. Anything else is exit 2 with the reason named, and nothing is written; --ledger is required. So the documented flow (submit, receipt --out, verify --anchors) cannot produce a file that comes out FAILED because of the address it read from (until the sixth review, N2, receipt wrote whatever the address answered, and a proxy without any key at the agent's --url could give an honest agent the true receipt of another agent's head, or one with a broken signature, which then came out FAILED when handed over).

verify --anchors takes a receipt (or the answer of GET /v1/agents/witness/<id> as it is) and accepts it as an anchor only after checking it here: the witness's signature on the checkpoint, that the witness is one the verifier pinned (--witness, repeatable), the agent's signature on the head, the leaf recomputed from the head and the receive time, the inclusion proof up to the checkpoint's root, the head and its predecessor as entries of the ledger shown, and then the checkpoint judged by the AIP-23 verifier on the chain (--verify-proof, --rpc): the witness's signature and the post-quantum finality PASSED, whose first-seen time F must not be before the receive time (beyond 300 s) nor later than the maximum merge delay (the witness's and the verifier's, --max-merge-delay, 1800 s by default). --chain and --max-merge-delay must be positive integers, and AERE_WITNESS_WAIT_MAX_S (below) a whole number of seconds; anything else is wrong usage (exit 2). A receipt without --rpc, in --anchors or taken from the address, is a NOT-MEASURED piece with the rule rpc, judged in its place after everything that does not need the chain (until the sixth review, N1, a receipt in --anchors without --rpc was wrong usage, returned before the signed list was judged, so any object shaped like a receipt put there by the agent hid a branch the list showed). With --witness-url, the verifier also reads the full list of heads that witness holds for this agent and policy. Only the pages SIGNED by the witness count (signedPage, checked against the agent, the policy and the page asked, chained by next, adding up to the count and latest it signs), and each must be signed within 300 s of the verifier's clock: a server at that address that is not the witness cannot sign the witness's list, and an old page replayed by a proxy is not the list of now (until the second review, R2-01, the list and the witness id, read from /health, were not signed, so a hostile server at the address passed as the pinned witness and hid a head). Without --witness, the witness that signs the list is then the pinned one.

verify is a complete evaluation followed by one verdict (fifth review, 2026-10-19; the same text stands beside the code in agent-cli.mjs). Until then it decided on the way, returning 2 or 1 at the first sign, in the order it read things, and the agent chose that order: a fresh head still pending at the witness, a {"status":"pending"} put in --anchors or an old copy of a receipt hid a backdating that the verified receipts proved (R5-01); a list signed by another witness, or a true plain anchor beside the receipts, came out FAILED though nothing showed a fault of the ledger (R5-02); and a receipt that did not hold because the notary was late, or because the RPC the verifier chose served a wrong header, gave 1 when the agent handed it over and 2 when it was taken from the address (R5-03).

  1. Gather. Every piece of evidence is collected before anything is decided: every entry of --anchors, whatever its form; with --witness-url, the signed list of heads, each head in it, and, for every held head without a VERIFIED receipt in --anchors (a receipt with the same id that does not hold does not count), its receipt taken from the address. Nothing returns during the gathering. A verification with no receipt, no answer of a witness and neither --witness nor --witness-url does not load the witness module (martor-agenti.mjs) at all, as before.
  2. Classify. Each piece gets one class.
    • VERIFIED: it holds and gives a bound (an anchor of the ledger).
    • LEDGER-FAULT, a fault of the ledger that the evidence PROVES: a head the pinned witness holds that is not an entry of the ledger (a branch); a kept proof of equivocation; a receipt of the pinned witness tied to another ledger (another agent, policy or branch, also through the signed predecessor of its head); a receipt the AGENT hands over whose signature of the witness it names (a pinned one, or any when none is pinned) does not verify; an entry backdated against a bound given by VERIFIED evidence (and any other refusal of the ledger itself by verifyLedger). The two kinds of receipt the agent answers for are the ones receipt no longer writes (above, since the sixth review, N2): a file receipt wrote for this ledger is not one of them, whatever the address answered.
    • NOT-MEASURED: anything else. A head or receipt pending or not notarized yet; a wrong form or wrong types; a receipt judged without --rpc ([rpc]); a notary that is behind ([intarziere]); a finality the AIP-23 verifier refuses or leaves pending through the RPC the verifier chose ([lant]); a receipt or a list of another witness than the pinned one ([martor]); a plain anchor under a pinned witness ([martor]); an answer the address breaks, a receipt with a broken signature taken from the address included (an address cannot make a FAILED); --witness with no receipt of a pinned witness and no list ([martor]).
  3. Verdict. FAILED (exit 1) if there is at least one LEDGER-FAULT; otherwise NOT MEASURED (exit 2) if a REQUIRED piece is NOT-MEASURED; otherwise OK (exit 0). Every piece is required except a receipt, or an answer without a receipt, in --anchors whose head has a VERIFIED receipt of its own: that old copy is listed as superseded. So a proven fault cannot be hidden by a piece that could not be measured, however early it comes, and an outage of the witness, its notary or the verifier's RPC cannot turn an honest ledger into a FAILED. The order in which the pieces come does not change the verdict: the negative control reverses it in three ways (the held heads before --anchors, --anchors from the last, the held heads from the last) and requires the whole probe to stay green.

Rule (c), the types: the type of every value that comes from outside (--anchors, the address, the service) is judged before it is used. A negative receivedAtMs, an object ({"toString":0}) where a string or a number is expected, in a receipt, in a page of the list, in a status or in the answers to submit, is a NOT-MEASURED piece with its rule named (chitanta-forma, punct-integritate, lant, a page refused by its form), or for submit exit 2 with --out not written, never an exception (until the fifth review, R5-04, these came out 1 through an exception; on the "nothing new" path of submit, the unsigned latest of the page and the state of the head it names, until the sixth, N3). The output: one line per piece on stderr (ok verified, FAIL a fault of the ledger, -- not measured and required, .. superseded) and a closing line; the JSON result carries verdict (OK, FAILED, NOT MEASURED), ok (true, false, null) and evidence (each piece with its source, class VERIFIED, LEDGER-FAULT or NOT-MEASURED, required, seq and rule).

The class of an entry of --anchors, by its form:

an entry of --anchors no witness pinned --witness or --witness-url
a receipt, or a GET answer that carries one, that holds here and on the chain VERIFIED; its witness is not pinned, so the chain alone bounds the head, and the result says so VERIFIED if its witness is a pinned one; a receipt of another witness, its signature valid: NOT-MEASURED [martor]
a receipt whose signature of the witness it names does not verify (receipt does not write one since the sixth review, N2) LEDGER-FAULT ([punct-semnatura], or [martor] for a key that is not the key of that witness) LEDGER-FAULT when it names a pinned witness
a receipt of the witness for another ledger: another agent, policy or branch, or a head whose signed predecessor is not an entry (receipt does not write one for the ledger it is given since the sixth review, N2) LEDGER-FAULT [registru] LEDGER-FAULT [registru]
a receipt whose inclusion proof, leaf, promise, receive rule or head signature fails, the witness signature valid NOT-MEASURED, by the rule that fails the same
a receipt not notarized yet, notarized too late ([intarziere]), with a finality refused or pending ([lant]), with no AIP-23 verifier, or judged without --rpc ([rpc]; until the sixth review, N1, wrong usage, returned before the list was judged) NOT-MEASURED the same
a receipt with wrong types (receivedAtMs -1, an object for a hash or a chain id) NOT-MEASURED [chitanta-forma] or the rule of the field the same
an answer of the witness without a receipt ({"status":"pending"}, checkpointed) NOT-MEASURED [fara-chitanta] the same
a plain anchor {seq, hash, at} VERIFIED, as the verifier's own anchor (anchors of your own run, such as agent-ancora.mjs anchors); one that is not an entry of the ledger: LEDGER-FAULT [ancora] NOT-MEASURED [martor]: the word of whoever wrote the file, not the witness's (until the fifth review, R5-02, FAILED)
anything else: null, a number, a string, an object of no known form NOT-MEASURED [forma] the same

A receipt taken from --witness-url is classified the same way, except that a broken signature of the witness is NOT-MEASURED there (the address, not the agent, gave it). Anchors of your own run are judged in a run without --witness and --witness-url; each anchor only adds constraints, so two runs catch what one would.

So an honest ledger whose last head the witness notarized late (a notary outage beyond the merge delay) is not measured, not refused, whether the agent hands over that receipt or the verifier takes it (until the fourth review, R4-01, it came out FAILED when taken, and until the fifth, R5-03, when handed over); a proxy at the address that breaks the answer for one head gives not measured, never FAILED and never an exception (R4-02, R5-04); and an agent that hands over only the receipt of an old head does not leave the entries after an INTERMEDIATE head backdatable down to the old one (R4-03), whatever else it puts in --anchors (R5-01). With --witness-url and a witness that holds no head of the ledger, the list is judged and a NOTE says that the time of the entries is not bounded by the witness. Without --witness-url the bound is still the one of the receipts the agent hands over.

The cost, and the read limit of the witness (fifth review, R5-06). The verifier takes one receipt per held head that has no verified receipt in --anchors, and runs the AIP-23 verifier once per checkpoint (the heads of one round share it). The service gives 1,200 reads per client in 10 minutes, the pages of the list included (a page holds 100 heads). A read over the limit answers 429 with Retry-After, the seconds until the client's window opens again, and the verifier waits as asked, within one budget for the whole run: AERE_WITNESS_WAIT_MAX_S, 900 s by default, named in a NOTE when it was used. Measured on 2026-10-19 with the real limits: an honest ledger with 1,250 held heads and no receipt handed over, exit 0 after waiting 595 s (601 s in all; until this review, exit 2 at the head seq 1,187, whose read was refused with 429). By arithmetic, not measured: the default budget covers two windows of reads (one wait of at most 600 s), so about 2,370 held heads; each further 1,200 heads ask up to 600 s more of budget, and a run whose budget is spent is NOT MEASURED, with the 429, its Retry-After and the seconds already waited named. An agent that hands over its own receipts spares those reads. The gateway passes Retry-After through (read in its code, not measured live); the limits of the public door itself (the gateway and its edge) were not measured.

A head sent for an older entry is a statement about now (fifth review, a finding rejected by its verifier, kept here as the intended behaviour). A head says "my head was seq at createdAt". An agent that comes back after a time offline and sends, one by one, heads for entries it wrote meanwhile (submit --seq <k> for each), signs for each an old position at a NEW time; the entries after it, written before, then declare times before that head, and verify --witness-url, which takes every head the witness holds as a bound, gives FAILED backdated (without --witness-url, with the receipts of older heads only, 0). The signed statement is false, and nothing tells it apart from a real backdating, so FAILED is the honest answer. The recovery that does not produce it is submit without --seq, which sends the current tip.

The arguments of both command lines come in pairs, a flag and its value. A flag that takes a value and is given without one (the last on the line, or followed by another flag) or with an empty value, a flag the command does not know (a typo such as --ledgr, or the form --flag=value), and a flag given twice (but --witness, which repeats) are wrong usage (exit 2), in agent-cli.mjs and in martor-agenti.mjs (third review, R3-03, and fourth, R4-05: --witness-url or --policy-hash put last, --revocations "", verify-receipt --ledger "", --witness-url=<URL>, --policy-hash=<h>, verify-receipt --witness=<id> or --ledgr used to drop the list of the witness, the pinned policy, the revocations, the pinned witness or the link of the receipt to the ledger, without a word); only --reason may be empty. The result names the witness of every receipt (witnessReceipts, with pinned), and when a witness was not pinned its time.lowerBound says the bound is the chain's alone.

An end-to-end run with a witness of your own on testnet 28001 (Node.js 24; ethers for the notarization: npm install in x402/):

node agent-cli.mjs id --out agent/
node agent-cli.mjs policy --spec spec.json --out policy.json
node agent-cli.mjs record --key agent/agent.key.pem --policy policy.json --ledger ledger.json --action pay.json
node martor-agenti-serviciu.mjs --stare witness/ --port 8802 --cheie testnet.key \
     [--robinet <client of the testnet faucet>]        # notarizes on testnet 28001 every 10 minutes (--interval); --fara-lant: no chain at all
node martor-agenti.mjs submit --key agent/agent.key.pem --ledger ledger.json --url http://127.0.0.1:8802
node martor-agenti.mjs receipt --url http://127.0.0.1:8802 --id 0x<id from submit> --ledger ledger.json --out receipt.json   # after the next checkpoint
node agent-cli.mjs verify --ledger ledger.json --policy policy.json --anchors receipt.json \
     --rpc https://testnet-rpc.aere.network --chain 28001 --verify-proof verify-proof.mjs --witness-url http://127.0.0.1:8802

--cheie is a testnet key file (a hex key, or a d=<hex> line); if it does not exist the service makes one there (mode 0600) and, given --robinet, funds it from the public testnet faucet; it never prints it. The service reads the chain id from --rpc and refuses any chain but 28001 before it touches the key.

What a receipt proves. That a head of the agent's ledger (its sequence number and entry hash), signed by the agent, was in the log of the witness that signed the receipt no later than a time the chain certifies post-quantum (the checkpoint's first-seen time on testnet 28001), with its inclusion checkable by anyone from the receipt alone. As an anchor: the agent signed that its head was seq at createdAt, so an entry written after the head that declares a time before createdAt minus 300 s contradicts the agent's own signature and is caught as backdated, and an entry up to the head cannot declare a time after it. The chain bounds createdAt to between F minus the merge delay and F, each widened by 600 s (the witness's 300 s rule between createdAt and the receive time, plus 300 s between the receive time and F). Only a witness the verifier pins (--witness, or the one at --witness-url) tightens it to 300 s around its clock and refuses an equivocating branch: any ML-DSA-65 key can be a witness of itself, so an agent can run its own witness, set its clock back to F minus 2,100 s, and obtain a receipt for a head claimed at F minus 2,400 s, or for a branch the hosted witness refused as an equivocation. Without pinning such a receipt is still accepted, as the agent's own signed statement bounded by the chain, and the result says so.

What it does not prove.

  • The witness never sees, and never judges, the actions: it receives a sequence number and a hash, and refuses any other field. Whether an action was allowed is the ledger verifier's job (verify), with the ledger.
  • The lower bound on the time of the entries after a head rests on the clock of a pinned witness up to 300 s; beyond that it is the chain's, within the merge delay. Without --witness-url it holds only after the heads whose receipts the agent hands over; with it, after every head the witness holds (the complete evaluation above), and a head held with no verified receipt makes the verdict not measured, unless the evidence proves a fault of the ledger. A witness that colludes with the agent (or a witness the agent runs, when the verifier pins none) can accept a head claimed up to the merge delay earlier than the truth.
  • The witness checks that a new head names its last head as the predecessor, not that it descends from it (that needs the entries). A branch that forks after the last head for which the agent hands over a receipt passes the receipts: it is caught only with the full list of heads the witness holds (verify --witness-url), not with the receipts the agent chooses to give. The list is signed by the witness page by page; what the signature does not cover is the order of the requests: a page is fresh for 300 s, so a proxy that recorded a page can replay it within those 300 s, and a branch whose head reached the witness within the last 300 s may be hidden that way. A witness that lies in its own signed list is the witness lying, which no list can catch (C2SP cosigning by other witnesses is not built here, below).
  • The witness's memory is two shards (at most 40,000 heads; at the hourly cap, at least the last day), and a third only while the final checkpoint of the oldest one waits for its notarization. A head of an older shard is no longer served (GET answers 404; its receipt, once notarized, stays verifiable without the witness), and the witness no longer remembers it: an agent whose last head was there starts again with previous null, and an equivocation against a head the witness no longer holds is not caught by the witness, nor kept (a kept proof leaves with the shard of the head it contradicts; receipts already given still show the equivocation to whoever holds both).
  • Sandbox: checkpoints are notarized on the public testnet 28001 with a test key; nothing here runs on chain 2800 (mainnet at activation).
  • The availability of a witness is not proven: a witness that is down or that drops a head breaks only its promise, which the agent holds signed. A flood can delay new heads for everyone (503 log_busy above the hourly cap, 429 per client); it cannot fill the log for good, and it cannot lose a head already answered. A notarization that fails for as long as a shard takes to fill (at least a day at the cap) stops new heads (503 notarization_behind) until it succeeds again: the log waits rather than drop heads it promised to anchor. Each rate limiter keeps at most 100,000 client keys; at that cap the key with the oldest window is dropped and the new client gets in (until the second review, R2-03, every NEW client was refused while the cap was full, so whoever filled 100,000 keys locked out every new client). A flood from more than 100,000 keys in 10 minutes therefore makes the per-client count partial (a dropped client starts a fresh window), never a lockout; /health shows the keys held and dropped. Whether the Cloudflare edge delivers IPv6 client addresses to the witness is not measured; the per-client count groups an IPv6 address by its /64 either way.
  • The log refuses to start on a damaged state: a leaf line damaged in the middle (not a line cut at the tail, which is never answered and is cut), a leaf without its head, or a checkpoint signed over more leaves than are on disk or with another root (the witness would otherwise sign a fork of its own log). The service then stays down until a person looks, so whoever runs it should alarm on its unit stopping. A write that fails halfway is cut back before the answer, so it does not leave such a line. The lock of the state (.lacat) carries the process id, the start of the machine (boot_id on Linux; elsewhere the boot time from os.uptime, within 120 s) and, where /proc has it, the start time of the process: a lock left by an unclean stop (a power cut, a reset) whose process id now belongs to another live process no longer keeps the witness from starting (until the second review, R2-10, it did, at every restart). On a system without /proc (Windows, the laboratory) a lock of the same boot whose process id was reused by another live process is still taken as held.
  • One witness is not a network of witnesses: someone who sees only one witness cannot know what another was shown; C2SP-style cosigning of the witness's checkpoints by other witnesses is not built here.

Bounds, derived from measurement (2026-10-19, Node.js 24.14.1, Windows; martor-agenti.mjs writes the arithmetic beside each constant):

  • Shards: at most 20,000 heads each, two kept (a third only while its final checkpoint waits for the notarization). At the hourly cap of 833 new heads (20,000 / 24) a shard takes at least a day to fill, so a head is served, and remembered by the witness, for at least a day after its shard is frozen.
  • The WORST state, measured after the second review (2026-10-19, R2-02 and R2-06): both shards full (40,000 heads), one checkpoint per head (low traffic gives that: at most one checkpoint per round, whenever a head came) and one kept proof of equivocation per head (a session per head: the bound of the proofs by construction). The first review's bounds were measured with one checkpoint every 1,000 heads and 2,000 proofs at most, and missed this state: with one checkpoint per head, the memory per interval of the Merkle tree (rebuilt at every open, and growing with every receipt served from a frozen shard) took ~5 KB per checkpoint, about 372 MB at the open (measured by a verifier), and above the unit's cap of then (MemoryMax=400M) once the limiters were full. The log's tree is now incremental (only the perfect subtrees, 32 bytes each, at most 2n per shard; no memory per interval), checked against merkleTree of aere-verify-layer on every size up to 70 and every pair of sizes up to 40.
  • Disk, measured on that state: 1,320 MB (33 KB per head: the signed head and promise ~15.5 KB, the leaf line 0.35 KB, a checkpoint ~7.9 KB, a kept proof ~7.9 KB, which holds only the new head: the head it contradicts is already in its shard). The installer asks for 2,048 MB free (~1.55x).
  • Memory, measured on that state in a fresh process: the open peaks at 266 MB of RSS (50 MB of it the empty process), serving 2,000 receipts, 2,000 signed pages of heads, 2,000 kept proofs and a consistency proof of the frozen shard peaks at 277 MB, and with the three rate limiters at their key cap (100,000 keys each) at 330 MB (314 MB after a collection). The unit's MemoryMax is 512M (~1.55x), and the installer asks the host for at least that much available memory. A state with one checkpoint per 1,000 heads now retains ~340 bytes of heap per head (before: ~900).
  • Time: the open of the worst state took 37 s on the laptop (reading 40,000 checkpoints and 40,000 proofs; on Linux not measured). Signing a page of 100 heads takes ~1.1 ms. Per-request latency was measured only before the second review (no submission above 200 ms, rotations included); the worst-state run, with a checkpoint built after every head and fsync off, averaged 8.6 ms per head. A shard is removed from disk after the answer, in the background. A page of GET .../heads reads nothing from disk.

Going back to a version before the second or the third review (the deployer's rollback restores the unit and the tools, not the state): the state format stays aere-agent-witness-state-2, so the version before opens it; what differs is this. Kept proofs are now written to echivocari-2/ (only the new head); the version before reads only echivocari/, so it does not see them (and does not delete them), and they are back when this version runs again, unless the head they contradict was removed meanwhile. Proofs of the version before are read by this one, tied to the shard of the head they contradict, and dropped when that head is no longer kept. The lock is JSON now; the version before reads it as no process, removes it and writes its own. The version before removes, at its first open, a shard older than the two newest even when this version kept it waiting for its notarization, and its heads then lose their certified time, as they did before the review. Going back also puts back the unit of before (MemoryMax=400M); on a state with one checkpoint per head the version before needed ~372 MB at its open (measured by a verifier of the second review) plus ~60 MB of limiters at their cap, above that cap. Since the third review (R3-01) a removed shard is renamed cioburi/.sters-<k>-* before it is deleted, and, when the rename fails, marked with a .de-sters file: the versions before do not know either. They ignore a .sters-* folder (not a shard name), which then stays on disk until this version opens the state again; and a shard folder marked .de-sters whose deletion was interrupted, or a rest without ciob.json, they keep as a shard (the defect R3-01 repairs). A proof that replaced another (R3-02) is an ordinary proof of form 2 for them.

What the verifier can and cannot see

  • Time. An entry's time is the statement of whoever holds the agent key. The verifier bounds it from above with its clock. It bounds it from below only with a witness: anchors (ledger heads seen by a witness at a known time, for example notarized) or notBefore. Without one, the key holder can backdate entries into past windows and spend the limit several times; the result says so (time.lowerBound: "none..."). With anchors, backdating is limited to the interval between two anchors; the chain itself can be that witness (above). The library itself refuses to write an entry more than 300 seconds away from its clock.
  • One ledger per agent and policy. The ledger's session is derived from the agent and the policy hash, so a "second ledger" is a branch of the same one. Two branches signed by the agent are a proof of equivocation (findEquivocation, verifyEquivocation) that anyone can check with the public key alone: this is how a double spend or an approval used twice across branches is shown. Someone who sees only one branch cannot know that another exists; anchors or a second copy reveal it. An agent that loses its ledger cannot continue it without looking like a branch: keep the ledger durable, or start under a new policy.
  • Revocation time is the owner's statement, as the agent's entry times are the agent's.
  • Nothing here proves that the actions happened in the world, only what the agent recorded and whether the policy allowed it.
  • Corrected on 2026-10-03: the agent key must be an ML-DSA-65 key. Until then verifyLedger did not require it: the agent id is derived from any key and the signature check accepts whatever key it is given, so a ledger written and signed with an Ed25519 key verified as the ledger of a post-quantum identity, and openLedger opened one for such a key. Found while this verifier was enrolled in the conformance suite (conformance/), where it is now a vector. Both now refuse by name. Every refusal of verifyLedger also carries a rule id from a declared list (REGULI, the field rule).

Tests

Measured on 2026-09-29 (Node.js 24.14.1, Windows):

test result
node proba-agent-policy.mjs 27/27 with the AIP-23 reference verifier (AERE_VERIFY_PROOF=<verify-proof.mjs from aere.network/tools>); without it 25 run, 2 are reported as skipped and the exit code is 2
node proba-agent-ledger.mjs 59/59 (measured 2026-10-19; since then an equivocation proof must be made with the agent's ML-DSA-65 key, AIP-25 finding C2): a ledger written and signed with a classical key refused by name, by the verifier and by the writer; limits over the ledger, identity, tampering, a re-signed false decision, a looser policy under the real hash, backdating (refused when written; caught with anchors or notBefore), a branch, equivocation proofs, resuming
node proba-agent-aprobare.mjs 39/39: threshold, unnamed or repeated approvers, classical keys, another action or other tool arguments, reused nonces (also after a restart), expiry, approvals across branches, revocation, an omitted revocation
node proba-agent-cli.mjs 23/23 on Windows, through files and processes only; on Linux and macOS one more test checks the 0600 mode of the key (not measured here)
node proba-agent-ancora.mjs 26/26 without a network (the AIP-23 verifier's answer in its own form): the head, the time read from the finality level (pending, failed, a mismatched or unknown form: no anchor), an envelope that claims another time, backdating caught with the anchor and not without it, another branch, the refusals before any transaction (a modified head, chain 2800 without confirmation, no contract at the notary)
AERE_TESTNET_KEY_FILE=<funded testnet key> node proba-agent-ancora-testnet.mjs 7/7 on the public testnet 28001, measured 2026-09-30: a real ledger's head notarized, read back under a post-quantum certified anchor by the published AIP-23 verifier within 20 s, the certified time equal to the contract's first-seen time, the honest continuation valid with the anchor, a backdated continuation valid without it and caught with it, another branch refused; evidence in dovezi-ancora-28001/
node control-negativ-ancora.mjs 11/11: each anchoring guard removed in a copy turns its named test red
node control-negativ-aprobare.mjs 28/28 (2026-10-19): each guard is removed in a copy, one at a time, and the named test must fail for that reason; a test that stops before its summary counts as a failure of the control
node proba-martor-agenti.mjs 158/158 offline, measured 2026-10-19 after the sixth review of the hosted witness (two reviewers and two verifiers in each of the first two, a reviewer and a verifier in the third, the fourth and the fifth, and as the sixth a targeted verification of the fifth's repairs; 18 findings in the first, all confirmed; 15 confirmed and one rejected in the second; 5 confirmed in the third; 6 confirmed and one rejected in the fourth; 6 confirmed and one rejected in the fifth; 4 in the sixth, N1..N4, of which N4 is this table; until the sixth review this row said 138/138, "after the fourth"), with keys made at run time and a local notary mock named as such: two agents, successive heads, a head that skips, an older head and one that does not continue the last (409), equivocation at the same position and through previous caught and returned, one proof kept per agent and policy, the named refusals of a request (form, the ledger's content, signature, key, identity, session, integrity, time), the rate limits, checkpoints signed by the witness with inclusion and consistency proofs, a restart on the same state, a leaf line cut at the tail by a crash, any chain but 28001 refused before the key, receipts checked without the witness and as anchors (backdating caught with the anchor and not without it), the command line, the gateway's door with and without AERE_AGENTS_WITNESS_PORT (in the development repository; the gateway is not part of this copy, where those rows are information), the checkpoint VALID for the AIP-23 reference verifier (AERE_VERIFY_PROOF; without it those rows are skipped by name and the exit code is 2); and a row for each finding (9.R<n>): a pinned witness and the receipt of a witness the agent runs itself, the full list of heads (--witness-url), the sharded log and the hourly cap, an equivocation on the "already seen" path, --chain 2800x, submit with nothing new, the vocabulary of the checkpoint kind, the cap on kept proofs, the paginated GET .../heads, a replay of the agent's public head, the limiters (IPv6 /64, key cap and cleanup) and the door's refusal of a browser Origin, short and failed writes, a damaged state refused at start, error codes instead of messages; and a row for each finding of the second review (10.R2-<nn>, with 10.P2-<nn> the controls of the guards its repairs added): the list of heads signed by the witness (a hostile proxy that drops a head, one that changes only the unsigned fields, an impostor, an old page replayed), kept proofs tied to the shard of the head they contradict (a stranger who fills the cap no longer keeps out another agent's proof), the limiter at its key cap, a list with malformed elements, plain anchors and an empty anchors file under a pinned witness, the incremental Merkle tree against merkleTree and the heap of a state with one checkpoint per head, the rotation that waits for a notarization, a shard born whole and one repaired, the route to a frozen shard, the lock after a reboot, the exit codes of receipt and verify-receipt, the log budget read before the agent quota, Retry-After through the door, and the "root" half of the opening guard. Run on a copy with the files of before the first review and its probe, 22 of its 23 rows failed (the 23rd, 9.P11, is the control of a guard the repair added, which the old code passed for another reason); run on a copy with the files of before the second review (cf56bcda6) and this probe, 21 of the 24 new rows fail, each on its scenario, and the other 3 (10.R2-15 twice, 10.P2-13) pass there too: the behaviour was already right, what was missing was a test that could turn red; and a row for each finding of the third review (11.R3-<nn>, with 11.P3-<nn> the controls of its new guards): the rest of a shard removal interrupted by a stop (in any order, and a rest of the form before, left in place), the one proof of a session that lives longest, flags given without a value, the receipt of the last head the witness holds under --witness-url (and a pending one: exit 2), and the exit codes of receipt and submit on answers that are not the state of a head. Run on a copy with the files of c34b34f1b and this probe, 7 of the 8 new rows fail, each on its scenario, and the 122 rows of before pass; the 8th, 11.P3-04b, gives the check of the list against the ledger a row of its own, which the receipt of the last head (R3-04) can no longer hide: it passes there too; and a row for each finding of the fourth review (12.R4-<nn>, 12.P4-<nn>), on the rule of --witness-url: a receipt notarized late taken from the address (not measured, not FAILED), a proxy that breaks the answer for one held head (not measured, no exception), a receipt for EVERY held head (an intermediate one too), a held head whose signed predecessor is not in the ledger (FAILED), submit on a 200 or 202 that is not the state of the head sent, flags written --flag=value, mistyped or given twice, the choice between two proofs of a session at the opening, and the .de-sters mark. Run on a copy with the files of c5183bcb8 and this probe, 5 of the 8 new rows fail, each on its scenario, and the 130 rows of before pass; the other 3 (12.P4-03b and the two 12.R4-06) give their own row to guards that were right there, which is what R4-06 found missing; and a row for each finding of the fifth review (13.R5-<nn>, 13.P5-<nn>), verify as a complete evaluation followed by one verdict: a head still pending, a {"status":"pending"} or an old copy of a receipt beside a backdating the verified receipts prove, a list signed by another witness and a plain anchor under a pinned one, a notary outage and a finality refused through the verifier's RPC on both paths, wrong types without an exception, a receipt of the agent that does not hold beside a pending head in both orders, and the wait on a 429. Run by the verifier of those repairs on a copy with the files of b55038c2a and that probe (no gateway in the copy), 129/150: 15 of the 16 new rows fail, each on its scenario, and so do 6 rows of before whose expected verdict the fifth review changed; 13.P5-01 passes there too; and a row for each finding of the sixth (14.N<n>): a receipt without --rpc beside a branch the signed list shows (not measured [rpc], the branch FAILED), receipt through a proxy without any key (the true receipt of another agent's head, a broken witness signature, the receipt of another head of the same ledger) and against --ledger and --witness, and wrong types on the "nothing new" path of submit. Run on a copy with the files of 786aa0038 and this probe (no gateway in the copy, so its 4 rows are information), 149/154: the 4 new rows fail, 14.N1 and 14.N3 on their scenarios and the two 14.N2 rows already at --ledger, a flag that version refuses (that receipt through such a proxy exited 0 and wrote the file there was measured by the targeted verification), and so does 10.R2-11, which now calls receipt with --ledger too; the other rows of before pass
node proba-martor-agenti.mjs --testnet 75/75 on the public testnet 28001, measured 2026-10-19 at 05:35 UTC with the version BEFORE the adversarial review (the 70 offline rows of that version plus 5): a fresh test key funded from the faucet, a checkpoint notarized on AereNotary (block 6,828,096), the receipt VALID for the AIP-23 reference verifier with the witness's signature and the post-quantum finality PASSED (51 s after the notarization), verify --anchors receipt.json on the live chain: the honest ledger 0, the backdated one 1. Evidence in dovezi-martor-agenti-28001/ (no private key). The versions after the first and the second review were not run on the testnet (not measured: the faucet allows one claim per 24 h, and it was cooling down); their testnet rows also pin the witness (--witness), with the receipt that pinning now requires. Without a funded key and a faucet that answers, the testnet rows are skipped by name (exit 2)
node control-negativ-martor-agenti.mjs 131/131 plantations red on their row and 3/3 neutral ones green (2026-10-19, after the sixth review; 1,102 s with 12 plantations at a time, the default; after the fourth review, with 112 plantations, ~475 s with 12 and ~747 s with 4, AERE_CONTROL_PARALEL=4; the B2 runner gives this test 1650 s since the sixth review, 1.5 x the measurement on an idle laptop, after the 1200 s of before stopped a green control at 1,212 s inside the suite while another workload held the processor (the arithmetic is in probele-b2.sh); until the sixth review this row said 112/112 "after the fourth", and the fifth's 123 plantations and 3 neutral ones were not written here): every one of the 99 guard markers (PAZA-MARTOR) of the witness, the service and, since the second review, the command line (agent-cli.mjs) has a plantation that removes it, and a coverage gate counts a marker without one as a failure of the control (with its own check: one plantation taken out, the gate names its marker); the guards the repairs added (the per-agent quota after "already seen", the "already seen" exit after the predecessor check, the write to the last byte and the cut-back, the paging, the /64 key and the key cleanup, the error codes, the command line's pinned witnesses, --chain and an unanswering --witness-url, the vocabulary in proof-kinds/, the door's Origin refusal) are planted too. Each removal is made in a copy, and the named row must fail; a pattern not found once, or a test that stops before its summary, counts as a failure of the control. The guards of the second review are planted too (the signed page: its form, integrity, signature, age and count, and reading it instead of the unsigned fields; the list signed by another witness than the pinned one; proofs tied to the shard of the head they contradict and the cap derived from the shards; the limiter dropping its oldest key; a malformed list; plain anchors and no receipt under a pinned witness; the rotation and the opening that keep an unnotarized shard; the shard born whole and the link repaired; the route to a kept shard; the lock across a reboot and a reused process id; the exit codes; the budget read before the quota; Retry-After through the door), and the opening guard is split into its size and its root, each with its row. So are those of the third (the rename before a shard is deleted and the removal of a rest at the opening; the newer proof taking the place of the older; a flag without a value, in both command lines; the receipt of the last head under --witness-url; the exit codes of receipt and submit), and those of the fourth (every held head with its receipt, the receipt of a head required, its id read without an exception, a receipt taken from the address judged as testimony both ways, submit on the main path, unknown and repeated flags in both command lines, the choice between two proofs at the opening, and the two halves of the rest of a removal, each with its row). Those of the fifth review are planted too (the order of the classes in the verdict, an early exit on the way, the class of each receipt both ways, the old copy, the types, the wait on a 429), with three NEUTRAL plantations that reverse the order in which the evidence comes and require the whole probe to stay green; and those of the sixth (a receipt without --rpc as a not-measured piece, planted both ways: the early exit of before and the guard removed; receipt writing only a verified receipt of the head asked, with its id, its ledger and its pinned witness each planted; the types on the "nothing new" path of submit). After the first review the control planted 64 guards over 45 markers and did not look at agent-cli.mjs; until the first review it planted 24, which covered 20 of the 34 markers of then
bash ../../cloud-gateway/proba-desfasoara-martor-agenti.sh (development repository) 12/12 (2026-10-19): the rollback functions and the laboratory copy of the deployer, extracted from its host script and run on the laptop with systemctl replaced: a reinstall that fails before step 5 leaves the live service and its unit untouched, one that fails after it puts the old unit back and restarts the service, a first install that fails is removed, the laboratory is beside the state (not under /root) and removed on the way back, a laboratory copy of a real state opens with the same leaves; and as negative control the rollback of before the review (it stopped the live service and deleted its unit) and five plantations, each red on its scenario

The data format is version 2 (2026-09-29). Code comments, test names and most internal names are in Romanian; messages, data and the exported interface are in English. No third party has reviewed this component.