Skip to content

review: solo whole-repo round on d5d7887 (config seed fix, cuts, owner calls) - #303

Merged
CMGS merged 3 commits into
mainfrom
review/solo-2026-10-03
Oct 3, 2026
Merged

CMGS merged 3 commits into
mainfrom
review/solo-2026-10-03

Conversation

@CMGS

@CMGS CMGS commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Whole-repo review round on main d5d7887: Go (sandboxd, protocol/wire, sdk/go, mcp, e2e harness and credsmoke), Rust (boot/init, silkd) and Python (cocoonsandbox, openai, langchain) production files read in full, plus every test file the hygiene ledger listed as changed by #299/#302.

Fix

  • 16f2af1 poolSeedHash stripped egress, warmup, capture_trim and storage but not egress_upstream_env. SetPools also rejects that field as config-owned. On a node with pools.json, editing a config pool's egress_upstream_env made the next boot log "config.json pools differ from the API-applied set and are overridden", even though the field still applies from the config.
    • Regression test TestPoolSeedHashIgnoresConfigOwnedFields: it fails on the old code (a egress_upstream_env edit changed the seed) and passes now.
    • The pinned seed bytes do not change, because the field is omitempty, so existing pools.json files keep matching.
    • The SDK PoolSpec doc and the PUT /v1/pools reference had the same omission and now list the field.

Cuts (behavior-preserving, no comments added)

  • 0fc0e7d
    • deleteCkLocked, retryArchiveDelete and resolveGolden now release the record lock once instead of separately on every branch.
    • NewManager, ValidateVolumes, handleSandboxes and the MCP tool-error path use cmp.Or for their fallbacks. Config validation already rejects a negative max_fork_count or refill_concurrency, and no test passes one.
    • Policy.Validate checks for a repeated port against the ports before it instead of building a map.
    • Untar drops a default: continue that did nothing.
  • 351a473 Python SDK:
    • decode_response now uses contextlib.suppress instead of try/except/pass, as /code-py requires.
    • _feed_stdin drops a non-empty check that its only caller already guarantees.

Owner calls (logic changes, not applied)

  1. claims.json whole-file rewrite. Every claim, renew and env write marshals and writes the whole claim set: O(N) per write, plus an fsync under sync_claims. Concurrent writers are group-committed by sequence. Candidate: an append-only claim journal with periodic compaction. This changes the on-disk format and the recovery path.
  2. engine.readLine reads the hybrid-vsock OK <port> reply one byte at a time. That is about 10 read syscalls on every DialSilkd, which every relay, exec and port dial pays. A buffered reader handed to the returned conn would remove them, but it changes the conn the relay copies over. It needs an interleaved A/B on hardware first.
  3. silkd claim_env() re-reads /run/silkd.env on every exec, pty and session spawn. The host can rewrite the file at any time, so caching it needs invalidation (mtime or an explicit signal). Spawn cost dominates today. Listed for completeness only.

Kept, with reasons

  • Forwarders refillGated, benignSweepErr and skipIdle: already recorded as kept in the ledger.
  • Template owner reads (HasPromotedTemplate / ownedTemplate / checkTemplateOwner): each maps errors differently, and a shared helper would hide each caller's policy.
  • ReloadConfig's append([]string{}, changed...): slices.Clone would turn an empty changed into JSON null.
  • tenants/pg Replace's slices.AppendSeq([]string{}, …): an empty set must reach ANY($1) as {}, not NULL. With NULL, the delete would remove nothing.
  • peer.dedupAddrs: it keeps the original order, and no stdlib helper does an order-preserving dedup.
  • Env.HasInject / HasGuest loops: the stdlib has no iterator ContainsFunc, and collecting the values first would allocate.
  • Missing godoc on Hibernate / Engine.Stop, and wrapped multi-line godoc in protocol/wire and the public SDK types: adding or rewrapping comments in a sweep is churn.
  • Rust ownership: no unjustified clones. Every surviving .clone() either builds an owned wire value (ProcInfo.argv for ps, the LSP server id for both the reply and the reaper, a session id that is both inserted and returned), crosses a 'static boundary (replace's path into spawn_blocking), or is an Arc (the per-file name shared by find matches).

Hot path

No change to the claim, relay or egress request path. The cuts touch config load, record-lock release order and admin endpoints.

Gates

gate result
GOWORK=off make go-lint (darwin) 0 issues. ×10
GOOS=linux GOWORK=off make go-lint 0 issues. ×10
asl -forwarder=false ./..., 5 modules × 2 GOOS all empty, rc=0
asl ./... (advisory forwarder) only the 3 forwarders listed above as kept
golangci-lint v2.13.2 fmt --diff on sandboxd and mcp empty
make go-test with SANDBOXD_TEST_PG_URL (darwin) every package ok
tenants/pg, uncached, verbose 5 top-level PASS, 0 SKIP
go test -race -count=1 ./..., 5 modules, golang:1.27.1 linux/arm64, non-root, PG reachable every package ok
Python SDK: ruff format --check, ruff check, pytest (py3.12) formatted, all checks passed, 224 passed
Rust gates not run: no Rust file changed
Hardware E2E not run: no runtime-path change

Not covered

  • The e2e hardware drivers other than credsmoke and the harness were not re-read: they are unchanged and already clean in the ledger.
  • The same applies to the unchanged Rust and Python test files.

LOC

This round:

  • prod −27 (+22/−49): 16f2af1 +1, 0fc0e7d −26, 351a473 −2.
  • tests +19.
  • docs ±0.
  • Comment lines: Go +2/−2 (two edited doc lines), Python 0/0.

Repo at this head:

total effective
Go prod 26254 22312
Go test 31558 —
Rust prod 4784 —
Rust test 3663 —
Python prod 2467 —
Python test 2387 —
  • Go prod includes 4554 lines of test scaffolding (e2e 3426, silkdtest 630, tenantstest 256, storetest 242), so Go prod without it is 21700.
  • Go prod comments are 1579 lines, 6.0%, so comments are not what drives the size.

Since 2026-09-03 (aab87ad):

Ledger (.hygiene/sandbox.tsv), files due:

lens before after
style 28 0
judge 18 0
loc 28 0
comments 28 0

CMGS added 3 commits October 3, 2026 02:30
…ig-owned fields

poolSeedHash stripped egress, warmup, capture_trim and storage but not
egress_upstream_env, which SetPools also rejects. Editing a config pool's
egress_upstream_env on a node with pools.json made the next boot warn that
the config pools were overridden, though the field still applies from the
config. The SDK PoolSpec doc and the PUT /v1/pools reference missed the
field the same way.
deleteCkLocked, retryArchiveDelete and resolveGolden release the record
lock once instead of on every branch; NewManager, ValidateVolumes,
handleSandboxes and the MCP tool-error path take cmp.Or for their
fallbacks (config validation already rejects a negative fork count or
refill concurrency); Policy.Validate checks a repeated port against the
ports before it; Untar drops a default branch that only continued the
loop.
…check

decode_response's fast path swallowed binascii.Error with try/except/pass,
which /code-py spells contextlib.suppress; _feed_stdin re-checked a stdin
its only caller already requires non-empty.
@CMGS
CMGS merged commit 22014c1 into main Oct 3, 2026
2 checks passed
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