Event Log
Table of contents
Summary
Event Log is an append-only record. Anything written to it stays, in the order it arrived, unchanged, for as long as the log exists. It is the foundation that audit trails, undo histories, activity feeds, transaction journals, and replay systems are all built on. It offers just two operations. One adds an event to the end and returns an identifier for it; the other reads events back in order. There is no way to edit or delete, by design. Every event gets a strictly increasing sequence number that fixes its place in line. That number is kept separate from the human-readable timestamp on purpose: clocks can drift or jump, but the sequence number never does, so the log can always be replayed faithfully even on a machine with a bad clock. The log itself takes no position on how long to keep events, how to prove they have not been tampered with, who wrote them, or how to search them. All of these are handled by separate patterns layered on top, which is why the same simple log can sit under a personal task history, a medical chart, a bank ledger, and a regulated audit trail.
Intent
WHY: A composing pattern records facts about state changes, and the same need recurs under a dozen names: audit trails, undo histories, activity feeds, event sourcing, write-ahead logs, replication journals, version-control logs, replay buffers. The shape is constant — a stream of facts, recorded in order, never altered afterward, available for retrospective query. This atom is that stream and nothing else. It carries no opinion about what an event means, how long to keep one, who wrote one, whether one has been tampered with, or how to search by payload; every one of those is a composing pattern’s, and the atom is useful under a task list, a patient chart, a bank journal and a regulated audit trail precisely because it declines all of them. What it does carry is the structural guarantee the others rest on: the sequence is faithful to what was recorded.
Structure
Identity model
Identity 1: The atom MUST identify an event by the event id.
Identity 2: The host MUST allocate an event id at the atom's seam.
Identity 3: The transition MUST NOT allocate an event id.
Identity 4: The business caller MUST NOT supply an event id.
Identity 5: The atom MUST NOT reuse an event id.
Identity 6: The atom MUST NOT reassign an event id.
Identity 7: The atom MUST compare event ids by equality.
Identity 8: The atom MUST NOT order events by event id.
Identity 9: The atom MUST NOT identify an event by the event's data.
Identity 10: A composing pattern MUST own how many log instances a deployment runs.
Term event id: the opaque value naming one event — an Event Id; allocated once, never again.
Term seam: the atom’s I/O boundary as the section titled Logic Confinement Principle in execution-contract.md declares it; the host injects the clock reading and the event id here. Term now: the wall-time reading the host takes at the seam and hands to the transition, as the section titled Logic Confinement Principle in execution-contract.md declares it; never read inside the transition, never supplied by the business caller.
Term transition: the atom’s evaluation of one call against the log, as the section titled Logic Confinement Principle in execution-contract.md declares it.
Term business caller: the party whose action the call carries, as the section titled Logic Confinement Principle in execution-contract.md declares it; never the source of an injected value.
WHY: Identity is allocated at the seam and handed in, which forecloses a caller that supplies an id of the caller’s choosing and a transition that answers two ways for one input (Identity 2 through 4). Ordering is sequence number’s alone: an id that sorts invites a reader to sort by it, and the day the id source changes shape, the order changes with it (Identity 8).
State
State 1: The log MUST hold events in EXACTLY ONE total order.
State 2: EVERY event MUST carry event id, sequence number, recorded at and data.
State 3: The log MUST carry log name.
State 4: The log MUST carry next sequence number.
State 5: A fresh log instance MUST begin next sequence number at one.
State 6: [Append] MUST raise next sequence number by one.
State 7: A durable implementation MUST preserve next sequence number across a restart.
State 8: The atom MUST NOT offer a delete surface.
State 9: The atom MUST NOT offer an edit surface.
Term event: one recorded fact in the log — an Event; fixed in place once landed.
Term sequence number: the strictly rising integer an event carries — a Sequence Number; the log’s order and nothing else.
Term recorded at: the wall-time instant an event was appended, stamped from the injected clock — a Recorded At; an annotation, never the order.
Term data: the opaque payload a composing pattern supplies — Data; the atom stores the payload and reads nothing in it.
Term log name: the name telling one log instance from another — a Log Name.
Term next sequence number: the sequence number the next landed event carries — a Next Sequence Number; part of the instance’s persistent state.
Term durability mechanism: a write-ahead log, or another mechanism making a committed write survive a crash.
Term landed: an event a successful Append wrote; a consumed sequence number under which nothing was written is not landed.
| Term event field: event id | sequence number | recorded at | data. |
WHY: A volatile instance that restarts next sequence number at one has broken Invariant 4 for the life of the instance while every individual append looks correct — which is why durability of that one datum is stated here and not left to a deployment note (State 7). There is no delete and no edit, and their absence is a rule rather than an omission, because the log only grows is the property every composing pattern rests on (State 8, State 9).
Capability requirement
Capability requirement 1: The deployment MUST supply now at the seam.
WHY: What the deployment supplies, which is what the family means. The rule stood under Operation — one action’s rules — while naming no action, because this spec was migrated before the standard family had a home in an atom; the five atoms migrated a day later put the same obligation here. The words are the words the rule carried (council read 76).
Operations
append(data)
answers event_id
refuses invalid-payload | storage-failure
read(query)
answers events
refuses invalid-query
Operation 1: [Append] MUST write the event at the tail.
Operation 2: [Append] MUST stamp recorded at from the injected clock.
Operation 3: [Append] MUST carry next sequence number into the event.
Operation 4: [Append] MUST answer event id.
Operation 5: IF data EXCEEDS the payload cap THEN [Append] MUST answer invalid-payload.
Operation 6: [Append] MUST accept empty data.
Operation 7: [Append] MUST NOT refuse for contention.
Operation 8: [Append] MUST NOT refuse for ordering.
Operation 9: IF the store refuses the write THEN [Append] MUST answer storage-failure.
Operation 10: [Append] MUST NOT answer event id with storage-failure.
Operation 11: A caller MUST read storage-failure as the event not landing.
Operation 12: The host MUST serialize EVERY append to one log instance.
Operation 13: [Read] MUST answer EVERY landed event the query matches.
Operation 14: [Read] MUST order the answer by sequence number, rising.
Operation 15: IF the query is malformed THEN [Read] MUST answer invalid-query.
Operation 16: [Read] MUST answer an empty sequence for a well-formed query matching nothing.
Operation 17: [Read] MUST NOT write.
Operation 18: The implementation MUST own the query's shape.
Deleted: Operation 19. Capability requirement 1 owns it.
Deleted: Operation 20. Execution Contract Logic confinement 3 owns it.
Operation 21: The business caller MUST NOT supply recorded at.
Term query: what a read asks for — a Query: a sequence number range, a wall-time range, a payload predicate, or a combination.
Term payload cap: the per-instance bound on data’s size; 64 kilobytes where a deployment declares none.
The case space, and the rule that owns each case:
| Call | Case | Answer | Effect on the log |
|---|---|---|---|
| Append | data within the cap, store accepts | event id | one event lands at the tail, next sequence number rises (Operation 1, Operation 3, State 6) |
| Append | data over the cap | Invalid Payload | none — the precondition failed before the write (Operation 5) |
| Append | store refuses the write | Storage Failure | nothing lands; a sequence number may be consumed (Operation 9, Sequence gap 1) |
| Read | query well-formed, events match | the events, ascending | none — the call reads (Operation 13, Operation 17) |
| Read | query well-formed, nothing matches | empty sequence | none (Operation 16) |
| Read | query malformed | Invalid Query | none (Operation 15) |
WHY: An append refuses for one reason before the write and one reason at it, and for nothing else: no contention arm, no ordering arm, no retry semantics (Operation 7, Operation 8). Serialization is the load-bearing precondition under Invariant 3 and Invariant 4 — neither holds without it, and it is the host’s to supply, not the atom’s to enforce (Operation 12). storage-failure is definitive on purpose: a caller that treats it as maybe writes the event twice (Operation 10, Operation 11).
Invariants
- Invariant 1 — Append-only.
Invariant 1.1: An event in the log MUST remain in the log for the life of the log instance. Invariant 1.2: The atom MUST NOT remove an event. - Invariant 2 — Event immutability.
Invariant 2.1: EVERY event field of a landed event MUST NOT change. - Invariant 3 — Total order.
Invariant 3.1: Two distinct landed events MUST NOT share a sequence number. Invariant 3.2: EVERY two distinct landed events MUST stand in EXACTLY ONE order. - Invariant 4 — Sequence-number monotonicity.
Invariant 4.1: A landed event MUST carry a sequence number above EVERY sequence number landed earlier.WHY: the invariant is over landed events, which is what leaves room for the gap a storage failure consumes (Sequence gap 1 through 4).
- Invariant 5 — Read consistency.
Invariant 5.1: A read MUST answer EVERY landed event the read's query matches. Invariant 5.2: A read MUST answer the events by sequence number, rising. Invariant 5.3: A read MUST NOT answer an event for a consumed sequence number no event landed under. - Invariant 6 — No id reuse.
Invariant 6.1: Two events in the log MUST NOT share an event id. - Invariant 7 — Wall-time best-effort monotonicity.
Invariant 7.1: IF the clock is non-decreasing THEN recorded at MUST NOT fall in append order. Invariant 7.2: sequence number IS AUTHORITATIVE FOR the log's order.WHY: under an unreliable or adversarial clock recorded at is an annotation that may lie, and nothing in the atom rests on it — which is the whole reason the two data are separate (Invariant 7.2).
Append-only and event immutability together give the immutable journal property, the one that tells an Event Log from a mutable record set. Total order and monotonicity give replay. Read consistency gives durable visibility. No id reuse forecloses identity collisions across time.
Examples
The same pattern, four domains, identical mechanic.
Personal Todo activity log
A composing system wraps each Personal Todo action as an event: {type: "add", id: "t1", description: "buy milk"}, {type: "complete", id: "t1"}, {type: "delete", id: "t1"}. The log records them in order, never alters them. The user can later query the log to see what they did this week, restore deleted tasks (compose with Reverse Index + Restore — see Undo History), or reason about completion patterns. The Personal Todo pattern itself is unchanged; the log is a side stream the composing pattern maintains.
Compliance audit log
A regulated system records every state-changing action: {type: "patient_record_accessed", patient_id: "p123", actor: "dr_smith", reason: "treatment", at: "2026-05-07T14:32:11Z"}. The log is append-only by definition. The Audit Trail composition composes this atom with Retention Window, Tamper Evidence, and Actor Identity to add policy-bounded retention, integrity proof, and verifiable attribution. The Event Log itself doesn’t know what compliance means; it preserves the sequence faithfully and lets compliance be layered on.
Patient medical record (clinical history)
Each clinical observation, prescription, lab result, and vital sign is appended as an event with structured data. The clinical record is an Event Log; the patient chart is a view over it (latest values per field). Mistakes are corrected by appending a correction event, never by editing the original — the record must show what was originally recorded and when it was corrected. ICD (International Classification of Diseases — the World Health Organization’s standard diagnostic coding system) coding, billing extraction, and longitudinal analytics all read the same log.
Bank transaction journal
Every credit, debit, transfer, and adjustment is appended as an event in the journal. Account balances are derived by replaying the journal up to a point in time. Reversals are appended as new events (a refund event referencing the original charge), never as edits. The journal is the source of truth; the balance display is a projection. Reconciliation, fraud detection, and regulatory reporting all read the same log.
The mechanic is identical across all four. What differs: payload schema, query patterns, and the composing patterns that derive views (current todo list, audit report, current chart, current balance) from the underlying log.
Rejection paths
A single sequence exercising all three rejection reasons:
append(65_000_bytes_of_data)→ rejected invalid-payload (payload exceeds the default 64 KB cap; configurable per instance).append({type: "deposit", amount: 500})→ accepted; returnsevent_id e1withsequence_number 1.read({sequence_range: [-1, 5]})→ rejected invalid-query (negative sequence number is not a well-formed range parameter).read({sequence_range: [1, 1]})→ returns[e1];sequence_number 1matches, ordered ascending.- Underlying store becomes temporarily unavailable.
append({type: "withdrawal", amount: 100})→ rejected storage-failure; event does not land; caller must treat the rejection as definitive. A sequence number may have been consumed; subsequent successful appends receive a strictly higher number, producing a gap in the dense sequence (see Edge cases — Sequence-number gaps on storage failure). - Store recovers.
append({type: "withdrawal", amount: 100})→ accepted; returnsevent_id e2with a sequence number strictly greater than 1.
All three rejection reasons (Invalid Payload, Invalid Query, Storage Failure) exercised in one thread.
Generation acceptance
An implementation is acceptable when an external auditor, given one log instance and the atom’s own read surface, can clear the checks below without recourse to source code, runbooks or developer narration. This atom is the corpus’s Start Here — the first pattern most readers meet — and it claims append-only, total order and read consistency while the evidence for those claims has until now lived in a formal model, a twin suite and five independent renders, none of which a first reader has met. This section is the bridge: the same claims, cleared from the log alone.
Conformance checks
Check 1.1: An auditor MUST find EVERY event of an earlier read in a later read of one log instance (Invariant 1.1).
Check 1.2: An auditor MUST find a re-read event's EVERY event field unchanged (Invariant 2.1).
Check 2.1: An auditor MUST find no two landed events sharing a sequence number (Invariant 3.1).
Check 2.2: An auditor MUST find no two events sharing an event id (Invariant 6.1).
Check 2.3: An auditor MUST find a landed event's sequence number above EVERY sequence number an earlier landed event carries (Invariant 4.1).
Check 2.4: An auditor MUST read a gap in the sequence numbers as an event that did not land (Sequence gap 3).
Check 3.1: An auditor MUST find a read answering the events by sequence number, rising (Invariant 5.2).
Check 3.2: An auditor MUST find two reads of one query answering alike (Invariant 5.1).
Check 3.3: An auditor MUST find a read answering an empty sequence for a well-formed query matching nothing (Operation 16).
Check 3.4: An auditor MUST find a read answering invalid-query for a malformed query (Operation 15).
Check 3.5: An auditor MUST find no read answering an event for a consumed sequence number no event landed under (Invariant 5.3).
Check 4.1: An auditor MUST find EVERY event carrying event id, sequence number, recorded at AND data (State 2).
Check 4.2: An auditor MUST find a fresh log instance beginning next sequence number at one (State 5).
Check 5.1: An auditor MUST read a falling recorded at as a clock finding (Invariant 7.2).
Check 5.2: An auditor MUST NOT read a falling recorded at as an order finding (Invariant 7.2).
NOTE: EVERY check names the rule the check tests.
External checks
External check 1: An auditor needing the log instance's durability confirmed MUST read the deployment's own store (Durability 2).
External check 2: An auditor needing the appends serialized confirmed MUST read the host's own concurrency control (Operation 12).
External check 3: An auditor needing the clock non-decreasing confirmed MUST read the deployment's own clock discipline (Invariant 7.1).
External check 4: An auditor needing the log untampered confirmed MUST compose Tamper Evidence (Non-goal 4).
External check 5: An auditor needing an event's writer confirmed MUST compose Actor Identity (Non-goal 6).
External check 6: An auditor needing the payload cap confirmed MUST read the deployment's own declaration (Operation 5).
WHY: Check 2.4, Check 5.1 and Check 5.2 are the three that stop an auditor filing against a correct log, and each of them is a place where the obvious reading is wrong. A gap in the sequence numbers is not a lost event — Sequence gap 1 permits an implementation to consume a number on a failed write, so an auditor counting rows against numbers reports a defect the atom has none of. A recorded at that falls is a clock fault and never an ordering fault, because sequence number is authoritative for the order and recorded at is an annotation this atom rests nothing on.
The external set is where the real limit sits, and it is larger than a reader expects from a log. Append-only is not tamper-evidence. Every check above passes over a log an adversary with store access rewrote, because the atom compares the log against itself; detecting that the store was rewritten is Tamper Evidence’s and is named here rather than implied. The same holds for who wrote an event and for whether the instance survived a restart at all — External check 1 is the one a deployment loses silently, since a volatile instance satisfies every conformance check above and loses the journal the composing patterns replay.
Non-goals
Non-goal 1: The atom MUST NOT prune an event.
Non-goal 2: A pattern needing time-bounded retention MUST compose Retention Window.
Non-goal 3: The atom MUST NOT detect tampering.
Non-goal 4: A pattern needing integrity proof MUST compose Tamper Evidence.
Non-goal 5: The atom MUST NOT record who appended an event.
Non-goal 6: A pattern needing attribution MUST compose Actor Identity.
Non-goal 7: The atom MUST NOT index data.
Non-goal 8: A pattern needing lookup by payload field MUST compose a reverse-index pattern.
Non-goal 9: The atom MUST NOT order events across log instances.
Non-goal 10: A pattern needing multi-host order MUST compose a consensus pattern.
Non-goal 11: The atom MUST NOT read data.
Non-goal 12: A pattern needing schema validation MUST compose a schema-evolution pattern.
Non-goal 13: The atom MUST NOT collapse events into a snapshot.
Non-goal 14: The atom MUST NOT push an event to a subscriber.
Non-goal 15: The atom MUST NOT append two events atomically.
Non-goal 16: A pattern needing one write across two events MUST compose a transaction pattern.
WHY: The bare log keeps everything, knows nothing about the payload, and serves one instance — and each of those is a seam a composing pattern fills: Retention Window prunes under an obligation, a Storage Tier pattern (forthcoming) moves cold events, Tamper Evidence proves nothing was rewritten, Actor Identity binds the writer, a Reverse Index pattern (forthcoming) finds an event by what is inside the payload, a Snapshot pattern (forthcoming) collapses a prefix, a Change Feed pattern (forthcoming) pushes. Events are immutable by this spec, which is not the same as tamper-evident: an adversary with write access to the store rewrites the log and the atom cannot tell (Non-goal 3, Non-goal 4). Each append is atomic and two appends are two writes; both or neither is a Transaction pattern’s promise, over a store that offers one (Non-goal 15, Non-goal 16).
Where the pattern breaks down: when the host cannot supply atomic, serialized appends — most adversarially-distributed settings; when an event must be edited or deleted in place; when order must come from something other than append order.
Edge cases
Durability across crashes
Durability 1: The atom MUST specify in-memory semantics.
Durability 2: The deployment MUST own persistence across a process restart.
Durability 3: A durable implementation MUST supply a durability mechanism.
Durability 4: A composing pattern MUST declare the log instance's durability as an instance capability requirement.
WHY: Append-only and event immutability are best-effort across a crash unless the implementation supplies durability, and a composition whose rebuilds and scans assume the log survived a restart is resting on something no constituent promised — the obligation is declared, in the composition, or it is assumed (Durability 4; Audit Trail’s open line of 2026-08-30).
Erasure where law requires it
Erasure 1: The atom MUST NOT erase an event.
Erasure 2: A deployment under an erasure obligation MUST compose an erasure pattern.
Erasure 3: A deployment under an erasure obligation MUST NOT read this atom as satisfying the obligation.
WHY: Append corrections, never edit history is the architecture, and it is the one place law overrides architecture: GDPR (EU General Data Protection Regulation) Article 17 and some healthcare regimes require true deletion of recorded content. The answer is a composing pattern designed with counsel — Erasure Tombstone or cryptographic shredding (forthcoming) — never a quiet edit to the log.
Sequence-number gaps on storage failure
Sequence gap 1: An implementation MAY consume a sequence number on a failed write.
Sequence gap 2: The next landed event MUST carry a sequence number above a consumed sequence number.
Sequence gap 3: A consumer MUST NOT read a gap as a lost event.
Sequence gap 4: An implementation avoiding a gap MUST take EXACTLY ONE OF allocating a sequence number ONLY AFTER the write lands, returning a consumed sequence number to the pool.
WHY: Invariant 4 holds over landed events, so a gap violates nothing — but a consumer counting rows against sequence numbers reads the gap as a missing event and files a finding against a log that is correct (Sequence gap 3).
Composition notes
Composition note 1: A composing pattern MUST append on every state change.
Composition note 1a: A composing pattern MAY derive state by replay.
Composition note 2: A composing pattern MUST own what an event means.
Composition note 3: A composing pattern MUST own the payload's schema.
Composition note 4: This atom's invariant numbers MUST stand as a frozen contract surface.
Composition note 5: A composing pattern MUST cite this atom's invariants by number.
WHY: The two contracts are append-on-change (the log is the durable record the pattern’s history is reconstructed from) and replay (the log is the source of truth and current state is a projection); most patterns take both. The invariant numbers are a frozen contract surface: Undo History, Audit Trail, Compensable Workflow and Reserve from Pool cite them wholesale, so adding one is forward-compatible and renumbering one re-passes every composition that cites it (Composition note 4). That a writer must not renumber is the grammar’s rule and stays there (GRACE-lang.md Hard invariant 26); what this note owns is the local fact that these numbers are cited from outside. Landed compositions over this atom: Audit Trail, Undo History. Forthcoming: Activity Feed, Event-Sourced Reservation.
Terms
Each [Term] marker above links to its term entry here; a term entry states what the concept is and its Kind.
Vocabulary
Term actors: the atom; the log (also: a log instance, a fresh log instance); the host; the transition; a composing pattern (also: a pattern, a writer); a business caller; a caller; a consumer; an implementation (also: a durable implementation); the deployment; the store; an event; a read; an append; an auditor.
Term records: event — one recorded fact, carrying event id, sequence number, recorded at and data; the log carries log name and next sequence number.
Term record verbs: derive, identify, allocate, supply, reuse, reassign, compare, order, own, hold, carry, begin, raise, preserve, offer, write, stamp, answer, accept, refuse, read, serialize, remain, remove, change, share, stand, fall, land, prune, detect, record, index, collapse, push, append, specify, compose, declare, consume, take, cite, renumber, add, erase, match, find.
| Term value sets: event field = event id | sequence number | recorded at | data. |
Term bounds: payload cap (the per-instance bound on data’s size).
Term cadences: empty.
Term qualifiers: migrated — rewritten in GRACE lang v0.35 (2026-09-11); landed — written by a successful append.
Term terms: durability mechanism, event id, seam, transition, business caller, event, sequence number, recorded at, data, log name, next sequence number, landed, event field, query, payload cap.
Event Log
The named append-only sequence this atom defines: anything appended stays, in append order, unchanged, for the lifetime of the instance. It is the substrate audit trails, undo histories, activity feeds, and event-sourced systems compose on top of. Multiple instances coexist; this card describes one.
Kind: Type
Event
A single recorded fact in an Event Log — one entry in the sequence, fixed in place once appended. It carries its Event Id, Sequence Number, Recorded At, and Data; nothing about it changes after Append.
Kind: Type
Append
The behavior a composing pattern invokes to record a new Event at the tail of the log. It allocates the next Sequence Number, stamps Recorded At, and returns the Event Id. It is the only way data enters the log.
Kind: Operation
Read
The behavior a composing pattern invokes to retrieve events matching a Query, returned in Sequence Number order. It only reads; the log is unchanged.
Kind: Operation
Event Id
The opaque, immutable identity of an Event, allocated by the host at the I/O seam on Append, never reused. It supports equality but carries no ordering — ordering is Sequence Number’s job.
Kind: Field Field of: Event Projection: event_id
Sequence Number
The strictly increasing integer assigned to each Event at Append. It fixes the Event’s place in the total order and is the authoritative basis for ordering — kept separate from Recorded At on purpose, because a clock can drift but the sequence never does.
Kind: Field Field of: Event Projection: sequence_number
Recorded At
The wall-time at which an Event was appended — an annotation of when, not the basis of order. Stamped from the host-injected clock on Append; best-effort monotonic, with Sequence Number authoritative if the clock misbehaves.
Kind: Field Field of: Event Projection: recorded_at
Data
The opaque payload a composing pattern supplies on Append and the Event then carries. The Event Log stores and returns it verbatim and never interprets it.
Kind: Field Field of: Event Projection: data
Log Name
The identifier that distinguishes one Event Log instance from the others co-existing in a system (one per audited subsystem, one per user history, and so on).
Kind: Field Field of: Event Log Projection: name
Next Sequence Number
The Sequence Number the next appended Event will receive. It begins at 1 for a fresh instance and increments on each Append; durable implementations preserve it across restarts, or sequence-number monotonicity breaks over the instance’s lifetime.
Kind: Field Field of: Event Log Projection: next_sequence_number
Query
The selection a caller passes to Read — a sequence-number range, a wall-time range, a payload predicate, or a combination. Its exact shape is implementation policy; the only requirement is that a valid Query returns events in Sequence Number order.
Kind: Parameter Parameter of: Read Projection: query
Invalid Payload
The refusal Append returns when the supplied Data violates the configured payload constraints (for example, exceeding the size cap). The Event does not land.
Kind: Member Member of: the Append rejection Role: Outcome Projection: invalid-payload
Invalid Query
The refusal Read returns when the Query is malformed — an invalid range, an unparseable predicate. No events are returned.
Kind: Member Member of: the Read rejection Role: Outcome Projection: invalid-query
Storage Failure
The refusal Append returns when the underlying store write fails after all preconditions pass. The caller must treat it as definitive — the Event did not land — though a Sequence Number may have been consumed (see Edge cases).
Kind: Member Member of: the Append rejection Role: Outcome Projection: storage-failure
Standards references
Event Log is a foundational primitive with deep standards backing:
- ISO/IEC 27001 (International Organization for Standardization / International Electrotechnical Commission — joint information-security management standard) — mandates event logging for security-relevant actions.
- NIST SP 800-92 (National Institute of Standards and Technology — US federal standards body) — Guide to Computer Security Log Management; describes log lifecycle, integrity, retention requirements.
- W3C (World Wide Web Consortium — the web standards body) Activity Streams 2.0 — JSON (JavaScript Object Notation — a lightweight text format for structured data) format for activity feeds; treats activities as events with actor / verb / object structure.
- Event Sourcing literature — Greg Young’s early write-ups; Martin Fowler’s Event Sourcing; foundational pattern in domain-driven design.
- Database write-ahead logging (WAL) — the same primitive at the storage layer; ARIES (Algorithms for Recovery and Isolation Exploiting Semantics — a classic database crash-recovery method) recovery, PostgreSQL WAL, MySQL binlog.
- Distributed-systems replication logs — Kafka topics, Raft logs, Paxos value logs.
- Version control — Git’s commit log is an Event Log with cryptographic tamper-evidence (a Merkle DAG — a directed acyclic graph whose nodes are linked by cryptographic hashes, so any change to history is detectable) layered on top.
It inherits from:
- Daniel Jackson, The Essence of Software — the conception of a freestanding concept with state, actions, and operational principles.
- Eiffel’s design-by-contract — preconditions on Append and Read.
- Linear temporal logic (a formal notation for reasoning about sequences of states over time) — append-only, event immutability, and sequence-number monotonicity expressed as temporal properties (
always,until).
Status
grounded on Final Critique 4 — 2026-06-18 — see the Ledger.
Ledger
status: grounded on Final Critique 4 — 2026-06-18
formal: verified — event-log.tla + 1 twin, 2026-06-03
last gate: 2026-06-18 — Final Critique 4, fresh reader — clean
open: none
Decisions
Directional changes only — the turns a future reader must know the pattern took, and why. Everything smaller lives in the commit that made it: git log -- atoms/event-log.md.
-
2026-09-11 — Rewritten in GRACE lang v0.35; nothing but language changed. Chose: labelled rules in fenced blocks, the two actions as a signature block, rationale under
WHY:, terms declared where they are used, the invariant numbers frozen exactly as the compositions cite them, Non-goals and Edge cases as two sections, the case table kept beside the rules. Over: the prose spec. Because: the migration plan takes the atoms the migrated compositions already cite first — Audit Trail and Recoverable Invocation cite this atom’s Invariants 1, 2, 3, 5 and 7, and a rewrite that moved a number would break those citations silently (tools/grace/cites.py --into event-log). -
2026-09-14 — The atom gained an acceptance surface, and the external half is the load-bearing half. Chose: fifteen
Checkrules cleared from one log instance and its read surface, and sixExternal checkrules naming what the log cannot show about itself. Over: declining by delegation, which would have been false — this atom is composed directly, not only through a substrate. Because: presence became mandatory on 2026-09-14, and this atom is the corpus’s Start Here: it claims append-only, total order and read consistency while the evidence sat in a formal model, a twin suite and five independent renders, none of which a first reader has met. The section is the bridge.External check 4is the line that had to be written down — append-only is not tamper-evidence, every conformance check above passes over a log an adversary rewrote, and the atom compares the log only against itself (council read 65).
NOTE: End of Event Log.