6.3.10 Remote Input Presentation

The input closure can be present in CAS and still be slow or fragile to hand to an executor. A large C++ action may declare a toolchain with thousands of headers while reading only a few of them; another action may walk every path before it starts useful work. Once 6.3.7 Remote Execution Storage has proved that the immutable Merkle/CAS closure is available, this is the next decision: how should the worker present that same closure as its execution-root files?

This is not an action-readiness check and it is not a claim that a filesystem is an isolation boundary. The action's declared closure and identity have already been established; the input-view implementation changes when the worker pays for directory metadata and bytes. The worker lifecycle and cross-action security boundaries remain the separate concern of 6.3.9 Remote Executor Environments and Isolation.

Start with the portable baseline

REAPI describes the Action, its input-root directory, and the CAS blobs that make up the declared closure. It does not require an executor to copy those blobs into ordinary files, mount a remote filesystem, use FUSE, use snapshots, or retain any local input cache.1 A portable executor can therefore walk the input tree, fetch the referenced directory metadata and file bytes from CAS, and create an ordinary execution root with read-only declared input paths and prepared output locations before starting the command. Call this eager materialization.

Eager does not mean that every byte was newly transferred from a distant service. A worker may have a local CAS cache; the important operational fact is that command start waits until its normal filesystem view is complete. Its costs are easy to locate: CAS directory traversal, metadata lookups, directory and permission creation, missing-content transfer, then the command. A failure in any of those steps is an input-presentation failure, not proof that the scheduler chose the wrong worker or that the command itself failed.

This baseline is valuable even when it is not the fastest path. It has a straightforward setup-failure recovery story: before the process starts, discard the failed view or root and rebuild the same readable input-root closure in a fresh action root. Keep this implementation tested as the ordinary fallback for every optimized path.

Lazy presentation trades startup work for access-time work

A lazy, CAS-backed view makes the directory shape visible first and obtains a file's content when the process reads or executes it. Buildbarn documents one such worker-side implementation: a FUSE view on Linux or an NFS view on macOS serves declared files on demand; its workers can record access and prefetch expected reads for similar actions.2 Its reported benefit is specific to actions whose declared closure is much larger than the part they touch. It is not a REAPI feature and it is not a universal performance result.

The trade is easier to reason about as a path, not a label:

PresentationWork before command startWork on first accessLikely losing workload
Eager materializationTraverse metadata and create the complete ordinary view; fetch all missing content.Normal local filesystem access.An action declares a very large, sparse toolchain and reads little of it.
Lazy CAS-backed viewCreate or mount a view and enough metadata to resolve paths.Fetches and may validate each first-needed file; metadata lookups can also fan out.An action quickly scans, stats, or reads most of its declared tree.
Snapshot or layered local viewAttach a prebuilt immutable base plus the action's writable layer.May fault or copy data when the chosen snapshot/layer cannot serve it.The base is stale, too broad, not locally available, or expensive to invalidate safely.

The snapshot row is deliberately not a portable third REAPI mode. A snapshot can be an implementation's way to reuse a read-only base or make a prepared view cheap to attach. It must still show that the exact declared input root is what the action sees, that writes go to an isolated layer, and that reuse cannot make another action's residue visible. A FUSE-like name proves even less: it only describes one local interface. Neither snapshots nor FUSE add hermeticity by themselves.1 6.3.9 Remote Executor Environments and Isolation supplies the separate process or VM boundary and the lifecycle tests around it.

Stripe's remote-execution design is a useful scoped example of these distinctions. It used LVM copy-on-write snapshots to attach large input roots to Firecracker microVMs, and evaluated read-only SquashFS images with an OverlayFS writable layer for large, relatively stable dependency trees. Those choices changed how inputs and writes appeared inside the guest; Firecracker supplied the isolation boundary. The combination is evidence that snapshot and layered views can serve one production workload, not a portable REAPI stack or a default for another fleet.3,4

Account for directory traversal as well as file bytes

Before any eager, lazy, or snapshot-backed view can expose the input root, the executor may need to enumerate its Merkle directory tree. REAPI's GetTree operation provides a paginated traversal of a directory tree rooted at a digest; how a service caches, parallelizes, and places that traversal is implementation-specific.1 A slow GetTree path can delay input-root construction even when the file blobs are already available, while optimizing it does not change the worker's isolation strength.

Stripe reported caching and parallel tree walking around this path. Use that as a hypothesis for similarly large directory trees, then retain GetTree spans, page or directory counts, storage locality, cache state, and traversal concurrency alongside mount or materialization timing.3,4 This keeps a metadata-enumeration bottleneck distinct from missing CAS content, view attachment, guest startup, and command execution.

think

Decide: A compile action declares a huge sysroot but reads only a small subset; a packaging action traverses nearly every file in the same sysroot. Which measurements decide whether a lazy input view helps, rather than merely making the compile start earlier?

Reveal

Measure the two action classes separately. Capture metadata operations, declared-versus-accessed files and bytes, time to a usable command start, first-read stalls, total completion time, and cold/warm local-CAS state. The compile may avoid much unused content; the packager can convert that saved startup work into many access-time waits. Include the cost of cache cleanup and the degraded path, not just a warm successful run.

Metadata can dominate before bytes do

“The process reads only 20 MB” is not enough evidence. Resolving that process's paths can mean walking many directories, stat calls, executable lookup, and small-file reads. With a lazy view, each may trigger a directory-object lookup, an RPC, a page or file fetch, or a local-cache validation. Conversely, eager materialization may spend time constructing paths that the process never touches. Buildbarn's access recording and predictive prefetch are an example of treating this as a workload-specific feedback loop, not a promise that lazy always wins.2

Run a version-pinned comparison with the same action class, input-root digest, worker image, CAS endpoint, configuration, and cold/warm conditions. Retain separate timings for input-view setup, metadata operations, byte fetches, command runtime, cleanup, and total result publication. A single “remote execution duration” hides the choice you are trying to make.

The comparison must also state what the local cache is allowed to retain. A warm directory or content cache may be a useful optimization, but it is not an input to silently inherit. Give it a version, an eviction/invalidation rule, and a cold-start capacity budget. When a different input root is requested, the new action must see the requested immutable paths, not a convenient mixture of old names and new bytes.

Treat loss and cleanup as normal branches

A mounted or lazy input view creates extra failure boundaries. The worker can have the correct action digest and still fail because the mount disappeared, the local view process wedged, a directory object was unavailable, a CAS read timed out, or a cached local entry no longer matched its intended closure. Do not relabel those cases as a generic executor failure. Preserve the action and input-root digests, worker and input-view implementation revision, local-cache state, CAS endpoint/tier, failing path or digest, and the phase in which the failure occurred.

Test the versioned implementation in conditions it must survive:

  1. A cold view and a warm view for a sparse reader and a full-tree reader.
  2. A CAS read failure before command start and a failure on the first lazy file access.
  3. Mount or view-process loss before the command and during an access.
  4. Cleanup after success, execution failure, cancellation, and worker reuse; then a next action with deliberately conflicting paths.

The expected answer need not be “continue successfully.” It can be a visible, classified failure followed by a retry or the fallback selected under 6.3.13 Remote Action Failure Handling. What matters here is that the implementation does not expose a partial, mutable, or prior action's view as if it were the declared closure. The FUSE worker case demonstrates demand loading and prefetching, but it does not specify a universal mount-loss or cleanup contract.2

Fall back without changing what the action means

Use different recovery branches depending on whether the command has started:

  • Before process start: discard the failed lazy view or partially prepared root, then materialize the same already-available input-root closure into a fresh ordinary execution root and start the command there.
  • After process start or a lazy access failure: do not switch a live process to another root. Terminate, classify, and clean up the failed attempt. The selected retry or fallback policy may then execute the same Action digest in a fresh materialized root under 6.3.13 Remote Action Failure Handling. That can create a new backend attempt or Operation; it preserves the action identity, not the identity of the in-flight attempt.1

In both branches, keep the command, input-root digest, declared environment, output paths, and execution properties unchanged. The change is the worker's way of exposing bytes, not what action was requested.1

That distinction rules out tempting but unsafe “fixes”: attaching a host directory, reusing another action's writable tree, or adding a local tool because the mount is down. Those are different inputs or ambient state, not a fallback. If ordinary materialization cannot read the required CAS closure, the selected execution path has an input-availability failure. Preserve the worker, CAS endpoint or tier, input digest, and read error; then use 6.3.7 Remote Execution Storage to distinguish a missing closure from a worker-local or transient storage-path failure and determine its scope. A different filesystem cannot restore missing content.

A maintained local REAPI implementation, actiond, is a useful bounded contrast: its guest exposes a lazy read-only input-tree filesystem backed by REAPI directory protos and CAS blobs, while its VM and sandbox control the lifecycle. That proves one current implementation can separate lazy presentation from the CAS contract; it does not make its guest, filesystem, or isolation model a requirement for other executors.5

key takeaway

Once the declared Merkle/CAS input closure is available, choose how the worker exposes it from measured access patterns. Eager materialization pays traversal and transfer before command start; a lazy or snapshot-like view moves some of that cost to metadata and first access. FUSE, snapshots, caches, and mounts are implementation choices, not REAPI guarantees and not isolation proofs.

Qualify the selected view with cold/warm access evidence, cleanup and reuse tests, CAS and mount-loss behavior, and a visible fallback. The fallback is ordinary CAS materialization of the same declared closure in a fresh action root—never a host directory or leftover state. Before process start, discard the failed root; after start, clean up and retry or fall back as a new attempt. That preserves action identity without pretending a live process can change roots.

Check your understanding · 3 questions

1.A worker can expose a declared input root through a FUSE-like lazy view. Which conclusion is portable across REAPI implementations?

Select one answer

2.Which evidence should a team collect before adopting a lazy input view for an action class?

Select all that apply

3.A lazy mount fails before the process starts, but the same input-root digest remains readable from CAS. What is the safe fallback?

Select one answer

0 of 3 answered

Footnotes

  1. Remote APIs — protocol contracts for caching and remote execution — REAPI defines immutable action/input-root and CAS wire contracts, not the executor's filesystem or lifecycle. 1 2 3 4 5

  2. Buildbarn - Remote execution with 100 to 100,000 CPUs — Buildbarn-specific Linux FUSE/macOS NFS demand loading, access records, and predictive prefetch. 1 2 3

  3. Fast Builds, Secure Builds. Choose Two. — Stripe's Firecracker/LVM input-root design, SquashFS experiment, and cached tree traversal. 1 2

  4. Remote execution, the DIY edition — later production measurements and implementation context for worker input presentation and tree traversal. 1 2

  5. actiond — local Linux REAPI executor and cache — pinned local implementation with a lazy read-only REAPI-directory/CAS input filesystem inside a guest.