Commit Graph
6042 Commits
Author SHA1 Message Date
abkslm 472b46157c sync(dev): VERSION 0.4.1 (892) -> 0.4.2 (899) — catch up to canary 2026-07-14 01:08:39 -07:00
abkslm 99f313eba4 Merge nucleic/amber-yarn-ferret-43bn into dev 2026-07-14 00:56:30 -07:00
abkslm 0fcf1c61f5 Merge claude/nucleic-stdio-stall-391480 into dev 2026-07-14 00:47:08 -07:00
abkslm 254e417cd5 Merge branch 'dev' into claude/nucleic-stdio-stall-391480 2026-07-14 00:45:03 -07:00
abkslmandClaude Fable 5 ab9f836a05 Fix the all-sessions stdio stall: UnixSocketByteConn read-after-close on recycled fds
The "agent started but produced no output within 60s / stdio transport
stalled" lockup was never in the container stack — it was the approval
server's unix-socket transport. UnixSocketByteConn.close() did
shutdown(2)+close(2), freeing the fd NUMBER while the serve loop could
still dispatch its next blocking read(2) on the stored raw int. The race
arms on every SSE-streamed tools/call (respondStreamingToolCall closes
the connection mid-serve-loop; instant auto-approvals make the window
widest). The straggler read then landed on a RECYCLED descriptor —
another session's MCP socket, a container's stdout vsock channel —
parking a global-queue thread forever on, and stealing bytes from, an
unrelated stream. Zombies accumulated until every session stalled at
once (the 2026-07-14 00:02 wedge: 26 threads parked in receive() with
only 2 live unix connections). Yesterday's container-side fixes were
correct but orthogonal, which is why build 898 still stalled.

Fix: close() now only shuts the socket down (wakes a parked read with
EOF, fails later writes with EPIPE); the descriptor is close(2)d exactly
once, in deinit, and every offloaded read/write block strongly captures
self so the fd number cannot be recycled while any block that could
still pass it to the kernel is in flight. receive() is additionally
cancellation-aware, so stop()'s task cancellation unwedges parked reads
instead of stranding them. Regression test drives ten SSE-close /
fresh-connect cycles over a real AF_UNIX socket.

Also found while validating the earlier patch: ensureInitfs trusted a
bare cached vminit.ext4 forever, so repointing vminitReference at the
custom -nucleic1 image never took effect (containers still boot the
Jun-21 upstream initfs — guest patch #8 never actually deployed). The
cache is now keyed on the reference via a sidecar file, the pull
authenticates against GHCR with the app's GitHub token (the package is
private; anonymous pulls 403), and a failed re-pull falls back to the
existing cache so an offline launch still boots.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-14 00:40:48 -07:00
abkslm a31215b523 Merge nucleic/olive-meadow-otter-vrgd into dev 2026-07-14 00:40:17 -07:00
abkslm 07100adb70 Merge nucleic/golden-river-urchin-xgtc into dev 2026-07-14 00:36:10 -07:00
abkslm 5e868fc776 Merge nucleic/dusky-pebble-koala-hhlc into dev 2026-07-13 23:42:21 -07:00
abkslm 3596d68803 Merge nucleic/hazy-drift-toad-gxbg into dev 2026-07-13 23:42:06 -07:00
abkslm dd34a94602 Merge nucleic/eager-quartz-ibis-ncl9 into dev 2026-07-13 23:41:44 -07:00
abkslm 57842cce30 Merge nucleic/dusky-grove-lemur-l5km into dev 2026-07-13 23:40:18 -07:00
abkslm 7332b36d1b Merge nucleic/olive-meadow-otter-vrgd into dev 2026-07-13 23:34:37 -07:00
abkslm 8b7ce6f527 Merge nucleic/hazy-jade-shrew-o4on into dev 2026-07-13 23:17:28 -07:00
abkslm 81d5524ca7 Merge nucleic/olive-thistle-weasel-jguv into dev 2026-07-13 23:16:14 -07:00
abkslm 7dbe911c6c Merge nucleic/warm-grove-civet-vo4c into dev 2026-07-13 23:10:17 -07:00
abkslmandClaude Opus 4.8 f3c056fd0d docs: add CONTAINER_ISOLATION.md — session-isolation model + build/validate workflow
Overview doc so other agents/humans understand the shared-control-container
isolation work: the failure vectors + fixes (stdio wedge, connection leak,
control-plane HOL, OOM cross-kill, CPU/fork-bomb, per-session memory.max), the
host-vs-guest shipping surfaces, the per-exec cgroup layout + graceful fallback,
and the local vminit-image build/validate workflow + -nucleicN tag invariant.
Cross-linked from the vendored PATCHES.md.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 22:03:03 -07:00
abkslmandClaude Opus 4.8 67a2244173 Per-exec cgroups follow-up: host-configured hard memory.max (no protobuf)
Adds an opt-in hard per-session memory ceiling on top of patch #9's scoped-OOM.
The exec already ships the full OCI Spec, so the limit rides
spec.linux.resources.memory.limit — no RPC/protobuf change:

- host framework: LinuxProcessConfiguration.memoryLimitInBytes; LinuxContainer.exec
  stamps it onto the exec spec.
- guest: Server+GRPC.createProcess reads it back and applies it as the exec
  cgroup's memory.max (new Cgroup2Manager.setMemoryMax) via createExec/ManagedProcess.
- Nucleic: ContainerServiceSettings.controlPerSessionMemoryGiB (default 0 = off),
  applied only to the shared control container (ContainerManager.exec); wired
  through ContainerEngine.exec.

So one session can't consume the whole shared container's memory before its own
(oom.group-scoped) OOM. Default off preserves #9's behavior. Compile-verified host
+ musl guest; rides the pending -nucleic2 image, still runtime-pending.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 20:12:42 -07:00
abkslmandClaude Opus 4.8 df0e4c0029 Per-exec cgroups (guest patch #9): scope a session's OOM/CPU/fork-bomb to itself
Restructures the guest cgroup layout so each exec gets its OWN child cgroup
(/container/<id>/<execID>) with memory.oom.group=1, a fair cpu.weight, and a
pids.max backstop — so one control session can't OOM-kill, starve, or fork-bomb
its siblings in the shared container. The container init moves to its own leaf
so the container cgroup can delegate controllers to children (cgroup v2
no-internal-process rule). New Cgroup2Manager helpers: setOomGroup/setCpuWeight/
setPidsMax/remove.

Best-effort with graceful fallback: any failure in the per-exec setup wipes the
partial state and reverts to today's flat layout, and each exec falls back to the
container cgroup — a cgroup hiccup degrades to current behavior, never a failed
start.

COMPILE-VERIFIED via the musl cross-build; NOT yet runtime-validated. Built as
image tag -nucleic2; vminitReference stays on the validated -nucleic1 until
-nucleic2 is checked in a real container. A hard host-configured per-exec
memory.max (exec-RPC resources field) remains a follow-up.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 20:03:20 -07:00
abkslmandClaude Opus 4.8 0799636103 vminit image: build cctl on demand so login/push work from any checkout
cctl is an uncommitted build artifact; the image lives in a user-global content
store. Make login/push depend on a real $(CTZN_DIR)/bin/cctl file target that
builds it once if missing, so they work from a fresh checkout after the session
worktree that ran 'make vminit-image' is gone.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 19:40:08 -07:00
abkslmandClaude Opus 4.8 3dd014405b vminit image: add 'make vminit-image-login' for Keychain-based GHCR auth
cctl login stores the credential in the macOS Keychain, which cctl images push
reads automatically — so pushing needs no REGISTRY_* env vars after a one-time
login. Env vars remain as a fallback.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 19:37:06 -07:00
abkslmandClaude Opus 4.8 b81d12553c Build the custom vminit image locally via make vminit-image; drop the CI workflow
The GitHub-hosted macos runners can't build the host framework (needs the
macOS 26+ Virtualization SDK), so publish the custom vminit guest image from a
local macOS 26/27 machine instead. Adds root-Makefile targets:
  - vminit-image-prep : one-time swiftly + musl static SDK install
  - vminit-image      : build cctl + cross-build vminitd, package the image
  - vminit-image-push : push to GHCR (REGISTRY_* env creds)
Forces WARNINGS_AS_ERRORS=false (Xcode Swift 6.4 rejects -warnings-as-errors
alongside SwiftPM's -suppress-warnings). Removes .github/workflows/vminit-image.yml
and repoints vminitReference + PATCHES.md docs at the Makefile.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 19:31:56 -07:00
abkslmandClaude Opus 4.8 3f939a84c6 containerization: guard patch #3's 'import os' behind #if canImport(os)
The swiftly toolchain used by the vminit-image CI resolves Foundation/
Virtualization but not the 'os' overlay, so 'import os' failed with
"no such module 'os'". Guarding the diagnostic logger degrades it to a
no-op under such toolchains while local (Xcode) builds keep it.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 19:15:11 -07:00
abkslmandClaude Opus 4.8 64d11eb0e2 vminit-image CI: run on macOS 26 (needs macOS 26 SDK for vmnet_network_* symbols)
The macos-15 runner's SDK lacks vmnet_network_ref / VZVmnetNetworkDeviceAttachment
(macOS 26 APIs used by Containerization's VmnetNetwork/NATNetworkInterface), so
`make containerization` failed to build cctl before reaching the init packaging.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 19:01:32 -07:00
abkslm 9b9d665a6b Merge branch 'dev' into claude/container-stdio-stall-187229 2026-07-13 18:47:05 -07:00
abkslmandClaude Opus 4.8 6fbc308fa4 Container isolation: fix stdio stall + per-exec connection leak; add guest image pipeline
Host-side (ships with a normal swift build):
- LinuxProcess: non-blocking stdio relay (O_NONBLOCK + nucleicDrainNonBlocking)
  so a wedged stream can't head-of-line-block sibling execs' relays; atomic
  stdio-or-abort start (patches #5, #6).
- Vminitd: bounded deleteProcess timeout so teardown can't hang a wedged
  channel (patch #7).
- ContainerizedProcessHandle: call LinuxProcess.delete() after exit and on
  force-close — fixes a per-turn leak (per-exec vsock/gRPC connection +
  runConnections() task) in the long-lived shared control container. Likely
  the "degrades until app restart" root cause.
- ClaudeCodeBackend: map the atomic-start abort to a recoverable AgentError so
  a failed launch settles as retryable instead of locking the composer.

Guest-side (rides the custom vminitd initfs; inert until the image is built):
- ManagedProcess: offload the blocking start off the gRPC event loop (patch #8).
- Per-exec cgroups (patch #9) recorded as design only — cross-cutting.

Pipeline:
- .github/workflows/vminit-image.yml builds vminitd from the vendored source
  and pushes ghcr.io/abkslm/vminit; ContainerEngine.vminitReference repointed
  at the custom image.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 18:46:48 -07:00
abkslm c19b538ea8 Merge nucleic/nimble-lunar-viper-ttz9 into dev 2026-07-13 18:06:29 -07:00
abkslm 919d6ad2c7 Merge nucleic/humble-feather-yak-edwe into dev 2026-07-13 17:51:17 -07:00
abkslm 976d0dc200 Merge nucleic/frosty-glass-shrew-2evb into dev 2026-07-13 17:21:56 -07:00
abkslm 2797613961 Merge nucleic/frosty-glass-shrew-2evb into dev 2026-07-13 15:02:45 -07:00
abkslm 9df273d24c Merge nucleic/upbeat-fern-quail-elue into dev 2026-07-13 15:02:02 -07:00
abkslm 5caafc6212 Merge nucleic/nimble-lunar-viper-ttz9 into dev 2026-07-13 15:00:39 -07:00
abkslm bd4890e71e Merge nucleic/upbeat-fern-quail-elue into dev 2026-07-13 14:58:47 -07:00
abkslm 28a761f034 Merge nucleic/eager-ember-urchin-pdke into dev 2026-07-13 14:30:23 -07:00
abkslm 23b5ce9d3c Merge nucleic/olive-thistle-weasel-jguv into dev 2026-07-13 14:20:45 -07:00
abkslm d4c76b28e7 Merge nucleic/calm-opal-bison-hktg into dev 2026-07-13 05:12:08 -07:00
abkslm 5f0f6e4c46 Merge nucleic/calm-opal-bison-hktg into dev 2026-07-13 05:09:44 -07:00
abkslm 6c0487909c Merge nucleic/calm-opal-bison-hktg into dev 2026-07-13 05:08:17 -07:00
abkslm 9d0b45b75a Merge nucleic/calm-opal-bison-hktg into dev 2026-07-13 05:06:25 -07:00
abkslm f7bfe25fa7 Merge nucleic/calm-opal-bison-hktg into dev 2026-07-13 05:01:37 -07:00
abkslm 04397846a6 Merge nucleic/calm-opal-bison-hktg into dev 2026-07-13 04:57:19 -07:00
abkslm c2c6221d63 Merge nucleic/calm-iris-badger-zxeq into dev 2026-07-13 04:56:48 -07:00
abkslm 457331d174 Merge nucleic/calm-opal-bison-hktg into dev 2026-07-13 04:52:39 -07:00
abkslm 2d052948fe Merge nucleic/frosty-drift-wren-hm99 into dev 2026-07-13 04:51:40 -07:00
abkslm 8e33159067 Merge nucleic/calm-opal-bison-hktg into dev 2026-07-13 04:44:24 -07:00
abkslm 36d72067ce Merge nucleic/calm-opal-bison-hktg into dev 2026-07-13 04:37:03 -07:00
abkslm bd42e3a1c3 Merge nucleic/calm-opal-bison-hktg into dev 2026-07-13 04:34:13 -07:00
abkslm 85b5135192 Merge nucleic/upbeat-slate-shrew-icrw into dev 2026-07-13 04:03:11 -07:00
abkslm 35bdbefd51 Merge nucleic/hazy-maple-gecko-lek5 into dev 2026-07-13 04:02:01 -07:00
abkslm 093f4a6dd8 Merge nucleic/plucky-dewy-lemur-ikel into dev 2026-07-13 03:55:48 -07:00
abkslm 3e9c4eb531 Merge nucleic/dusky-willow-weasel-znsn into dev 2026-07-13 03:25:53 -07:00