Problem
The two per-call transports disagree on what happens to a command with no explicit timeout, and the disagreement is invisible to the conformance battery.
packages/k8s-sandbox/src/exec.ts arms a timer only when the caller passes opts.timeout > 0. With no timeout, the kubectl exec child runs until it finishes.
packages/k8s-sandbox/src/grpc-relay-transport.ts applies DEFAULT_DEADLINE_MS = 120_000 unconditionally, so any exec without an explicit timeout is cancelled at 120 s with timeout:120.
Pi's bash tool documents no default timeout (pi-fork/packages/coding-agent/src/core/tools/bash.ts), so a model-issued bash with none runs unbounded on the in-cluster pod path and dies after two minutes on the remote-worker path. A pnpm install, a full test run, or a long build crosses that line routinely.
The shared conformance battery cannot catch this: its timeout case always passes an explicit timeout (packages/k8s-sandbox/test/conformance.ts), so neither transport's default is ever exercised. The battery's green status therefore does not speak to this divergence at all — which is worth noting, because that battery is the evidence behind the epic's transport-swappability claim (#89, driver #2).
Recorded in spec §8's "Accepted divergences" pending this decision. Found by the whole-branch review of the epic-closing work.
The decision
- Give
KubectlTransport the same 120 s default. Makes the transports agree. Cost: commands that work today on the pod path start dying at two minutes — a real regression for legitimate long-running work, and the kind that surfaces as a confusing mid-build failure.
- Raise or remove the gRPC default. Removing it means the harness can hang on a silent or malicious worker, which is the specific thing §8's dual-ended timeout exists to prevent — so this is really "raise it", and then to what?
- Keep them different, deliberately, and add a battery case asserting each transport's documented default. The divergence stops being accidental and starts being tested; the docs already state it.
Whatever is chosen, option 3's test belongs in it — right now nothing pins either default, so both could drift silently.
Refs
Epic #89 · spec §8 "Accepted divergences" and its dual-ended timeout bullet · related #180, #181.
Problem
The two per-call transports disagree on what happens to a command with no explicit timeout, and the disagreement is invisible to the conformance battery.
packages/k8s-sandbox/src/exec.tsarms a timer only when the caller passesopts.timeout > 0. With no timeout, thekubectl execchild runs until it finishes.packages/k8s-sandbox/src/grpc-relay-transport.tsappliesDEFAULT_DEADLINE_MS = 120_000unconditionally, so any exec without an explicit timeout is cancelled at 120 s withtimeout:120.Pi's bash tool documents no default timeout (
pi-fork/packages/coding-agent/src/core/tools/bash.ts), so a model-issuedbashwith none runs unbounded on the in-cluster pod path and dies after two minutes on the remote-worker path. Apnpm install, a full test run, or a long build crosses that line routinely.The shared conformance battery cannot catch this: its timeout case always passes an explicit
timeout(packages/k8s-sandbox/test/conformance.ts), so neither transport's default is ever exercised. The battery's green status therefore does not speak to this divergence at all — which is worth noting, because that battery is the evidence behind the epic's transport-swappability claim (#89, driver #2).Recorded in spec §8's "Accepted divergences" pending this decision. Found by the whole-branch review of the epic-closing work.
The decision
KubectlTransportthe same 120 s default. Makes the transports agree. Cost: commands that work today on the pod path start dying at two minutes — a real regression for legitimate long-running work, and the kind that surfaces as a confusing mid-build failure.Whatever is chosen, option 3's test belongs in it — right now nothing pins either default, so both could drift silently.
Refs
Epic #89 · spec §8 "Accepted divergences" and its dual-ended timeout bullet · related #180, #181.