Files
alkblobs/tasks/ops-fetch.md
T

101 lines
4.8 KiB
Markdown

---
id: ops-fetch
name: blobs/fetch — the verified Sub op and the fanout seam's consumer side
status: pending
depends_on: [ops-foundation, ops-call-harness]
scope: moderate
risk: medium
impact: component
level: implementation
tags: [wave-7, ops, fetch, fanout, verification]
---
## Description
`blobs/fetch` (ops-surface.md §Op family) — the server→client
streaming op: `{namespace, digest, ranges?}` in; **verified bytes
out** over the binary data channel.
- **The op shape**: `OperationType::Sub` (alkcall ADR-021's streaming
handler kind) with the **`channel_open` marker** (alkcall ADR-047)
— the binary data plane rides a `channel_open`-allocated channel;
the establishment phase (alkcall ADR-049) carries the fetch's ack
shape in the `Establishment` reply fields as the wire requires. The
**read** action (ACL exactly like stat/have — closed-by-default).
- **Verified streaming** (ADR-006; ops-surface.md): the *consumer*
hash-checks the received whole against the carried digest —
whole-blob verification; there are no per-chunk or per-range checks
derivable under the canonical digest. The handler streams from the
facade only: `Store::get` (the whole) or `Store::read_range` (the
ranged form). **Ranged fetch** (`ranges?`): the response carries
the same ADR-006 slice-digest convention `read_range` returns —
SHA-256 over exactly the returned bytes, out-of-band.
- **The fanout seam's consumer side** (ops-surface.md; POC #3 finding
A3): the fetch handler consults the foundation's fanout registry —
a live broadcast for the digest → a **subscriber arm** taps it; no
live broadcast, or one that ended (a **late joiner**) → the normal
post-commit verified `get` — identical bytes under CAS. The
slow-subscriber policy (drop-and-late-join) is ops-layer policy,
not a store concern. Named design point: **the producer side's
shape** — the put handler's stream reader as the canonical producer
(serve-while-persisting, A3's shape), and whether fetches also
produce read-side broadcasts (concurrent fetchers of one stored
digest sharing one store read) — decide and record against the A3
text.
- **The miss shape**: a fetch of an absent digest is the typed
missing-error schema (the need announcement *is* the fetch miss —
the have/need diff is caller-side; no separate need op exists).
- **Tests through the harness**: the whole-blob verified round-trip
(byte-exact; the client's hash-check passes); the ranged form
(bytes + slice digest matching `read_range`'s convention); the
fanout consumer side (a live broadcast tapped — the subscriber
receives while the producer runs; a late joiner degrades to the
get path — asserted by which path served); the miss shape; the ACL
denial (no read grant on the namespace → denied).
## Acceptance Criteria
- [ ] fetch exported as a Sub spec/handler pair with the
`channel_open` marker + ALPN; the establishment reply fields
carry the specced ack shape
- [ ] Whole-blob verification: the received whole hash-checks against
the carried digest (the consumer-side discipline documented on
the op; the server streams verified-store bytes)
- [ ] Ranged fetch carries the ADR-006 slice-digest convention
(out-of-band, over exactly the returned bytes)
- [ ] The fanout consumer side: a live broadcast → subscriber arm; a
late joiner → the verified get path; the producer-side design
point decided and recorded
- [ ] The miss shape is the typed missing error; the have/need diff
stays caller-side (no need op invented)
- [ ] ACL: the read action; closed-by-default verified by test
- [ ] Handlers touch only the store facade (no backend side-door)
- [ ] Harness tests green; `cargo test` (default) green;
`cargo test --features ops` green; clippy/fmt green on both
shapes; `cargo doc --no-deps` clean
## References
- docs/architecture/ops-surface.md (§Op family — the fetch bullet +
the fanout text; the need-half note)
- docs/architecture/decisions/006-verification-posture-and-transfer-encoding.md
(whole-blob verification; the slice-digest convention)
- docs/architecture/decisions/008-trait-size-probe-fleet-gc-and-large-engines.md
§3 (the re-routing topology this op serves — large-blob access
through a storage node)
- docs/research/poc-largeblob-findings.md finding A3 (the fanout
seam: one reader, store arm + subscriber arms; late joiners
degrade to get-after-commit)
- alkcall (upstream checkout): ADR-021 (streaming handler for
subscriptions), ADR-046/047/049 (the sink kind, the channel_open
marker, the establishment phase), `src/channels/client.rs`
- tasks/ops-foundation.md (the fanout registry's mechanics),
tasks/ops-call-harness.md (the harness)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion