Skip to content

Worker-side truncation is invisible to the seam's truncated flag: a capped non-streaming exec returns a real exit code over cut output #189

Description

@pdettori

Problem

PR #188 made truncation explicit on the SandboxTransport seam (truncated: boolean, with the invariant truncated === true ⇒ exitCode === null). One path can still cut output and report success: the Go worker's own buffer cap.

remote-worker/internal/exec/runner.go:295-296, on the non-streaming path (runner.go:233, if !s.Streaming):

} else if room := BufferCap - buf.Len(); room > 0 {
    buf.Write(b[:min(n, room)])
}

Output past BufferCap is dropped silently, and the worker then sends End carrying the command's real exit code. GrpcRelayTransport receives exactly BufferCap bytes — which is not > outputCap, since BufferCap == DEFAULT_OUTPUT_CAP == 8 MiB — so it resolves { truncated: false, exitCode: <real code> } over output the worker truncated.

The equality of the two caps is precisely what makes it silent. If they differed by a byte in either direction, the harness would either trip its own cap or never fill the buffer.

Reachability

Not reachable from this repo today. packages/k8s-sandbox/src/grpc-relay-transport.ts:51 hardcodes streaming: true on every Exec, so the non-streaming branch is never taken by our client.

But runner.go:36 warns about exactly this: Exec.streaming is relay-supplied and false is the proto3 default, so any other relay or client — buggy, third-party, or hostile — reaches this path with no privilege at all. sandbox/v1 is a language-neutral contract intended for third-party workers, so "our client happens not to do it" is a weak guarantee.

Why it matters

This is the one remaining path where the seam's contract is violated rather than merely qualified: a caller gets a success exit code over incomplete output, with no signal. That is the same defect class as #181 (a killed bash reported as success), which #188 just closed on the other transports.

Options

  1. Make the worker signal truncation on the wire. Requires a field on End (or a distinguished exit code) and a sandbox/v1 change, so it is a contract decision across three languages — the same class of change req_id is not globally unique: colliding ids from multiple harness replicas misroute frames at the relay #179 weighed.
  2. Make the caps deliberately unequal, so the harness's cap always trips first (e.g. worker BufferCap = harness cap + 1 chunk). Cheap and no proto change, but it encodes a subtle invariant in two repos that packages/k8s-sandbox/test/output-cap-coupling.test.ts currently pins as equal — that test would need to pin the offset instead.
  3. Reject streaming: false at the relay, since our client never sets it. Narrows the surface without fixing the contract for third-party workers.

Refs

Found by the whole-branch review of #188 (ST6, docs/specs/2026-08-30-seam-output-cap-truncation-design.md), whose §2 explicitly excluded worker changes. Pre-existing, not introduced by that branch. Related: #181, epic #89.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions