summaryrefslogtreecommitdiff
path: root/docs/cloud9.md
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 19:25:00 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commit57b30ba3e38153a4446626449b0fed5120da954c (patch)
tree7b9381327a05791181a855bd8d4ba3cfb4df5301 /docs/cloud9.md
parent0fd908eea63d04886b269438aa7529d3dd422256 (diff)
downloadpardes-57b30ba3e38153a4446626449b0fed5120da954c.tar.gz
pardes-57b30ba3e38153a4446626449b0fed5120da954c.zip
The docs and the 9P skill say each fact once, in the file that owns it, and say only what a live session does
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'docs/cloud9.md')
-rw-r--r--docs/cloud9.md139
1 files changed, 39 insertions, 100 deletions
diff --git a/docs/cloud9.md b/docs/cloud9.md
index 7365bf65..cd92fd05 100644
--- a/docs/cloud9.md
+++ b/docs/cloud9.md
@@ -1,107 +1,46 @@
-# cloud9 integration
+# cloud9
-The published `cloud9` package owns the base 9P2000 wire format, client and server
-connections, and TCP/Unix/QUIC transports. `build.zig.zon` pins a commit from
-`[email protected]:~gbrls/cloud9`, so `zig build` fetches it into `zig-pkg/` like every
-other dependency; no sibling checkout is required. Re-pin with
-`zig fetch --save=cloud9 git+https://git.sr.ht/~gbrls/cloud9#<commit>`, and swap in
-`.cloud9 = .{ .path = "../cloud9" }` while editing both packages at once.
+The `cloud9` package owns the 9P2000 wire format, client and server
+connections, the file-server engine and the Unix/TCP/QUIC transports.
+`build.zig.zon` pins a commit from `git.sr.ht/~gbrls/cloud9`, fetched into
+`zig-pkg/` like any dependency. Re-pin with
+`zig fetch --save=cloud9 git+https://git.sr.ht/~gbrls/cloud9#<commit>`, or
+use `.cloud9 = .{ .path = "../cloud9" }` while editing both.
-The file-server engine (fids, jobs, parking, flush, hangup) is cloud9's
-`fs.Server`; the control tree in `src/ninep/` is its backend, using cloud9's
-`fs.Req`, `fs.Op`, `fs.Status`, `fs.E` and `fs.ReplyWith` (extended with the
-editor's reply payload locator). `src/9p.zig` names the editor's and the
-board's `fs.Options` and re-exports the wire names the transports use.
-Mounting, Unix namespace discovery and permissions, the editor event loop,
-connection limits, and exported tree policy remain here. The Unix and TCP
-listeners run on cloud9's `serve.Runner` (`std.Io`: an accept task per
-listener, a reader and a writer task per connection, four slots); its handler
-answers every backend request on the connection's task, taking the editor's
-turn with the core (`pardes.turn`) while the editor waits for input or is out
-in a syscall. A request that would change a pane while the editor is mid-step
-is parked with `Status.again` -- the engine parks reads, writes, opens,
-truncations, clunks and removes -- and retried by `Runner.wakeAll` when the
-editor next rests. A read with nothing yet parks the same way, but is never
-retried for news: the core holds it (`ctlfs.hold`) and `answerHeld` answers
-it through the ticket `Conn.hold` gave its park, with `Conn.answerWith`,
-which makes the answer only while that very park still waits (not flushed,
-its fid not clunked, not out being retried) and under the same lock. `src/9p_quic.zig` selects the existing `pardes-9p` ALPN for
-cloud9's optional OpenSSL transport; QUIC still runs on the poll loop in
-`src/9p_io.zig` on the editor's thread, since cloud9's QUIC adapter is
-nonblocking-descriptor based rather than `std.Io` based.
-The standalone protocol/GPIO tests import the same module. The separate
-`05-zig-p4` build also supplies cloud9 for the GPIO firmware entry.
+- The engine (fids, jobs, parking, flush, hangup) is cloud9's `fs.Server`;
+ the control tree in `src/ninep/` is its backend. `src/9p.zig` names the
+ editor's and the board's `fs.Options` (msize 8192, 256 fids).
+- Unix and TCP listeners run on cloud9's `serve.Runner` (`std.Io`: an accept
+ task per listener, a reader and a writer task per connection, 16
+ connections). Requests are answered on the connection's task, which takes
+ the editor's turn (`pardes.turn`) while the editor waits for input or is
+ out in a syscall. A request that would change a pane while the editor is
+ mid-step parks (`Status.again`) and is retried when the editor rests. A
+ read with nothing to answer yet is held by the core and answered through
+ the ticket `Conn.hold` gave it, only while that park still waits.
+- QUIC (`src/9p_quic.zig`, ALPN `pardes-9p`) still runs on the editor's
+ poll loop in `src/9p_io.zig`, since cloud9's QUIC adapter is
+ nonblocking-descriptor based.
-Run `zig build 9p-test` for the engine configurations and
-`zig build 9p-io-test -Dquic=true` for native transport/client integration. Run cloud9's `zig build test`,
-`transport-test`, `quic-test -Dquic=true`, `fuzz`, and `differential` steps for the
-shared implementation. See cloud9's `docs/validation.md` for recorded runs and
-known test-environment limits.
-
-Invalid framing now terminates a server connection. Cloud9 also checks reply
-counts and reserves tags until flush completion. Client metadata is slightly
-larger to track those reservations, and its bounds tests reflect that fixed cost.
+Tests: `zig build 9p-test` (engine configurations), `zig build 9p-io-test
+-Dquic=true` (transports and client). cloud9's own `zig build test`,
+`transport-test`, `quic-test -Dquic=true`, `fuzz` and `differential` cover
+the shared code.
## The posted-9P registry
-`$XDG_RUNTIME_DIR/9p` is this machine's `/srv`: a server posts itself in it
-under a name, and clients dial names rather than paths. cloud9 owns both
-sides (`cloud9.post`), and `9ns --mntgen` mounts the whole registry at
-`/mnt/9p` for programs that want it as a filesystem. pardes's only part in
-it is to put itself there.
-
-**Serving.** A listening editor advertises itself at
-`$XDG_RUNTIME_DIR/9p/pardes/<name>`, a symlink to the socket it already
-binds. One directory for the program, one entry per editor, so several
-editors group instead of crowding the registry root — the layout zmx posts
-its sessions under. The socket itself does not move: adopting the registry
-only advertises. Only the runtime-directory socket posts; an instance that
-fell back to `~/.local/state/pardes` stays out of the user's registry, the
-way a private `ZMX_DIR` does for zmx. Stopping unposts, and only while the
-entry is still ours, so a name another editor has since claimed is never
-unlinked.
-
-An exit that cannot run any code of its own — an aborted test, a kill, a
-crash — leaves its entry and its socket behind, so posting first sweeps the
-group: every entry that is a symlink and whose socket answers a connect with
-a definite ECONNREFUSED is unlinked, along with the socket it points at when
-a `stat` agrees that is a socket of ours. Anything that is not a symlink is
-somebody else's, and any other answer — connected, busy, refused permission,
-a surprise — counts as live, because uncertainty belongs to the server that
-owns the socket rather than to the sweeper. That is `cloud9.post.Probe`'s
-classification, repeated in `src/9p_io.zig` only because `post.probe` is raw
-Linux syscalls and pardes also builds for darwin.
-
-**Consuming.** Nothing. `9ns --mntgen` mounts the whole registry at
-`/mnt/9p`, and an interactive fish already self-wraps in one, so a pardes
-started from a terminal sees every posted service as ordinary files —
-`/mnt/9p/harness/active/...` is read with the same code that reads any other
-path. Teaching pardes to dial the registry itself would put discovery in a
-second place for no gain: mounting is the client's job and 9ns is the
-client. `--mount=<name>=<dial>` keeps meaning exactly what it always did,
-and a dial keeps resolving exactly as it always did — a bare name is another
-pardes session, and anything with a slash is a path, relative ones included.
-
-The one case that is not free: a pardes started outside a mntgen mount has
-no `/mnt/9p`. That is 9ns's problem to solve — by being in the namespace —
-not a reason for pardes to carry its own registry client.
-
-### What this diverges from, deliberately
+`$XDG_RUNTIME_DIR/9p` is this machine's `/srv`: servers post themselves
+there by name, and `9ns --mntgen` mounts the whole registry (default
+`/mnt/9p`). A pardes whose socket is in the runtime directory posts
+`$XDG_RUNTIME_DIR/9p/pardes/<name>`, a symlink to its socket (one directory
+per program, as zmx posts its sessions); a socket that fell back to
+`~/.local/state/pardes` is not posted. Stopping unposts the entry if it is
+still ours. Posting first sweeps the group: an entry that is a symlink whose
+socket refuses a connect (ECONNREFUSED) is removed with its socket; anything
+else counts as live.
-* **pardes binds its own socket; it does not post through `cloud9.post`.**
- `post` would give us its hardened claim protocol (temp-bind plus atomic
- rename under a lock) instead of the stale-socket retry in `listen`, but it
- claims *flat* names only: `legalName` rejects `/`, and `claimName` derives
- its lock directory by stripping `/9p` from the registry path, so a name
- inside a subdirectory cannot go through it. zmx hand-rolls the same
- symlink for the same reason. Unifying them means teaching `post` a group —
- passing the lock directory in rather than deriving it — and that is a
- change to adversarially-hardened code, not a rename.
-* **The registry entry is a symlink, not the socket.** A reader that expects
- every registry entry to be a socket must `stat` following symlinks.
- `9ns --mntgen` and `cloud9.post.dial` both do.
-* **Dialing is untouched.** An earlier draft taught `resolve` to fall back
- to the registry for a bare name and to read `<group>/<name>` as a
- subdirectory entry. Both were reverted: the second reinterpreted relative
- dials, which are a feature, and the first duplicated what 9ns already
- does. `src/9p_io.zig`'s `resolve` is byte-identical to what it was.
+pardes does not dial the registry: `9ns` is the client, and `--mount` dials
+resolve as always (a bare name is a pardes session, anything with a slash a
+path). pardes binds its own socket instead of posting through `cloud9.post`,
+because `post` takes only flat names and pardes posts into a group
+directory. A reader of the registry must `stat` through the symlink.