> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mnemom.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Transparency Log

> An append-only public log of every canonical card identity Mnemom has ever composed. Sigstore-Rekor-compatible row shape, Merkle inclusion proofs on demand.

The **transparency log** is an append-only public record of every canonical card identity Mnemom has ever composed. Each row carries a [signed AAP attestation token](/concepts/aap-attestation) + the Merkle leaf hash + the tree size at integration time. Inclusion proofs are computed on demand from rows ordered by `log_index`.

## What it proves

For any historic timestamp `t` and any `agent_id`:

| Question | Endpoint |
| - | - |
| **What canonical alignment did this agent commit to at time `t`?** | `GET /v1/transparency/log/{agent_id}?at=<t>` returns the row with the greatest `composed_at ≤ t` |
| **Was the canonical card I'm holding actually composed by Mnemom?** | The row's `signed_attestation` verifies against [`/v1/.well-known/jwks.json`](/specifications/attestation-token) |
| **Could a row have been silently rewritten?** | The Merkle tree is deterministically rebuildable from `merkle_leaf_hash` values ordered by `log_index` — any edit breaks the leaf hash + the cached layer arrays + verification |

## Endpoints

All of these are **unauthenticated** — the log is meant to be publicly verifiable.

### `GET /v1/transparency/root`

Returns the current signed Merkle root + tree size + published\_at, signed by the active AAP signing key under a distinct `typ` (`AAP-TransparencyRoot/v1`) so the per-card attestation and the root commitment can't be confused.

```json theme={null}
{
  "typ": "AAP-TransparencyRoot/v1",
  "tree_size": 12345,
  "root_hash": "<sha256-hex>",
  "published_at": "2026-05-22T12:34:56Z",
  "signing_key_id": "aap-2026-05-22",
  "signature": "<base64url-Ed25519-over-canonical-json>"
}
```

### `GET /v1/transparency/log/{agent_id}?at=<ISO>[&card_kind=alignment|protection]`

Point-in-time query. Returns the row whose `composed_at ≤ at` is greatest, plus a freshly-computed inclusion proof against the current root.

### `GET /v1/transparency/log/{agent_id}/{log_index}`

Direct by-index lookup; returns the row + an inclusion proof against the current root. Use this when you already know the `log_index` (e.g., from a previous response).

### `GET /v1/transparency/log/{agent_id}/recent?limit=<n>[&card_kind=alignment|protection]`

Returns the last N entries for an agent, newest first (`log_index` descending), each with a freshly-computed inclusion proof. `limit` defaults to 10 and is server-clamped to 100. An agent with no attestations returns `200 { "data": [] }`.

### `GET /v1/transparency/consistency?first=<n>[&second=<n>]`

Returns an [RFC 6962](https://datatracker.ietf.org/doc/html/rfc6962) / RFC 9162 §2.1.4 **consistency proof** that the tree of size `second` contains the tree of size `first` as a prefix — i.e. the first `first` entries were not reordered, altered, or removed. `second` defaults to the log's current size.

This is the only endpoint that can distinguish "the log grew" from "the log was rewritten and re-signed": an inclusion proof verifies against whatever root it's given, so it can't detect a wholesale reissue. Chaining consistency proofs across successive signed roots from `GET /v1/transparency/root` is what makes the append-only claim checkable rather than promised. It does **not** prove Mnemom published every root it computed — detecting a "split view" (a consistent-but-different chain shown to someone else) requires gossip between independent monitors, which this log doesn't yet implement.

## Row shape

Mirrors the [schema](/specifications/transparency-log-schema). One row per canonical card identity:

```json theme={null}
{
  "log_index": 4711,
  "agent_id": "smolt-e2ca60ef",
  "card_kind": "alignment",
  "content_hash": "<sha256-hex>",
  "version": 17,
  "composed_at": "2026-05-22T12:00:00Z",
  "signed_attestation": "<jws-compact>",
  "signing_key_id": "aap-2026-05-22",
  "merkle_leaf_hash": "<sha256-hex>",
  "tree_size_after": 4711,
  "integrated_time": "2026-05-22T12:00:01Z"
}
```

`merkle_leaf_hash = SHA-256(0x00 || canonical_json({agent_id, card_kind, content_hash, version, composed_at}))`. The `0x00` prefix is the [RFC 6962-style](https://datatracker.ietf.org/doc/html/rfc6962) domain separator.

## Append discipline

* **Append-only in the database, not just the application** — the service role has only `SELECT, INSERT` grants on `card_attestations` (no `UPDATE`/`DELETE`/`TRUNCATE`), and a `BEFORE UPDATE OR DELETE` trigger additionally blocks mutation at the table level — including for the table owner, which a `REVOKE` alone doesn't cover.
* **Idempotent** — unique index on `(agent_id, card_kind, content_hash, version)` makes re-append a no-op. The compose-hook and the 5-minute reconciler are both safe to retry.
* **Best-effort from the compose path** — the canonical write commits first; the log append + signing happen post-commit. A 5-minute reconciler closes any gap that arose from a worker crash mid-flight.

## Merkle tree

| Property | Value |
| - | - |
| **Leaf** | `SHA-256(0x00 \|\| canonical_json(...))` |
| **Internal node** | `SHA-256(0x01 \|\| left \|\| right)` |
| **Leaf ordering** | by `log_index ASC` |
| **Odd-count** | last unpaired hash promoted unchanged — this **is** RFC 6962's tree shape (root-equivalent to RFC 6962 §2.1's `MTH` split at every tree size), not Bitcoin's convention of duplicating the last leaf |
| **Storage** | rebuilt on demand from rows; layer arrays are cached for 60 seconds; cache busts on every append |

## Sigstore Rekor compatibility

The row shape is intentionally [Sigstore Rekor](https://www.sigstore.dev/rekor)-shaped so the future migration is a **data move** rather than a schema rewrite. The mapping is documented in [the schema spec](/specifications/transparency-log-schema#rekor-mapping) and the migration plan at [migration/sigstore-rekor-migration](/concepts/transparency-log).

Until that migration ships (post-V1-GA), the thin Postgres log serves as Mnemom's authoritative public log. Backups land in S3 with object-lock to defend against database compromise + rewrite.

## See also

* [Schema reference](/specifications/transparency-log-schema) — canonical row shape
* [AAP attestation tokens](/concepts/aap-attestation) — the JWS embedded per row
* [`mnemom verify-card`](/guides/verify-card) — operator CLI that consumes the log + JWKS
* [Sigstore Rekor migration](/concepts/transparency-log) — forward-looking data-move plan


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.