Aroha
Get started
All documentation

DocsConformance

Aroha Conformance Test Matrix

Owner: @projectmed99
Version: 1.0 — 2026-05-28
Protocol: Aroha 1.0
Status: Initial draft — pending external implementer review

This matrix defines what it means to be "Aroha 1.0 conformant." Every row is a testable requirement. Pass/fail is binary.


How to Read This Matrix

  • MUST = required for any conformance claim
  • SHOULD = strongly recommended; non-conformance must be documented
  • MAY = optional extension
  • Pass criteria = machine-verifiable condition
  • CI column = whether this test runs in the reference CI suite
  • Row IDs are stable test identifiers used by the conformance suite. Their L0–L4 prefixes predate the specification's layer numbering and do not match it; each section heading names the specification layer (Layers 0–3) or extension the rows belong to.
  • Extension rows apply only to implementations that adopt that extension (Aroha 1.0 §11).
  • Status codes follow Aroha 1.0 Appendix A; the code string is normative and the HTTP status is a recommendation for HTTP transports.

Identity (spec Layer 1)

IDRequirementLevelPass CriteriaCI
L0-01Agent generates a valid did:aroha: DID backed by Ed25519 keypairMUSTDID resolves; public key in DID document matches keypair✅
L0-02DID document conforms to W3C DID Core 1.0MUSTJSON-LD validation passes against W3C DID Core context✅
L0-03Agent can rotate keys without changing DIDMUSTNew keypair registered; old messages signed with prior key still verify against version at time of signing✅
L0-04Agent rejects messages signed with unknown DIDMUSTReject with 401; log reason✅
L0-05Agent supports did:web as alternative DID methodMAYdid:web DID document resolves and passes L0-02—

Rotatable identifiers (did:aroha:E…) and Key Event Logs

Normative source: spec did-method.md, "Rotatable identifiers (E-form) and Key Event Logs". Tests: packages/aroha-core/src/conformance/l0-kel-identity.conformance.test.ts (run by vitest.conformance.config.ts).

IDRequirementLevelPass CriteriaCI
L0-KEL-01An E-DID is did:aroha:E + base58btc(sha256(JCS(inception event without sig))); events are signed over the same JCS bytesMUSTPinned vector reproduced exactly: from fixed seeds (current key seed 0x01…, next key seed 0x02…, createdAt 2026-10-07T00:00:00.000Z) the implementation produces the same canonical inception body, Ed25519 signature and DID, and the following rotation (next-next seed 0x03…) has the same event digest✅
L0-KEL-02An inception-only log verifies with no other inputMUSTverifyKel(did, [inception]) succeeds and reports the inception's key as the current key — no registry, network or controller log consulted✅
L0-KEL-03A rotation is valid only when signed by the pre-committed next keyMUSTThe same rotate event body signed by the CURRENT key is rejected; signed by the revealed next key (whose digest the prior state committed to) it verifies✅
L0-KEL-04Controller-authorised events (agent recover, controller revoke) are valid only when sealed in the controller person's KELMUSTAn agent log with a controller revocation verifies (and reports revoked) when the controller's anchoring log is supplied; without it, verification fails with controller-unavailable✅
L0-KEL-05A verifier that has accepted a log rejects a fork of it (duplicity)MUSTAfter accepting one validly signed rotation into a KEL store, a different validly signed rotation at the same sequence is rejected with duplicity✅
L0-KEL-06A verifier that has accepted a log does not accept a shorter oneSHOULDAfter accepting a rotated log, offering the inception-only prefix is rejected with stale✅

Messaging and transport (spec Layers 3 and 0)

Rows L1-01 to L1-05 cover signed envelopes (Layer 3, §6); L1-06 covers TLS (Layer 0, §3.4); L1-07 to L1-11 cover aroha-sig caller authentication (Layer 0, §3.5).

IDRequirementLevelPass CriteriaCI
L1-01Every outbound message is signed with sender's Ed25519 keyMUSTSignature verifies against sender DID document✅
L1-02Receiver rejects messages with invalid signaturesMUSTReturns 401 (Aroha_INVALID_SIGNATURE); does not process payload✅
L1-03Receiver rejects replayed messages (timestamp + nonce)MUSTSecond receipt of identical envelope returns 401 (Aroha_REPLAY_DETECTED)✅
L1-04Envelope includes expires field set to a future timestamp; receiver rejects envelopes where expires is in the pastMUSTExpired envelopes rejected with 401 (Aroha_EXPIRED_MESSAGE); accepted nonces retained, keyed per sender, at least until expires (§6.3)✅
L1-05Envelope schema validates against Aroha 1.0 message specMUSTJSON Schema validation passes✅
L1-06Agent enforces TLS 1.3+ for all connections; plaintext HTTP connections are rejectedMUSTTLS 1.3 handshake succeeds; plaintext HTTP returns connection error or 400✅
L1-07An agent requiring aroha-sig rejects unsigned requestsMUSTMissing signature headers return 401; payload not processed; never downgraded to anonymous✅
L1-08Signature covers method, path, timestamp, nonce and body hashMUSTA signature captured from one endpoint fails on another; altering the body fails verification✅
L1-09Caller DID is checked against the allow-list before key resolutionMUSTA non-allow-listed DID is rejected without a registry lookup — verified by the absence of a resolution call, not by timing alone✅
L1-10Nonce is consumed only after all other checks passMUSTA request with a valid nonce and bad signature is rejected, and the same nonce is still accepted on a subsequent valid request✅
L1-11Requests outside the clock-skew window are rejectedMUSTTimestamp older or newer than the permitted skew returns 401✅

Registry (spec Layer 2)

IDRequirementLevelPass CriteriaCI
L2-01Agent publishes capability manifest to registry on startupMUSTManifest retrievable via registry query within 30s of start✅
L2-02Capability manifest includes: DID, capabilities[], endpoint, versionMUSTSchema validation passes✅
L2-03Registry supports capability discovery by name and tagMUSTQuery returns matching agents within 500ms (p95)✅
L2-04Agent deregisters from registry on graceful shutdownSHOULDManifest no longer returned in queries within 30s✅
L2-05Agent handles stale registry entries (TTL-based expiry)SHOULDEntries older than configured TTL are not returned—
L2-06Registry supports pagination for large result setsSHOULDcursor-based pagination returns consistent pages—
L2-07Records carry a visibility level (public | unlisted | private), defaulting to publicMUSTRecord created without the field is discoverable exactly as before✅
L2-08private records are absent from capability queries by non-entitled viewersMUSTAnonymous and unrelated-credential queries omit the record; owner's query includes it✅
L2-09Visibility filtering happens inside the retrieval query, not by post-filteringMUSTResult counts and pagination boundaries are identical whether or not private records exist—
L2-10No-access and does-not-exist are indistinguishableMUSTResolving a private record without entitlement returns the same status and body as resolving an unregistered didHash — never 403✅
L2-11An invalid discovery credential degrades to the anonymous viewMUSTRequest with a malformed or unknown API key returns the public result set, not an auth error✅
L2-12A live grant admits its grantee; a revoked or expired one does notMUSTGrantee sees the record; after revocation or expiry the same request returns not-found✅
L2-13At most one live grant per (resource, grantee), and re-granting after revocation succeedsMUSTDuplicate grant rejected; grant → revoke → grant sequence succeeds✅

Extension: Orchestration (sagas)

Applies only to implementations that adopt the orchestration extension (extensions document §1, §3). Formerly numbered Layer 4 in the specification.

IDRequirementLevelPass CriteriaCI
L3-01Saga coordinator sends Reserve before CommitMUSTReserve step logged before any Commit issued✅
L3-02On participant failure, coordinator issues Cancel to all committed participantsMUSTAll prior Commit recipients receive Cancel within timeout✅
L3-03Cancel is idempotentMUSTDuplicate Cancel for same saga ID returns success without side effects✅
L3-04Saga ID is globally unique (UUID v4 or equivalent)MUSTNo two concurrent sagas share an ID✅
L3-05Participant enforces timeout on Reserve (releases lock if no Commit within TTL)MUSTLock released after TTL; subsequent Reserve succeeds✅
L3-06Saga state is persisted durably (survives coordinator restart)SHOULDAfter restart, in-progress sagas resume or cancel cleanly—
L3-07Agent reports saga metrics (success rate, rollback count) via telemetrySHOULDMetrics endpoint returns current saga KPIs—

Extension: Commerce and settlement

Applies only to implementations that adopt the commerce or settlement extensions (Aroha 1.0 §2).

IDRequirementLevelPass CriteriaCI
L4-01Payment envelope includes: amount, currency, recipient DID, saga IDMUSTSchema validation passes✅
L4-02Payment amount is non-negativeMUSTNegative amounts rejected with 400✅
L4-03Payment is refunded on saga rollbackMUSTRefund issued to payer DID after Cancel✅
L4-04Agent rejects duplicate payment for same saga IDMUSTSecond payment attempt returns 409✅
L4-05Agent supports USD and at least one additional currencySHOULDCurrency code in payment envelope is validated—
L4-06Agent can emit signed payment receiptSHOULDReceipt verifiable against payee DID—

Pass/Fail Rubric

Conformant: All applicable MUST rows pass (core rows, plus the rows of every extension the implementation adopts). SHOULD failures are documented.
Non-conformant: Any applicable MUST row fails.
Provisional: MUST rows pass but SHOULD rows are untested — must resolve within 90 days.


Scoring

GradeCriteria
Full conformanceAll MUST + all SHOULD pass
Core conformanceAll MUST pass; ≥50% of SHOULD pass
ProvisionalAll MUST pass; SHOULD untested
Non-conformantAny MUST fails

To validate your implementation: see implementer-packet.md.

This page is the repository file docs/conformance/test-matrix.md, copied October 28, 2026.