Home / Projects / Orchestrata Ultimate / Decisions / ADR index / ADR-0037
ADR-0037: Idempotent KG event ids are SHA1 content digests
| field | value |
|---|---|
| Status | Accepted — Accepted (human-ratified by Mohamed, 2026-07-26) |
| Date | 2026-07-22 |
| Register | factory (docs/adr, 4-digit ids) |
| Source | docs/adr/0037-idempotent-kg-event-ids-are-content-digests.md — permalink at bdafa201a (unchanged on master since that commit) |
| Wiki register entry | ADR-0037 (wiki status: Accepted) |
The record
Status: Accepted (human-ratified by Mohamed, 2026-07-26) Date: 2026-07-22 (decided by U:Ar in a live pipeline run); recorded here 2026-07-26
Context
Pipeline runs write event nodes (artifacts, decisions) into the operational Neo4j KG. Ids generated from timestamps, UUIDs, or run counters make every re-run append a fresh node for the same logical event — the KG's append-only-duplicate debt class (the session-254 orphan census measured ~13.9K isolated event nodes, and the earlier canonical-schema work found Session/audit writes un-MERGEd for the same reason). MERGE-on-id semantics only deduplicate if the id is a pure function of the event's content.
Decision
Idempotent event ids are derived from a SHA1 digest of the event's identifying content, truncated to 16 hex chars, embedded in a typed, readable prefix:
- Pipeline artifact:
{thread_id}:{stage}:{type}:{sha1(thread|stage|type|content)[:16]} - Volk decision:
dec:{volk_alias}:{sha1(volk|rationale|files)[:16]}
(Implementation: kernel/pipeline_kg.py.) Re-running a pipeline MERGEs onto
the same node instead of appending a duplicate; the id is stable across
processes with no coordination, and the prefix keeps ids greppable and
project-scopable.
Alternatives rejected
- UUIDs / timestamps — unique per write, so MERGE never matches; this is the exact mechanism that produced the duplicate/orphan debt.
- Run-scoped counters — stable within a run, collide or drift across runs and workers; require coordination.
- Full-content ids (no digest) — unbounded id length; rationale text and file lists don't belong in an id.
- SHA256 — no collision-resistance requirement here (ids are namespaced by prefix and truncated anyway); SHA1[:16] is shorter and already the convention elsewhere in the codebase.
Consequences
- Same logical event ⇒ same id ⇒ MERGE is genuinely idempotent; crash/retry loops cannot multiply nodes.
- Editing an event's content (e.g. a decision's rationale) produces a NEW id — content-addressed events are immutable-by-construction; amendment means a new node, matching the ADR-log append-only doctrine.
- The digest input tuple is a contract: adding a field to it changes every future id for that event type. Extend inputs only with a migration note.
Provenance
Decided autonomously by the Architect volk (U:Ar) during a pipeline run
on 2026-07-22 and written to the KG as Decision node
dec:U:Ar:eeb02ddd38b184ee ("Use SHA1 digest for idempotent ids") — itself
an instance of the scheme. The node was orphaned (the writer stored its volk
as a property, not an edge) and recovered during the session-254 orphaned-
node census; added to this log at Mohamed's direction. First ADR in this log
originated by a volk rather than a human or review round.
Related ADRs
No other ADR is named in this record.
Rulings cited
None.
Specs cited
None (or no spec page exists for the ones named).