Skip to content

Latest commit

 

History

History
1461 lines (1304 loc) · 76.1 KB

File metadata and controls

1461 lines (1304 loc) · 76.1 KB
doc DETAILS
package LocusKit
repo moot-memory
authored_commit daa855b9e43c6978d8481561f1e073533059735b
authored_date 2026-07-23
sources
path blob
Sources/LocusKit/Adjectives.swift
d95d3ad8b02c61b166be790138b710b595f30c3d
path blob
Sources/LocusKit/Association.swift
4b6f442c58dd6f182b3f5273348aa892eb1a5c55
path blob
Sources/LocusKit/AssociationOperational.swift
3228571f3f04aa662fa45c3ea098a97e0cd6cc96
path blob
Sources/LocusKit/AuditTypes.swift
872b7b19dc652f11b695361101d026b31a1a581d
path blob
Sources/LocusKit/BitmapEvaluator.swift
f2e25b7a0037131f4ea230bff62d33601a4af1f5
path blob
Sources/LocusKit/BitmapOps.swift
44dc29d22b712eb8631e07531e0bd3398d367197
path blob
Sources/LocusKit/BundleMaterializer.swift
59eae4efba9df236c0a7953df2b9649053e8133f
path blob
Sources/LocusKit/ContainerFingerprintStore.swift
fa7cb95c176cae53f0f24546112d87701ac1cf55
path blob
Sources/LocusKit/DefaultWings.swift
a3469fce1fab0754cd379aa2e3742562dbc01717
path blob
Sources/LocusKit/DiaryEntry.swift
7b6d202251630f26b4a88110ecf4c91a5712c0b9
path blob
Sources/LocusKit/DiaryOperational.swift
a5dc4ac124da1217fbaa716a63a194005d70523f
path blob
Sources/LocusKit/Drawer.swift
cc75fb3b8bc2450614dae65fb6d976d3f025cf5b
path blob
Sources/LocusKit/DrawerFingerprint.swift
30bf6bf545f1699c1a5f7f31053ce77e65508b06
path blob
Sources/LocusKit/DrawerOperational.swift
d3da4b100ba5a9a3d4511fc78fd6dba5efdb0a0f
path blob
Sources/LocusKit/DrawerStateValidator.swift
0fcc6d5affd39342d2263c841c5fd67894b7f163
path blob
Sources/LocusKit/DrawerStore.swift
71343870973a463961c089c05de9a55412730ab5
path blob
Sources/LocusKit/Estate.swift
96cfaf24d9a52c11c5199fd567d897640ccd1b9a
path blob
Sources/LocusKit/EstateAudit.swift
f17f901ea714fee7b7c2a6b8dc3c18e6684586d8
path blob
Sources/LocusKit/EstateIdentityKeyStore.swift
6a0cfc4dcc0c539c5ad0b5af4400dc0e0ee532e6
path blob
Sources/LocusKit/EstateTypes.swift
9afca8d07eee38ac8f0ad12fcb26aec4f732c1e8
path blob
Sources/LocusKit/EstateVerbs.swift
ce68fa4cbb672a4cf24a7ea175b1b4c82305b723
path blob
Sources/LocusKit/Filter.swift
4260cd963863bbc6f31f87d7f037e92ae7d95e16
path blob
Sources/LocusKit/Fingerprint256Adapters.swift
a7db452b9cc676b4af53a1c0f78c98d15df9c6c7
path blob
Sources/LocusKit/ForbiddenCombinationValidator.swift
809c5fdf1e7a6bcc219b9410f6f247eec65b275d
path blob
Sources/LocusKit/Frames.swift
f66e7e5c2103f150a4ee03bb6f1d3e01061598b1
path blob
Sources/LocusKit/KGFact.swift
3d018021557fa23cdce8aa803cd99ce6be109ccd
path blob
Sources/LocusKit/KGFactOperational.swift
635c214307e50e506ee9263fb7847cbcbbc2e165
path blob
Sources/LocusKit/LearnedReference.swift
9425889adb88a2a6348d134c0acbd6f1103cf8b8
path blob
Sources/LocusKit/LearnedReferenceOperational.swift
c4a4154017577072f258996ca74c9d240cec7fcf
path blob
Sources/LocusKit/LocusKit.swift
f201f00a27e2b906a0fc1502bfdef55282844119
path blob
Sources/LocusKit/LocusKitError.swift
13ed8aa56fb91dec378f0ad116f48fe3df6f271b
path blob
Sources/LocusKit/LocusKitSchema.swift
bc8317bd50c24850f4e45ccb444f164d616b9d72
path blob
Sources/LocusKit/LocusKitTelemetry.swift
732f995c52e8af16477f34243b5d898080cec7da
path blob
Sources/LocusKit/LocusKitVocabulary.swift
201186c9a525f129bc4a9daaeecba1400575e282
path blob
Sources/LocusKit/Manifest.swift
206d4ce171a49d96512f68e6398746edcc2ea13a
path blob
Sources/LocusKit/MerkleRollup.swift
ad7b32eb7d9ed1938e1c88c8abfedecb40500562
path blob
Sources/LocusKit/Node.swift
8d59f6721beca08b957c60eddc96c67df9cb39bb
path blob
Sources/LocusKit/NodeBundleStore.swift
f24b4bd9fa5b7ef0f4c63b3e9f066c484af17e56
path blob
Sources/LocusKit/NodeStore.swift
5fe41a84a4594365c16fe8616df24eb828092dbe
path blob
Sources/LocusKit/Proposal.swift
e92d684ddb11ec7d9babfc577f9b68d7730c0ec2
path blob
Sources/LocusKit/ProposalOperational.swift
65477d9fcafe5bdd9e53927833a08b27f6779247
path blob
Sources/LocusKit/Provenance.swift
95d989f9cf53084c29e2c9d506c2f18f6fd9bb07
path blob
Sources/LocusKit/RecallStream.swift
bb038171818090f8b7b7db0cb39d25d4563ed9e1
path blob
Sources/LocusKit/RecallTraceItem.swift
1a96a2daf6dc5edb46b8ac6934b6f8670227a3dd
path blob
Sources/LocusKit/SourceCatalogEntry.swift
b91b6b61cb59150270488c7451bb8556449a3bc1
path blob
Sources/LocusKit/Summaries.swift
fa624f6b00d8bf40f1ccc02821e3e2b94bf94f6e
path blob
Sources/LocusKit/Tunnel.swift
8b1590668c930fb0e03eb2e89d2c31cd3d66c34b
path blob
Sources/LocusKit/TunnelOperational.swift
b58de521d2a2e7cf3b8839359cc7624d32fd9b30
path blob
Sources/LocusKit/DatasetHandle.swift
196e7250abbe2ae3d1ab88b6320d1dee3d9b3855

LocusKit Details

Current Release Details

DrawerStore now seeds its HLC generator from wall time on open. That keeps new audit stamps after already committed events across a restart.

Drawer inserts and updates refresh content_fingerprint. The read path fails loudly if the stored fingerprint is missing or malformed. Estate.activeDrawersAfter exposes bounded paging for backfill jobs. addTunnel copies the maximum endpoint sensitivity into the tunnel bitmap.

DatasetHandleContent links a drawer to one typed data table. captureDatasetHandle is the only path that makes this drawer kind. The handle can store table and column proof hashes. An erase can drop the table and add an audit event.

Active tunnel reads require active state and a clear retired bit. They also apply the drawer recall sensitivity ceiling. Tunnel review only accepts proposed edges. Association inserts ignore an existing stable endpoint pair.

This document walks through every source file in the package. Read OVERVIEW.md first for the big picture. Files appear here in pipeline order. First come the module surface and the estate lifecycle. Next come the nine verbs and their frame types. Then comes the storage engine. After that comes the drawer value type and its shared bitmap machinery. Next comes the recall filter and its evaluator. Then come the remaining eight noun types and their bitmap decoders. After that comes the containment tree and the bundle algebra. Next comes the fingerprint and integrity machinery. Then comes the manifest and setup data. Next come the recall-result and trace types. Telemetry comes last.

DatasetHandle.swift

This file defines the data drawer payload. It stores the table ID, columns, row count, and source note. Empty proof fields allow later work without a schema change.

captureDatasetHandle creates the correct dataset content kind. It sets a private export rule and the chosen sensitivity. Data handles do not enter the vector path.

findDatasetHandles finds all handles for one table ID. patchDatasetHandleSignatures updates the proof fields. drawerById supports the erase cascade before content is zeroed. appendAuditEvent logs the table drop beside the drawer erase.

LocusKit.swift

This file provides the module surface. It carries a doc comment describing the package. That comment points to the files holding the real public types. LocusKit has no module-level namespace enum of its own, unlike some sibling libs. Every public type lives in its own file. This file exists only to orient a reader arriving at the package for the first time.

LocusKitError.swift

This file provides LocusKitError, the single error enum every LocusKit method throws. Centralizing every failure mode in one type lets a caller recover in exact ways. For example, a caller can treat a missing drawer as a routine miss. It can still propagate a genuine SQLite failure.

The cases split into three groups. The not-found group names a missing row by id: drawerNotFound, tunnelNotFound, diaryEntryNotFound, and recallTraceItemNotFound. The storage group describes the storage layer misbehaving: databaseUnavailable, sqliteError, schemaTooNew, and corruptStoredValue. corruptStoredValue names the table, column, and raw stored text. So a caller can locate and repair the offending row, rather than receive a fabricated default value. The domain group describes LocusKit's own validation refusing a write: invalidContent, disciplineViolation, and notSupported. invalidContent carries a human-readable rule violation. Tests assert on this message text, as a validation-test contract. disciplineViolation names an illegal state transition or forbidden bitmap combination. It uses the raw integer state values, rather than the State enum. So the error type does not need to depend on Adjectives.swift.

LocusKitError.description renders each case as plain English, without Swift's EnumCase(...) noise. GeniusLocusKit consumes this description at its boundary. A caller there parses the English text back out, to decide how to react to a rejected write. So the wording is a soft contract, not just a log message.

LocusKitSchema.swift

This file provides LocusKitSchema, the entire on-disk schema. The schema is declared as data, not as SQL text. Storage.open(schema:), a PersistenceKit primitive, reads this declaration. It creates every table, generated column, and index from it. No file in LocusKit issues a raw CREATE TABLE or CREATE INDEX string. A hand-rolled SQL implementation used to do this. This declarative approach replaced it. So the schema is portable across SQLite, PostgreSQL, and an in-memory test backend. It needs no three copies of the same DDL.

LocusKitSchema.schema assembles seventeen tables. Fourteen of them are: drawers, tunnels, diary, manifest, kg_facts, proposals, associations, learnedReferences, source_catalog, node_bundles, container_fingerprints, recall_trace, keys, and nodes. Three more tables come from two sibling schema fragments: ErasureLedgerSchema and SnapshotSchema. Every persistent noun table carries a nullable .json column named ext. This column is a forward-compatible extension slot. It absorbs an unforeseen future field, without a schema migration. Version 1.0 writes NULL into it and never reads it. LocusKitSchema.version is currently 8. The file's header comment documents each version bump. Bumps include a BLOB Merkle root, a nullable content_hash column, and the nodes table, among others. The comment states plainly that there is no incremental migration ladder. No estate data has shipped under an earlier version.

The file's most distinctive feature is its generated columns. g_state_cluster on drawers is one example. It is computed as adjectiveBitmap & 0x3F. A generated column is a column whose value the backend derives on its own. The backend computes it from an expression over other columns in the same row. So a generated column can be indexed like an ordinary column, without the application computing and storing it by hand. LocusKitSchema.indices then declares an ordinary index on each generated column. This turns a hand-written functional index into a declarative, backend-portable statement. The old form looked like CREATE INDEX ... ON drawers (provenance & 0xF). The file's header comment also documents a bitmap reservation map. This map shows which bit ranges of each Int64 bitmap column are assigned, and which are free headroom. So adding a future flag means claiming a documented free bit, not running a schema migration.

LocusKitVocabulary.swift

This file provides LocusKitVocabulary, LocusKit's contribution to the write gate's vocabulary. A vocabulary here is the set of legal values a bitmap field may take. It is the fixed rulebook the write gate checks every proposed value against. A value outside the vocabulary is refused before it ever reaches storage.

LocusKitVocabulary.unionSlots declares one FieldSlot per operational and provenance field LocusKit defines. These fields include capture channel, content kind, feature flags, and source type. Each slot names its bitmap column, bit position, and width. An enumerated field's slot also lists its legal raw values. The adjective axis's vocabulary covers state, sensitivity, exportability, and trust. The write gate itself supplies that vocabulary, from SubstrateLib, not this file. unionSlots is purely LocusKit's own consumer-side addition. LocusKitVocabulary.frozen() compiles this set into a Vocabulary value once, at estate open, through VocabularyValidator.freeze. Every later write in the estate's lifetime is checked against this frozen vocabulary. It never changes after that first freeze.

EstateTypes.swift

This file provides five small supporting types used across the estate surface. RowID is a plain String type alias. It names a row's stable identifier. FrameFilteredDrawers is the result of a frame-aware by-id load. It pairs the frame-admissible drawers with the full set of ids that physically loaded. OwnerCredentials is the estate owner's identifier. It is validated non-empty at open or create time. LatticeAnchor is the four-field classification anchor every drawer carries. It holds a UDC code, plus optional Wikidata enrichment. EstateError is the error enum for Estate lifecycle failures, distinct from LocusKitError.

FrameFilteredDrawers.loadedIDs is reported apart from admissible, for a specific reason. A caller needs to tell two cases apart. The first case is an id that loaded but failed the frame's filter, a legitimate drop. The second case is an id that never loaded, a transient or partial read that must be treated as degraded, not silently dropped. LatticeAnchor.udc(_:) is a convenience constructor. It handles the common case of a bare UDC code with no Wikidata enrichment, the shape most content has before an enrichment daemon has run over it. EstateError covers three failure shapes. substrateUnavailable means the backing storage failed to open. manifestMismatch means a stored manifest value does not match what this build expects. Most importantly, the bitmap layout version must match. emptyOwnerIdentifier is raised before any storage call. So a caller gets a structurally distinct error, rather than a generic one. keychainError covers a failing Keychain call during identity key handling.

Estate.swift

This file provides Estate, the single public entry point to a LocusKit-backed memory store. An Estate is an actor. An actor is a Swift type that serializes access to its own state. So concurrent callers can never interleave two operations against the same estate unsafely. Estate owns one DrawerStore, the storage engine described below. It owns one ContainerFingerprintStore, the recall-pruning totals. It owns one NodeStore, the containment tree. It is the only public surface most callers should ever touch.

Estate.open(storage:owner:identityKeyStore:) opens an existing estate. It refuses to open a database whose manifest carries a different bitmap_layout_version than this build expects. Bitmap bit positions are part of the durable on-disk contract. So opening a database written by an incompatible future schema would silently misread every bitmap field. On first open, it also mints a fresh Curve25519 Ed25519 keypair for the estate's federation identity. The public half is written to the manifest, safe because a public key has no confidentiality requirement. The private half is handed to an injected EstateIdentityKeyStore, the Keychain in production, an in-memory store in tests. It is cached for the lifetime of the Estate instance. Estate.create(storage:owner:manifest:) is the sibling constructor for a brand-new estate. It does not mint the identity keypair, because that only happens on the first open after creation.

The bulk of the file is a set of typed pass-through reads. These exist so higher kits, chiefly GeniusLocusKit, never need to import or construct a DrawerStore. They include allDrawers, getDrawers(ids:), hydrateBodies, tunnelsFromWing, recentRecallTraces, allTunnels, retireTunnel, pruneRecallTraces, countDrawerRows, allProposals, allAssociations, allLearnedReferences, allKGFacts, allDiaryEntries, and resolveNodeNames. getDrawers(ids:matchingFrame:hydrationLevel:) is the most elaborate of these. It runs the exact same frame-filtering pipeline recall uses, but over a caller-supplied id set rather than a full corpus scan. This is the shape a dense-first candidate-pool search needs. meta(key:) and setMeta(key:value:) expose the estate manifest as a general per-estate key-value store. Higher kits can use it for durable state of their own, on the condition that they namespace their keys to avoid colliding with LocusKit's own typed manifest keys.

EstateAudit.swift

This file provides Estate's audit and history API: auditTrail(rowID:) and bitmapState(rowID:asOf:). Both delegate to the row's sealed audit log, rather than to any separate history table. The audit log, not the live row, is the estate's source of truth for what happened and when.

auditTrail(rowID:) returns every sealed AuditEvent for a row in HLC order. An HLC, or hybrid logical clock, is a timestamp format. It puts events in one order, even across machines with their own clocks. bitmapState(rowID:asOf:) rebuilds what a row's three bitmaps looked like at an earlier point in time. It does this by folding the row's audit log forward, from the beginning up to and including the requested HLC. This folding runs through SubstrateLib's AuditLogFold.projectStateAt. This is what lets a caller ask what a drawer's state looked like a week ago. LocusKit needs no separate append-only history table alongside the live row for this. The live row is redundant with the log by construction. The log is the only place that needs to remember the past.

EstateIdentityKeyStore.swift

This file provides the protocol and two implementations for persisting an estate's Ed25519 private signing key outside the manifest table. The manifest table is ordinary, unencrypted metadata. Anyone with database or backup access can read it. So the private half of the estate's federation identity keypair must never be written there. Only the public half is safe to store in the manifest.

EstateIdentityKeyStore declares two methods: loadPrivateKey and storePrivateKey. Both are keyed by the estate's UUID. KeychainEstateIdentityKeyStore is the production implementation. It stores the raw key bytes as a kSecClassGenericPassword Keychain item. The item stays accessible after the first device unlock following a restart. It is never synced to iCloud Keychain. This matches the same device-bound posture as the estate's own SQLite file. InMemoryEstateIdentityKeyStore is the test double. It is a plain dictionary guarded by a lock. It carries a _storedPrivateKey accessor. A test can use this accessor to check what was persisted, without touching the real Keychain. The real Keychain would require entitlements. It would also pollute state across test runs.

EstateVerbs.swift

This file provides the nine verb methods as an extension on Estate: capture, captureBatch, recall, withdraw, expunge, mutate, reanchor, propose, learn, and associate. It is declared as a separate file for a specific reason. It needs to reach Estate.store, which is declared internal rather than private in Estate.swift for exactly this reason.

capture(_:CaptureFrame) is the drawer entry point. It validates that content and room are both non-empty. It also validates the lattice-anchor UDC code, the actor, and the embedding-model id. It assembles the three bitmap columns from the frame's named fields, through BitField.writeField, never hand-rolled shift-and-mask arithmetic. It resolves the target wing and room to containment-tree node ids, creating them on demand. It writes the drawer through addDrawerCovered, the one sanctioned internal chokepoint. That chokepoint bundles the row insert with the container-fingerprint update. So a drawer can never be captured without its fingerprint total being updated in the same call. captureBatch(_:) is the bulk-import sibling. It resolves all wing and room node ids up front, with a per-call cache. It batches every fresh, non-superseding insert into one storage transaction, through DrawerStore.insertFreshBatch. It defers the Merkle rollup entirely. This turns a 40,000-drawer import from roughly 34 minutes of per-row commits into roughly 30 seconds.

capture(_:TunnelCaptureFrame) is the tunnel entry point. capture is legal on exactly two nouns, drawer and tunnel, and this overload handles the second. recall(_:RecallFrame) is the read path. It reads the live, non-tombstoned, candidate rows through liveRows. It runs them through BitmapEvaluator.evaluate. It optionally writes a bounded number of recall-trace rows, only when the caller opts in through frame.traceLimit. So internal and bulk-export scans never accumulate trace rows. recall returns a RecallStream. Both liveRows and the evaluation step surface any internal read failure as a named degraded stage on the returned stream, rather than silently returning an empty result. This is the mechanism by which a caller can tell a genuinely empty estate from a recall that failed partway through.

withdraw(rowID:reason:) moves a drawer's state to .withdrawn, through mutateState. This is the only correct path, because a state transition must go through the automaton's legality check. expunge(rowID:reason:confirmation:now:) is the destructive delete. It requires an explicit confirmation: true. It walks the drawer's full lineage chain, every version sharing its lineageID, so a hard delete scrubs every historical version. It always seals a sealed audit event recording the fact of the expunge, even though the content itself is gone. expungeReturningUnsealedEvent and the paired sealExpungeAudit and sealExpungeOrphanAudit methods exist for GeniusLocusKit's two-step orchestration. There, a cross-kit vector delete must happen between the storage tombstone and the audit seal. Splitting the seal out prevents any caller from suppressing the audit event by accident.

mutate(rowID:kind:payload:) dispatches on MutationKind to move a drawer along one of three axes. The first axis is confirmation, through mutateProvenance. The second is state, through mutateState. The caller-facing guards for .resolve, .accept, and .revive are implemented here. This happens before the store's automaton check even runs. So the error message is clearer. The third axis is an adjective field, sensitivity, trust, or exportability, through mutateAdjective. The .revive case is the most elaborate. It implements the full per-source-state legality table from the cookbook's revive rule. This includes the living-successor lineage check. That check refuses to revive a superseded row while a later version in the same lineage is still alive. reanchor(rowID:toRoom:toWing:toLattice:) moves a drawer's room, wing, and lattice position, without touching its bitmaps. propose(_:now:) and associate(_:now:) build a Proposal or Association from their respective frames. Each derives its lattice anchor from a specific source. For propose, the anchor comes from the target row. For associate, it comes from the first endpoint. Neither ever fabricates an anchor. learn(_:now:) catalogs the frame's source, once, keyed by handle. It writes a LearnedReference anchored to that catalog entry's genuine lattice position, never a sentinel anchor invented from a bare handle.

seedWing(_:hint:addedBy:embeddingModelID:now:) files one ordinary, fully recallable drawer per default wing, at estate provision time. This gives a fresh agent a plain-language description of what each wing is for.

Frames.swift

This file provides the frame structs that carry a verb's arguments: CaptureFrame, TunnelCaptureFrame, RecallFrame, LearnFrame, ProposeFrame, and AssociateFrame. It also provides three supporting enums: MutationKind, HydrationLevel, and Ordering. Every field on every frame is named after a domain concern, a capture channel, a sensitivity tier, a filter chain. No raw bitmap value or bit position crosses the public verb boundary anywhere in this file.

CaptureFrame carries every named axis a captured drawer's three bitmaps encode: channel, sensitivity, kind, and the matching provenance-side channel, source type, sensitivity, confirmation, and confidence. It also carries lineage, room, lattice anchor, actor, and embedding model. It carries an optional event time too, for backdated bulk ingestion. It also carries feature flags, exportability, and an optional wing. Nearly every field defaults to the value that produced the same all-zero bitmap a caller got before that field existed. So adding a new capture-time axis stays source-compatible with every existing caller. RecallFrame carries the filter chain, hydration level, page-size limit, and ordering. It also carries an optional past asOf HLC and traceLimit. traceLimit is the opt-in recall-trace write count.

MutationKind enumerates the mutate verb's seven cases: .confirm, .reject, .contest, .resolve, .supersede, .revive, and .accept. Three more cases carry a new value: .correctSensitivity, .correctTrust, and .correctExportability. HydrationLevel names the three read-cost tiers: .bitmapOnly, .structured, and .full. Ordering names the three result orderings recall supports. A relevance ordering is absent on purpose. LocusKit has no scoring signal of its own. That signal lives in VectorKit, composed on top by GeniusLocusKit. The file's comment explains that shipping a .byRelevanceDesc case here, without a real relevance signal, would be an honesty violation.

DrawerStore.swift

This file provides DrawerStore, the actor that owns every table in the schema. It implements the full CRUD and mutation surface for all nine nouns. It is the largest file in the package. Almost every write in the estate lands here in the end.

DrawerStore.init(storage:hlc:) opens the schema. This is idempotent: a second open on an existing database is a no-op for tables and indices. It freezes the write-gate vocabulary once. It populates the v1 manifest defaults, writing each key only if absent, so a first-open value is never overwritten by a later open. It classifies the manifest's estate_uuid value into one of three outcomes. The first outcome is absent: a genuinely fresh estate, resolved to a freshly minted UUID. The second outcome is present and well-formed, the normal case. The third outcome is present but unparseable. This third outcome throws corruptStoredValue, rather than silently fabricating a random replacement UUID, because conflating corruption with a fresh estate would mask real data loss. The HLC clock's node id is derived from that same classified value, by hashing the raw stored text. So a standalone estate gets a stable, estate-specific clock identity. A Rust port of the same estate derives that identity identically.

The gated write path is the file's central pattern. It is used by addDrawer, mutateProvenance, mutateAdjective, mutateOperational, mutateState, expungeGated, and reanchorGated. Each of these reads the row's current bitmaps inside a serializable transaction. Each decomposes the proposed new value into per-field FieldWrites, never a whole-column replacement. This is what lets the gate validate each field on its own. It also lets the gate check the forbidden-combination invariant on the merged result. Each calls AuditGate.admit, a SubstrateLib primitive. On success, each writes both the merged projection column and the sealed AuditEvent, in the same transaction. gatedColumnWrite is the shared helper behind the three whole-column mutators. It excludes the adjective bitmap's state field from the field list, because state is verb-driven and must never move through a field edit. mutateState also checks the verb against the caller's requested target state. Both must agree with what the automaton's transition table produces. The verb itself is a RowVerb value. So an illegal from-via-to triple is rejected before any row is touched.

addDrawer implements the supersession cascade. Sometimes the new drawer's lineageID matches an active predecessor. findActivePredecessor finds this match, through an indexed query on the generated state-cluster column. When a match exists, addDrawerWithCascade inserts the successor and a .supersedes tunnel in one transaction. So a failed tunnel insert never leaves an orphaned successor row. addDrawerWithCascade then separately flips the predecessor's state to .superseded, through the normal gated mutateState path. insertFreshBatch is the bulk-import sibling used by EstateVerbs.captureBatch. Every drawer in the batch already has no active predecessor. The caller pre-verifies this before the batch runs. Each drawer is inserted and gated inside one single transaction. This eliminates per-row commit overhead.

expungeGated is the lineage-wide hard delete. It tombstones the target drawer through the gate. It zeroes the drawer's content. It sets the dreaming_recalc_required obligation flag. It records the event in the erasure ledger. It then repeats a content scrub across every other member of the lineage chain. Where the state transition is legal, it also repeats a full gated tombstone. A sibling whose state cannot legally transition to tombstoned, an audit-grade accepted row forbidden by invariant S-3, still has its content zeroed no matter what. The destruction contract is stronger than the state machine. Leaving verbatim content behind, when the gate refuses the state flip, would be a privacy violation. sealExpungeAudit, sealExpungeOrphanAudit, and sealExpungeOrphanForSweep support GeniusLocusKit's two-step orphan recovery. This recovery matters when a crash separates the storage tombstone from its audit seal. tombstonedRowsWithoutExpungeAudit is the query the recovery sweep uses to find rows stuck in that crash window.

The remainder of the file provides CRUD for the other eight nouns. Tunnel CRUD includes addTunnel, getTunnel, tunnelsFrom, tunnelsTo, and allTunnels. It also includes the tunnel-retirement pair retireTunnel and unretireTunnel. It includes the outline helpers outlineChildren, outlineAncestors, and reparentDrawer. Fact CRUD includes addKGFact, getKGFact, kgFacts(forDrawerID:), and withdrawKGFact. Proposal CRUD includes addProposal, getProposal, and proposals(forTargetRowID:). Association CRUD includes addAssociation, getAssociation, associationsFrom, and associationsTo. Learned-reference CRUD includes addLearnedReference, getLearnedReference, and learnedReferences(forSourceCatalogID:). Source-catalog CRUD includes addSourceCatalogEntry, getSourceCatalogEntry, and sourceCatalogEntry(forHandle:). Diary CRUD includes addDiaryEntry, getDiaryEntry, and readDiary. The file also provides the recall-trace surface: insertRecallTrace, insertRecallTraces, recentRecallTraces, markRecallTraceUsed, markRecallTracesUsed, pruneRecallTraces, and countRecallTraces. It provides the manifest surface: setMeta, getMeta, and readManifest. It provides the node-tree name-resolution helpers: roomNodeIdsInWing, roomNodeId, and resolveNodeNames. It provides the summary surface: listWings, listRooms, and taxonomy. It provides the temporal-read surface: fingerprintsCaptured(in:) and fingerprintBitSeries. These feed the FFT-based rhythm-spectrum and moment-summary lenses built on top of LocusKit.

Every row-decode function follows the same resilience pattern. drawerFromRow and its siblings throw corruptStoredValue for a clearly malformed stored value, such as a non-UUID lineageID or an unparseable timestamp. Corpus-scan callers instead route through decodeDrawerRowsSkipCorrupt. This function logs and skips a corrupt row, rather than aborting an entire estate-wide scan. Point lookups fail loud. Corpus scans degrade gracefully.

Drawer.swift

This file provides Drawer, the value type behind verbatim content. A Drawer is the thing callers file, and the thing recall returns. Its content field is preserved unchanged, with no truncation and no normalization. The verbatim-first contract requires retrieval to surface exactly what was filed.

Every drawer references its containing room by parentNodeId, a foreign key into the nodes table, rather than storing wing and room names. Display names are resolved separately, through DrawerStore.resolveNodeNames. filedAt and eventTime are two distinct clocks. filedAt is the ingest clock. It marks when the row entered the local store. It is monotonic, and it anchors audit ordering. eventTime is when the content happened, or was authored, in the world. For streaming capture the two clocks coincide. A bulk backfill importer instead supplies a real, possibly much earlier, eventTime. The three bitmap fields, provenance, adjectiveBitmap, and operationalBitmap, all default to zero. The four lattice fields are udcCode, udcFacets, wikidataQID, and wikidataQidsSecondary. They locate the drawer in the classification lattice. udcCode is required non-empty at every capture path, per invariant I-5. Drawer's custom Codable conformance backfills a missing eventTime to filedAt on decode. So a row encoded before the eventTime column existed still decodes to a sensible value.

DrawerFingerprint.swift

This file provides the derivation of a drawer's 256-bit structural fingerprint. This fingerprint is the coordinate system LocusKit uses for structural similarity and for recall pruning. A fingerprint is built from four 64-bit SimHash blocks. Each block is a projection of one facet of the row, through its own family of random hyperplanes. The first block is bitmap: the three bitmap columns. The second is lattice: UDC prefix, direct Q-ID, and Q-ID closure. The third is lineage-and-temporal: lineage hash and capture week. The fourth is channel-and-source: channel, source type, capture channel, sensitivity, and an estate identity hash.

EstateFingerprintFamilies derives the four hyperplane families for one estate from its UUID, once, at estate open. Two replicas of the same estate, started on their own, still share the same UUID. So they always derive the same families. So they derive the same fingerprint for the same drawer content. This determinism property is what recall pruning depends on. EstateFingerprintFamilies.fingerprint(of:) is the per-drawer entry point. It resolves the drawer's Wikidata Q-ID, if the drawer has one, through LatticeLib.QIDClosure. This gives the drawer's full ancestor chain. It folds that chain into a 16-bit hash for the lattice block's qidClosureHash slot. It hands all four assembled inputs to SubstrateLib.SimHash. Some fields do not apply to a drawer: lineage-clustering, defer-pattern, and stream-source data. These fields only apply to a different noun type, AmbientSample. For a drawer, they default to a null value of zero, per invariant I-17. This default keeps Hamming distance well-defined across every noun type that shares the same fingerprint shape.

DrawerOperational.swift

This file provides the three named axes packed into Drawer.operationalBitmap. The first is CaptureChannel: how the content entered the system. Its values are typed, voiced, OCR, imported file, sensor, and actuator. The second is ContentKind: the shape of the content. Its values are prose, code, transcript, list, structured JSON, image caption, and fingerprint-only. The third is DrawerFeatureFlags: a non-exclusive bitset of seven named flags. The flags are attachments, voice, image, links, pinned, keystone, and locked-zone. Feature flags form a bitset, not an exclusive choice. So DrawerFeatureFlags is declared as an OptionSet. The other two axes in this file are declared as enums instead.

Each axis has a computed accessor on Drawer: captureChannel, contentKind, featureFlags, hasFeatureFlag(_:), stateExtensionActive, and lineageClusteringActive. Each accessor decodes the relevant bit range. Each falls back to a safe neutral default, typed input or prose content, for any raw value this build does not recognize. So a row written by a future version, with a case this build has never heard of, degrades gracefully instead of crashing.

DrawerStateValidator.swift

This file provides DrawerStateValidator, a thin bridge from LocusKit's State enum to SubstrateLib's canonical RowStateAutomaton. This automaton is the single implementation of the row-state legal-transition table. Every LocusKit noun with a state axis is validated against it. DrawerStateValidator used to carry its own parallel transition table. That table permitted four transitions the specification actually forbids, including accepted to tombstoned. So it was retired, in favor of using SubstrateLib itself.

validate(from:to:via:) is the transition-legality-only overload, used by StateTransitionTests. It bridges State to RowState. It looks up the legal target for the from-and-via pair in the automaton. It throws LocusKitError.disciplineViolation when a check fails, naming the rule violated. A check fails in either of two ways. The from-via pair may have no legal transition. Or the caller's requested target may disagree with what the automaton actually produces. validate(from:to:via:targetingFields:) is the overload DrawerStore.mutateState actually calls. It also checks field-level invariants against the post-write bitmap fields, in the same call. One such invariant, S-1, requires that an accepted row have trust at or above canonical. Other invariants cover further bitmap-combination rules, such as S-2.

Adjectives.swift

This file provides the four cross-noun adjective axes: State, Trust, AdjectiveSensitivity, and AdjectiveExportability. It also provides their computed accessors on Drawer. These four enums are the single source of truth for these axes, across every LocusKit consumer, including GeniusLocusKit and NeuronKit. Layers beneath LocusKit cannot import them, because the dependency graph points the other way. So those layers carry the raw integer encoding instead. A build-time Guardian tool checks that the two sides never silently drift apart.

State has ten cases. They partition into three clusters, at raw-value boundaries sixteen and thirty-two. These boundaries let a state's cluster be computed as one shift-and-mask operation. Cluster A is "currently believed": active, pending, contested, and accepted. Cluster B is "knew past": superseded, decayed, withdrawn, and expired. Cluster C is terminal: rejected and tombstoned. Drawer.isCurrentlyBelieved, isKnewPast, and isTerminal expose these three clusters as predicates.

Trust orders seven levels. The lowest is .verbatim, unqualified as-filed content. Levels rise through .canonical up to the highest, .ambient. It conforms to Comparable. So a filter like "trust at least canonical" reads as an ordinary comparison, rather than raw-value arithmetic. AdjectiveSensitivity and AdjectiveExportability are both scale-gapped. Their case raw values skip numbers, leaving room for future intermediate tiers without disturbing any existing bitmask. AdjectiveSensitivity carries three ADR-007-driven predicates: isBulkExportable, requiresOwnerKeyForBulk, and isExcludedFromBulk. These are the enforcement hooks VaultKit's bulk-export path consults, to decide whether a drawer may ride a bulk channel without additional friction. Drawer.dreamingRecalcRequired and Drawer.sealed decode two single-bit obligation and trust-hint flags, living above the four main axes.

Provenance.swift

This file provides the seven named axes packed into Drawer.provenance: SourceType, Channel, a mirrored CaptureChannel reference, Confirmation, Confidence, Sensitivity, and EnrichmentStatus. It also provides their computed accessors on Drawer. The adjective bitmap records a row's current standing. The operational bitmap records mechanical facts about the content. The provenance bitmap records something different: how the row came into being, and how it has been reviewed since.

SourceType names ten origins: user, observed, imported, canonical, derived, federation-aggregate, tier-aggregate, paired-estate, ambient, and actuator. Channel names the system surface content arrived through: UI typed input, UI voiced input, an MCP agent, a file import, federation, or a dreaming-daemon channel. Confirmation is the review axis. Its levels run from unconfirmed through user-confirmed, automated-confirmed, peer-confirmed, and actuator-confirmed. isUserConfirmed is the convenience predicate retrieval layers use, to surface only user-vetted content. Confidence and Sensitivity are both scale-gapped. Confidence orders from .null to .verified. Sensitivity mirrors the raw values of AdjectiveSensitivity on purpose. So the two axes can be compared directly: sensitivity at capture, versus the estate's current access posture, which may since have been mutated. EnrichmentStatus tracks a Q-ID enrichment daemon's lifecycle for a row. It usually ends at .qidCompleted. When deterministic re-inference fails instead, it ends at the terminal in-workflow state .qidProposed.

BitmapOps.swift

This file provides three small, @inlinable field-extraction helpers: andMask, thresholdCompare, and shiftExtract. BitmapEvaluator uses them to translate a Filter case into a check against a packed Int64 bitmap. These helpers are not math primitives. They carry no algorithm to prove. They need no platform-specific optimization to gate. The substrate primitives are different: SimHash, Hamming distance, and OR-reduction live in SubstrateLib. Those primitives participate in the cross-platform conformance gate. Each function here delegates its actual bit manipulation to a SubstrateLib primitive: BitField.maskedEquals, BitField.extractField, or BitField.popcount. So LocusKit never hand-rolls a shift-and-mask sequence that could silently diverge from the Rust port's equivalent.

andMask(_:mask:expected:) tests whether a field equals an expected, already-shifted value, in one masked comparison. thresholdCompare(_:mask:shift:op:value:) extracts a field. It compares the field against a threshold. The comparison uses one of three orderings: .lessThan, .lessThanOrEqual, and .greaterThanOrEqual. This is the mechanism behind cluster-boundary filters, such as "trust below the action threshold." shiftExtract(_:shift:mask:) returns a field's raw integer value. It is used wherever the evaluator needs the value itself, rather than a yes-or-no comparison.

ForbiddenCombinationValidator.swift

This file provides ForbiddenCombinationValidator. It documents one core rule: a forbidden bitmap combination. Where a live call site exists, it also enforces that rule. The rule: a row must never carry adjective sensitivity .secret together with adjective exportability .public_. Storage can physically represent that combination. Nothing stops the bits from being set. The verb layer still must refuse to produce it. Current write paths route this check through AuditGate and SubstrateLib. So this validator itself has no live call site today. It exists as an explicit, reviewable statement of the rule. It stays ready to be wired in, wherever a future write path bypasses the gate.

validate(_:) extracts two fields from a full adjectiveBitmap value. The sensitivity field spans bits six through eleven. The exportability field spans bits twelve through seventeen. It throws LocusKitError.disciplineViolation if both match their forbidden raw values, 48 and 32. These raw values are hand-derived from the enum cases' shipped values, rather than imported. This is deliberate, so a future rename of an enum case cannot silently change what this validator checks.

Filter.swift

This file provides Filter, the named recall-filter algebra. It also provides five small supporting type aliases: LineageID, RoomID, WingID, WikidataQID, and ProvenanceChannel, FeatureFlag, plus the StateCluster enum. No Filter case takes a raw bit position, mask, or threshold integer. Every case names a domain concern, such as .trustworthy, .inRoom(_:), or .contentMatches(_:). BitmapEvaluator is the sole place that translates a Filter into the bitmap primitives internally.

The cases group by concern. State queries include .currentlyBelieve, .usedToBelieve, .knewOnceAndErased, .state(_:), and .stateInCluster(_:). Trust queries include .trustworthy, .requiresConfirmation, .trust(_:), and .trustAtMost(_:). Other groups exist too. Sensitivity and exportability queries form one group. Provenance queries form another: confirmation, source type, channel, and confidence. Operational queries form a third: capture channel, content kind, and feature flags. Structural queries cover room, wing, lineage, time bounds, lattice anchor and prefix, and Wikidata concept. One content query, .contentMatches(_:), searches text. Three composition cases let filters nest arbitrarily: .all, .any, and .not. A RecallFrame.filterChain is a plain array of Filter values. It is interpreted as an implicit .all. Every filter in the chain must pass.

BitmapEvaluator.swift

This file provides BitmapEvaluator, the compiler and interpreter for a RecallFrame.filterChain. This is the heart of the recall pipeline. It is declared internal rather than public, because it takes a DrawerStore argument, itself internal. Public callers reach it only indirectly, through Estate.recall.

evaluate(frame:drawers:store:nodeNames:) runs four stages. These stages run against the candidate row set its caller has already narrowed down, through Estate.liveRows, which applies fingerprint pruning ahead of this call. The first stage is default insertion. It prepends implicit filters for any concern the caller left unconstrained. State defaults to .currentlyBelieve. Trust defaults to .trustworthy. Sensitivity defaults to .sensitivityAtMost(.elevated), the Normal-tier ceiling per ADR-007. So recall with an empty filter chain returns only content by default: currently believed, trustworthy, and normal-or-elevated in sensitivity. A caller need not spell any of this out. The second stage is bitmap-tier evaluation. It compiles each Filter case to a check over the row's three raw bitmaps, using the BitmapOps.swift primitives. Tombstone exclusion is always enforced here, apart from the caller's chain. A tombstoned row can never surface through recall, no matter what the chain says. When frame.asOf is set, each row's bitmaps are first rebuilt as they stood at that past HLC. This rebuild runs through AuditLogFold.projectStateAt, before the bitmap tier runs. The third stage is structured-tier evaluation. It applies filters that need the drawer's non-bitmap fields: room, wing, lineage, time bounds, and lattice. For room and wing filters, it also needs a resolved node-name lookup. The fourth stage is content-tier evaluation. It applies .contentMatches, through a case-insensitive substring search over the verbatim content. A final ordering pass then sorts the survivors.

chainHasPrunableFilter, chainHasContentPredicate, and chainHasStructuredNameFilter are classifiers. Estate.liveRows and Estate.getDrawers(ids:matchingFrame:hydrationLevel:) consult them before even fetching rows. The first classifier decides whether fingerprint pruning can apply at all. The second decides whether the fetch needs to pay for the content blob. The third decides whether a node-name lookup is needed. containerSurvives(chain:fingerprint:) is the actual pruning predicate. It returns false only when the chain provably cannot be satisfied by any row in a container. This is sound only for set-bit filters, such as .hasFeatureFlag. A threshold or exact-value filter can never be decided from an OR-reduced fingerprint alone. So those filters never prune a container. They only ever get evaluated per row.

Tunnel.swift

This file provides Tunnel, the typed cross-reference between two locations in the estate. A tunnel is stored directionally: from a source endpoint to a target endpoint. Each endpoint carries a wing and a room. Each endpoint also carries an optional specific drawer id. A nil id means the room itself is the endpoint. So a query asking what this side knows about never needs to scan both directions. kind is a TunnelKind. This is the closed, indexed relationship vocabulary the retrieval layer dispatches on. label is a free-form, unvalidated human annotation. orderKey is a fractional-index sibling ordering value. It is used only by .parent tunnels in the outline graph, per ADR-017. Siblings under the same parent sort by ascending orderKey. So no sibling needs to be rewritten when a new one is inserted between two existing siblings.

This file also provides Tunnel.adjectiveSensitivity. This computed accessor decodes bits six through eleven of adjectiveBitmap as an AdjectiveSensitivity. An unrecognised raw value falls back to .normal. This fail-closed default matches KGFact.adjectiveSensitivity and Drawer.adjectiveSensitivity. The accessor is named adjectiveSensitivity, not sensitivity, so it does not collide with the provenance-bitmap sensitivity accessor pattern used elsewhere in LocusKit.

TunnelOperational.swift

This file provides TunnelKind, the ten-case closed relationship vocabulary. Its cases are: .supersedes, .references, .blocks, .validates, .contradicts, .derivesFrom, .covers, .elaborates, .respondsTo, and .parent, the outline-containment edge. This file also provides the four operational axes packed into Tunnel.operationalBitmap: TunnelDirection, TunnelLifecycle, TunnelOriginClass, and TunnelStrength, plus their accessors.

Two bits above those four axes carry standalone boolean flags, rather than enumerated fields. hasInverse records whether a paired reverse tunnel exists. isRetired is bit 13. The T13 mechanism, per ADR-021, added this bit for dreaming retirement. withRetired() and withUnretired() return a copy of a tunnel with that bit flipped. This is the reversible mechanism by which the dreaming pipeline's OMEGA cycle suspends a tunnel from active reads, without tombstoning it. So a later co-recall can re-propose the same pairing. A separate provenance-bitmap section adds isDreamed, bit 0 of provenanceBitmap. This flag is set only for tunnels the dreaming pipeline itself proposed and later accepted. It is never set for a user-explicit, imported, or federated tunnel. OMEGA's retirement predicate requires isDreamed == true. So a declared tunnel is never retired, no matter how much or little it is recalled.

DiaryEntry.swift

This file provides DiaryEntry. This is the first-person record of what an agent thought, did, or learned at a point in time. A diary entry is stored alongside drawers. It is queried separately, keyed by agentName and an unvalidated topic tag. So one agent's diary never leaks into another agent's wing-filtered recall by accident. This is a convention, not an enforced constraint. wing and room are plain required strings the caller supplies. reward and rewardProvenance are the explicit quality-signal channel. When a caller has a direct quality score for an entry, such as a user rating or a model confidence value, it is recorded here. Otherwise it is left for the dreaming daemon's implicit recall-based reward inference to guess at later.

DiaryOperational.swift

This file provides the four axes packed into DiaryEntry.operationalBitmap, plus a single flag bit and their computed accessors. DiaryEventClass has twelve cases. It records what kind of substrate event this entry describes: capture, mutation, withdraw, expunge, propose, associate, learn, signal emission, maintenance, migration, training, or audit-tombstone. DiarySeverity is scale-gapped, with four levels: trace, info, warning, and error. DiaryActorClass records who produced the entry: user, substrate daemon, MCP agent, migration tool, or federation peer. DiaryBatchMembership has four values: standalone, batch-start, batch-member, and batch-end. The single flag bit is requiresFollowup.

KGFact.swift

This file provides KGFact, a subject-predicate-object triple distilled from a verbatim drawer. It retains sourceDrawerID as a backreference, so a fact's provenance is always recoverable. subject, predicate, and object are all free-form strings at this rung. The value type itself enforces no entity vocabulary. That enforcement, when it arrives, belongs to a later federated knowledge-graph layer. sourceDrawerID may legitimately be an empty string. An empty string is an unanchored-fact sentinel. A caller uses it when asserting a freestanding triple, one not extracted from any specific drawer.

KGFact reuses the same three-bitmap pattern every other bitmap-backed noun uses. Its adjective accessors are state, adjectiveSensitivity, exportability, and trust. These decode the same bit layout Drawer uses. So a fact and its source drawer can be filtered by the same retrieval predicates. They share the same encoding.

KGFactOperational.swift

This file provides the four axes, plus one flag, packed into KGFact.operationalBitmap. KGExtractorClass has six cases. They are ordered roughly by rigor: manual, foundation-model, specialized-model, rules-based, imported-KG, and federated. KGAssertionKind has four cases: asserted, inferred, hypothesized, and contradicted. The last case records that another fact disputes this one, without either fact being retracted. Resolution is deferred to retrieval time. KGSpecificity and KGConfidenceBand are both scale-gapped and Comparable. So a filter can read as fact.specificity >= .specific. The isCanonical flag marks a fact promoted to estate-wide, load-bearing status.

Proposal.swift

This file provides Proposal, a suggested change awaiting confirmation. It is the durable record produced by the substrate's only autonomous write surface. Proposal structurally mirrors KGFact, with one addition KGFact predates: a required latticeAnchor. KGFact was written before the cookbook universalized the every-row-has-an-anchor invariant. candidateState is the adjective set the proposal would apply to its target, if accepted. The accept path reads this value, to know what to write. Proposal.state decodes the proposal's own lifecycle position, from its adjective bitmap's state field, the same field Drawer.state decodes. This position starts at pending, while the proposal awaits confirmation. It then moves to accepted, rejected, or withdrawn.

ProposalOperational.swift

This file provides the five typed axes packed into Proposal.operationalBitmap. ProposalKind has nine cases. It records what kind of write this proposal proposes: .newTunnel, .mutateDrawer, and seven more, including the newer .actionProposal, .recordObservation, and .tierAdvisory. ProposalTargetObjectType records which kind of row this proposal targets. This includes the .noneBrandNew sentinel, for a not-yet-existing target. It also includes .systemState, for a proposal about the estate itself. ProposalConfirmationSource has four values: human, agent, automated threshold, and actuator. ProposalGeneratedByClass has five values: dreaming daemon, MCP agent, federation sync, manual, and tier aggregator. ProposalConfidenceBucket is scale-gapped and Comparable.

This file notes that the operational layout for ProposalKind and its siblings comes straight from the engineering cookbook, rather than being LocusKit-internal. So a conformance test pins every field position and raw value against the cookbook table. composeOperational(kind:targetObjectType:generatedBy:confidence:) assembles a full operational bitmap from four of the five axes, in one call. Confirmation source is left at its default, until a confirmation step actually runs. Autonomic daemon sinks use this function. They need to stamp genuine provenance on the proposals they emit.

Association.swift

This file provides Association, the graph edge recording that two rows belong together. This is a statistical or dreaming-derived pairing, distinct from a Tunnel's typed semantic claim. Association structurally mirrors Tunnel: a source and target endpoint, three bitmap columns, and the Rev 1.0 soft-delete reservation. Two differences set it apart. It carries no kind column. An association's semantics live entirely in its operational bitmap. It also carries a required latticeAnchor, anchored to the lattice midpoint of its two endpoints. Tunnel predates this requirement, so it lacks the field.

AssociationOperational.swift

This file provides the three axes packed into Association.operationalBitmap. AssociationSignalSources is a twelve-bit bitset, an OptionSet rather than an enum, because more than one signal can support the same pairing on its own. Its signals include a co-recall signal, a co-confirmation signal, a dream-pairing signal, a vector-similarity signal, a shared-entity signal, an explicit-human signal, a fingerprint-similarity signal, and three v0.36 additions: cross-estate, cross-tier, and action-outcome. AssociationDecayClass is scale-gapped and Comparable, with four levels: pinned, slow, normal, and fast. This axis records how quickly an association ages out of relevance. AssociationArity is binary today. An n-ary form is reserved for a future version, per invariant I-23's current binary-only limit.

LearnedReference.swift

This file provides LearnedReference, the durable record of an external reference the grounding-driven learn verb brought into the estate. It structurally mirrors Association: an id, content columns, a required latticeAnchor, three bitmap columns, and the soft-delete reservation. Association was chosen as the template because it is the freshest content-bearing noun that already honors the anchor requirement. sourceCatalogID is a foreign-key reference to the SourceCatalogEntry this reference was learned from. It is stored as an identifier string, the same way KGFact stores sourceDrawerID, rather than embedding the full catalog entry inline. handle is the reference's own locator. It is distinct from the source's own locator, on the catalog entry it points into.

LearnedReferenceOperational.swift

This file provides the four axes packed into LearnedReference.operationalBitmap. RefreshPolicy is scale-gapped and Comparable. Its order runs from none through monthly, weekly, daily, on-demand, and realtime. DriftSeverity is scale-gapped and Comparable, with four levels: none, minor, major, and critical. This axis records how far a reference has drifted from its source, since it was last re-grounded. LearnMode is a single bit. It records how the reference was acquired. .byReference means the reference is held by pointer. .byIngestion means its content was ingested wholesale. LearnedReferenceSource records where the reference was acquired from: user, federation, household pairing, fleet pairing, tier inheritance, or paired estate. This is distinct from sourceCatalogID, which names which catalog entry the reference came from, not how the reference arrived.

SourceCatalogEntry.swift

This file provides SourceCatalogEntry, the durable, queryable record of an external source from which references are learned. It is the substrate behind the source slot of the learn verb. Its reason for existing is grounding integrity. Every LearnedReference must carry a genuine lattice anchor, never a fabricated sentinel. An anchor is a property of the source: a web domain, a document corpus, or a paired estate. It is not a property of each individual handle learned from it. Cataloging a source once lets every reference from it inherit that catalog entry's anchor. This is what makes a genuine anchor available, without inventing one per reference. SourceKind names six source classes: user, federation, household pairing, fleet pairing, tier inheritance, and paired estate. This is the same vocabulary LearnedReferenceSource uses, on purpose. The acquisition channel a reference was learned through is the same vocabulary as the kind of source it came from.

Node.swift

This file provides Node, a container node in the estate's containment tree. The estate root sits at depth zero. A wing sits at depth one. A room sits at depth two. Every node carries two name fields. displayName preserves whatever casing the first writer used. lookupName is a normalized form: Unicode NFC, trimmed, with internal whitespace collapsed and casefolded. This normalized form is used for lookup and to keep names unique. So "Personal " and "personal" resolve to the same node. The node's display name still shows the casing it was first written in. lifecycle has two values, active or tombstoned. A pair of HLC-typed timestamps, createdHlc and tombstonedHlc, support this. They let the containment tree read its own past state, the same way drawers do. Neither needs a wall-clock timestamp to double as the ordering key. Node.normalizeLookupName(_:) is the single, conformance-relevant normalization function. Both the Swift and Rust ports must produce byte-identical results from it.

NodeStore.swift

This file provides NodeStore, the actor that owns the containment tree's storage. It also owns the tree's create-on-demand lookup. Given a display name and a parent id, it finds the active node with that normalized lookup name under that parent, or creates one if none exists. NodeStore is an actor for a specific reason. This find-then-insert sequence stays race-free without needing an INSERT OR IGNORE clause or a conflict-column mechanism. Two concurrent requests to create the same wing under the same estate serialize through the actor. So they produce exactly one node. The second request's findActiveNode call cannot run until the first request's insert has completed.

createNode(displayName:parentId:now:) enforces two structural invariants before writing. The parent must already exist, per invariant I-NT-5. The new node's depth is the parent's depth plus one. This depth must not exceed two, per invariant I-NT-2. A room cannot have a child, because there is no fourth tier. createRoot(displayName:now:) is the once-per-estate seed for the depth-zero root. It enforces that exactly one root exists, per invariant I-NT-1, by returning the existing root unchanged if one is already present. Tombstoned nodes are invisible to lookup. A tombstoned wing does not block a later request for a wing with the same name. It also cannot be reused by mistake, for that later request. This is the no-resurrection guard, per section five.

NodeBundleStore.swift

This file provides NodeBundleStore, persistence for the bundle-algebra count-vector totals. One row exists per node, room or wing, per bundle kind. Each row is stored in the node_bundles table. A count-vector here is a 256-element array of counts, one per fingerprint bit, encoded as 1024 bytes of little-endian UInt32 values. BundleKind.activeA is the active centroid, a fold of a node's currently active members. BundleKind.departedB is the departed accumulator, eager-folded at departure time. The per-row drawer fingerprints that feed these totals are never themselves stored. Only the folded total is stored. This keeps the table small, no matter the estate size.

put, get, and rooms(forWing:kind:) are the read-and-write surface. encodeCounts and decodeCounts handle the wire format. decodeCounts throws LocusKitError.invalidContent, rather than trapping, when a stored blob is not exactly 1024 bytes. So a corrupt row surfaces as a recoverable error, instead of crashing the process.

BundleMaterializer.swift

This file provides BundleMaterializer, the operation that computes a Bundle A total from live drawers. It is the first real consumer of SubstrateKernel.countFold256. Bundle A cannot be maintained bit by bit. Active membership changes over time, and the fold operation has no subtraction. So Bundle A is fully recomputed on demand, typically by a periodic dreaming tick.

materializeRoom(wing:room:now:) fetches every non-tombstoned drawer in a room. It filters to State.isClusterA rows, the currently believed ones. It derives each survivor's Fingerprint256, through EstateFingerprintFamilies. It folds the set with kernel.countFold256. It stores the result. rollUpWing(wing:now:) merges a wing's already-materialized room bundles into one wing-level bundle. The count-vector fold is associative. So this merge produces the same result as folding every active drawer in the wing. Rooms may be materialized in any order before the wing roll-up runs.

Fingerprint256Adapters.swift

This file provides a small marshaling convention. It packs a single Int64 bitmap column into block zero of a Fingerprint256, with blocks one through three zeroed. This lets a per-column bit operation route through a SubstrateLib primitive instead: an OR, an XOR, or a popcount. That primitive operates at the substrate's canonical 256-bit width. LocusKit avoids reimplementing the same math at Int64 width this way. This file is explicit that the convention is purely a type-shape choice, with no algorithm of its own. The file also warns that this packing differs from the cookbook's Bitmap-LSH SimHash interpretation of block zero. A caller must not mix the two uses of the same 64-bit lane.

init(int64Column:) and the int64Column computed property are the pack and unpack directions. They are used throughout ContainerFingerprintStore.

ContainerFingerprintStore.swift

This file provides ContainerFingerprintStore, the per-container OR-reduction totals. These totals make fingerprint-based recall pruning possible. For every room, the store keeps the bitwise OR of the three bitmap fields, across every active drawer in that container. It also rolls this total up to every wing. OR is monotone. So a container's total can only ever gain bits as content is added. So a bit absent from the total is provably absent from every row in the container. This is exactly the soundness property recall pruning needs. A filter requiring that bit can safely skip the whole container, without fetching a single row.

orIn(wing:room:adjective:operational:provenance:now:) is the incremental maintenance path. It runs on every drawer capture. It folds the new drawer's bitmaps into both the room-level and the wing-level row, through ContainerFingerprint.merging(_:). That function itself routes through SubstrateLib.ORReduce.reduce, at canonical 256-bit width, using the Fingerprint256 packing convention above. The clear side is absent on purpose. Withdrawing or expunging a drawer never clears bits from the total. A stale set bit is a harmless over-approximation. It can only cause an unnecessary scan, never a missed match. Meanwhile, three other functions exist for a different purpose. They are rebuildRoom, rollUpWing, and rebuildAll. They tighten the total back down, now and then, from a fresh full scan. rebuildAll is what Estate.open calls once at startup. So an existing estate's total is guaranteed complete, and thus sound, before any recall runs against it.

MerkleRollup.swift

This file provides the Merkle content-integrity rollup, an extension on Estate. It computes a hash tree from the bottom up: room, then wing, then estate. This hash tree covers the same containment tree NodeStore maintains. A Merkle tree is a hash tree where each parent's hash is computed from its children's hashes. So a single top-level root hash can attest to the exact contents of an entire subtree. Changing any leaf changes every hash on the path up to the root. A caller must invoke the rollup by hand. It does not run on its own after every write. Computing it inline on every drawer capture would be costly. The cost would be proportional to room size, on every write. This would peg the CPU during a bulk import.

computeRoomMerkleRoot(roomNodeId:) hashes a room's live drawers. It reads each row's stored content_hash column when present, written by a separate hash-on-write hook. It computes a leaf hash on demand from the drawer's content when the column is absent. It always excludes two kinds of rows from the snapshot. The first kind is tombstoned rows. These rows are irreversibly deleted. The second kind is withdrawn rows, at state raw value 18. A withdrawn drawer's content has been retracted by the user. So it must not remain retrievable through a content-attesting snapshot. computeEstateOrWingMerkleRoot(parentNodeId:) hashes a set of children's already-computed roots. The same function serves two levels. At the wing level, it hashes room roots. At the estate level, it hashes wing roots. rollupMerkleRoots(roomNodeId:now:) runs all three levels for one changed room. recomputeAllMerkleRoots(now:) is the full bottom-up recompute, used after bulk import, migration, or corruption recovery. rollupAllMerkleRoots(now:) is a documented alias of the full recompute, named for the batch-capture reindex path. createSnapshot(label:now:additionalAttestations:) recomputes the full tree, so a snapshot is never taken against stale roots. It then writes an attestation row for the estate root and every wing, plus any attestations a higher composition-layer kit supplies.

Manifest.swift

This file provides ManifestKey, the eighteen required and seven optional typed keys of the v1 manifest key-value table. It also provides ManifestValues, the typed, read-only snapshot DrawerStore.readManifest() produces. The manifest table itself is a plain key-value store. This file turns a table of plain strings into a fully typed record a caller can rely on. ManifestKey.ed25519PublicKey and ed25519PrivateKeyWrapped are the two identity-related keys. ed25519PublicKey is the estate's federation public key. It is safe to store here, because a public key has no confidentiality requirement. ed25519PrivateKeyWrapped is different: a reserved, never-written seam. It exists only for backward read-compatibility, with an estate opened before the Keychain migration. The private key itself lives exclusively in EstateIdentityKeyStore.

DefaultWings.swift

This file provides the seven default wing definitions. These are seeded into a fresh estate at provision time. It also provides three related constants. defaultWingName is "Agentic Memory," the wing capture uses when a caller supplies no explicit wing. hintRoom is "AI_Charter_Hint," the room each seeded wing's hint memory lives in. hintUDCCode is "001," the UDC Knowledge-class code stamped on hint drawers. Each WingDefinition pairs a wing name with a plain-language hint describing the wing's role. The seven wings are: Agentic Memory, User Canon, Source Corpus, Personal, Professional, Projects, and Temp. Each hint is seeded as an ordinary, fully recallable, user-deletable drawer. So a fresh agent has a working orientation to its own memory structure, from its first session. The set is only a suggestion, not a fixed schema. An agent may create any extra wing it needs.

RecallStream.swift

This file provides RecallStream, the paged async sequence Estate.recall returns. Iterating a RecallStream produces one RecallPage at a time. The first page arrives synchronously, on the first next() call. Later pages arrive lazily. isLast is true only on the final page. So a caller can drive a uniform for await loop, without special-casing an empty result. A genuinely empty corpus still emits exactly one page, with zero rows and isLast == true.

degradedStages is the channel by which a failed internal read becomes observable to a caller. A failed read might come from several places: the bounded corpus scan, the room-fingerprint enumeration, a room's drawer read, or the bitmap evaluator itself. recall never throws. Section 7.8.1 of the specification requires it stay non-throwing. So an internal failure would otherwise be indistinguishable from a genuinely empty result. A non-empty degradedStages array is what lets a caller, chiefly GeniusLocusKit's RecallDirector, tell the two apart. AsyncIterator.hydrate(_:) applies the requested HydrationLevel per page. At .bitmapOnly, it rebuilds each drawer with content blanked to the empty string, while preserving every bitmap and metadata field. At .structured and .full, rows pass through unchanged. The content-stripping decision for .structured was already made upstream, at the storage-fetch layer, not here.

RecallTraceItem.swift

This file provides RecallTraceItem, one record of a single drawer returned by a recall operation. This is the substrate for the "later two-source reward" mechanism. A dreaming daemon uses this mechanism to distinguish rows a user acted on from rows that were returned but ignored. The used flag is bit 0 of operationalBitmap, decoded through a computed property rather than stored as a separate Bool column. So the type carries no stored boolean fields at all. Every bitmap-backed LocusKit noun follows this convention. score, when present, is the recall's own similarity score for the row. A nil score means the recall that produced this trace carried no score, for example an ordinary ordered-by-capture-time query.

AuditTypes.swift

This file provides BitmapState, the snapshot of a row's three bitmap columns at a specific past HLC. Estate.bitmapState(rowID:asOf:) returns this snapshot. BitmapState exists as a small, focused return type, for a precise reason. The reconstruction that produces it, AuditLogFold.projectStateAt, is a SubstrateLib primitive. It folds a row's sealed audit events forward in HLC order. Yet it returns its result in a different shape. BitmapState is LocusKit's own public-facing wrapper. It names the three bitmaps by hand, rather than exposing the substrate's internal projection type directly.

Summaries.swift

This file provides WingSummary and RoomSummary, the two small summary types DrawerStore.listWings and listRooms produce. Both are computed projections over the current drawer set. LocusKit has no separate wings or rooms table. Wing and room identity lives entirely in the nodes table. A summary's drawer and room counts are simply whatever the live query finds, at the moment it runs. They are not a maintained running total.

LocusKitTelemetry.swift

This file provides LocusKit's opt-in telemetry emission functions. They are wired through IntellectusLib.Intellectus.report(_:). Every emit function here follows the same three rules, stated in the file's header. First, the reported value is always an @autoclosure. It is never evaluated when monitoring is disabled. The off-path cost is one atomic boolean load and a branch: no lock, no allocation. Second, the now timestamp is always caller-supplied, never read from a clock inside the function. This preserves IntellectusLib's own determinism contract. Third, the metric namespace follows the fleet-wide <kit>.<noun>.<field> convention. Examples include locuskit.drawer.capture_latency_ms, locuskit.kgfact.add_count, and locuskit.gate.reject_count.

emitDrawerCapture, emitDrawerQuery, emitKGFactAdd, emitKGFactQuery, emitTunnelAdd, emitGateAdmit, and emitGateReject share one pattern. Each is called from its corresponding DrawerStore method. Each call happens at the exact moment its operation completes. For the gate functions, the call happens when AuditGate.admit returns instead. Telemetry is purely additive. It is never consulted by any control flow that decides what a method returns. So every store method's functional behavior is byte-identical, whether monitoring is enabled or not.

Rust Port and Conformance

The rust/ directory contains the second leg of the kit. It holds fifty-seven source and test files, under rust/src/ and rust/tests/. These files mirror the Swift implementation file-for-file: drawer.rs, drawer_store.rs, bitmap_evaluator.rs, merkle_rollup.rs, estate.rs, and more. The Rust side also carries three concrete DrawerStore backends the Swift side does not carry: drawer_store_inmemory.rs, drawer_store_sqlite.rs, and drawer_store_postgres.rs. All three build over a shared, storage-agnostic DrawerStoreCore.

Conformance tests under rust/tests/ gate byte-for-byte agreement with the Swift implementation. These tests cover adjective and operational bitmap conformance, provenance bitmap conformance, corrupt readback, Merkle rollup, outline proofs, recall pruning, temporal reads, and the LP0 fixed-vector suite. They gate agreement on every bitmap layout, every fingerprint derivation, and every state-transition legality decision. Suppose you change a bitmap layout, a fingerprint derivation, or a transition rule on either leg. Mirror that change on the other leg. Then run both test suites. The fixtures and conformance tests are the contract, not a convenience.