Files
poimen/tasks/T4.3-lazy-blob-access.md
T

3.3 KiB
Raw Blame History

T4.3 — Lazy blob access

Field Value
Phase P4 — Verification
Size S — under 1 day
Status Not started
Flags
Spec inlined below
Blocks

Goal

A verifier that needs no text performs no blob reads.

Facts (inlined — no spec read needed)

  • Context partitions hold identifiers — packed, available-but-not-packed, dropped — and are small enough to inline. Prompts and outputs are large and go by reference.
  • Laziness matters concretely: a verifier that shells out and checks an exit code needs none of this. Making every verifier carry prompt text penalizes the common case and blows broker payload limits.
  • VerifierCtx.blobs: Arc<dyn BlobStore> is the mechanism — the verifier calls get if and only if it wants a body.
  • get may return None after reduction (T8.4); that is a normal answer, and a verifier must not treat it as an error.

Steps

  1. Confirm EpisodeView carries BlobRef only. No prompt_text field, no eagerly-resolved cache.
  2. Pass the store handle through VerifierCtx.blobs.
  3. Instrument the store with a call counter behind a test-only wrapper — counting is what turns this from an intention into an assertion.
  4. Write the exit-code verifier used as the acceptance case: it reads the attempt state and nothing else.
  5. Write a second, text-reading verifier and assert its call count is exactly the number of refs it asked for — no over-fetch, no prefetch-all.

Acceptance

  • An exit-code verifier records zero BlobStore::get calls.

Verify

Harness: a counting BlobStore decorator wrapping the real store, injected through VerifierCtx.blobs.

Integration testtests/it_lazy_blobs.rs:

  1. Run a real run with an exit-code verifier that reads only attempt state.
  2. Assert the counter is exactly 0.
  3. Run a text-reading verifier that resolves 2 refs. Assert the counter is exactly 2 — not more (no prefetch) and not fewer (no silent cache hit masking a missing read).
  4. Assert EpisodeView has no field holding blob bytes — a compile-level check if the type is closed, otherwise a serialization size assertion on a run with a 1 MB prompt: the view must stay small.
  5. Reduction interaction: delete a blob body, then run the text verifier; assert get returns Ok(None) and the verifier handles it without erroring.
  6. Assert the counter is per-run, not global, so parallel tests do not mask each other.

Command: cargo test -p verify lazy_blobs

False pass:

  • Counting at the store level while a caching layer sits above it. The count then measures cache misses, not verifier behaviour. Wrap the handle the verifier actually receives.
  • Step 4 omitted: a prompt_text convenience field makes every verifier pay, and steps 13 still pass if the resolution happens at view-build time rather than through cx.blobs. The size assertion catches that.

Traps

  • A "convenience" EpisodeView::prompt_text() that resolves on access. Every verifier then pays, invisibly.
  • Prefetching all refs when the view is built, which is the same regression one layer earlier.

Background (not required to do this task): rust-agentic-sys.md §10.1 · rust-agentic-task.md