Skip to main content
Reality Oracle
OverviewCitizensReality FeedVerified ActorsIntel SubscribersMarket PredictionInvestment FundsHow It WorksGates
Products
Backtest ForensicsLiving MapDrift AlertsPath QueriesCustom AxesRisk Maps
Solutions
Compliance OfficersRisk Managers / CROPortfolio ManagersCTOs & Engineering
Enterprise
Enterprise OverviewReality Oracle · SuperappThe AppsArchitectureAudit ManifestTrust CenterPricing
Developers
DocumentationAPI ReferenceSDKsArchitectureAudit Manifest
Resources
BlogUse CasesCustomer StoriesPressChangelog
Company
AboutFoundersCareersContact
Trust
Trust Center
More
PricingJoin Waitlist
··11 min read

Dependencies point down: the rule that keeps the core pure

Why deino-core has zero I/O, and why every other crate is glad it does.

Dependencies point down: the rule that keeps the core pure

A hexagonal architecture is easy to draw and hard to enforce. The arrow on the diagram points one way; the imports in the code point every way. DEINO has one rule that keeps them honest: dependencies point down, and the bottom crate does nothing.

The rule is simple to state and brutal to keep: deino-core depends on nothing. No I/O, no async, no database, no HTTP. It holds types, IDs, enums, value objects, and the geo primitives the World Monitor routes on. Every other crate in the workspace depends on it; it depends on none of them. That asymmetry is the thing that makes the whole shape hold.

The dependency direction is the architecture

Hexagonal architecture is usually drawn as ports and adapters around a domain core. The drawing is correct; the problem is that nothing in most languages stops a domain crate from reaching sideways into an adapter. In Rust, the workspace dependency graph does. Our crates compile in an order that mirrors the architecture: deino-core first, then the use-case slices that depend on it, then deino-api that composes them all. If a domain crate tried to import sqlx, it would not compile — not because of a linter, because the dependency edge does not exist in Cargo.toml.

What zero I/O buys you

A domain crate with no I/O is a crate you can reason about by reading. The types tell you what the system does; the adapters tell you how it talks to the world. When a regulator asks "what is your domain model," the answer is deino-core — and it is a crate that contains no database calls, no network code, no file reads. It is pure data and the rules that govern it. That purity is what makes the manifest provenance claim meaningful: the domain the manifest records is the one that actually ran, because it cannot reach outside itself to change anything.

Arrows that only point down: deino-core at the bottom, adapters at the sides, composition at the top. Nothing in the core reaches up.
Arrows that only point down: deino-core at the bottom, adapters at the sides, composition at the top. Nothing in the core reaches up.

The composition root is the only seam

deino-api is the composition root — the one crate that depends on everything. It wires the Pg* adapters into the Arc<dyn Trait> repositories that the use-case slices expect. It is also the only crate where wiring lives; no slice knows which adapter it is running against. That is INV-5: AppState repositories are Arc<dyn Trait> so tests swap mocks. The test for a use-case crate constructs its mock trait and runs; it never spins up Postgres. The composition root is the seam where the abstract meets the concrete, and it is the only seam.

The dependency direction is the architecture. The diagram is a picture; the Cargo.toml is the law.

  • deino-core: zero I/O, depends on nothing — the pure center that mirrors the DB enums.
  • Use-case slices depend on traits, never on sqlx — tests swap mocks, business logic never touches a pool.
  • deino-api is the only crate that knows which adapters are live — the composition root, and the only seam.

What it costs, and what it buys

The cost is discipline at the boundary. A developer who wants to add a quick database call inside a domain crate has to instead add a method to a trait, implement it in the adapter, and wire it at the composition root. That is three files instead of one. The payoff is that the domain crate stays testable in isolation, the adapter stays swappable, and the manifest claim that the domain is what ran stays true. We are pre-revenue and building the POC; the architecture is built and the discipline is what keeps it from rotting into a ball of mud by the time the POC has to defend itself.

A domain crate with no I/O is a crate you can reason about by reading. The types are the spec; the adapters are the plumbing. An auditor reads the spec.

— hexagonal design note
§Keep reading