#The Claim
The constitutional ledger is the single data structure from which messaging, provenance, coordination, and the entity graph all derive. It is a Merkle-CRDT: a content-addressed, append-only directed acyclic graph where entries are conflict-free and concurrent appends merge deterministically. Constitutional rules govern which appends are valid. Invalid appends do not fail — they fork into new tag partitions. This is productive inconsistency: the system does not reject disagreement; it makes disagreement visible and contained.
The ledger unifies five systems that HAAK currently maintains separately:
- Dispatch (agent-to-agent messages) — ledger entries with sender/recipient qualities.
- Boards (domain coordination) — ledger entries with domain tag qualities.
- Roster (agent lifecycle) — ledger entries with lifecycle state qualities.
- Entity graph (knowledge structure) — the ledger IS the entity graph; every entry is a belonging.
- Git history (code provenance) — one materialization of the ledger, not the ledger itself.
The key ontological insight: the ledger entry and the entity belonging are the same object. A ledger entry IS a belonging with provenance, hash-linked into a DAG. The ledger IS the entity graph, append-only. Building them separately would mean spending months reconciling two implementations of the same structure. The ontology already defines the primitive — belongs-to with a quality ([[02-relations]], Definition R1). The ledger adds three things: content addressing, DAG linkage, and constitutional proof. Nothing else.
#The Entry
Every entry in the ledger is a belonging — the sole primitive relation from [[02-relations]] — extended with provenance and DAG linkage.
{
"cid": "<blake3-hash-of-canonical-json>",
"entity_id": "<who-or-what>",
"target": "<belongs-to-what>",
"quality": "<nature-of-belonging>",
"rank": null,
"timestamp": "<iso-8601-utc>",
"source": "<provenance-session-or-system>",
"actor": "<who-appended-this>",
"parents": ["<cid-1>", "<cid-2>"],
"tags": ["place:lisbon", "role:architect"],
"envelope": null,
"proof": null
}
Field definitions:
| Field | Type | Purpose |
|---|---|---|
cid | string (BLAKE3) | Content identifier — hash of the canonical JSON form of all other fields. Immutable. If any field changes, the CID changes. |
entity_id | string | The entity that belongs. An agent, a person, a document, a situation. |
target | string | What the entity belongs to. Another entity, a situation, a domain. |
quality | string | The nature of the belonging — "actor", "author", "materialization", "governs", "episode-of", etc. From the quality vocabulary in [[02-relations]]. |
rank | integer or null | Ordinal position within a quality group. Author position, track number, episode sequence. From [[12-situation-nesting]]. |
timestamp | string (ISO 8601) | When the belonging was asserted. |
source | string | Provenance — which session, script, or system produced this entry. |
actor | string | Who appended this entry. May differ from entity_id — the actor records who made the assertion, not who the assertion is about. |
parents | array of strings | CIDs of parent entries in the DAG. One parent for linear appends. Multiple parents for concurrent appends (merge). Empty for genesis entry. |
tags | array of strings | Tag set defining visibility and routing. Format: namespace:value. Determines audience and constitutional scope. |
envelope | object or null | Encryption envelope. Null in v1.0. In v1.5+: {audiencelabel, encryptedkey, ciphertext}. |
proof | object or null | Constitutional compliance proof. Null in v0 (bootstrap). In v1.0: {type: "attestation", ruleschecked, signature}. In v2.0: {type: "zk-stark", starkproof, public_inputs}. |
Canonical form. Fields are serialized in the fixed order above using JSON Canonicalization Scheme (RFC 8785 JCS). This ensures deterministic hashing — the same entry always produces the same CID regardless of serialization quirks. The CID is computed over all fields except cid itself. No optional omission: null fields are serialized as null, not elided.
Hash function. BLAKE3. Faster than SHA-256 by a factor of four to ten, parallelizable across cores, supports keyed hashing (useful for KDF in the encryption layer), and stream-friendly for large payloads. CIDs are prefixed with a multicodec identifier for algorithm agility — if BLAKE3 is ever superseded, old CIDs remain valid and new entries use the new algorithm.
#The DAG
Entries form a directed acyclic graph via their parents field. The DAG has three structural properties.
1. Append-only. No entry can be modified. Changing any field changes the CID, which breaks all references to it. The ledger only grows. Deletion is expressed as a new entry with quality "supersedes" pointing at the entry being logically removed. The superseded entry remains in the DAG — it is not erased, only marked as replaced. Audit trails are permanent. This is the same commitment that the constitution makes about policy: norms accumulate downward through domain subsumption ([[01-objects]], Definition 12). The ledger makes that commitment structural.
2. Concurrent. Multiple agents can append simultaneously without coordination. Each agent references the heads it knows as parents. When two agents append concurrently, the DAG branches. The next append that references both becomes a merge point. This is Merkle-CRDT semantics — no central coordinator, deterministic convergence. The merge is automatic because entries are self-contained: an entry's validity depends on its own content and its constitutional proof, not on the global order of appends. Two entries that reference the same parent are not in conflict; they are concurrent assertions, both valid, both preserved.
3. Forkable. When an append violates constitutional rules at a tag intersection, it is not rejected. It is appended to a new branch with a new tag partition. The fork is visible in the DAG: sibling entries with the same parents but different tag sets. This is productive inconsistency — disagreement becomes structure, not error. A fork says: "these two entries cannot coexist under the same constitutional scope, so they coexist under different scopes." The fork is not a failure state. It is the system's way of preserving both assertions while recording that they are incompatible within the scope where the conflict arose. Resolution — if it ever comes — is a new entry that merges the branches, itself carrying a proof of how the conflict was resolved.
#Constitutional Rules
Constitutional rules are themselves ledger entries — belongings with quality "governs":
{
"entity_id": "rule:externalization",
"target": "tag:domain:*",
"quality": "governs",
"tags": ["scope:universal"],
"proof": null
}
A rule entry specifies: what entity (the rule), what it governs (a tag scope), with what quality ("governs"), and at what scope (its own tags determine where it applies). Rules inherit downward through tag refinement — a rule tagged scope:universal applies everywhere; a rule tagged domain:inscription applies only within that domain.
Policy resolution follows [[12-situation-nesting]], Definition S5: innermost applicable policy prevails, unless the outer policy is marked non-overridable. The constitution ([[01-objects]], Definition 14) is always non-overridable — it governs how other policies are created and amended. Domain policies are overridable by default. When two policies conflict at the same scope, the more recently appended entry prevails, because the append itself is an assertion of authority. If the authority is contested, the append forks — productive inconsistency again.
Enforcement progression:
| Version | Mechanism | What proof contains |
|---|---|---|
| v0 (bootstrap) | No enforcement | null — entries are accepted without proof. The JSONL dispatch era. |
| v1.0 | Policy-as-code + attestation | {type: "attestation", ruleschecked: [...], predicateresults: {...}, signature: "..."} — executable predicates evaluated at append time, agent signs the result. |
| v1.5 | Formal rule specification | Rules expressed as SMT constraints. Predicate evaluation becomes formally verifiable. |
| v2.0 | ZK-STARK proofs | {type: "zk-stark", starkproof: "...", publicinputs: {...}} — agent proves compliance without revealing content. Constitutional enforcement becomes mechanical. |
The progression from v0 to v2.0 is a progression from social enforcement (agents follow rules because they are instructed to) through attested enforcement (agents prove they followed rules, but the proof is trust-based) to cryptographic enforcement (compliance is mathematically verified, and entries without valid proofs cannot be accepted). At v2.0, drift resistance ([[04-drift-resistance]]) is solved at the mechanism level — structurally impossible to violate, not merely detectable after the fact.
#Tags and Topology
Tags are the mechanism by which the ledger produces structure. Every entry carries a tag set. Tags serve three simultaneous functions.
1. Topology. Agent A can see entry E if and only if A's tags overlap with E's tags. No overlap, no visibility. Edges in the communication graph emerge from tag overlap, not explicit wiring. Two agents tagged {domain:inscription} can see each other's entries in that domain. An agent tagged {domain:inscription, role:reviewer} can see everything in the inscription domain and everything addressed to reviewers. The communication topology is not configured — it is computed from the tag graph.
2. Observation frames. Any tag or combination of tags defines a "view" — the subgraph of entries visible from that vantage. Watching domain:inscription shows all entries tagged with that domain. Watching role:architect shows all entries from or to architects. Watching domain:inscription AND role:architect shows the intersection. Views compose by set intersection on tags. Every agent's perspective is a view. Every project board is a view. The board.md files that HAAK currently maintains are materializations of views — human-readable projections of the tag-filtered subgraph.
3. Search index. Hierarchical tags (e.g., domain:ai-ontology/inscription) create a tree that the Library Theorem's O(log N) navigation applies to. The tag hierarchy IS the search index. Navigating from domain:ai-ontology to domain:ai-ontology/inscription to a specific entry within that domain is logarithmic descent through the tag tree — the same operation that [[09-recursive-index]] performs over the filesystem, now performed over the ledger.
Ontological grounding. Tags are qualities on belongings. An agent tagged {place:lisbon, role:architect} has two belongings in the ledger: belongs-to(agent, lisbon, quality: located) and belongs-to(agent, architect-role, quality: holds-role). Tag overlap between agents is shared qualities. The DCG topology that Paper 4a describes — the dynamic communication graph where edges form and dissolve as agents' tag sets change — emerges from the quality graph that [[02-relations]] defines. No separate routing layer. No wiring table. The topology is a read view over the ledger's own content.
Reserved namespace. bridge:<hash> tags are reserved for inter-constitutional bridge domains. When two Filix instances negotiate a shared scope, the bridge tag is bridge:blake3(sorted-party-identifiers). This ensures no collision with either instance's existing tags. Bridge entries are visible to both parties (tag overlap through the bridge namespace) and governed by a negotiated sub-constitution specific to the bridge scope. Full bridge protocol is deferred (ontology/13, G7) but the namespace reservation prevents retrofitting costs later. The entry format, DAG structure, and visibility model already support bridges — only the namespace needs reserving.
#Encryption (v1.5+)
In v1.0, entries are plaintext. Tags determine logical visibility — what you should see — but any agent with ledger access can technically read everything. This is acceptable for single-user Filix installations and trusted multi-agent setups.
In v1.5, visibility becomes physical. The envelope field encrypts the entry's payload:
{
"audience_label": "blake3(sorted-tag-set)",
"encrypted_key": "encrypt_to(audience_key, entry_secret)",
"ciphertext": "age_encrypt(payload, entry_secret)"
}
Key derivation: KDF(mastersecret || audiencelabel) -> audience_key. Each unique tag combination has its own derived key. Agents who share tags derive the same keys — this is how tag overlap translates into cryptographic access. When an agent joins a tag group, it receives the current master secret and can derive all audience keys for its tag set. When an agent leaves, the master secret rotates and new keys are derived. The rotation cost is O(n) messages where n is the size of the departing group — each remaining member receives the new secret.
The CID is computed over the envelope (encrypted form), not the plaintext. This means content addressing works without decryption. The DAG structure — who appended what, when, with what parents — is visible to everyone. The payload — the semantic content of the belonging — is visible only to the audience. Privacy is topological: your position in the tag graph determines what you can decrypt, and that position is itself recorded in the ledger as belongings with tag qualities.
#How Current Systems Map
| Current system | Ledger equivalent |
|---|---|
| Dispatch message | Entry: entity_id=sender, target=situation:conversation, quality="communicates", tags include recipient. |
| Board post | Entry: entity_id=agent, target=domain:project, quality="reports", tags include domain. |
| Roster update | Entry: entity_id=agent, target=role:architect, quality="holds-role" or state quality ("live", "frozen", "dead"). |
| Entity belonging | Entry: the entry IS a belonging. No mapping needed — identity, not translation. |
| Git commit | One materialization of ledger entries into the filesystem. The git DAG is a projection of the ledger DAG. |
| Freeze-state | Entry: entity_id=agent, target=situation:session, quality="freeze-state", payload contains the structured summary from [[32-lifecycle-manager]]. |
The mapping is not metaphorical. Each row describes a literal replacement. When Filix v1.0 ships, the dispatch JSONL, the roster JSONL, the board.md files, and the entity graph SQLite are all replaced by views over the ledger. The views are materialized for performance — SQLite indices, rendered markdown — but the ledger is the source of truth for all of them.
#Implementation Path
The ledger does not replace everything overnight. It grows from the current JSONL bootstrap.
Phase 0 (now). JSONL dispatch + JSONL roster + board.md files. Working, unstructured. The immediate step: add content hashes (BLAKE3 of canonical form) to every record written by the dispatch and roster systems. This makes interim records content-addressable — the first ledger property — without changing any existing tooling. Records that already have hashes can be imported into the ledger at Phase 1 without recomputation.
Phase 1 (Filix v1.0). Single-file append-only ledger. Entries follow the schema above. Policy-as-code predicates evaluate at append time, and the appending agent signs an attestation. No encryption. The entity graph becomes a read view over the ledger — entities.db is a materialized index, not the source of truth. The materialization is rebuilt by scanning the ledger and projecting entries into relational tables. Boards become tag-filtered views rendered to markdown on demand. The roster becomes a quality-filtered view over entries with lifecycle state qualities.
Phase 2 (Filix v1.5). Per-entry encryption. Tags become physical visibility boundaries. KDF-based audience keys. Master secret rotation on group changes. The ledger can now be replicated to untrusted nodes — the DAG structure is public, but payload visibility is cryptographically enforced by tag overlap.
Phase 3 (Filix v2.0). ZK-STARK proofs. Every append carries a zero-knowledge proof that it satisfies the applicable constitutional rules without revealing the entry's content. Verification is mechanical: a node accepts an entry if and only if its proof verifies against the public rule set. Drift resistance is no longer a social or architectural problem — it is a mathematical guarantee. An invalid append cannot enter the ledger because it cannot produce a valid proof.
#Amendments (Post Stress Test)
Four structural clarifications added after the spec was stress-tested with a worked example and a failure modes survey. Ontological grounding by Nagarjuna (ontologist-01).
#Content is material, not structure
The entry schema records structure — who communicated, to whom, in what capacity. But messages carry content. Where does the content live?
Content is a material belonging to the situation. Every entry in the ledger is an act-scale situation (ontology/12, Definition S1). The content of that act is a material that belongs to it. This means a dispatch message produces two entries:
- Structural entry.
entity_id: agent:lina, target: situation:conv-01, quality: communicates. Records the act. - Material entry.
entity_id: payload:<content-hash>, target: cid-of-structural-entry, quality: material. Records what was said.
The structural entry is always visible to tag-overlap agents. The material entry can be separately encrypted — you can know that Lina communicated without knowing what she said. This is privacy as granularity, not all-or-nothing.
The same two-entry pattern applies to any belonging that carries content: board posts (structural + body), roster updates (structural + summary), document writes (structural + document content).
#Every entry is an entity
Every entry is simultaneously a belonging (it relates an entity to a target) AND an entity (it can be the target of other belongings). The CID serves double duty: content address and entity identifier. This is the reflexive closure from ontology/02-relations applied to the ledger.
When you annotate a specific message, you write: entity_id: your-annotation, target: cid-of-message, quality: annotates. The message's CID is its entity identity. No special mechanism needed — the graph is already reflexive.
This resolves the dual-identity problem identified in testing: entity_id identifies the subject of the belonging (who or what belongs), while cid identifies the entry itself as a referenceable entity. Both are necessary. They serve different functions.
#Broadcasts use the root tag
scope:universal is the root of the tag hierarchy. Every agent's tags overlap with it by definition — it is the node from which all other tags descend. This is not a wildcard exception to the overlap-only visibility rule. It is the Library Theorem's root node: the top of the index that makes O(log N) navigation possible. A broadcast is an entry tagged scope:universal, meaning it belongs to the universal context.
The convention: all agents carry scope:universal implicitly. It does not need to appear in their explicit tag set — the system adds it at tag resolution time.
#Fork reconciliation requires human authority
The productive inconsistency model (invalid transitions fork rather than fail) has a known distributed systems risk: fork proliferation. If agents disagree frequently, the DAG fractures into branches that never merge.
The answer: the human decides when forks merge. This is Constitution §2 (Human Authority). In the productive inconsistency model, persistent forks represent genuine disagreement. Mechanical auto-reconciliation would mean the system resolves disagreements without human judgment — contradicting the system's central claim that human participation is irreplaceable at the points where formal systems cannot decide.
The oracle (LLM) can propose a merge by generating a resolution entry. But the merge is only valid when a human-authorized agent signs the proof. Fork proliferation is bounded by this: forks accumulate until a human-authorized resolution is appended.
In practice, most forks are trivial (concurrent non-conflicting appends) and merge automatically via CRDT semantics. The forks that persist are the interesting ones — genuine policy disagreements that need human judgment. That is the system working as designed.
Operational bound: Unresolved forks cost tracking overhead (more branches to navigate), not structural integrity (the DAG remains valid). The historian (methods/29) monitors fork accumulation and surfaces persistent forks to the user for resolution.
#Governance integration (ontology/13)
Ontology/13 (Governance as Situation) establishes six definitions that tighten the ledger spec in three areas.
Merge is governance (G3). A merge of forked branches is not a technical operation -- it is a governance situation. The merge entry must carry: actors (the parties who participated in the decision), method (the decision process: vote, consensus, delegation, arbitration), materials (the matters under deliberation -- the forked entries being reconciled), and a governance proof (G4). The merge entry's quality field is "governs" and its belongings include the forked entries as materials. A merge without a governance proof is structurally invalid.
The proof field carries governance evidence (G4). Two tiers, matching the existing v1.0/v2.0 progression:
- v1.0: Attestation with quorum signatures. The proof specifies: which agents attested, what decision process was used (G2), whether quorum and threshold were met. Format:
{type: "governance-attestation", process: "consensus", quorum: 3, signers: [...], threshold_met: true}. - v2.0: ZK proof that quorum and threshold were met without revealing individual positions. The proof demonstrates procedural legitimacy cryptographically.
Authority is traceable (G5). The actor field on every entry must be resolvable to a delegation chain terminating in a human-authorized governance process. An agent appending an entry does so under authority delegated from the user (Constitution section 2). The delegation chain is itself a sequence of ledger entries with quality "delegates-authority" -- the authorization to act is recorded in the same ledger as the actions. Unattributable entries (where the actor cannot be traced to a human authorization) are structurally suspect, flagged by the auditor.
Nested governance (G6). Three levels: constitutional (founding rules, non-overridable), institutional (standing bodies operating under the constitution), operational (atomic governance acts -- a single vote, a single merge). This maps to the existing policy resolution (ontology/12, S5): innermost prevails unless outer is non-overridable. The ledger's constitutional rules (entries with quality "governs" at scope:universal) are the constitutional level. Domain-scoped governance entries are institutional. Per-merge governance is operational.
#What This Document Does NOT Cover
- Wire protocol for ledger replication between nodes (network layer — separate spec).
- Specific constitutional rules (policy content — separate from the mechanism that enforces them).
- Migration plan from HAAK to Filix (strategy — see [[strategy/19-filix-v1-plan]]).
- The relationship between the ledger DAG and git (materialization details — the git DAG is one projection, but the projection rules need their own spec).
- Performance characteristics (benchmarking — deferred to implementation; the schema is designed for append-only sequential writes and indexed reads, but concrete numbers depend on entry volume and materialization strategy).
haak architecture . 33 . the constitutional ledger . 2026-03-16 . designed by Lina (architect, session architect-new) with ontological grounding from Nagarjuna (ontologist, session ontologist-01). The foundational data structure of Filix v1.0: a Merkle-CRDT where every entry is a belonging, constitutional rules govern valid transitions, and productive inconsistency is structural.
Architecture 33 — 33. The Constitutional Ledger — 2026 — Zachary F. Mainen / HAAK