Epistemic OS Hardening — current capability catalog¶
Purpose of this page. This is the code-verified, line-anchored catalog of every capability the "Epistemic OS Hardening" program (Phase 0 → Phase 3 + the "exceed" tracks) shipped into
epistemic-graph. It exists so a static audit can useCHANGELOG.mdfor release history anddocs/capabilities.mdfor the operation-by-operation parity matrix) can read what is actually true of the shipped code without re-deriving it from source. Where the program's original intent and the shipped reality diverge, this page documents the shipped reality — every claim below is kept aligned with currentcrates/,src/, andCargo.toml, not inferred from a design document or historical CHANGELOG prose.How this page relates to the other capability docs (read this before citing any of them):
docs/capabilities.generated.mdis the machine-checked ledger — one row per wireMethod, generated bycargo run -p eg-capabilities --features canonical-ledger --bin gen_ledgerfrom the eleven domain-ownedROWSdeclarations and their sole deterministic registry iterator incrates/eg-capabilities/src/domains/mod.rs. It is authoritative for mutates / durability-domain / authz-action / idempotent / audited / emits-CDC / txn-participation facts, per method.docs/capabilities.mdis the hand-maintained, per-surface parity matrix (SQL / SPARQL / Cypher / GraphQL / vector / …) — coarser-grained, answers "which surface supports which operation", not per-method security semantics.- This page is the per-capability, program-narrative catalog: for each thing the hardening program built, what it is, where it lives, whether it is default-on or opt-in (and the exact feature name/env var), how to exercise it, and its honest limitations. It goes deeper than the CHANGELOG's release-note prose and cross-links into the other two rather than duplicating their tables.
- Release-certification evidence is tracked separately from source completeness: hardware, multi-host soak, and live external-service runs prove a particular build in a particular environment; they are not described here as missing source features.
Verification discipline for this page: every code anchor below (file path, item name, env var, feature name, exact count) was grep/read-confirmed in this worktree. Counts that are mechanically derived are intentionally not copied into prose. Use the generated ledger and exhaustive tests so a new protocol method cannot make this page's hard-coded count silently stale. Environment-dependent evidence is called out in Release-certification evidence.
Phase 0 — Trustworthy core¶
Phase 0 (shipped in 2.19.0, with one closeout item — the mutation-gateway rollout — completed in 2.20.0) makes the engine's own mutation/durability/security machinery internally self-consistent and machine-checked, rather than relying on hand-maintained classifiers agreeing with each other by convention.
The generated capability ledger (eg-capabilities)¶
- What it is: a complete, mechanically enforced
MethodPolicyfor every variant of the wire-protocolMethodenum (crates/eg-types/src/protocol.rs). The cratecrates/eg-capabilities(workspace member,crates/eg-capabilities/src/lib.rs) declares:The domain-owned registry is joined against the complete protocol-method inventory; a missing or duplicatepub struct MethodPolicy { pub mutates: bool, pub durability_domain: DurabilityDomain, // durable state domains | VolatileControl | None pub authz_action: &'static str, // "<domain>:<verb>" scope string pub idempotent: bool, pub audited: bool, pub emits_cdc: bool, pub txn_participation: TxnParticipation, // Atomic | Saga | Snapshot | None } pub fn method_policy_entries() -> impl Iterator<Item = (&'static str, MethodPolicy, &'static str)>; pub fn policy(m: &Method) -> MethodPolicy;Methoddeclaration fails the static and Rust consistency gates (CONCEPT:EG-P0-1). - Inventory invariant:
crates/eg-capabilities/tests/consistency.rschecks the feature-selected canonical registry iterator. The generated ledger is the current count and policy inventory; this narrative does not duplicate that changing number. - Default-on or opt-in: the crate is a workspace member but is not linked
independently — it is pulled in only via the facade's
serverfeature (server = ["dep:tokio", "dep:clap", "dep:tracing-subscriber", "dep:async-trait", "dep:eg-capabilities"],Cargo.toml), because the one consumer (the mutation gateway, below) is server-only. - How to exercise it:
cargo run -p eg-capabilities --features canonical-ledger --bin gen_ledgerregeneratesdocs/capabilities.generated.mdfrom the live domain registry (crates/eg-capabilities/src/bin/gen_ledger.rs). - Honest limitation:
authz_action,idempotent, andtxn_participationare judgment calls — the crate's own doc comment onMethodPolicysays so plainly: there is no pre-existing classifier in the codebase to cross-check them against, unlikemutates/durability_domain(cross-checked againstaccess.rsand the canonical commit gateway) andaudited/emits_cdc(cross-checked againstaudit.rs/cdc.rs).
The MutationPlan commit gateway (src/server/mutation.rs)¶
- What it is: the single place a routed mutation's authz + durable write + CDC
emission happen together, driven by
eg_capabilities::policy()rather than a re-hardcoded classifier.MutationPlanis populated FROM the ledger;commit_mutation(and, for the runtime-conditional family,commit_conditional_mutation/commit_conditional_mutation_async) is the one call site. - Exhaustive rollout state: every mutating method in the live ledger is assigned
exactly once to the canonical gateway or to a named domain-owned transaction
protocol.
OPEN_NOT_JUSTIFIEDis machine-checked empty bymutation::tests::gateway_routed_set_matches_mutating_policy_surface; adding an uncovered mutating method is a test failure. The test, not a prose count, is the current inventory. RunRuleswas found, during this rollout, to be a policy correction, not a route:handle_run_rulesreasons over an off-lock snapshot and returns inferred triples with no writeback (unlike its siblingRunDatalogReasoning, which materializes in-place) — the ledger'smutates: trueguess for it was wrong and was corrected rather than the method being routed.- What the gateway does NOT reimplement: the tamper-evident hash-chain audit log
(
src/audit.rs+redb_store::append_audit_entry) stays inside the durable-commit path (PersistenceBackend::record/record_durable) — the gateway delegates to it rather than risking a second, diverging chain. - Coalescer interaction (L18, closed): step 4 of
commit_mutationroutes a coalescable routed mutation (AddNode/RemoveNode/AddEdge/RemoveEdge) through the singleWriteCoalescerRegistry::writer_forpath, so the hot-path structural writes still batch — this was a real scale regression (found by the full--libsuite, not a filtered subset) that was fixed by re-entering the coalescer from inside the gateway rather than bypassing it. - Default-on or opt-in: not feature-gated separately — it is part of the
serverbuild (every server binary links it); there is no way to disable the gateway short of building withoutserver. - Exercise it:
cargo test -p epistemic-graph --lib mutation::(in-crate); the cross-check test builds a realRedbBackendand reads the audit chain back.
Authoritative durability closure¶
- Every method policy declares its state domain exhaustively. Any mutating method
assigned
DurabilityDomain::Nonefails the capability consistency gate. Explicit process/session-only transitions useVolatileControl, which never acknowledges a user-data commit or claims crash durability. - Graph mutations share one canonical mutation applier and authoritative redb commit path. Domain-specific stores provide equivalent transactional gateways.
- Commit-before-ack is unconditional in served mode. There is no file-WAL, snapshot-backend, checkpoint, or write-behind branch.
- Runtime-conditional mining and query methods resolve their write status before
authorization and commit, so
writeback=truecannot bypass durability.
Canonical time-series store (EG-P0-4)¶
- What it is: unifies two stores (the authoritative graph shard and
series.redb) that cannot share aWriteTransaction(exclusive-lock conflict). The fix is not a single-file merge — it is a documented two-hop write with a reconciliation pass closing the gap: - Graph + vector + blob-ref + measurement (+ lowered axiom/CONSTRUCT/plan-writeback)
land in one authoritative-shard
WriteTransaction(redb_store.rs::commit_crossmodal) — that set is the true cross-modal ACID boundary. - The measurement is then replayed into the served
series.redb(state.tsdb_store) immediately after step 1 commits, soTsRange/TsAsofJoin/TsWindow/TsGapFill/UQLOp::TsScansee it post-commit and post-restart. - This replay is a separate, non-atomic redb write on a different file: a crash
strictly between the two commits leaves the measurement durable in the shard but
not yet reflected in
series.redb. L16 closes this window:RedbBackend:: reconcile_time_seriesruns once at boot, scans every authoritative shard's SERIES tables, and replays intoseries.redbany series whose point count hasn't converged — an exact multiset diff, so it is idempotent and never duplicates a point. - Process note (found during the ledger-closeout wave): the Phase-0 integration pass initially missed merging this workstream's branch to main (additive, so build gates passed regardless of the miss) — it was caught later by the L16 agent and restored. Worth remembering when auditing "is X really on main": additive changes can pass every gate while silently absent.
- Default-on: part of the
redb-backed durable server; not a separate feature flag.
Fail-secure verified request context (src/server/auth.rs)¶
- Only posture: a served engine accepts only the
eg2.envelope. It binds principal, tenant, audience, effective agent, roles, scopes, policy version, delegation, request/method/body, timestamp, nonce, and idempotency. Startup requires thesecurityfeature, a non-empty secret, configured audience/tenant/policy revision, durable replay state, and a non-empty trusted signer-key registry. - Fresh-store bootstrap: an empty durable identity/RBAC store permits only a
signer-backed
eg2.self-registration in__commons__asSystem, with no teams, roles, or delegation and the single exactsecurity:bootstrapscope. Once the first rule is durable, all requests use ordinary graph/admin policy. - Replay:
EPISTEMIC_GRAPH_ENVELOPE_SKEW_SECSbounds timestamp skew;eg2.nonce acceptance uses the durable replay ledger and survives process restart. - Native federation:
RemoteEngineSourcenow signs the live UQL/Cypher request with the same context. Empty secret, missing claims, invalid delegation, or a routable target without TLS fails before dialing.
Default-deny RLS (crates/eg-core/src/isolation.rs)¶
IsolationLayer filters every served GraphView before query execution. An
unowned, undecodable, or untagged row is denied unless it is explicitly
_visibility: "public" or its _owner/grant policy authorizes the verified
agent. The served engine always uses this posture; there is no environment
switch or builder path that weakens it. The result-cache key includes the full
RLS context so a filtered result cannot cross an authority boundary.
Exhaustive audit + admin scopes (EG-P0-6)¶
- 8 broker/stream mutating ops previously classified as read in
access.rs(StreamDeclare/Publish/Trim/CommitOffset,PublishConfirmed,BrokerAck/NackTag,PublishIdempotent) were a real security gap (L10) — a read-only caller could invoke them — and are now correctly classified as writes. - Admin scoping is driven off the ledger's
authz_actionfield, checked once indispatch_inner— covering every existing admin method and, by construction, every future one the ledger declares. - A 64-method exhaustive audit surface backs
audit.rs's coverage.
Phase 1 — Universal modality & work contracts¶
eg-modality runtime registry + the 12-point TCK¶
- The trait (
crates/eg-modality/src/contract.rs):ModalityContracthas 4 core methods every implementer must answer (storage_kind,to_rowset,txn_stage,cdc_topic), 4 default-empty methods overridden only where meaningful (provenance,evidence,policy_labels,analytics_ops), and — added by EG-P1-1 — 4 more default-"unsupported" hooks that make the TCK genuinely 12-for-12 (ingest_report,storage_stats,backup_selfcheck,recovery_selfcheck), plus one honesty escape hatch,tck_not_applicable(point) -> Option<&'static str>, for a point that genuinely does not apply to a given modality's nature (distinct from "not yet implemented"). - The 12 TCK points (
crates/eg-modality/src/tck.rs,TckPoint::ALL):SchemaAndIds,IngestStreaming,CodecUnsupportedFormat,StorageIndexStats,TypedQueryOperators,TxnOrSagaOutbox,CdcDeleteRetentionGc,TenantRowRegionPolicy,ProvenanceEvidenceLineage,BackupRestoreMigrateRecover,SingleNodeFailure,InteropWorkloadSmoke. Each point resolves to one of three honestTckStatusvalues:Pass,NotApplicable(reason)(counts as first-class — not a gap), orNotImplemented(reason)— there is deliberately no silent-skip / default-pass status. Production serving is stricter:TckReport::is_production_ready()accepts only 12Passresults plus a passing native codec/normalization/index/query/resource probe; N/A or a missing probe is never a production exemption. - The registry:
crate::register_modality/registered_modalities()(crates/eg-modality/src/registry.rs) is aOnceLock<Mutex<Vec<ModalityDescriptor>>>— a deliberate choice overlinkme/inventory(neither is a workspace dependency anywhere; both would be the first proc-macro dependencyeg-modalitypulls in, which is meant to stay the thinnest possible seam). Important nuance, verified in the registry module's own doc comment:register_modality()is called from inside the#[cfg(test)]conformance-test module themodality_conformance_tests!macro generates — soregistered_modalities()only populates when that crate's own test binary actually runs its conformance suite. This is a per-process, test-time registry, not the server's routing table ("Cross-process caveat" in the crate's own README). Production serving does not depend on this test registry: the closedServedModalityKindenum dispatches document/image/audio/video to concrete decoders, and its capability operation rejects any runtime whose TCK is not 12/12 PASS with a passing native production probe. - The macro:
modality_conformance_tests!($T)(exported fromeg-modality) generates the full battery per implementer: round-trip losslessness, rollback symmetry, provenance-family non-panic,cdc_topicwell-formedness, a malformed-payload decode-as-Errcheck,analytics_ops()well-formedness, and the TCK-report-generation - registration test. Invoked inside each crate's own
#[cfg(feature = "contract")]module. Document/image/audio/video additionally expose the commonservingruntime and are enabled by the main build'smodality-servingfeature. - Adoption is source-enforced: each
ModalityContractimplementation invokesmodality_conformance_tests!behind its crate'scontractfeature. Fleet validation discovers the live invocations rather than trusting a copied crate count.
Arrow-backed KnowledgeBatch (eg-plan/knowledge_batch.rs)¶
- What it is: a third
RowSetprojection (alongside the row-orientedRowSetand the graph-nativeKnowledgeSet) laying results out as a real ArrowRecordBatch(crates/eg-plan/src/knowledge_batch.rs). Columns (arrow_schema()/to_record_batch()/from_record_batch(), round-trip tested):id(Utf8),kind(Utf8), onescore_<name>(Float32) per named score,confidence(Float64),evidence_kind(Utf8 — a filterable summary spanning the governedEvidenceLocusaddress kinds, see X-1 below), bitemporalvalid_from/valid_until/tx_from/tx_to(Int64), plus list-typed provenance/policy/evidence-ref/contradiction/proof/transformation/alternative-id columns and a lazyblob_handle(Utf8) +has_payload(Boolean). - Reserved epistemic columns — populated, not stub (L22 closure):
contradiction_ids(symmetric, viaAuxEdgeIndex),proof_ids(viaexplain_belief), andtransformation_ids(viaGENERATED_BY→:Activityedges) are populated by the mining and job write-back paths.ALTERNATIVE_TOis read-wired for explicitly modeled alternatives; calibration is populated by calibratedeg-jobsresults and remains honestly null for producers that compute no calibration signal. - Native served currency: the facade
knowledge-batchfeature is folded intofull.result_stream.rsadapts graph, SQL, RDF, vector, time-series, job, and cross-modal producers to bounded, snapshot-boundKnowledgeBatchEnvelopes. Every row receives verified tenant/policy/snapshot/query/derivation/evidence references, andwrite_arrow_ipcholds only one bounded batch at a time. RowSetremains the internal operator algebra; served results cross the public query/job boundary as governedKnowledgeBatch, rather than as a family-specific terminal encoding.
eg-document / eg-image / eg-audio / eg-video + eg-alignment (EG-P1-3)¶
- What it is: five leaf crates —
eg-document(bounded UTF-8 page/layout/table/ private-lexeme extraction),eg-image(strict PNG pixel reconstruction and pHash),eg-audio(strict PCM/WAV waveform/spectral feature extraction),eg-video(strict ISOBMFF sample tables, timing, keyframes, and 24-bit raw-RGB samples), andeg-alignment(the sharedEvidenceResolvertrait). Each media crate exposes its normalized data model, header parser, governed contract, and native runtime; alignment exposes its resolver and graph. Each of the four data-model crates implementsModalityContractandGovernedModalityand is registered in the EG-P1-1 TCK via its owncontractfeature. - Served status: all four expose
ServedModalityRuntime<T>aliases and are enabled in the main build. The runtime provides atomic batch/stream ingest, OCC update, idempotent replay, governed delete/legal hold, policy-filtered paging, monotonic CDC, cold/restore lifecycle, snapshot recovery, rebuilt lexical/spatial/temporal/ multi-probe-signature postings, and exact typed native queries. Their fleet TCK reports are exactly 12 PASS and zero N/A with passing native probes. - Universal identity:
eg-modality::ArtifactBundleties Artifact, Occurrence, Rendition, Segment, Feature, and EvidenceLocus to policy, privacy attestation, and derivation. Its validatedOpaqueRefcannot encode source paths, endpoints, email addresses, or display names. See governed modality serving. - The one facade-reachable piece:
CasEvidenceResolver(src/server/blob/cas_resolver.rs:52, implementseg_alignment::EvidenceResolver). Gated by thealignmentfeature (alignment = ["blob", "dep:eg-alignment", "dep:eg-modality"], Cargo.toml, included infull). It resolves a governed text/tableEvidenceLocusto a real UTF-8 excerpt read from the engine's own blob CAS (ChunkStore/stream_blob_get, ablob_refproperty looked up in aGraphViewsnapshot); every other locus kind resolves to a real CAS-digest reference, never a fabricated excerpt. This resolver remains a provenance lookup boundary; native image/audio/video decoding and extraction stay in the served runtimes rather than being duplicated here. - The blob-CAS and epistemic resolvers consume only the single
ArtifactBundle/EvidenceLocusprotocol.
Persistent index pushdown into the served planner (EG-P1-4)¶
- What it is: the served planner now binds directly to the maintained persistent
BM25 text index and the live SemanticStore (vector index) via a
ServedTextIndexdowncast seam overIndexManager, instead of rebuilding/cloning a snapshot copy of the whole index on everyUnifiedQuery/NlQueryrequest. - Adaptive re-optimization: cardinality-based cost re-optimization now runs
automatically mid-execution, gated by the same
EPISTEMIC_GRAPH_COST_OPTkill-switch (0→ identity/off) that already governed plan-time optimization. - Streaming cursor:
KnowledgeBatchStreamis the sole governed producer. Its authority- and snapshot-boundKnowledgeStreamCursorresumes bounded iterator-backed batches without a materialized compatibility cursor. - Current closeout: vector and spatial indexes publish completeness manifests;
SQL cancellation uses
CancelRequestand the bounded request-timeout contract; and both serial andpar-runtimedrivers run the same adaptive re-optimization loop. Snapshot-derived text and diagnostic materializations remain bounded fallbacks when a complete persistent index is unavailable.
Phase 2 — Distributed planes¶
PlacementCatalog (src/raft/placement.rs)¶
- What it is: an epoch'd catalog (
PlacementCatalogstruct,src/raft/ placement.rs:217) tracking which(group, epoch)a graph — or a split partition-key range (split_tenant_key,PartitionStateenum) — currently belongs to. Online split/merge/move runs a prepare-then-fenced-cutover sequence:MultiRaft::placement_fence_cutover(src/raft/multi.rs:724) bumps the epoch so any caller still presenting a pre-cutover epoch is redirected, never served stale data. The catalog takes priority over the hash-ring router for any graph with an explicit placement entry (an unpinned graph still falls back to the ring). - Crash-safe moves: every move stores an immutable graph inventory, original
route/epoch, target, completed graph set, and stage in a replicated
PartitionMoveJournal. The placement leader reconciles non-terminal journals at startup and re-verifies authoritative rows before cutover. Journal decoding and stage/placement mismatches fail startup closed; transitions and completed-graph evidence are monotonic. Exactly the placement leader drives a move, with an opaque per-partition local guard preventing competing local workflows.abort_moveis permitted only before the epoch fence; if abort intent races a committed fence, recovery records the cutover and rolls forward rather than stranding an ambiguousAbortingstate. - Wire surface (DIST-P2-4 read / DIST-P2-5 admin):
Method::PlacementRouteis always in the enum (pure serde, present in every build perdocs/capabilities.generated.md); the real answer needs theraft/clusterfeature plus a liveMultiRaftcluster, otherwise it returns a well-formed authoritative-unplaced route — not an error.Method::PlacementAdmin { op }(DIST-P2-5,opone ofAssign/Move/AbortMove— oneMethodvariant with a nested op enum, mirroringServedModality { op }) is the admin mutation that closes the gapPlacementRoutealone left: before it existed, the assign/split/merge/online-move machinery below was reachable ONLY from in-process Rust (tests/harnesses) — there was no way for an external caller, on a real multi-node cluster, to trigger a placement decision or drive an online move. It is a thin RPC entry point over the SAME already-provenMultiRaft/TenantManagerAPI (src/server/handlers/placement.rs), admin-scoped ("admin:cluster", the same tier asReshard/CatalogAssign), returning a typed "not available" error on a non-raftbuild, and classifiedClusterMutationRoute::VolatileControl(notConsensusNative) since it replicates via its own internalcommit_placementround-trip rather than the generic native-command proposal wrapper. Proven against a REAL three-node cluster (three independent tokio-spawned nodes, real openraft consensus — not the one-node/two-group simplification below) bysrc/raft/tests.rs::placement_admin_wire_rpc:: placement_admin_wire_rpcs_move_data_across_a_real_three_node_cluster: assign the decision, write data, move it to the other group, and read it back — from a DIFFERENT physical node at every step — asserting the data is actually placed and readable post-reshard, not merely that the RPC returnedOk. - Default-on or opt-in: gated
raft/cluster(opt-in layer stacked onfull, perdocs/architecture/tiers.md). The gate stays default-OFF by design (a single-node homelab deployment has no second group to place anything on); what changed is that the path BEHIND the gate is now wire-reachable and exercised end-to-end, not merely present.
Multi-group production startup + cross-shard read fan-out (DIST-P2-2)¶
- Env var:
EPISTEMIC_GRAPH_RAFT_GROUPS(src/raft/config.rs:90,parse_groupsat:126), default1— unset/empty/"0"all collapse to the single-group path, byte-for-byte unchanged from before this workstream. - Cross-shard reads:
CrossShardReader::read(src/raft/xread.rs) first takes a linearizable placement-catalog barrier, then fans bounded keyset pages to each owning group's current leader through the authenticated shared Raft peer channel. Requests cap graph count, fan-out, rows, an aggregate response-byte budget, and the end-to-end deadline (including route discovery); the byte budget is divided across active legs rather than multiplied by them. Completion is either require-complete or an explicitly typed partial result. Placement epoch changes are re-resolved once, and stale or bound-violating peer replies fail closed. - Consistency contract: each leg reports its own ReadIndex and durable graph version. Continuations reject a changed version. These are per-group linearizable pages, not a fabricated global snapshot; a true cross-group snapshot requires a separately replicated global read fence.
- Deterministic pagination: the coordinator performs a keyset K-way merge ordered
by
(node_id, input-leg-order)and consumes duplicate ids from every leg before a page boundary, preventing duplicate reappearance on continuation. - Proven by live harnesses (not just unit tests):
src/raft/xread_harness.rs,src/raft/xshard_harness.rs,src/raft/placement_harness.rs(a one-node/two-group live setup).
Lazy graph lifecycle + bounded hot-context cache (DIST-P2-3)¶
- Served mode performs a catalog-only scan. A graph's durable identity is known
at boot, but its rows hydrate on first access through
BackendGraphMaterializer. There is no eager served profile. EPISTEMIC_GRAPH_MAX_RESIDENT_GRAPHScaps simultaneously resident graphs and evicts the coldest eligible graph through the durability-gated cold-offload path.__commons__is never evicted. The default is 1024 and zero is rejected.- L38 "paged adjacency" — ✅ CLOSED (surpass-6mo WS-3, 2026-07-13). Was: "lazy"
meant when a graph's data loads (deferred past boot to first access), not
partial/paged loading —
BackendGraphMaterializer::materializecalledread_graph_material_blocking, which returned the whole graph's material in one shot, so first access to a lazily-opened graph still fully rehydrated it into memory. Now:eg_core::registry::GraphMaterializer::materialize_page(a seam that already existed, unit-tested in isolation, but was never called by the facade/ server) is wired end to end: EPISTEMIC_GRAPH_LAZY_OPEN_PAGE_SIZE(src/server/persistence/cold_offload.rs::lazy_open_page_size) — a positive value switchescold_offload::lazy_openfrom a full rehydrate to a source-bounded paged load. The unset production default is 4096 records; development retains 0. Incomplete graphs are intentionally not queryable: graph operations receive typedPARTIAL_MATERIALIZATIONmetadata and can retry once the background continuation completes.RedbBackend::read_graph_material_page_blocking(src/server/persistence/redb_backend.rs) overrides the trait's default (full-fetch-then-slice) with a genuinely SOURCE-bounded scan —redb_store::read_graph_dump_pageskips/takes a bounded window of the per-graphnodes/edgestable range directly, never collecting the whole graph's rows into memory first.BackendGraphMaterializer::materialize_page(src/server/persistence/read_through.rs) routes to it.- Lifecycle correctness: every catalog entry has an immutable incarnation id and cancellation token. Create/delete/evict/open serialize on the graph's lifecycle lock. Durable pages carry the source incarnation and version captured in one read transaction; publication is rejected after delete/recreate, cancellation, or source-version drift. Durable fetches run outside the global registry lock, and a failed mixed partial image is evicted so the next access restarts at page zero.
- Maintained-index correctness: text, spatial, temporal, and semantic indexes
publish a manifest containing source snapshot, build version, completeness
cursor, and validity. Lazy recovery rebuilds every maintained index before the
graph becomes available. Served indexes reject a stale/incomplete manifest;
HealthandListGraphsexpose graph and index completeness/freshness. - Adversarial evidence: registry tests cover stale-page rejection after
delete/recreate and source-version drift; served completeness tests cover index
publication only after final-page rebuild;
scripts/check_lazy_lifecycle_architecture.pyis the static architecture gate for fences, cancellation, bounded I/O, manifests, explicit partial responses, and durable identity. - Default policy: served mode is always lazy and bounded. Positive explicit resident/page limits override 1024/4096; zero and invalid values fail startup.
Durable analytics-job plane (eg-jobs, INT-P2-1)¶
- What it is:
Method::AnalyticsJob { op }(async submit/status/cancel/resume,src/server/handlers/jobs.rs) over a redb-backedAnalyticsJobstate machine (crates/eg-jobs/src/model.rs):pub struct AnalyticsJob { pub job_id: JobId, pub input_snapshot: InputSnapshotHandle, // pinned OCC version — re-readable via AS OF, never a row copy pub policy: JobPolicy, pub algo: AlgoVersion, // full algorithm/params/code-version lineage pub retry: RetryPolicy, pub state: JobState, pub cancel_requested: bool, pub created_at_ms: i64, pub updated_at_ms: i64, }result_ref()is a deterministic function of(input_snapshot, algo), notjob_id— two jobs (an original run and a retry under a freshjob_id) that ran the same algorithm+params over the same snapshot converge on the sameresult_ref, the basis for idempotent result-commit. The result-commit path writes the same:Claim/:Evidenceconventioneg-epistemicreads (see Phase 3). - Default-on or opt-in: feature
(
Cargo.toml) — included infull. P2 adds renewable leases/epoch fencing, placement and tenant quotas, durable retry/checkpoint/cancellation state, typed KnowledgeBatch results, and a non-terminalPublishingphase so success is impossible before evidence-bearing result claims commit.
Governed external compute stream (INT-P2-2)¶
Method::KnowledgeStreamis the single signed handoff protocol for query and nativeAnalyticsJobresults. ItsKnowledgeStreamCursoris authority-, snapshot-, and placement-bound; producers page bounded Arrow IPC and consumers resume without a row-by-row protocol projection. External workers submit work through the durable analytics-job state machine and retrieve evidence-bearing committed results through the same stream, avoiding a second listener, registry, or result-publication protocol.- The engine's outer async driver and every Tokio worker use the same explicit 4 MiB
stack contract.
server::spawn_engine_driverowns the driver-thread boundary and normalizes spawn/join failures without reflecting panic payloads or environment data;RUST_MIN_STACKis not a deployment requirement or fallback.
Change-ledger → lake materialization + Iceberg-REST catalog + OpenLineage (INT-P2-3, lake)¶
- What it is:
LakeManagermaterialize/compact/delete runs emit a real OpenLineageRunEvent(src/server/lake/lineage.rs) — job/run/input-dataset/output-dataset with schema/datasource/output-statistics facets plus an engine-specific LSN/Iceberg-snapshot custom facet (schema URLhttps://openlineage.io/spec/1-0-5/OpenLineage.json#/$defs/RunEvent). - Optional push: env var
EPISTEMIC_GRAPH_OPENLINEAGE_URL(OPENLINEAGE_URL_ENVconstant,src/server/lake/lineage.rs:36) — unset means a silent no-op; lineage export never blocks or fails a materialization run. - Default-on or opt-in:
lake = ["server", "blob", "tsdb", "dep:eg-lake", "eg-lake/lake", "dep:ureq"]— as of W4.8, folded intofull(the maintained Polars native-Parquet codec + pure-Rustapache-avro, NOT the heavier upstream arrow/parquet crates, measured within the Pi-4 release-binary budget). The materialization tier and the Iceberg-REST listener (lake-rest, also infull) remain opt-in at runtime (GRAPH_SERVICE_PERSIST_DIR+EPISTEMIC_GRAPH_LAKE_MATERIALIZE_INTERVAL_SECS/--iceberg-addr). The Iceberg v2 Avro manifest/manifest-list writer (crates/eg-lake/src/iceberg_avro.rs, pure-Rustapache-avro) is real (per-column stats for predicate pushdown), not a stub.
Phase 3 — Epistemic differentiation (eg-epistemic)¶
eg-epistemic (crates/eg-epistemic/, ~5,760 lines across model.rs, propagate.rs,
tms.rs, recompute.rs, causal.rs, ranking.rs, redact.rs, query.rs,
evidence.rs, adapter.rs, contract.rs) is the epistemic layer. Claims/Evidence/
Sources are ordinary type-tagged graph nodes — no new persistence — and
Support/Contradict/Attack are ordinary edges; the base epistemic feature
(epistemic = ["query", "dep:eg-epistemic", "eg-types/epistemic", "dep:eg-plan",
"eg-plan/epistemic", "dep:eg-modality"], Cargo.toml) is folded into full (verified:
full = [… , "epistemic"] is the last entry in the full feature list) — so a standard
build always links the epistemic substrate and its TMS, redaction, evidence and
causal layers. Expensive argumentation searches remain request-bounded; steady-state
TMS/conflict/causal/materialization maintenance consumes committed MutationBatch
outbox records incrementally and advances a durable projection cursor.
Claim/Evidence/Source/BeliefState + confidence propagation¶
- Base
epistemicfeature (shipped 2.16.0, restated here as the foundation Phase 3 builds on).eg_epistemic::propagate_confidence(crates/eg-epistemic/src/ propagate.rs) does cycle-guarded Bayesian-conjugate confidence propagation over support/contradiction/attack edges.Method::ExplainBeliefreturns the full justification tree.
Paraconsistent TMS + Dung argumentation (tms.rs)¶
- What it is:
crates/eg-epistemic/src/tms.rs(687 lines) implements Dung abstract-argumentation semantics over aBeliefGraph:grounded_extension,preferred_extensions,stable_extensions,is_skeptically_accepted/is_credulously_accepted, plusretract(RetractionResult) for dependency-directed retraction. Paraconsistent means a contradiction is contained to the arguments actually in tension, never an explosion into "everything is now unbelieved." - Default-on or opt-in: gated for composition as
epistemic-tms, and included in the one mainfullbuild.
Dependency-driven recompute + durable projection¶
- The recompute engine (
crates/eg-epistemic/src/recompute.rs):TruthMaintenance—register(id, depends_on, …),on_change(&ChangeEvent) -> BTreeSet<String>(which ids just wentStale),status_of,stale(),dependents_of,recompute(re-derives a stale id toFresh/Retracted), andregister_from_provenance(tm, view, derived_id)— the intended real-world registration path, reading a node's:DerivedFrom/:GeneratedByedges (EPI-P3-1's lineage) to auto-populate dependencies rather than requiring a caller to hand-list them (L45 closure). Dependency and generator reverse indexes make ordinary invalidation and model/ontology retirement proportional to the affected closure rather than the complete materialization registry. - The served authority (
crates/eg-epistemic/src/incremental.rsandsrc/server/reasoning_projection.rs): one compact, per-graph projection consumes authoritative MutationBatch outbox records in graph-version order. It indexes epistemic/causal edges, provenance dependencies, generators, stale/retracted state, and recompute fence epochs. State-backed batches carry a digest-bound, privacy-safe projection wake-up containing only domain-separated identity hashes and closed relationship/invalidation tags; source properties and labels are not duplicated. - Failure and restart semantics: the projection image is fsync'd before its outbox lease is acknowledged. Exact-position replay is idempotent. Missing or corrupt images fail served status/recompute closed; a corrupt image is never silently replaced with an empty index. A missing image is bootstrapped once from the recovered authoritative graph and then maintained incrementally.
- Invalidation coverage: committed node/edge/CAS mutations, provenance edge
changes, and explicit
policy_changed,model_retired, andontology_evolvedmutation events invalidate the affected transitive closure. Model and ontology invalidations use the generator reverse index instead of scanning all rows. - Fenced recompute:
RecomputeMaterializationrequires both the authoritative graph version and durable projection watermark to equal the caller's expected source version. A monotonically increasing per-materialization epoch prevents a late writeback from clearing a newer invalidation. Provenance is resolved from the graph post-image; callers cannot submit a dependency set. - Default-on or opt-in: gated for composition by
epistemic-tmsand included in the one mainfullbuild.
Calibrated causal reasoning (causal.rs) — engine-native, partially wire-exposed¶
- What it is:
crates/eg-epistemic/src/causal.rs(632 lines) — a genuine linear-Gaussian structural causal model (CausalGraph,StructuralEquation) with real Pearl do-calculus: intervene(...)(causal.rs:232) — graph surgery: cuts incoming edges to the intervened variable, does not just condition on it. This is the operationally meaningful distinction betweendo(X=x)andobserve(X=x).observe(...)(:262) — conditional, backward-inference-aware.counterfactual(...)(:342) — abduction/action/prediction (Pearl's three-step counterfactual recipe).- Every query returns a
CausalEstimate(:73) with a calibrated credible interval, not a point estimate. - Wire exposure:
CausalEstimateandCausalCounterfactualexpose intervention and counterfactual inference; observation remains a crate-level primitive used by the same causal engine. - Feature gating (two compositional layers, included in
full): eg-epistemic's ownepistemic-causalfeature gates the crate-internal implementation.- The facade feature
epistemic-causal = ["epistemic", "eg-epistemic/epistemic-causal"]turns on the wireMethod::CausalEstimate/Method::RankByProvenancehandler arms (#[cfg(feature = "epistemic-causal")]insrc/server/handlers/query.rs).
Provenance-aware retrieval ranking (ranking.rs)¶
- What it is:
crates/eg-epistemic/src/ranking.rs—rank(candidates: &[RetrievalCandidate], weights: RankWeights) -> Vec<RankedResult>, scoring byevidence_quality(reliability, corroboration, calibration precision, freshness) in addition to similarity, not similarity alone. - Wire exposure:
Method::RankByProvenance(handlerrank_by_provenance_wire,src/server/handlers/query.rs), a pure function over request-carried candidates — no graph snapshot needed. - Default-on or opt-in: same composable facade
epistemic-causalfeature asCausalEstimate; included infull.
Policy-aware proof redaction (redact.rs, Method::ExplainBelief disclosure_level)¶
- What it is:
crates/eg-epistemic/src/redact.rs(614 lines) definesDisclosureLevel—Full<Skeleton<ExistenceOnly(a total ordering by how much is hidden) — andExistenceSignal(Supported/Contradicted/Uncertain, the coarse "is this believed at all" signal surfaced even atExistenceOnly, deliberately never a raw float confidence).explain_belief_redacted/explain_belief_redacted_capped(:238/:299) reuse the exact sameRowVisibility/can_see_rowcheck (crates/eg-core/src/isolation.rs) every other RLS-aware read path enforces — masking (never silently dropping) an evidence node the caller's RLS context cannot see. - The dual-arm handler (
src/server/handlers/query.rs, both verified by direct read): #[cfg(feature = "epistemic-redaction")]arm:disclosure_level: Nonetakes the byte-for-byte classicexplain_beliefpath;Some(cap)routes throughexplain_belief_redacted_wireunder the caller's own RLS actor.#[cfg(all(feature = "epistemic", not(feature = "epistemic-redaction")))]arm:disclosure_level: Some(_)returns an explicit error ("requires the epistemic-redaction feature, not enabled in this build") rather than silently ignoring the parameter and returning an unredacted tree — the one behavior that would actually be dangerous.- Default-on or opt-in:
epistemic-redaction = ["epistemic", "security", "eg-epistemic/epistemic-redaction"]— requiressecuritytoo (for the sharedIsolationLayer); infullsince WS-1b (2026-07-12; bothsecurityandepistemicare already infull, so this was a zero-new-dependency fold-in).
The bitemporal epistemic_status capstone (query.rs, EPI-P3-5)¶
- What it is:
crates/eg-epistemic/src/query.rs(740 lines) implements the why/why-not/what-changed/what-would-invalidate acceptance query family over the bitemporalAsOfaxis, layered on the paraconsistent TMS. Two wire methods: Method::EpistemicStatus { node_id }— the acceptance capstone: "is this still believed, as of when, and why" (handlerepistemic_status_wire).Method::WhatChanged { tx_from, tx_to }— a whole-graph bitemporal diff between two transaction times; the one facetEpistemicStatusdoes not subsume (handlerwhat_changed_wire).- Default-on or opt-in: both gated by the composable
epistemic-tmsfeature, included infull.
Exceed tracks¶
X-1: multimodal evidence graph spine¶
EvidenceLocusis the sole located-evidence identity. Its governedEvidenceAddresscovers text spans, table cells, image/page regions, audio/video intervals, metric windows, versioned rows, code symbols, and trace spans while policy, derivation, occurrence, rendition, and content references remain attached to one validated artifact bundle.- The citation resolver:
evidence_citations/resolve_locus/justification_citationsincrates/eg-epistemic/src/evidence.rs(387 lines) — walks the same support/contradiction/attackBeliefGraphtopologyExplainBeliefwalks and returns every transitively-cited node'sEvidenceLocusplus itsAssetOccurrence/Blobidentity chain. - Wire exposure:
Method::ExplainEvidence { node_id }(handlerexplain_evidence_wire,src/server/handlers/query.rs). - Feature gating and resolution:
- The wire
Method::ExplainEvidencevariant itself is gated only by the baseepistemicfeature (already infull). - The handler arm that actually answers it is gated
#[cfg(feature = "evidence-graph")](evidence-graph = ["epistemic", "eg-epistemic/evidence-graph"]— infullsince WS-1b, 2026-07-12); a build that explicitly disables it (--no-default-featureswithout re-adding it) falls through to the not-built catch-all. alignment'sCasEvidenceResolverimplements content resolution for this sameEvidenceLocuscontract; it is not a second identity model.
X-6: reversible intelligence, via the TMS recompute engine¶
- Realized entirely by the truth-maintenance + live CDC hook covered under Phase 3
above: a retraction propagates
Stalealong real dependency edges (never across an unrelated contradiction — the paraconsistency property is preserved), andTruthMaintenance::recomputere-derives a stale id toFreshorRetracted— this is genuinely reversible, dependency-directed derived-knowledge maintenance, not just forward-append. Provenance-bearing commits auto-register materializations, and the durable outbox/cursor projection persists and resumes incremental recomputation.
Feature-gating map¶
The default build is full (default = ["graph", "algorithms", "metrics", "full"],
Cargo.toml). The table below covers only the features this program introduced or
wired; consult the build feature map for the complete composition.
| Feature | In full? |
What it turns on | Depends on / implies |
|---|---|---|---|
epistemic |
yes | Claim/Evidence/Source/BeliefState, confidence propagation, base ExplainBelief |
query, dep:eg-epistemic, dep:eg-modality |
epistemic-tms |
yes | Paraconsistent TMS + Dung argumentation, durable incremental projection worker, EpistemicStatus/WhatChanged |
epistemic, eg-epistemic/epistemic-tms |
epistemic-redaction |
yes (WS-1b) | ExplainBelief's disclosure_level (policy-aware proof redaction) |
epistemic, security, eg-epistemic/epistemic-redaction |
epistemic-causal |
yes | CausalEstimate, counterfactuals, RankByProvenance, incremental causal dependency projection |
epistemic, eg-epistemic/epistemic-causal |
evidence-graph |
yes (WS-1b) | ExplainEvidence citation resolver (crate-internal, eg-epistemic-side) |
epistemic, eg-epistemic/evidence-graph |
alignment |
yes | CasEvidenceResolver (blob-CAS-backed, facade-reachable) |
blob, dep:eg-alignment, dep:eg-modality |
knowledge-batch |
yes | Native governed streaming query/job result (eg-plan) |
query, dep:arrow |
modality-serving |
yes | Universal governed document/image/audio/video state machine and concrete dependency-light runtimes | server, redb, security, streaming, media runtime crates, eg-modality |
contract (per-crate) |
no | ModalityContract conformance-test battery, selected directly for each implementation |
dep:eg-modality (+ crate-specific extras, e.g. eg-rdf also needs owl/sparql) |
jobs |
yes | Method::AnalyticsJob distributed durable analytics-job plane (eg-jobs) |
server, mining, epistemic, dep:eg-jobs |
lake |
yes (W4.8) | Parquet/Delta/Iceberg-REST materialization + OpenLineage | server, blob, tsdb, dep:eg-lake |
lake-rest |
yes (W4.8) | Iceberg-REST catalog endpoint on top of lake |
lake |
raft / cluster |
no (opt-in layer) | PlacementCatalog, multi-group Raft, lazy lifecycle's cross-shard leg |
server, redb, dep:openraft |
Small-footprint invariant: the native knowledge-batch and dependency-light media
serving features are intentionally part of full; external codec/model toolchains remain
outside it. KnowledgeBatch shares the Arrow dependency already used by the main query
stack, while the media runtimes add no native library. A cargo tree
on the default build links no new heavy dependency class from this program beyond what
the pre-existing full build already carried (DataFusion, Tantivy, redb) — the workspace
[features] block's comments assert the dependency boundary at each opt-in
feature's definition site.
Release-certification evidence¶
The source contracts above are implemented. The following environment-dependent runs belong to exact-release certification; absence of a result for a new release does not mean the source feature is deferred:
cargo tree --features fullandcargo tree --features clusterdependency-policy evidence for the exact source revision.- The 24–72 hour multi-host soak/chaos campaign at the target resident-graph count.
- Live GPU/robotics parity on the target hardware and driver/toolchain versions.
- OpenLineage delivery against the deployment's configured collector and trust profile.
The generated capability ledger supplies the current method count. This narrative never freezes that count or substitutes release-history estimates for the executable gates.