Files
containerization/PATCHES.md
T
NucleicandClaude Opus 4.8 050605b13e Fix Nucleic Control container breakage: balloon, stop, interceptor
Root-cause and fix the four reported container regressions plus two
adjacent confirmed bugs.

- Memory balloon (CPU 100% + output freeze that never recovered): the
  autoballoon drove the whole-VM target from a per-container cgroup figure
  with no guest swap, spinning a swapless guest in perpetual direct
  reclaim. Default memoryManagement to off; make the target whole-VM-aware
  (reserveBytes) so it never inflates below the working set plus the
  guest's non-cgroup footprint; deflate the balloon on a failed stats read
  instead of freezing it inflated.
- Stop button: signal the agent's whole process group (new vendored
  LinuxProcess.killProcessGroup, negative pid) so forked children die too;
  replace the unbounded wait() in every teardown/shutdown with a bounded
  terminate() that escalates SIGTERM -> SIGKILL; interrupt escalates to a
  group kill so a wedged agent always stops.
- MCPApprovalServer port-0 race: single-flight start(host:) so concurrent
  sessions sharing one control-container server all receive the real bound
  port; publish listener+port only after .ready (a failed bind no longer
  pins a stale port 0); guard the Claude call site against port 0.
- Container CPU metric: divide the CPU delta by the actual measured window
  instead of a fixed 200 ms, so it stops over-reading under load.
- Command interceptor: drop the ~40 coreutil Node shims so cat/grep/etc
  run their native binaries (no Node-per-command); the bash tracer still
  records them as metadata.
- Make the bash command tracer opt-in (commandTracingEnabled, default
  off) — the per-command DEBUG trap only activates when enabled; the
  git/gh interception the conflict/merge system relies on stays always-on.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-25 13:55:31 -07:00

47 lines
3.0 KiB
Markdown

# Vendored `containerization` — Nucleic patches
This is a **vendored copy** of [apple/containerization](https://github.com/apple/containerization)
at upstream commit `6b7b42ca3efeee8c706070e4355e6a807c5336ae`, referenced by the root `Package.swift`
via `.package(path: "third_party/containerization")` instead of the github URL.
It is vendored (not pulled) because we carry a local patch upstream doesn't have. Keeping it
in-tree means the patch can't be lost to a dependency re-resolve.
## What's changed vs. upstream
1. **`Sources/Containerization/LinuxContainer.swift` — forward VM extensions.**
`LinuxContainer.Configuration` gains a `vmExtensions: [any Sendable]` field, and
`LinuxContainer` assigns it into `VMConfiguration.extensions` when it builds the VM config.
Upstream already supports `VMConfiguration.extensions` + the `VZInstanceExtension` hook
(`configureVZ`/`didCreate`), but `LinuxContainer` — the only entry point we use — never forwarded
it, so there was no way to attach a device (e.g. a virtio memory balloon) to a container's VM.
Search for the marker comment `[Nucleic vendored patch]` to find both edit sites.
Nucleic uses this to attach a `VZVirtioTraditionalMemoryBalloonDeviceConfiguration` and drive its
target at runtime for automatic VM memory reclamation — see `MemoryBalloon.swift` /
`ContainerEngine` in NucleicCore.
2. **`Sources/Containerization/LinuxProcess.swift` — process-group kill.**
`LinuxProcess` gains `killProcessGroup(_:)`, which signals the negative pid (`-pid`) so the
guest's `kill(2)` targets the exec'd process's whole **process group**, not just the leader.
Every exec is `setsid()`'d by `vmexec`, so the process is its own group leader (pgid == pid) and
a group signal reaches the children it forked. Upstream only exposes the leader-only `kill(_:)`,
which let a forked child survive a Stop in a long-lived shared container. Marked with
`[Nucleic vendored patch]`; used by `ContainerizedProcessHandle.sendSignal` in NucleicCore.
3. **Trimmed for footprint (no behavior change).** `Tests/`, `docs/`, `examples/`, and `images/`
were dropped, and the corresponding `.testTarget(...)` entries removed from `Package.swift`. The
library/executable targets we build are untouched.
## Re-vendoring a newer upstream commit
1. `git clone` upstream (or copy `.build/checkouts/containerization` after bumping the URL pin
temporarily), check out the desired commit.
2. `rsync -a --exclude=.git --exclude=.build --exclude=.swiftpm --exclude=Tests/ --exclude=docs/ \
--exclude=examples/ --exclude=images/ <upstream>/ third_party/containerization/`
3. Remove the `.testTarget(...)` blocks from `third_party/containerization/Package.swift`.
4. Re-apply patch #1 (the `vmExtensions` field + the `vmConfig.extensions = …` forward) and patch
#2 (`LinuxProcess.killProcessGroup(_:)`). Grep for `[Nucleic vendored patch]` to find every site.
5. Update the commit hash above and in the root `Package.swift` comment.
6. `swift build` and run the balloon tests.