How Gatekeeper Builds a did:cid Document
The infographic should show two distinct phases:
The key visual correction: validation gates belong primarily to event import, not to the normal resolution path.

Use a left-to-right flow with two large labeled regions:
Incoming Operations -> Gatekeeper Import Pipeline -> DID Event Store -> Resolution Replay -> Resolved DID Document
Below the import pipeline, show three side outputs:
Rejected
Deferred
Merged / Replaced
Keep the DID resolution side visually calmer than the import side. It should feel like replaying a clean event log, not re-litigating every operation.
On the far left, show several operation sources converging into Gatekeeper:
POST /api/v1/didqueue / batch/api/v1/dids/import/api/v1/batch/import/api/v1/batch/import/cidsRepresent the incoming stream as signed operation cards:
create
update
update
delete
Each card should carry small metadata chips:
registry
time
ordinal
opid
proof
previd
Caption:
Operations arrive from clients, peer gossip, batch imports, and registry mediators.
Show a queue box labeled:
Import Queue
Inside it, show operations waiting to be processed.
Important callout:
Shape checks and duplicate detection happen before events enter or drain from the queue.
Small pseudocode callout:
verify event shape
drop duplicate proofValue per registry
queue for processEvents()
This is the main visual centerpiece. Show an operation moving through import-time decision gates. Each gate should have green, amber, blue, or red outputs.
Checks:
valid registry
valid time
operation present
operation <= 64 KB
proof format valid
type in create/update/delete
Outputs:
Show Gatekeeper computing or filling:
event.did
event.opid = cid(operation)
For create operations, event.did is generated from the operation CID. For
update/delete operations, event.did comes from operation.did.
Output:
Show Gatekeeper acquiring a lock and loading the current chain:
current = store.get_events(did)
Caption:
Per-DID import is serialized so competing updates see the current chain.
Checks:
same proof.proofValue already exists?
Outputs:
MERGED if the existing event is already on the expected registryREPLACED if this event confirms the same operation on the expected registryMERGED if it is a harmless duplicate from another pathVisual detail:
Show a local or gossip event being replaced by a later confirmed registry event for the same operation.
Checks:
verifyOperation(operation)
For create:
created, registration, type, registry, proof format.#key-1 proof against publicJwk.proof.created, verify controller signature.For update / delete:
Outputs:
DEFERRED if the controller or previous dependency is not imported yetREJECTED if invalidImportant label:
Most cryptographic and controller checks happen at import time.
For non-create operations, check:
operation.previd
current event with opid == operation.previd
Outputs:
previd points to current chain tipDEFERRED if the previous event has not arrived yetREJECTED if missing or incompatibleWhen previd points into the middle of the current chain, show a decision:
expected registry?
earlier ordinal than next event?
Outputs:
Caption:
Registry ordering can replace a previously stored branch when the new event is the expected confirmed event.
Below the import pipeline, show four outcome bins:
Accepted into DID event store.
Examples:
Already represented; no chain change.
Examples:
Try again later.
Examples:
previd not imported yetDoes not enter the active event chain.
Examples:
previdImportant visual implication:
Rejected operations are excluded during import. Resolution normally sees the accepted event chain.
In the center, show a database cylinder labeled:
DID Event Store
Inside, show the resulting accepted chain:
v1 create -> v2 update -> v3 update -> v4 delete
Each stored event card should include:
opid
registry
time
ordinal
operation
Caption:
The store contains the event sequence Gatekeeper will replay for resolution.
On the resolution side, show a user/client/API call:
GET /api/v1/did/:did
Below it, show optional query toggles:
versionTime
versionSequence
confirm=true
verify=true
Caption:
Resolution reads the stored event chain and materializes a DID document.
Show the resolution path as a replay loop over the accepted event chain:
load events
generate initial document from create
for each stored event:
stop at versionTime or versionSequence
apply update/delete
return document
The normal path should not show red rejection gates. Instead, show a clean document builder:
create -> doc v1 -> update -> doc v2 -> update -> doc v3 -> delete -> deactivated doc v4
For the create event:
verificationMethod, authentication, and
assertionMethod.controller and didDocumentData.For update events:
merge didDocument
replace didDocumentData if present
replace didDocumentRegistration if present
versionId = opid
updated = event.time
For delete events:
{
"didDocument": { "id": "did:cid:..." },
"didDocumentMetadata": {
"deactivated": true
},
"didDocumentData": {}
}
Show these as small overlays on the replay loop, not as the main validation pipeline:
versionTime / versionSequenceStop replay at requested historical point.
confirm=trueStop before unconfirmed events when the confirmed chain is requested.
verify=trueRe-check signatures and previd while replaying; throw if invalid.
Important label:
Resolution may verify again when requested, but import is where operations are accepted, deferred, merged, replaced, or rejected.
On the far right, show a polished output card labeled:
Resolved DID Document
Include four sibling compartments:
{
"didDocument": {},
"didDocumentMetadata": {},
"didDocumentData": {},
"didResolutionMetadata": {}
}
Highlight key metadata fields:
versionId
versionSequence
created
updated
deleted
deactivated
confirmed
retrieved
Caption:
Gatekeeper returns the deterministic document state produced by replaying the stored event chain.
Use four horizontal zones:
Incoming operations Sources -> signed operations -> import queue
Import and merge engine Shape checks -> duplicate/registry upgrade -> proof/controller checks -> previous-version checks -> added/merged/deferred/rejected
Accepted event store Materialized per-DID event chain
Resolution replay API request -> replay accepted chain -> final DID document
The strongest visual metaphor is:
Import validates the log. Resolution replays the log.
Use restrained technical colors:
Avoid making the whole thing look like generic blockchain art. It should feel more like a distributed systems diagram.
Use these as small callout bubbles:
versionTime and versionSequence stop replay at a historical point.verify=true re-checks signatures during resolution.deactivated: true.Bottom caption:
Gatekeeper builds DID documents in two phases: first it imports operations into a per-DID event chain by accepting, merging, deferring, replacing, or rejecting them; later it resolves a DID by replaying that stored chain into a deterministic DID document.