@zanii/status-feed
v0.1.0
Published
One signed, append-only, hash-chained status feed per jurisdiction: delegation revocations, Certify certificate suspensions, revocations and reinstatements, incident references and jurisdiction bindings, each with evidence hashes. Append, verify (chain, s
Readme
@zanii/status-feed
One signed, append-only, hash-chained feed of status events per jurisdiction, each event with its evidence.
A regulator (or the Ledger operator) publishes what changed for the AI agents in its sector: delegation revocations, Certify certificate suspensions, revocations and reinstatements, incidents opened and closed, jurisdiction bindings issued and expired. Each entry names the previous entry's hash and its sequence number and is signed by the feed signer. Readers verify the whole chain, or catch up from a head they already trust.
appendEvent(feed, event, signerKey)returns{ entry, head }, the next signed entry and the new head{ seq, hash }. It is pure: storeentryyourself. It refuses a malformed event and an event dated before the head.verifyFeed(entries, { signers, jurisdiction?, after? })returns{ ok, reasons, head }. It checks the entry shape, signatures by allowed signers, one jurisdiction, sequence numbers from 1 with no gaps, theprevhash chain, non-decreasing time and well-formed events.afteris a trusted earlier head for verifying a suffix.feedSince(entries, seq)returns the entries afterseq.toAtom(entries, opts)(Atom 1.0, RFC 4287) andtoJsonFeed(entries, opts)(JSON Feed 1.1) are for publishing. Each item carries the entry's canonical JSON, so a reader can verify what it fetched.anchorFeedHead(entries)returns{ target: 'regulator.status_feed.head', payload }foragent.record(...)(@zanii/sdk). The receipt's payload hash commits to the head and the log's inclusion proof dates it. No new server routes.- Event builders derive
refandevidencefrom the record:revocationEvent(record)(a@zanii/corerevocation, which must verify),certificateStatusEvent({ certificate, holder, action, reason, since, statusDocument }),incidentEvent({ action, incident, subject, report, ts }),jurisdictionEvent(binding, 'issued' | 'expired').
import { appendEvent, revocationEvent, certificateStatusEvent, verifyFeed, toAtom, anchorFeedHead } from '@zanii/status-feed';
const feed = { jurisdiction: 'AE-DIFC', entries: [] as FeedEntry[] };
feed.entries.push(appendEvent(feed, revocationEvent(revocationRecord), operatorKey).entry);
feed.entries.push(appendEvent(feed, certificateStatusEvent({
certificate: certHash, holder: agentDid, action: 'suspend', reason: 'FALSE_DECLARATION',
since: '2026-10-29T08:00:00.000Z', statusDocument, // the signed certify.status document, or its hash
}), operatorKey).entry);
verifyFeed(feed.entries, { signers: [operatorDid] }); // { ok: true, reasons: [], head: { seq: 2, hash } }
const atom = toAtom(feed.entries, { link: 'https://example.org/feeds/ae-difc.atom' });
await agent.record(anchorFeedHead(feed.entries)); // anchor the head on the LedgerFeed format
{
"v": 1, "type": "zanii.status_feed", "jurisdiction": "AE-DIFC", "seq": 2, "prev": "sha256:<hash of entry 1>",
"event": { "kind": "certificate.suspended", "subject": "did:key:...", "ref": "sha256:<certificate hash>",
"ts": "2026-10-29T08:00:00.000Z", "reason": "FALSE_DECLARATION", "evidence": ["sha256:<status document hash>"] },
"signer": "did:key:...", "sig": "ed25519:..."
}The entry is a @zanii/core signed object. An entry's hash is jcsHash of the whole signed entry, and the first entry has prev: null, seq: 1.
| kind | ref | evidence | reason |
|---|---|---|---|
| delegation.revoked | delegation cert hash (certHash) | revocation record hash | null or text |
| certificate.suspended, certificate.revoked | certificate hash | certify.status document hash | Certify reason code, versions 1 to 3, e.g. FALSE_DECLARATION, EVIDENCE_LAPSED (Certify spec/status.md) |
| certificate.reinstated | certificate hash | status document hash | null |
| incident.opened, incident.closed | incident id | incident report hash | null or text |
| jurisdiction.issued, jurisdiction.expired | binding hash | binding hash | null |
Honest limits: the feed proves that its signer published these events in this order. It does not make them true, so check the evidence each hash names. Without an anchored head, an operator could serve different feeds to different readers. Anchor heads regularly and compare them.
Changelog
- 0.1.0: initial release. Append, verify, since, Atom and JSON Feed rendering, Ledger head anchoring and event builders. Python twin
zanii.status_feed, checked by shared vectors.
License
Apache-2.0
