Skip to content

review: phase-A round of the e2b drop-in series - #58

Merged
CMGS merged 12 commits into
masterfrom
review/phase-a-round
Sep 27, 2026
Merged

CMGS merged 12 commits into
masterfrom
review/phase-a-round

Conversation

@CMGS

@CMGS CMGS commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Summary

The phase-A end review round of the e2b drop-in series, run at repository scope on master 2ef6a7c (the batch #50–#56) and rebased onto 4e10f5c2 (#57). Four style readers over the 30 files the hygiene ledger listed as due, three adversarial judges (e2b API contract, store concurrency and protocol, meshinventory after its fix), the four /simplify lenses over the batch diff. Every finding was adjudicated against the source; the applied ones are below, the kept ones are in the round report.

Twelve commits, each one thing:

  • review: layout move and three comment cuts (store, e2b surface).
  • review: one logs handler for both routes; warmByKey over PoolCapacity replaces two copies of the pool mapping; the list filter's redundant guard; a page drops entries before sorting; the connect failure message is one constant; two tests reuse pageOfList.
  • docs: snapshot-placement.md said the client never follows redirects (feat: the claim loop follows sandboxd claim redirects #52 changed that); pkg/scale's package doc names both inventory sources; ListNodes no longer says cache-fed.
  • fix: the fleet HTTP client gets a one-second dial timeout. Without it a black-holed dial (a dead node on a routed network) ended as the client's request timeout, which carries no dial OpError, so the store read it as a possibly delivered claim and answered 500 after ten seconds instead of trying the next node. Probe on the store's transport: before took=2s undelivered=false (Client.Timeout exceeded), after took=1s undelivered=true (dial tcp 10.255.255.1:7777: i/o timeout). Table test pins the classification.
  • fix: AddressIPs cuts a client origin's scheme; with client_advertise set the kube path stamped https as a pod IP.
  • fix: an unnamed mesh member leaves only after MaxStale silent ticks. A discovered sandboxd that restarts gracefully leaves the mesh on shutdown and rejoins after its reconcile, so "unnamed and failed ⇒ leave at once" hid the node for ~2 ticks on every rolling restart (List dropped its sandboxes, watch emitted Deleted/Added, Get 404, verbs failed). Two rules the tests did not pin now are: publish keeps the fewest-fails member per key, and a seed wins the dedupe. Each new test fails on the previous code.
  • fix: the chart passes the template alias file (apiserver.e2b.templateAliases → ConfigMap → flag); on a chart deploy Sandbox.create() still asked for base and got 503.
  • fix: the v2 page cursor keys on the raw claim time; an entry without claimedAt rendered startedAt as the read time, so its cursor key changed every second (an ascending walk repeated it, a descending one skipped its block). Regression test fails on the old key.
  • fix: GET /templates/aliases/{alias} also answers for an image a pool advertises, the names the template list reports, so Template.exists(image) agrees with Sandbox.create(image). Docs: reconnect by id needs SDK 2.6 or later.
  • review: one-line comments in the warm-pool driver, the sandboxd client and the mains (+25/−70).
  • review: --e2b-template-alias-file, named like --e2b-api-key-file; no release carries the old name.
  • docs: an unnamed mesh peer leaves after the same ticks its snapshot survives.

Numbers

  • Prod lines net −42 (+94/−136); test +59; comment lines +33/−82 (every remaining comment is a one-line godoc on an exported identifier or a one-line WHY).
  • Hot path: the warm-hit claim is unchanged; the redirect hop unchanged; list pays the same sort on fewer items; the alias lookup pays a fleet inventory scan only on a miss of the alias table; the dial timeout removes a ten-second stall on a dead node.
  • Hardware: the phase-A real-SDK matrix on 2ef6a7c is all PASS (.hygiene/e2b-matrix-2026-09-27-phaseA/, README table and 18 raw files); the fixes here are unit-pinned and change no verified path's behavior except the dead-node and restart cases described above.

Gates (my run, GOWORK=off)

  • go build ./..., go vet ./... and the three tagged harnesses: ok
  • go mod tidy -diff: clean
  • asl -forwarder=false ./...: 0 findings on darwin and linux
  • go test -race -count=1 ./...: 10 ok
  • make lint fmt-check: 8/8 0 issues.
  • helm lint, helm template with and without templateAliases: ok

CMGS added 12 commits September 27, 2026 16:29
WithClaimRouting joins WithWatchPollInterval instead of sitting between the SandboxdClientFactory type and its constructor. Three comments go: the section label above the synthesized-Sandbox labels, whose four constants carry their own godoc; the apiKeyHeader line, which the name and its one use carry; and the floating note in types.go, which the package doc already states by naming the OpenAPI contract.
… trimmed

The two e2b logs handlers differed only in their reply, so one handler takes the reply and the mux registers it twice; the reply is built once at registration. The warm-pool driver mapped pools onto warm counts in two places and duplicated scale.PoolCapacityFromInfo in a third; warmByKey over PoolCapacity serves both call sites. The list filter's template guard goes, since poolImage of an empty string is empty. A page drops the entries at or before its cursor before sorting, which sorts less for the same result. The connect failure message is one constant. Two tests reuse pageOfList instead of their own copies of it.
…ory sources

snapshot-placement.md still said the client does not chase redirects and the store answers 503 on any redirect, which #52 changed. The package doc named only the Kubernetes source; #54 added the mesh source. The ListNodes contract no longer says cache-fed, since the mesh source answers from a polled snapshot.
…ity miss

The fleet HTTP client set no dial timeout. On a routed network a dial to a
dead node is black-holed until the client's request timeout fires, and that
error carries no dial OpError, so the store read it as a possibly delivered
claim and answered a hard error after ten seconds instead of trying the next
candidate; a dead node's inventory stays a candidate, so every create that
sampled it paid that. A one-second dial timeout surfaces as a dial OpError,
which claimUndelivered already classifies as nothing sent. Probe on the
store's transport: before, took=2s undelivered=false (Client.Timeout exceeded
while awaiting headers); after, took=1s undelivered=true (dial tcp
10.255.255.1:7777: i/o timeout). The table test pins the classification.
sandboxd reports owner_addr as the client origin when client_advertise is
set, and the apiserver's Create stamped it through AddressIPs onto
Status.PodIPs; net.SplitHostPort on https://host yields the scheme as the
host, so the pod IP read https. The scheme is cut before the host is taken.
A discovered sandboxd that restarts gracefully leaves the gossip mesh on
shutdown and rejoins only after its reconcile, while its sandboxes keep
running. The source dropped an unnamed member at its first failed tick, so
every rolling restart hid the node for about two ticks: List lost its
sandboxes, watch emitted Deleted then Added, Get answered 404 and the
lifecycle verbs failed to resolve the node. An unnamed non-seed now leaves
the membership only after MaxStale consecutive failed ticks, the same
window its snapshot survives, so a restart inside it is invisible. Two
rules the tests did not pin are pinned: publish keeps the member with the
fewest failures for a key, and a seed wins the dedupe over the gossiped
spelling of its own node. The smoke tool shares one fleet HTTP client the
way cmd/sandbox-e2b does.
--e2b-template-aliases landed in #56 without a chart value, mount or flag,
so on a chart deploy the SDK's default Sandbox.create() still asked for
base and got 503. apiserver.e2b.templateAliases holds the file's lines; the
chart renders them into a ConfigMap, mounts it and passes the flag when the
value is set.
detailFor renders startedAt as the read time when an entry carries no
claimedAt, and the v2 page cursor keyed on that rendering, so such a
sandbox changed its cursor key every wall-clock second: an ascending walk
repeated it without end and a descending walk skipped the rest of its
block. The cursor now keys on the raw creation time, where an absent one
is a fixed zero, and the rendered startedAt is unchanged. Entries without
claimedAt exist only for claims that outlived an upgrade from a sandboxd
that predates the field.
GET /templates lists each pool image under names, which on e2b is exactly
the set the alias lookup accepts, but the lookup knew only the alias
table, so Template.exists(image) was false while Sandbox.create(image)
worked. The lookup now also answers 200 for an image a pool advertises.
The docs say reconnect by id needs SDK 2.6 or later: older JS SDKs read
the envd token from the detail read, which carries no secret here.
…t and the mains

The driver carried six-line justifications on a const, on a predicate and
inside a goroutine; each now states its one fact. Comments that restated a
name or a struct literal go, and the two-line godocs that fit one line are
one line. No code changes.
The flag takes a file path, as its siblings --e2b-api-key-file and
--sandboxd-token-file do, and no release carries the old name.
@CMGS
CMGS merged commit 6da4f6f into master Sep 27, 2026
2 checks passed
@CMGS
CMGS deleted the review/phase-a-round branch September 27, 2026 08:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant