src/artifactstore/dataplane/:
- spi.py: DataPlane Protocol with the five operations ingest_stream,
serve_object, verify_object, delete_object, backend_health
(ADR-0004). Dataclasses: IngestHints (size_hint, primary_algorithm,
backend_id overrides), IngestResult (primary_digest + sha256_digest +
size_bytes + StorageReceipt), VerifyResult (verified bool, mismatch
reason, actual digests + size).
- inproc.py: InProcessDataPlane wraps one StorageBackend. ingest_stream
is two-pass against a tempfile (drain stream while dual-hashing into
BLAKE3+SHA-256, then forward the tempfile to backend.put under the
primary content address); fsync+cleanup on exception. serve_object
passes byte ranges through; verify_object re-reads bytes via backend.get,
re-digests with the stored algorithm, and reports mismatches. delete
and health are thin pass-throughs.
tests/unit/test_dataplane_inproc.py (11 cases):
- ingest_stream computes correct dual digests, returns receipt, stores
bytes at the content-addressed path.
- empty-input ingest returns the BLAKE3/SHA-256 of empty.
- serve_object round-trips ingested bytes; supports byte_range.
- verify_object verifies intact bytes; detects on-disk corruption.
- delete_object passes through (True then False).
- backend_health passes through.
- IngestHints override of primary_algorithm (sha256-as-primary path).
- Missing-object serve raises ObjectNotFoundError.
- Architectural test (ADR-0004 invariant): no control-plane module
(api / registry / retention / audit) imports
artifactstore.storage.backends.* or artifactstore.dataplane.inproc
directly. Enforced via AST scan of every .py file in those packages.
Gates: ruff clean, mypy --strict clean on 44 files, 70 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>