Events and facts see history edit this page

Talks about: , , , and

A ticket is an append-only set of events. Everything else about it is computed.

Seven event types

The vocabulary is closed and versioned, because the semantics of a verifiable kernel have to be enumerable:

EventMeaning
:ticket/createthe ticket exists, pinned to a process definition by hash
:fact/asserta claim about a path: [:severity] = :high
:fact/retractwithdraw a claim, with no replacement
:fact/disputereject a claim, with a reason
:artifact/attacha file, stored and addressed by its hash
:attestation/adda signed claim the kernel does not interpret
:process/migratere-pin this ticket to a newer definition

Things that look like they need their own type turn out not to. Comments are artifacts — text blobs attached by hash. Links are facts under a [:link …] path. Work records are :work attestation claims. Witness countersignatures are detached sidecars over a head rather than events, because an event would move the very head it witnesses.

Content addressing

An event’s id is the SHA-256 of its canonical bytes, and the stored file is named for that id. The bytes on disk are exactly the hashed region, so a store audits with nothing but coreutils:

sha256sum tickets/*/events/*.edn   # filename must equal the digest

Signatures never live inside the hashed region. They are detached sidecars alongside the event, which is what lets a second person add their signature to an event without changing its identity.

Every event names its parents, forming a Merkle DAG. Parents carry integrity and causality — they are how a replica knows whether two writes saw each other. They never carry ordering: the fold orders by (at, id) over the event set, which is what makes the reducer total, commutative, and idempotent.

Fact status

One function decides why a fact does or does not satisfy a guard, and guards consult nothing else:

StatusMeaning
:presenta value stands
:absentnothing has been claimed
:retractedwithdrawn, no replacement offered
:disputedrejected with a reason, and unusable until corrected
:conflictedcausally concurrent claims disagree

What a dispute means

A dispute rejects the value that stood when it was raised, so the assertion that answers it has to claim something else. Re-asserting the rejected value verbatim leaves the path :disputed — otherwise the party a dispute holds accountable could clear it in one command by retyping the same fact.

A retraction clears disputes too, because the rejected claim is gone. A dispute raised on a path holding nothing rejects no particular value, so the first assertion answers it, which is what keeps a dispute from making a path permanently unusable.

Disputes accumulate: several people may reject the same claim, and each withdraws only their own.

tik dispute 3184 category --reason "this is billing, not technical"
tik dispute 3184 category --withdraw     # takes back your own objection

What a conflict means

When two replicas write the same path without having seen each other, and they disagree, the fact reads :conflicted and every guard that depends on it fails with a reason saying so. Nobody has to win. A later write that observed both supersedes them, and the conflict resolves by derivation.

Concurrent writes that happen to agree are not a conflict — there is no disagreement to surface.