This post builds on a conversation that started in Ian Johnson's harness stack thread and the research being published by @zep1997 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 FIPSign — ML-DSA-65, NIST FIPS 204, free tier. The JS/TS SDK (fipsign-sdk on npm) and Python SDK (fipsign-sdk on PyPI) implement the full lifecycle shown above. If you're building in this space and want to run the packet against a real external source — which is what CLAIM-24 was waiting on — drop a note here or open an issue on the Keystone repo.
Top comments (3)
This is exactly the gap CLAIM-26 leaves open.
is_immutable: true is still self-description. A system that can write the record can
write that field. The useful shift is moving from "the record says it is immutable" to
"the event still verifies under a key the agent does not control."
The certificate-scope point maps cleanly to the governs schema too. governs.action_types
is useful metadata, but without an issuing authority it can still become the CLAIM-22
self-description problem in another form. A certificate signing over the action classes
gives that scope a verification path and a revocation path.
I would treat FIPSign as a strong candidate for the CLAIM-24 SourceAdapter slot, with one
narrow test first: can the gate fetch a signed source state from an authority the agent
cannot write to, verify the signature, and distinguish current signed state from stale or
substituted state?
If that works, CLAIM-24 moves from mock-source validation to real external-source
evidence. That is the evidence level we have been waiting for.
Then next move is not another huge claim yet. It is: open a narrow Keystone/FIPSign issue
for the adapter test.
The three properties you identified map directly to what FIPSign's CA exposes — signed state via ML-DSA-65, a provenance boundary the agent cannot write to, and freshness baked into the certificate payload. Keniel already opened the narrow issue in Keystone (#4) — I left a comment there confirming the endpoint and naming one design constraint worth knowing before building the adapter.
This is exactly the detail I needed. Thank you.
The important constraint is the one you named: FIPSign does not mutate certificate scope
inside the certificate lifetime. Scope change means revoke and reissue.
That actually makes the adapter boundary cleaner.
For CLAIM-24, the SourceAdapter should not pretend it can observe arbitrary scope
mutation inside a signed certificate. It should test the CA-shaped version of source
drift:
So the adapter test becomes narrower and more honest:
Can a re-derivation gate read a real agent-unwritable signed source at execution time and
detect stale authority through revocation or expiry?
That would move CLAIM-24 from mock-source validation to real external-source evidence for
this CA-shaped authority model.
I’ll keep the wording scoped there.