Not a bug — phase 0 of the swarm-llm-workloads feature (openspec
swarm-llm-workloads, design D13). Distributed LLM work needs file inputs
and outputs, but Krill’s state spine (H2 → SharedFlow → SSE → peer mirrors)
carries every snapshot value on every hop, so inline file bytes would
balloon the whole pipeline and die on asymmetric WAN links.
The design tension: files must be first-class values, but the spine must
never carry bytes. Resolved with the claim-check pattern — a FILE
snapshot holds a ~200-byte serialized FileRef (sha-256 hash, size, mime,
owning host) and the bytes live in a per-server content-addressed blob
store, pulled lazily and only by whichever server wins the work.
BlobStore(root, selfId) — content-addressed by sha-256, write-once by
construction, streaming putStream that enforces the size cap and hashes
while copying (an oversized body is refused mid-stream, never buffered).POST /files (local submission upload → FileRef) and
GET /files/{hash} (peer pull; opaque octet-stream — the puller already
holds the metadata). Unlike the public diagram/image GETs, both require
the cluster bearer.WorkFileCache(root) — pull-side cache keyed by work id; every put
verifies hash+size before caching, cleanup on DONE/FAILED/lease-expiry
so a reclaim strands no foreign bytes.fileRefOrNull — the pure validation seam DataProcessor uses so a
malformed FILE snapshot is refused at ingestion.The strict hex-64 hash shape check doubles as the path-traversal guard —
validate-by-construction beats canonical-path comparison. Storage roots and
the server’s own id are constructor parameters with production values bound
only in Koin (ServerModule), so every test runs on a temp dir with a
fixture id; the suite passes under HOME=/nonexistent. When adding a route
that writes to disk, put the branching in pure functions and keep I/O at
the handler boundary — that is what makes it testable under this repo’s
pinned Ktor test classpath (no testApplication).