# Plan: POSIX Adapter

## Overview

Implementation track for the POSIX adapter sketched in
`docs/proposals/posix-adapter-proposal.md`. The proposal's Phase P1.1
through P1.3 decomposition is the source of truth; each task below maps to
one phase. This plan is ad-hoc until selected.

The v0 phases are parallel-safe with the kernel-core selected milestone in
the directories they own (new `libcapos/`, new `libcapos-posix/`, new
`vendor/dns-c-wahern/`, new `vendor/dash/`, new `demos/c-hello/`,
`demos/posix-dns-resolver/`, `demos/posix-pipe-shim/`, repo-root
`system-c-hello.cue`, `system-posix-dns.cue`, `system-posix-pipe.cue`,
matching `Makefile` targets, and proposal/plan docs). P1.2 and P1.3 add
new interfaces under `schema/capos.capnp` and must serialise on the shared
schema serial surface per `docs/plans/README.md` Concurrency Notes.

P1.1 is the strict prerequisite for P1.2 and P1.3 and is being landed
under a separate libcapos C-substrate v0 task; this plan's Task 1
tracks closeout coordination rather than re-doing the implementation.

## Conflict Surface

Owned by this plan:

- `libcapos/` (NEW Rust crate, `crate-type = ["staticlib"]`, standalone like
  `capos-rt/`).
- `libcapos-posix/` (NEW Rust crate, same staticlib pattern, links above
  `libcapos`).
- `include/capos/` and `include/capos/posix/` (NEW C header trees).
- `vendor/dns-c-wahern/` and `vendor/dash/` (NEW vendored upstream sources
  at pinned tags).
- `demos/c-hello/`, `demos/posix-dns-resolver/`, `demos/posix-pipe-shim/`
  (NEW per-phase smoke binaries; demos workspace addition).
- `Makefile` (new `libcapos-build`, `libcapos-posix-build`, `c-build`,
  `run-c-hello`, `run-posix-dns-smoke`, `run-posix-pipe-smoke`, and the
  successor `run-posix-shell-smoke` target).
- Repo-root `system-c-hello.cue`, `system-posix-dns.cue`,
  `system-posix-pipe.cue`, and the successor `system-posix-shell.cue`
  focused-proof manifests.
- `docs/proposals/posix-adapter-proposal.md` (status updates, closeout
  stamps, phase progress).
- `docs/plans/posix-adapter.md` (this file).
- `docs/plans/README.md` Track Map row only.
- `docs/SUMMARY.md` Plans + Proposal Index entries for the new files.
- `book.toml` (new proposal entry, `enable = false` until implementation
  lands).

Coordinated overlap with sibling tracks:

- `Cargo.toml` workspace member entries (or standalone-crate handling) --
  the new `libcapos/` and `libcapos-posix/` crates are coordinated with
  the libcapos C-substrate v0 task that introduces `libcapos/`. Treat
  `libcapos/` itself as owned by P1.1 until that task closes; this plan
  owns `libcapos-posix/` from P1.2 onwards.
- `schema/capos.capnp` (P1.2 adds `UdpSocket` + `NetworkManager.createUdpSocket`;
  P1.3 adds `Pipe`). Both phases queue on the shared
  `schema/capos.capnp` serial surface per `docs/plans/README.md`
  Concurrency Notes; do not run concurrently with other schema-touching
  plans, and do not run P1.2 and P1.3 concurrently against each other.
- `kernel/src/cap/network.rs` and `kernel/src/virtio.rs` (P1.2 UDP path).
  Coordinate with Device Driver Foundation if that work also touches these
  files.
- `kernel/src/cap/process_spawner.rs` (P1.3 fd-action grant path).
  Coordinate with anything mutating spawn grants.
- `capos-rt/src/client.rs` (P1.2 `UdpSocketClient`, P1.3 `PipeClient`).
- `tools/` (new `c-build` helper if it lands as a standalone tool).

Do not touch from this plan:

- Kernel-core cap tables, scheduler, device manager, or other userspace
  runtime files outside `capos-rt/src/client.rs` extensions described
  above.
- `tools/remote-session-client/` (owned by remote-session plan).
- `docs/topics.md` (auto-regenerated; never edit manually).
- `docs/proposals/userspace-binaries-proposal.md` and
  `docs/programming-languages.md` (owned by the libcapos C-substrate v0
  task that introduces the C library row). Cross-link from this plan
  only after that task closes, to avoid duplicating the row update.
- `WORKPLAN.md` (track-add row update is owned by the planning audit
  refresh, not by this docs-only lift).

## Validation Commands

- `make fmt-check`
- `make generated-code-check`
- `cargo build --features qemu`
- `cargo test-config`
- `cargo test-lib`
- `cargo build-demos-capos`
- `make capos-rt-check`
- `make run-smoke`
- Per-phase smoke targets (added as the matching task lands):
  - P1.1: `make run-c-hello`
  - P1.2: `make run-posix-dns-smoke`
  - P1.3: `make run-posix-pipe-smoke`
  - Successor (after Namespace + File caps land): `make run-posix-shell-smoke`

Treat the matching `make run-*` target for the most recent phase as
required for any iteration that touches this plan's owned files.

## Success Criteria

Each landed phase must keep its `make run-*` target green, leave unrelated
`make run-*` targets unaffected, and stamp the phase closeout in
`docs/proposals/posix-adapter-proposal.md` with commit hash and minute-
precision timestamp. The track is recorded done when the dash port lands
green against `make run-posix-shell-smoke`. P1.2 (DNS resolver smoke) and
P1.3 (pipe primitive smoke) close independently as their dependencies land.

### Task 1: Phase P1.1 -- libcapos C-substrate v0 + C hello-world smoke

- [ ] Owned by the separate libcapos C-substrate v0 task: thin Rust
      staticlib mirror of `capos-rt` for C consumers. That task owns
      `libcapos/`, `include/capos/`, the `c-build` Make helper,
      `demos/c-hello/`, and `system-c-hello.cue`. Tracked here for
      closeout only -- do not duplicate the implementation work in this
      plan.
- [ ] On merge of the libcapos C-substrate v0 task, stamp the phase
      closeout in `docs/proposals/posix-adapter-proposal.md` with commit
      hash and minute-precision timestamp.
- [ ] On merge of the libcapos C-substrate v0 task, refresh the Track
      Map row in `docs/plans/README.md` to reflect that P1.1 is closed
      and the next schema-touching iteration (P1.2 or P1.3) is the
      current owner of this plan's queue position.

### Task 2: Phase P1.2 -- UDP cap surface + dns.c stub resolver smoke

- [ ] Resolve open question §2 (DNS resolver candidate, recommended
      dns.c) before vendoring; promote to a final decision in the
      proposal.
- [ ] Resolve open question §8 (UDP cap surface scope: shape of
      `createUdpSocket`, `sendTo`, `recvFrom`, `close`; readiness vs
      blocking-with-timeout `recvFrom`) before adding the schema
      additions; promote to a final decision in the proposal.
- [ ] Resolve open questions §4 (errno representation) and §5 (fd table
      location) before writing the wrappers; promote each to a final
      decision in the proposal.
- [ ] Add `UdpSocket` interface and `NetworkManager.createUdpSocket`
      method to `schema/capos.capnp`. Queue on the shared schema serial
      surface; do not run concurrently with another schema-touching plan.
      Run `make generated-code-check` before downstream Cargo builds.
- [ ] Extend `kernel/src/cap/network.rs` with the UDP path mirroring the
      existing TCP path; add UDP RX demux on the existing
      scheduler-polled smoltcp runtime in `kernel/src/virtio.rs`.
- [ ] Add typed `UdpSocketClient` in `capos-rt/src/client.rs`.
- [ ] Create `libcapos-posix/` crate with the minimal
      `socket`/`sendto`/`recvfrom`/`poll` surface for one UDP fd at a
      time, plus `malloc`/`free` re-export, errno cell, fd 2 stdio
      wrapper, `clock_gettime`/`gettimeofday`.
- [ ] Vendor dns.c by William Ahern under `vendor/dns-c-wahern/` at a
      pinned tag (single `.c` plus header).
- [ ] Add `demos/posix-dns-resolver/` (new C demo binary).
- [ ] Add `system-posix-dns.cue` (its own distinct CUE package; imports
      the shared `capos.local/cue/defaults` package per the slice-3
      defaults pattern).
- [ ] Add `make run-posix-dns-smoke` target. Smoke must print
      `resolved <name> -> <addr>` for a known A record (e.g. against
      QEMU slirp's 10.0.2.3) and exit cleanly under QEMU.
- [ ] Stamp the phase closeout in
      `docs/proposals/posix-adapter-proposal.md` with commit hash and
      minute-precision timestamp.

### Task 3: Phase P1.3 -- Pipe capability + libcapos-posix pipe / fork-for-exec scaffolding

- [ ] Resolve open question §6 (fork policy: whether the shim records
      inter-call `dup2`/`close` as `posix_spawn` file actions or
      requires the port to call `posix_spawn` with explicit file
      actions) before writing the wrappers; promote to a final decision
      in the proposal.
- [ ] Resolve open question §9 (pipe cap design: kernel-allocated
      bounded SPSC ring with EOF on close vs shared MemoryObject +
      userspace ring) before adding the schema additions; promote to a
      final decision in the proposal.
- [ ] Add `Pipe` interface to `schema/capos.capnp` (small additive
      change, distinct from UDP and `LaunchParameters` surfaces). Queue
      on the shared schema serial surface; do not run concurrently with
      P1.2 or another schema-touching plan. Run
      `make generated-code-check` before downstream Cargo builds.
- [ ] Add `kernel/src/cap/pipe.rs`: bounded SPSC byte ring backed by a
      kernel-allocated MemoryObject page, with EOF semantics on close.
- [ ] Extend `kernel/src/cap/process_spawner.rs` so spawn grants can
      mint `Pipe` halves and bind them to the child's standard fds.
- [ ] Add typed `PipeClient` in `capos-rt/src/client.rs`.
- [ ] Extend `libcapos-posix/` with `pipe`/`dup2`/`close` over the new
      cap.
- [ ] Extend `libcapos-posix/` with `fork`/`execve`/`waitpid`/
      `posix_spawn` over ProcessSpawner (TLS "next exec is the real
      spawn" state machine, with the §6-confirmed handling of inter-call
      file actions).
- [ ] Add `demos/posix-pipe-shim/`: minimal C program that `pipe()`s,
      `posix_spawn()`s a child whose stdout is the write end, parent
      reads from the read end and prints. This covers the
      `posix_spawn`-direct path.
- [ ] Add a second smoke that exercises the §6-selected fork-for-exec
      path: if §6 chooses the inter-call recording shim, the smoke must
      `pipe()` then `fork()` then `dup2(fd, STDOUT_FILENO)` then
      `execve()` and prove the recorded file actions are applied to the
      spawn; if §6 chooses the patched-port variant, the smoke must
      drive the patched call sequence end-to-end. Either path must fail
      closed when the recorded action allowlist is violated.
- [ ] Add `system-posix-pipe.cue` (its own distinct CUE package; imports
      the shared `capos.local/cue/defaults` package).
- [ ] Add `make run-posix-pipe-smoke` target. Smoke must drive both
      the `posix_spawn`-direct path and the §6-selected fork-for-exec
      path, print the child's emitted line through the parent for each
      path, and exit cleanly under QEMU.
- [ ] Stamp the phase closeout in the proposal.

### Task 4: Successor -- vendor dash + ship `make run-posix-shell-smoke`

- [ ] **Blocked** on Namespace + File cap surface (Phase 2 of
      `docs/proposals/storage-and-naming-proposal.md`). Note the block
      in the proposal status header until storage proposals land.
- [ ] Vendor dash 0.5.13.x under `vendor/dash/` at a pinned tag.
- [ ] Extend `libcapos-posix/` with file I/O wrappers over Namespace +
      File caps (`open`/`read`/`write`/`stat`/`access`/`unlink`,
      directory iteration via Directory cap), plus
      `getenv`/`setenv`/`putenv` over the per-process env vector
      (populated from `LaunchParameters` if available, else manifest
      rodata).
- [ ] Add `system-posix-shell.cue` and `make run-posix-shell-smoke`
      target. Smoke must run `ls; echo done` from a heredoc and print
      `done` cleanly under QEMU.
- [ ] Stretch goal: extend the smoke to `cat foo | grep bar`
      end-to-end, exercising the P1.3 pipe primitive in a shell
      pipeline.
- [ ] Resolve open questions §1 (shell candidate, confirm dash) and §7
      (fd 0 backing) before vendoring; promote each to a final
      decision in the proposal.
- [ ] Stamp the phase closeout in the proposal.
