Souspli

Souspli / Docs / Design notes

Design note — 2026-07-21. A decision record, written when this was built and kept as written. It uses the code's names (thing, shell, cage — see the glossary) and may describe things that have since changed. Current documentation: locators.

Build brief — transport

Phase 4. Phase 3 built the shell that admits, indexes, and mounts things from file / paste / drag. Transport is how those same bytes arrive from anywhere — a magnet link, a peer, a URL — without changing anything downstream. The whole design already anticipates this: a bundle is self-contained and verify-at-the-gate means the fetch is untrusted for content. This brief makes the fetch real and keeps that property load-bearing.

Depends on: the merged shell (admission, library, mount) and the existing interface Transport stub in src/shell/transport/.

The one principle that governs everything here: the transport is untrusted for content; admission is the only gate. A transport hands the shell raw bytes. It cannot make the shell admit anything — admission re-verifies every signature and hash over the received bytes. So a malicious peer, a corrupted download, or a buggy transport yields at worst a rejected bundle, never a compromise. What the transport CAN do is exhaust resources (stream unbounded data, hang), so the fetch path is resource-bounded even though it is content-untrusted.


1. The interface and the locator

A locator is a scheme-tagged string naming where/what to fetch. The transport layer dispatches by scheme; adding a transport MUST NOT require touching admission or the library.

interface Transport {
  supports(locator: string): boolean
  fetch(locator: string, limits: FetchLimits): Promise<Uint8Array>
}

v1 locators:

Naming (thing:<name> → locator) is the next brief; it resolves a name to one of these locators. Direct locators work with no resolver at all.

2. Resource bounds — the fetch is the boundary

The fetch pulls attacker-influenced bytes into the trusted process before admission runs, so it MUST be bounded:

A fetch that exceeds a bound is a clean TransportError, never a crash.

3. Content-addressed integrity (before admission)

For a content-addressed locator (bundle:<hash>), the service verifies sha256(fetched bytes) == <hash> before handing the bytes to admission. This is the "the locator names the exact bytes" guarantee: a transport that returns the wrong bytes for a bundle:<hash> request is caught at the fetch layer, not left to admission. (For file: and magnet: there is no content hash in the locator — magnet has its own infohash integrity inside webtorrent — so admission is the sole gate.)

4. webtorrent — wired, live path manual

magnet: routes to a WebtorrentTransport that lazily imports webtorrent and downloads the bundle, enforcing maxBytes / timeoutMs. webtorrent is a heavy WebRTC/DHT dependency and this environment has no peers, so:

Seeding: an admitted bundle is retained in a seed store (content-addressed by tar-hash) so the shell can re-serve it — bundle:<hash> fetches from it in tests, and webtorrent seeds from it when enabled. Seeding a sealed bundle re-serves its ciphertext (the paper-flyer forward property, §7); the seed store holds the raw admitted bytes, which for sealed things are already encrypted.

5. Fetch → admit → library

TransportService.fetch(locator, limits) returns bounded bytes; the shell then runs the existing ingest path (admission → library). Nothing about admission or the library changes. A new shell hook + omnibar affordance let a user paste a locator (magnet/bundle/file) instead of raw bytes.

On admit, the raw bundle is added to the seed store so it can be re-served.

6. Tests (deterministic, no network)

7. Definition of done

A Transport interface with dispatch by locator scheme; real file: and content-addressed bundle: transports; a seed store that retains admitted bundles; webtorrent wired behind the interface for magnet: with a clean degrade when absent; the fetch path resource-bounded (size + timeout) and content-addressed locators integrity-checked before admission; a verify-at-the- gate test battery proving a hostile/oversized/hanging transport cannot compromise or wedge the shell; the fetch→admit→library→seed flow wired end to end with a shell hook and an omnibar affordance.

8. Out of scope (// LATER:)

Naming resolution (thing:<name> → locator) — the next brief. HTTP(S) transport. webtorrent live-network testing and seeding-to-peers in CI. DHT privacy hardening. Partial/streaming render before full fetch. Peer reputation / rate-limiting.