This post builds on a conversation that started in in the Self-Correcting Systems series. The problem is real and I've been building in this space.
CLAIM-24 tested whether an agent checks a grant against current source conditions, not just the clock.
CLAIM-25 tested whether a signed response is both authentic and fresh — signed-AND-fresh, not just signed.
CLAIM-26 tests what happens after the action is taken: can an auditor reconstruct exactly what authority justified it?
The finding: a log that says ALLOW is not evidence. An authority event written after the action, even with matching hashes, is reconstruction — not prior authorization. The gap between a SeparateWriteGate (5/7) and a PairedAuthorityActionGate (7/7) is two failure modes that look clean but aren't: post_hoc and audit_gap.
That's the structural boundary. But there's a layer below it that the CLAIM-26 findings leave open:
What makes the authority event itself tamper-proof?
is_immutable: truein a JSON field is self-assertion.
The missing piece: cryptographic weight
The minimum audit-safe shape from CLAIM-26 looks like this:
{
"authority_event_id": "auth-001",
"grant_id": "grant-abc",
"decision": "ALLOW",
"snapshot_hash": "sha256:policy_v21_sequence_42",
"source_sequence": 42,
"is_immutable": true,
"written_at": "2026-06-06T12:00:01Z"
}
The is_immutable: true field tells you nothing. Any system can write that field. Any system can modify the record and rewrite it. The audit trail is internally consistent — and externally unverifiable.
What closes this: a cryptographic signature over the authority event, issued by an external authority the agent cannot write to.
Not just any signature. For audit trails that need to survive regulatory scrutiny years from now — or more concretely, the harvest-now-decrypt-later threat where adversaries are recording signed traffic today — ECDSA and RSA signatures have a known expiry date. Shor's algorithm breaks both. The NIST finalized the replacements in August 2024: ML-DSA-65, NIST FIPS 204.
What this looks like in practice
The conversation in Ian's thread landed on a three-layer architecture:
L1: Memory carries authority metadata —governs.action_types,verification_required,resource_sensitivity. This is the schema zep1997 is building: structured claims about what a memory is authorized to govern.
L2: Actions are signed against a certificate. Each agent action produces a signed token —sub: "agent_id", scoped to the specific operation, short TTL, revocable.
L3: A CA issues certificates per agent, fleet-wide. Not just a token for the action, but a certificate that encodes what action classes this agent is authorized to perform.
The certificate doesn't replace the L1 schema. It becomes the issuing authority for it. governs.action_types: ["execute", "write"] is a claim. The certificate makes that claim verifiable and gives it a revocation path.
Here's what that looks like with actual code:
import { PQAuth, generateKeyPair } from 'fipsign-sdk'
const fipsign = new PQAuth('pqa_your_api_key')
// At agent provisioning time: issue a certificate that encodes
// what action classes this agent is authorized to perform
const { publicKey, secretKey } = await generateKeyPair()
const { certificate, meta } = await fipsign.ca.issue({
subject: 'agent_summarizer_v2',
publicKey,
expiresInSeconds: 30 * 24 * 60 * 60, // 30 days
meta: {
action_types: ['read', 'summarize'],
resource_sensitivity: 'low',
verification_required: false,
},
})
// Store certificate and secretKey on the agent
// meta.certId is what you use for revocation
console.log(meta.certId) // cert_...
At runtime, when the agent takes an action, it signs the action event:
// Agent signs the authority event before taking the action
const { token } = await fipsign.sign({
sub: 'agent_summarizer_v2',
action: 'document:summarize',
authority_cert: meta.certId,
snapshot_hash: 'sha256:policy_v21_sequence_42',
source_sequence: 42,
grant_id: 'grant-abc',
expiresInSeconds: 300, // short TTL — this is evidence of this specific action
})
// token is the authority_event with a quantum-resistant signature
// Store it alongside the action record — this is what CLAIM-26 calls for
The authority event is now:
{
"authority_event_id": "auth-001",
"grant_id": "grant-abc",
"decision": "ALLOW",
"snapshot_hash": "sha256:policy_v21_sequence_42",
"source_sequence": 42,
"token": {
"payload": "eyJzdWIiOiJhZ2...",
"signature": "oi5UKsTn...",
"algorithm": "ML-DSA-65",
"issuedAt": 1749254401
}
}
is_immutable: true is gone. The signature is the immutability guarantee. Any modification to the payload — snapshot_hash, source_sequence, grant_id — invalidates the signature. An auditor verifying this event doesn't need to trust the storage system. They verify the signature against the public key, which they can fetch independently.
The revocation piece
CLAIM-26 notes that write order matters: authority written before or atomically with the action, not after.
The signing model gives you something stronger: the token has a issuedAt timestamp that's part of the signed payload. You cannot backdate a signature. If the authority event was signed at 12:00:01 and the action record shows 12:00:02, you have cryptographic proof of the ordering — not just a timestamp field that any process could have written.
But what if the agent is compromised mid-session? zep1997 and I worked through the lazy/eager revocation split in the thread:
Lazy revocation — the certificate remains valid but the gate checks it against the CRL before authorizing each action. If the certificate has been revoked, the action is blocked. No out-of-band channel needed — the next gate check catches it.
// Before any action: check the CRL
const { crl } = await fipsign.ca.getCrl()
if (fipsign.ca.isCertRevoked(meta.certId, crl)) {
throw new Error('Agent certificate has been revoked — action blocked')
}
// Then sign the action
const { token } = await fipsign.sign({
sub: 'agent_summarizer_v2',
action: 'document:summarize',
// ...
})
Eager revocation — required when the agent has long sessions and the revoked scope covers high-sensitivity action classes. The window between "certificate revoked" and "next gate check" is too large to accept. In this case, the agent controller needs to be notified out-of-band and flush the agent context immediately. This requires a separate notification mechanism in your own infrastructure — a message queue, an internal event bus, or a polling loop against ca.getCert() for real-time status.
// Real-time status check for a specific certificate (free, no token cost)
const { status } = await fipsign.ca.getCert(meta.certId)
if (status.revoked) {
// Flush agent context immediately — eager path
flushAgentContext(agentId)
}
Lazy is sufficient for most cases. Eager becomes necessary when session length and action sensitivity combine to create a window too large to accept.
The governs field maps to certificate scope
The insight from the thread: governs.action_types in the memory schema is exactly the field a certificate would sign over. The certificate doesn't replace that schema — it verifies it.
A memory that self-asserts action_types: ["execute", "write"] without external verification is what CLAIM-22 flagged: 3/3 false-certainty errors on mislabeled scenarios. The metadata is the authority and the assertion simultaneously.
Certificate-scoped retrieval changes the architecture: before ranking by relevance, the retriever filters by certificate scope. The question becomes not "which memory is most relevant to this query" but "which memories are authorized for this action class, and of those, which is most relevant." Relevance becomes a tiebreaker within an authorized set.
The missing verification layer — what moves from self-asserted to externally verifiable — is the certificate. And for that certificate to mean anything a decade from now, the signing algorithm needs to be post-quantum.
What this is and isn't
This is not a production trust model. It's the layer that closes the gap between "the log says ALLOW" and "the log proves it was authorized before it happened, by an agent that was authorized to perform that action class, with a signature that cannot be forged."
The open questions from CLAIM-26 remain open at this layer too:
- What storage substrate holds the high-water mark for replay protection?
- What canonicalization scheme covers the full authority event?
- How does multi-source authority work when the action depends on multiple policy registries?
Those are next layers. The claim here is narrower: is_immutable: true is self-description. A quantum-resistant signature over the authority event is evidence.
The CA and signing API used in this post is .
SOCIAL SHARE CARD GENERATOR