Skip to content

refactor(endpoint): split 998-LoC endpoint.rs into named subsystem modules (ADR-014 D1) #192

Description

@momics

Summary

crates/iroh-http-core/src/endpoint.rs is 998 LoC, larger than the 747-LoC file the original epic-#182 evidence section called out as the symptom of structural drift. ADR-014 D1 prescribed a four-subsystem split (Transport, HttpRuntime, SessionRuntime, FfiBridge) as named modules with strict boundaries. Slice C.6 (commit b146b0c) inlined them all back into one file plus the configuration types from crate::config and crate::stats.

The result satisfies the canonical-root-layout invariant on paper but contradicts ADR-014 D1's "named subsystems with strict module boundaries." The four pub(crate) structs live as anonymous siblings inside one file, accessed via endpoint.inner.http.active_connections — there is no module boundary protecting any subsystem from any other.

This is the exact same drift pattern (named-but-not-delivered split) the epic body listed as the canonical example of what to prevent.

Evidence

endpoint.rs:1-13 header references the four ADR-014 D1 subsystems by name:

[IrohEndpoint] is a thin façade over [EndpointInner], which is composed of the four named subsystems from ADR-014 D1: [transport::Transport], [http_runtime::HttpRuntime], [session_runtime::SessionRuntime], [ffi_bridge::FfiBridge].

But those module paths don't exist. The structs are inline:

endpoint.rs:27-101:

  • pub(crate) struct Transport (L27)
  • pub(crate) struct HttpRuntime (L40)
  • pub(crate) struct SessionRuntime (L66) — with stale "Slice E carve-out" comment
  • pub(crate) struct FfiBridge (L96)

Plus 11 pub struct configuration / observability types (NetworkingOptions, DiscoveryOptions, PoolOptions, StreamingOptions, NodeOptions, NodeAddrInfo, EndpointStats, ConnectionEvent, PeerStats, PathInfo) and the IrohEndpoint facade itself.

Callers reach across subsystems freely. Example: crates/iroh-http-core/src/http/server/accept.rs:75-77 does endpoint.inner.http.active_connections directly. There is no encapsulation.

Impact

  • ADR-014 D1 is partly aspirational. The names exist in the doc and the comment header; the boundaries don't. Anyone reading the ADR gets a misleading mental model.
  • Future drift has no friction. A new field belongs in one of the four subsystems by ADR; in practice it lands wherever in the 998-line file is convenient. The "drift back to a god-object" pattern the epic was filed against is structurally available.
  • The canonical-root-layout test, which is otherwise excellent, is currently doing extra work to prevent a problem that the named-modules split would have prevented more naturally. The test was filed to stop random files at root; allowlisting endpoint/ as a folder doesn't reopen that vector.

Remediation

Promote the four subsystems to a folder:

crates/iroh-http-core/src/
├── lib.rs
├── endpoint/
│   ├── mod.rs           — IrohEndpoint facade + EndpointInner only
│   ├── transport.rs     — Transport struct + impls
│   ├── http_runtime.rs  — HttpRuntime + ConnectionTracker
│   ├── session_runtime.rs — SessionRuntime + serve handle plumbing
│   ├── ffi_bridge.rs    — FfiBridge + StoreConfig
│   ├── config.rs        — NetworkingOptions, DiscoveryOptions, PoolOptions,
│   │                      StreamingOptions, NodeOptions
│   └── stats.rs         — EndpointStats, PeerStats, PathInfo,
│                          ConnectionEvent, NodeAddrInfo
├── http/
└── ffi/

Update tests/architecture.rs::crate_root_has_canonical_layout ALLOWED to be &["lib.rs", "endpoint", "http", "ffi"] (folder, not file). The structural intent of ADR-014 D1 returns; the mod http / mod ffi invariant is unaffected.

Each subsystem pub(in crate::endpoint) struct so cross-subsystem reads must go through accessor methods on IrohEndpoint, not field access. That moves the encapsulation invariant from "trust review" to "trust the compiler."

If this is rejected, ADR-014 D1 should be edited to say "subsystems are inline structs in endpoint.rs" so the doc and the code agree. Status quo leaves them disagreeing, which is the whole pattern epic #182 was filed to prevent.

Acceptance criteria

  1. The four subsystems live in their own files under endpoint/.
  2. Cross-subsystem field access is no longer possible — callers go through accessor methods on IrohEndpoint (or the relevant subsystem facade).
  3. tests/architecture.rs::crate_root_has_canonical_layout allowlists endpoint/ (a folder) and still rejects any other top-level entry under src/.
  4. endpoint/mod.rs is ≤ 200 LoC (façade + module declarations only).
  5. ADR-014 D1 is updated if any names diverge from the prescription, or stays unchanged if the new structure matches it verbatim.
  6. npm run ci green; 92 interop pairs pass.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium priorityapiAPI design / ergonomicsenhancementNew feature or requestrustPull requests that update rust code

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions