valis / Reference / API reference

Namespace - API reference

Exported surface for the namespace subsystem. Part of the API reference.

Package valis/src/namespace/acme

Classes

acme-dir-root

The /acme axis root directory node. Its one fixed leaf is ctl; node-walk is a cond over the leaf name and returns nil for anything else (sovereignty-as-absence). A certs listing leaf can join it once the store enumeration surface is settled.

Functions

make-acme-dir-root

(make-acme-dir-root)

Construct the /acme axis root. The fabric instantiates this and binds acme-dir-root to it at start; root.lisp mounts it under /acme in the owner frame only.

Variables

*acme-dir-root*

The /acme axis node. Set by the fabric at start-fabric; nil before the fabric is up or after teardown. root.lisp's node-walk walks /acme through this variable, so a nil value means the axis is absent (sovereignty-as-absence).

Package valis/src/namespace/assembler

Classes

live-view-entry

Per-view state tracked in the live-view registry for revocation eviction. LOCK is a per-view mutex held during mount-table structural mutations; reads are lock-free (SBCL setf of a slot value is atomic on x86-64).

ID names the session to an operator, who has to be able to type it: the registry is keyed by view-root object identity, which is unspeakable outside the image. HANDSHAKE is the auth conversation the session was admitted through, kept so a fence can survive a re-attach on the same transport. ADMITTED-AT and LAST-ACTIVITY are Unix seconds; LAST-ACTIVITY is stamped on the request path and so is written without the lock. FENCED-AT is nil for a live session and the Unix second of the fence otherwise, which is what distinguishes a session emptied on purpose from one that simply holds nothing.

Conditions

reassembly-unreachable

Signalled when a manifest mount's referenced subtree root is unreachable during pre-assembly reachability verification. A namespace-tier fault kept distinct from the store-tier MANIFEST-CORRUPT: the whole assembly aborts fail-closed (no partial mount table) before any view-root is built.

unhashable-grant

Signalled when a capability that has already verified nonetheless yields no grant hash. The hash is what revocation evicts by, so a mount carrying none would keep serving after its grant was revoked. The view or mount is refused instead: an ungovernable grant is worse than an absent one.

Generic functions

reassembly-unreachable-name

(reassembly-unreachable-name condition)

Undocumented: this exported symbol needs a docstring.

unhashable-grant-carrier

(unhashable-grant-carrier condition)

Undocumented: this exported symbol needs a docstring.

Functions

build-base-view

(build-base-view root auth-identity)

Dispatch on AUTH-IDENTITY's principal class to build the base namespace view for a new session (phase one of two-phase resolution).

AUTH-IDENTITY is the principal resolved by node-attach-identity at Tattach. It is never nil for an admitted session (either a keyed principal or the anonymous sentinel).

Returns a view-root under a three-way principal-class policy:

owner DID → the full canonical frame (assemble-canonical-frame): proto, bus, id, cap, pub, edge, and /ctl. anonymous → the read-only /pub published floor (%assemble-published-floor): exactly /pub, projected read-only. This mirrors the anonymous HTTP edge, where an unauthenticated GET resolves to the /pub published view; an unauthenticated 9P mount now resolves to the same surface. The credential-gated axes stay absent. non-owner keyed → an empty view. Sovereignty as absence: a keyed principal that is not the owner widens to nothing — not the owner frame, and not the anonymous /pub floor.

Ahead of all three: an attach whose auth conversation has been fenced gets an empty view whatever its principal class. Without that check the fence lasts until the client asks for another attach, which a client that has just lost its namespace does immediately.

decorate-bearer-view

(decorate-bearer-view view auth-identity grant-string)

Finish a view-root built for a verified bearer-name attach.

Stamps GRANT-STRING's grant hash on VIEW's existing mount entries so the revocation eviction sweep reaches live bearer views — revoking the grant evicts the mount from sessions already holding it, not just future attaches. Appends the per-view ctl door (when ctl-node-factory is wired) so the session can issue phase-two mount/unmount commands over 9P. Registers VIEW in the live-view registry under AUTH-IDENTITY; the registry is weak-keyed, so an abandoned view is collected when its session dies. Returns VIEW.

Signals UNHASHABLE-GRANT when GRANT-STRING yields no hash: the sweep matches on that stamp, so an unstamped view would keep serving after its grant was revoked, and a session revocation cannot reach is worse than a refused attach.

Installed into root's bearer-view-decorate-fn by start-fabric — the same downstream-installs-the-hook pattern as ctl-node-factory, and for the same reason: root cannot import the assembler back.

deregister-view

(deregister-view view-root)

Remove VIEW-ROOT from LIVE-VIEW-REGISTRY. Returns NIL silently when LIVE-VIEW-REGISTRY is NIL (fabric not up). Acquires LIVE-VIEW-REGISTRY-LOCK when present to guard the remhash against concurrent evict-by-hash maphash.

evict-by-fence-epoch

(evict-by-fence-epoch superseded-generation)

Sweep every live write-capable, capability-backed grant out of active sessions on an authority transfer. SUPERSEDED-GENERATION is accepted for symmetry with the revocation-log member and the verifier consult; the sweep is by the write-right bit, not by the fence-epoch hash. A grant's hash is the digest of its canonical bytes and signature, never the epoch hash, so a hash match would sweep nothing. Base-policy entries carry a nil grant-hash and are immune; capability-backed read-only entries keep their write bit clear and survive.

For simple entries an entry is removed when it carries a non-nil grant-hash and the write right. For union-node entries the sweep operates per-member: each capability-backed member carrying the write right is removed independently, preserving sibling members; a union that loses its last member is removed from the mount table entirely.

This runs on the bump-caller's thread. The registry is snapshotted under LIVE-VIEW-REGISTRY-LOCK and the lock is released before acquiring any per-view LIVE-VIEW-ENTRY-LOCK, maintaining the registry-lock to per-view-lock acquisition order. Returns no meaningful value.

evict-by-hash

(evict-by-hash hash-32-bytes)

Sweep all live view-roots and remove capability grants matching HASH-32-BYTES. Base-policy entries (nil grant-hash) are unaffected.

For simple (non-union) entries the entry is removed when its GRANT-HASH matches. For union-node entries the sweep operates per-member: each member whose per-member grant hash matches is removed independently, preserving sibling members whose grants were not revoked. A union that loses its last member is then removed from the mount table entirely.

This runs on the revocation-caller's thread. The registry is snapshotted under LIVE-VIEW-REGISTRY-LOCK and then the lock is released before acquiring any per-view LIVE-VIEW-ENTRY-LOCK, maintaining the registry-lock → per-view-lock acquisition order. Returns no meaningful value.

fence-owner-sessions-on-authority-transfer

(fence-owner-sessions-on-authority-transfer superseded-generation)

Fence every live owner session when write authority moves to another locus. SUPERSEDED-GENERATION is accepted for symmetry with the capability sweep that runs beside it; the decision here is by principal, not by generation.

This is a separate step from evict-by-fence-epoch on purpose. That sweep removes capability-backed write grants and leaves base-policy entries alone, which is right for what it does and is relied on elsewhere. But an owner's namespace is base policy from end to end, so the sweep cannot reach it: an owner admitted to the surrendering instance would go on naming the full frame after the transfer, and the instance that gave up authority would go on serving them.

Fencing rather than pruning is what the escape architecture needs. An owner whose instance has relocated has to be able to tell whether they are talking to the real one, and a session that quietly survives the move is the thing that makes that question unanswerable. Cutting the session makes them re-establish it, which is where that question gets asked and answered.

Returns no meaningful value. Runs on the caller's thread, and takes the per-view locks only after releasing the registry lock, in the order the registry documents.

fence-session

(fence-session session-id)

Fence the session named by SESSION-ID, returning its registry entry, or NIL when no live session carries that id.

Fencing the session the caller is using is supported and does what it says: the command lands, and the next name that session reaches for is not there. Getting back in means authenticating again, which is the point. An operator who has lost control of a session should not have to weigh whether they are about to cut themselves off, and an attacker sharing that session should not be able to keep it by being the one still holding it.

live-sessions

(live-sessions)

Return the live-view registry entries, ordered by session id.

The ordering is for the operator reading the listing: ids are issued in admission order, so sorting by id puts the oldest session first and keeps a line in the same place between two reads.

live-view-entry-admitted-at

(live-view-entry-admitted-at instance)

Undocumented: this exported symbol needs a docstring.

live-view-entry-fenced-at

(live-view-entry-fenced-at instance)

Undocumented: this exported symbol needs a docstring.

live-view-entry-id

(live-view-entry-id instance)

Undocumented: this exported symbol needs a docstring.

live-view-entry-last-activity

(live-view-entry-last-activity instance)

Undocumented: this exported symbol needs a docstring.

live-view-entry-principal

(live-view-entry-principal instance)

Undocumented: this exported symbol needs a docstring.

live-view-entry-view-root

(live-view-entry-view-root instance)

Undocumented: this exported symbol needs a docstring.

make-live-view-registry

(make-live-view-registry)

Construct the weak hash table used as the live-view registry. SBCL-specific: make-hash-table with :weakness :key (SBCL extension) so view-root objects that are no longer reachable by any session are collected without requiring an explicit deregistration hook. A session-close callback seam is the upstream clean solution for a cross-implementation port.

mount-capability

(mount-capability view cap-string &optional (bind-flag :after))

Verify CAP-STRING (a "valis:…" bearer name or "token:…" wire token) and mount the designated subtree into VIEW under its leaf name.

Returns (values T NIL) on success; (values NIL reason-string) on any failure. BIND-FLAG is :replace / :before / :after (default :after). A read-only grant wraps the target in a read-only-projection-node.

The entire body is wrapped in a handler-case; any unhandled condition becomes a (values nil reason-string) return so this function is fail-closed.

name-grant-hash

(name-grant-hash name-string)

Public entry to the bearer-name grant-hash computation: SHA-256(canonical-bytes || sig-64) of the decoded name. Returns a 32-byte octet vector, or NIL when NAME-STRING does not decode. Exported so consumers — the edge seam's revocation check, tests asserting store membership — test against exactly the hash this package and the verifier use, rather than re-deriving the format.

NIL means the string is not a capability name at all, never that the hash could not be computed: a fault anywhere past the decode propagates. A caller deciding whether a grant is still good must treat NIL as unknown standing and refuse, not as clearance.

note-session-activity

(note-session-activity view-root)

Stamp VIEW-ROOT's session as active, or fence it when it has gone idle past SESSION-MAX-IDLE-SECONDS.

Called from the request path, so it does its work with a slot read, a comparison and a slot write, and takes no lock: an integer slot assignment is atomic on the platforms this runs on, and a torn read here would at worst delay one fence by one operation.

Checking the bound here rather than from a sweeper is what makes the bound mean something after a relocation. An instance that has moved leaves sessions behind that believe they are still attached to it, and the moment worth catching is the one where such a session is next used, not some arbitrary tick before or after. A session nobody touches costs nothing and reaches nothing.

register-view

(register-view view-root principal)

Add VIEW-ROOT and its PRINCIPAL to LIVE-VIEW-REGISTRY for eviction sweep. Returns the registry entry, or NIL when LIVE-VIEW-REGISTRY is NIL (fabric not up). Acquires LIVE-VIEW-REGISTRY-LOCK when present to guard the structural setf gethash against concurrent evict-by-hash maphash.

The entry is also stored on the view itself, so the request path can stamp its activity mark from a slot read rather than a lookup on the weak registry. The auth conversation is read from PRINCIPAL here, at the one moment it is still known, so a later fence has something durable to name.

session-descriptors

(session-descriptors)

Describe the live sessions as plain plists, one per session, carrying :ID, :PRINCIPAL, :ADMITTED-AT, :LAST-ACTIVITY and :FENCED-AT.

Plists rather than registry entries because the door that publishes this sits upstream of the registry and cannot import it. Handing plain data across that seam also keeps the wire format a decision of the door, which is where a reader's needs are actually known.

session-handshake-fenced-p

(session-handshake-fenced-p handshake)

Return true when HANDSHAKE names an auth conversation that has been fenced. A nil HANDSHAKE is never fenced: an unauthenticated attach carries no conversation, and treating its absence as a match would fence every anonymous arrival at once.

unmount-name

(unmount-name view name &optional member-index)

Remove the mount-table entry for NAME from VIEW.

If MEMBER-INDEX is NIL, remove the entire entry. If MEMBER-INDEX is an integer and the entry's node is a union-node, remove that member from the union; if the union becomes empty, remove the entry entirely. If the node is not a union-node, MEMBER-INDEX is ignored.

Refuses to unmount "ctl" — a self-narrowing unmount must never sever the view's own control channel.

Returns (values T NIL) on success; (values NIL reason-string) on failure.

Variables

*assembler-root*

The valis-root the assembler resolves designations against. Set by start-fabric; cleared by stop-fabric. Nil before fabric is up.

*ctl-node-factory*

A function of one argument (the view-root) that constructs and returns the /ctl node for that view. Set by start-fabric to #'make-view-ctl-node; cleared by stop-fabric. Nil means no ctl node is mounted — the canonical frame lacks /ctl, which is the correct behavior outside a running fabric (unit tests that call build-base-view without a fabric should not pull in view-ctl).

This seam breaks the compile-time circularity: view-ctl imports assembler (for mount-capability / unmount-name), so assembler cannot import view-ctl back; fabric is downstream of both and installs the factory at start time.

*durable-head-reader*

The block-store the assembler reads the namespace manifest from. Set by start-fabric from the live store-store's block-store accessor; nil before the fabric is up — then assemble-canonical-frame falls back to the default manifest, so a unit test that calls build-base-view without a fabric gets today's behavior unchanged. This is the store current-head / read-manifest / read-block take on the read path; the write-side publish is driven by the fabric from the store's head handle directly, so only the block-store is held here.

*fenced-handshakes*

The auth conversations whose sessions have been fenced. Weak on the key, so a row goes away with the conversation it names.

Emptying a view stops the session that holds it, but a client can ask for another one: a second Tattach over the same transport would otherwise assemble a fresh owner frame and hand the fence straight back. Consulting this table at attach closes that door, and closes it exactly as far as intended, because re-running the handshake yields a conversation this table has never seen.

*live-view-registry*

Weak hash table (view-root → live-view-entry) for revocation eviction. Constructed with make-hash-table :weakness :key (SBCL extension) so dead sessions are GC'd without an explicit deregistration hook. A session-close callback seam would be the upstream clean solution for other implementations.

*live-view-registry-lock*

Mutex protecting structural mutations of LIVE-VIEW-REGISTRY: setf gethash in register-view, remhash in deregister-view, and maphash in evict-by-hash's snapshot step. Set by start-fabric; cleared by stop-fabric.

Lock order: acquire LIVE-VIEW-REGISTRY-LOCK FIRST, then per-view LIVE-VIEW-ENTRY-LOCK. Never hold both simultaneously: evict-by-hash releases the registry lock before acquiring any per-view lock.

*session-max-idle-seconds*

How many seconds a session may go untouched before its next operation fences it, or nil for no bound at all. Nil is the default and preserves the behavior a deployment already has: a session lives until it is fenced or its transport dies. That default is deliberate, because the alternative is a lockout nobody asked for on an upgrade.

The bound is enforced when a session is next used, not by a sweeper. A dormant session issues no requests and can harm nothing; the case worth catching is someone picking up an abandoned one, and that arrives as an operation.

+recommended-session-max-idle-seconds+

The idle bound a deployment is advised to adopt for owner sessions. It is not applied on its own: a launcher or an operator chooses it explicitly by setting SESSION-MAX-IDLE-SECONDS. Fifteen minutes is short enough that an unattended browser tab stops being a live management console over a lunch break, and long enough that ordinary editing is never interrupted.

Package valis/src/namespace/backup

Classes

backup-dir-root

The /backup axis root directory node. Its one fixed leaf is ctl; node-walk is a cond over the leaf name and returns nil for anything else (sovereignty-as-absence).

Functions

make-backup-dir-root

(make-backup-dir-root)

Construct the /backup axis root. The fabric instantiates this and binds backup-dir-root to it at start; root.lisp mounts it under /backup in the owner frame only.

Variables

*backup-dir-root*

The /backup axis node. Set by the fabric at start-fabric; nil before the fabric is up or after teardown. root.lisp's node-walk walks /backup through this variable, so a nil value means the axis is absent (sovereignty-as-absence).

Package valis/src/namespace/cap

Classes

cap-dir

The /cap directory node: ctl and verify child files exposing the capability service over 9P.

Generic functions

cap-dir-ctl

(cap-dir-ctl object)

Undocumented: this exported symbol needs a docstring.

cap-dir-verify

(cap-dir-verify object)

Undocumented: this exported symbol needs a docstring.

Functions

decode-wire-token

(decode-wire-token payload-bytes)

Decode PAYLOAD-BYTES — the raw (canonical-bytes || sig-64) byte vector obtained by base58-decoding the payload after the "token:" prefix — into a CAPABILITY-TOKEN object.

This is a thin public wrapper around the internal wire decoder so the namespace assembler can reconstruct a token from a bearer string without reaching into cap.lisp internals via ::. Signals on any structural mismatch.

make-cap-dir

(make-cap-dir &key custody revocation-store)

Construct a fresh cap-dir with ctl and verify child nodes. CUSTODY and REVOCATION-STORE are captured on the instance for a future per-instance service; the live lookup path goes through cap-custody and cap-revocation-store, which fabric.lisp sets at start.

mint-token-bearer

(mint-token-bearer custody audience-did designation rights expiry-seconds)

Mint one owner-issued capability token: CUSTODY signs a grant to AUDIENCE-DID over DESIGNATION carrying RIGHTS, expiring EXPIRY-SECONDS from now.

Returns (values BEARER TOKEN): BEARER is "token:" + base58 of (canonical-bytes

  signature) — the wire form /cap/verify accepts — and TOKEN is the constructed

CAPABILITY-TOKEN, so a caller can read the grant back (to record its grant hash, say) without re-decoding the bearer.

This is the single owner-issued mint path: both the /cap ctl parser and the ssh-reality proof-of-reality driver construct the token here, so a maximal Tier-1 grant is byte-identical to a /cap ctl mint and no second token-construction copy exists. The signing key never leaves CUSTODY; the issuer is always the owner custody DID, so this path cannot mint a self-issued token whose issuer is its own audience.

split-ws

(split-ws s)

Split S on runs of ASCII whitespace (space, tab, newline, carriage return) and return a list of nonempty tokens. All input here is attacker-controlled bytes; no Lisp reader is involved. Exported so view-ctl.lisp can share the implementation.

Variables

*cap-custody*

The active custody-store the capability service signs and verifies with. Set by fabric.lisp at start-fabric time (it points to the same store factotum-custody holds); nil before the fabric is up. The ctl and verify nodes guard against nil at open so a pre-fabric caller gets a clear error rather than a nil-deref mid-request. Tests bind it dynamically.

*cap-revocation-store*

The active revocation-store consulted and appended by the capability service. Set by fabric.lisp at start-fabric time; nil before. Tests bind it dynamically.

*cap-service*

The active cap-dir node serving the /cap axis. Set by fabric.lisp at start-fabric time; nil before the fabric is up or after stop-fabric. root.lisp walks /cap through this variable once the axis is wired.

Package valis/src/namespace/edge

Classes

edge-dir

The /edge status directory node. node-entries and node-walk call edge-bound-ports fresh on every invocation; opening /edge in a 9P client sees the ports the controller has bound at that moment, plus the anonymous status file.

Functions

make-edge-dir

(make-edge-dir)

Construct a fresh edge-dir node.

Package valis/src/namespace/id

Classes

factotum-dir

The /id directory node — factotum(4)-faithful tree with ctl, rpc, proto child files. Replaces id-stub when the live factotum is wired; root.lisp keeps both so the axis stays traversable either way.

The sessions and session-ctl children are the owner's view of, and control over, the attachments to this node. They sit on /id because what they act on is who is currently admitted, which is an identity question rather than a capability one: the sessions listed here hold no capability to revoke.

id-stub

Static empty directory node for the /id axis, used when no live factotum subtree is wired.

Functions

make-factotum-dir

(make-factotum-dir &key custody)

Construct a fresh factotum-dir backed by CUSTODY (a custody-store). The directory holds the factotum's own child files (ctl, rpc, proto, owner) and the owner's session door (sessions, session-ctl); the custody slot is captured here so a multi-owner factotum can be added without rewriting the seam-variable lookup chain.

make-id-stub

(make-id-stub)

Construct a fresh id-stub node.

Variables

*factotum-custody*

The active custody-store carrying the owner's Ed25519 master key pair. Set by fabric.lisp at start-fabric time; nil before the fabric is up or after stop-fabric. The rpc-node's node-open reads this to seed each fresh Noise auth conversation (using the derived X25519 transport key); ctl-node's node-read renders the key descriptor list from it. Tests bind it dynamically.

Package valis/src/namespace/mail

Classes

mail-dir-root

The /mail axis root directory node. Its children are the four fixed leaves outbox/inbox/queue/ctl, each instantiated fresh per call over the mail block STORE and its fenced HEAD — the child nodes query the live head on every call, so a fresh instance per walk holds no snapshot. Unlike /pub's store-listed slugs, the children are a FIXED set: node-walk is a cond over the four leaf names and returns nil for anything else. STORE/HEAD are nil before the fabric is up; the children then list/serve nothing of their own accord.

Functions

make-mail-dir-root

(make-mail-dir-root &key store head resolver)

Construct the /mail axis root over the mail block STORE and its fenced HEAD, threading the outbound MX RESOLVER the /ctl drain resolves relay recipients through. The fabric instantiates this and binds mail-dir-root to it at start; root.lisp mounts it under /mail as a /pub sibling, and the assembler walks it into the owner's canonical frame. A NIL RESOLVER makes a drain defer every relay entry fail-closed — there is no smarthost fallback.

Variables

*mail-dir-root*

The /mail axis node. Set by the fabric at start-fabric; nil before the fabric is up or after teardown. root.lisp's node-walk walks /mail through this variable, so a nil value means the axis is absent (sovereignty-as-absence), exactly as /pub and /edge behave.

Package valis/src/namespace/mail-ctl

Classes

mail-ctl-node

The /mail/ctl file: owner-only mail-queue control. node-open mints a fresh mail-ctl-conversation closing over STORE and HEAD; node-write parses a status or drain command; node-read returns the result. mode #o600 — only the owner's session writes it, and it is mounted only in the owner frame and never named in an operational grant. The base backend-node :after mints a qtfile QID, which is correct for a file node.

Functions

make-mail-ctl-node

(make-mail-ctl-node &key store head resolver)

Construct the /mail/ctl node over the mail STORE and its fenced HEAD, threading the outbound MX RESOLVER a drain step resolves relay recipients through. The /mail axis root instantiates this and mounts it under /mail in the owner frame; node-open mints a conversation closing over STORE, HEAD, and RESOLVER. A NIL RESOLVER makes a drain defer every relay entry fail-closed — there is no smarthost fallback.

Package valis/src/namespace/mail-inbox

Classes

inbox-dir-root

The /mail/inbox directory node. Its children are per-identity Maildir roots keyed under a DID (even with one identity). node-walk gates the DID through the fail-closed valid-did-slug-p charset gate and resolves only a DID with a landed inbox subtree; an unknown DID or a charset-invalid name returns nil — sovereignty- as-absence. STORE/HEAD are the mail block store and its fenced head; both nil before the fabric is up, in which case the inbox lists nothing.

Functions

make-inbox-dir-root

(make-inbox-dir-root &key store head)

Construct the /mail/inbox directory node over the mail STORE and its fenced HEAD. The /mail axis root instantiates this and mounts it under /mail; per-DID Maildirs and their owner read-state mutations resolve through STORE/HEAD on every call against the live head.

Package valis/src/namespace/mail-outbox

Classes

outbox-dir-root

The /mail/outbox directory node — the writable submission bridge. STORE and HEAD are the content-addressed block store and its fenced head the staged submission commits through at clunk; both nil before the fabric is up, in which case node-create fails closed. node-entries / node-walk expose nothing: a submission has no read-state, so the outbox lists and names no child after the create that minted its staging fid.

outbox-submission-file

A staging message file — the qmail tmp/ equivalent. Octets written across node-write calls accumulate in BUFFER; nothing is content-addressed or queued until node-close (the clunk) commits. A fid abandoned without a clunk never reaches node-close, so it lands no queue entry — complete-or-absent, structural. SUBMITTER-DID and AUTHENTICATED-SUBMIT-P were captured from the session principal at the write gate (node-create) — the DID, and whether the session is a keyed principal; both are stamped onto the provenance at commit, never parsed from the message bytes.

Functions

make-outbox-dir-root

(make-outbox-dir-root &key store head)

Construct the /mail/outbox directory node over the mail STORE and its fenced HEAD. The /mail axis root instantiates this and mounts it under /mail; the staged submission commits through STORE/HEAD at clunk.

Package valis/src/namespace/mail-queue

Classes

mail-queue-dir-root

The /mail/queue directory node: a synthesized body-free status projection over the transport queue. STORE is the content-addressed block store the queue lives in; HEAD is its fenced head, carried for the construction contract (the live read authority is the on-disk head). node-entries / node-walk query the head on every call — never a snapshot. Read-only by construction: no write paths exist, and the ops grant wraps this node in read-only-projection-node at mount. A nil STORE (fabric not up) lists empty rather than signalling.

Functions

make-mail-queue-dir-root

(make-mail-queue-dir-root &key store head)

Construct the /mail/queue status projection over the mail STORE and its fenced HEAD. The /mail axis root instantiates this and mounts it under /mail; the operational grant wraps it in read-only-projection-node at mount.

Package valis/src/namespace/names

Classes

names-cert-dir

The axis-level cert control directory, names/cert. Its obtain child accepts the owner-gated ACME first-obtain verb, driven in the resident that serves :53. A sibling of the per-zone surfaces at the :names axis root, since an obtain is not scoped to a single zone (a fresh node obtains its first cert before any zone edit).

names-cert-obtain-file

The axis-level cert obtain /ctl node, names/cert/obtain. The owner writes a newline-framed obtain verb — the identifiers, the account contact, and the optional profile / directory-url — then reads the outcome and clunks. The verb drives an ACME first-obtain IN this resident so the dns-01 challenge TXT is refreshed into the serving index by the in-process commit hook; the outcome is a newline-framed reply body whose FIRST line is the machine token obtained, followed by one domain line per issued identifier and a next-renewal line. Because the client reads before it clunks, the read is the commit point: the order runs on first demand and the result is memoised for the fid's lifetime, so read and clunk together drive exactly one order and a fid abandoned without either drives none. A twin of the record /ctl node: it inherits the staging buffer and node-write, but overrides node-close to run the order and map the obtain conditions (a missing contact, a non-authoritative identifier, a live-order failure) to a clean nine-p-error so a refusal returns an Rerror rather than escaping the clunk thread. Owner-gated by the unchanged mount machinery — a non-owner reaches a read-only projection whose write refuses.

names-cutover-ctl-file

The per-zone /ctl flip node: the operator writes a cutover verb (answer-as-secondary | promote-to-primary) and clunks to commit the transition for this zone via commit-cutover-transition. Reached as a child of the per-zone read node; the published-by-design read node stays read-only (#o444) — control writes ride this separate writable child, owner-gated by the unchanged mount machinery.

names-cutover-declare-file

The axis-level /ctl declaration node: the operator gate that bootstraps a brand-new HELD secondary BEFORE its first transfer. A cold secondary has no per-zone node yet (its zone does not exist), so declaration lives at the :names axis root, not per-zone. The operator writes "declare-secondary <origin> <master-ref>" and clunks; node-close runs declare-secondary-zone, which creates the held zone shell + the upstream-master allowlist entry in FK order so the first transfer can self-authorize.

names-dir-root

The :names axis root directory node. GENERATION-READER is a thunk returning the live store write-epoch (my-generation) this instance holds; the fabric sets it to read the durable head generation LIVE per call, so every commit / delete asserts the instance fence against the current epoch (never a cached snapshot). node-create mints a master-file submission staging node; node-walk / node-entries surface each existing zone as a per-zone node read from the operator-state PG seam.

names-record-ctl-file

The per-zone structured record write node, names/<origin>/records/ctl. The owner writes a newline-framed verb — add-record / delete-record / replace-record — then reads the outcome and clunks. The verb is dispatched to the durable single-rrset-member seam under the session principal's ownerdid, and the outcome is reported as a newline-framed reply body whose FIRST line is a machine token from a closed set — committed-served or committed-unserved — followed by key/value lines. committed-unserved is a SUCCESS: the edit is durable but did not reach the serving side, which is a distinct outcome from a refusal and rides the success body so a client never reads a landed edit as a failure.

Because the client reads before it clunks, the read is the commit point: the staged verb is committed on first demand and the result memoised for the fid's lifetime, so read and clunk together commit exactly once and a fid abandoned without either commits nothing. A twin of the cutover /ctl node: it inherits the staging buffer and node-write, but overrides node-close to map the record-domain conditions (malformed rdata, a structural invariant violation, a not-found replace target, a superseded instance) to a clean nine-p-error. A refusal signals with its own ename and never reaches the reply rendering, so it returns an Rerror rather than crashing the serve path. Owner-gated by the unchanged mount machinery — a non-owner reaches a read-only projection whose write refuses.

names-record-list-node

The per-zone structured record read node, names/<origin>/records/list. node-read renders the zone's DURABLE records as a table of tab-separated lines (digest owner ttl class type rdata), read through the connection seam from list-durable-zone-records — the published-by-design structured editing surface, with a stable per-member digest identity. The rendering is memoised for the fid's lifetime. A file node — no directory override.

names-records-dir

The per-zone structured record directory, names/<origin>/records. Its `list` child renders the durable records as a digest-keyed table; its `ctl` child accepts the owner-gated add/delete/replace record verbs. Reached by an explicit walk off the per-zone node and surfaced in that node's entries, kept distinct from the per-zone master node-read so the exterior-nameserver-seam rendering stays intact.

names-submission-file

A staging master-file — the mail outbox tmp twin. RFC 1035 master text written across node-write calls accumulates in BUFFER; nothing is parsed or written to PG until node-close (the clunk) commits the atomic full-zone replace. A fid abandoned without a clunk never reaches node-close, so it imports nothing — complete-or-absent, structural. SUBMITTER-DID was captured from the session principal at the write gate (node-create) and is stamped as the zone's write- authority owner DID at commit, never parsed from the zone bytes.

names-zone-control-dir

The axis-level zone control directory, names/zone. Its create child mints a new domain and enrols its shared secondary as one act. It lives at the axis root rather than under a per-zone node for the same reason the secondary declaration does: a domain that does not exist yet has no per-zone node to reach, which is exactly the create case.

names-zone-create-file

The axis-level zone create door, names/zone/create. The owner writes a newline-framed create verb – the origin, the instance address, the secondary to enrol, whichever template parameters differ from the defaults, and zero or more typed override records – then reads the outcome and clunks. The verb mints the domain's default record set and enrols the shared secondary as ONE act; the outcome is a newline-framed reply whose FIRST line is a machine token from a closed set, followed by key/value lines and the BIND fragment the secondary side pastes. A twin of the cert obtain door: it inherits the staging buffer and node-write, opens :rdwr, and memoises the terminal outcome for the fid's lifetime so a read and a clunk together create exactly one domain and a fid abandoned without either creates none. Every create-domain condition is mapped to a clean nine-p-error at this boundary, so a refusal returns an Rerror rather than escaping the clunk thread. Owner-gated by the unchanged mount machinery – a non-owner reaches a read-only projection whose write refuses.

names-zone-master-node

One existing zone's flat master-file read node, the `master` child of the per-zone directory (names/<origin>/master). node-read renders the zone's full serving set as canonical master-file lines via %render-zone — the published-by-design, world-readable exterior-nameserver read seam preserved from the pre-directory per-zone node. The rendering is memoised for the fid's lifetime so length / read report one consistent snapshot. A file node — no directory override.

names-zone-node

One existing zone's per-zone node, a directory keyed by canonical ORIGIN and surfaced in the :names listing. It walks as a directory — a qtdir QID override, the same the axis root and the records directory apply — into three children: `master` renders the zone's full serving set as canonical master-file lines (published-by-design, world-readable — reads require no capability); `ctl` accepts the owner-gated cutover flips; `records` is the structured record-editing directory. node-remove deletes the whole zone (apex/SOA removal = whole-zone removal), owner-gated by the unchanged owner mount machinery — removing the zone directory removes the zone.

Conditions

illegal-cutover-transition

Signaled by commit-cutover-transition when the requested cutover flip is not legal per runciter's cutover-transition-legal-p (consumed through the serving seam), or when no held anchor exists to flip. The persisted state is left unchanged; node-close translates this to a clean nine-p-error.

secondary-timer-not-ready

Signaled by commit-cutover-transition when a flip to :answer-as-secondary is attempted without a populated, non-expired persisted expiredeadline. An answering secondary must have a live SOA expiry from its last successful transfer; without one the flip is refused (commits nothing), so a secondary can never be made answerable with a stale or absent timer. node-close translates this to a clean nine-p-error.

zone-already-exists

Signaled by commit-zone-create when the origin already holds a zone. The refusal NAMES the origin, because the correction differs entirely by which domain it is: an operator who meant to edit reaches for the record verbs, and an operator who meant to replace reaches for the import door. commit-zone-records is a full-zone REPLACE, so a create that reached it would destroy the existing zone's records; this is the condition that stops it.

Generic functions

cert-obtain-refusal

(cert-obtain-refusal object)

Undocumented: this exported symbol needs a docstring.

cert-obtain-reply

(cert-obtain-reply object)

Undocumented: this exported symbol needs a docstring.

illegal-cutover-transition-from

(illegal-cutover-transition-from condition)

Undocumented: this exported symbol needs a docstring.

illegal-cutover-transition-origin

(illegal-cutover-transition-origin condition)

Undocumented: this exported symbol needs a docstring.

illegal-cutover-transition-to

(illegal-cutover-transition-to condition)

Undocumented: this exported symbol needs a docstring.

secondary-timer-not-ready-origin

(secondary-timer-not-ready-origin condition)

Undocumented: this exported symbol needs a docstring.

zone-already-exists-origin

(zone-already-exists-origin condition)

Undocumented: this exported symbol needs a docstring.

zone-create-refusal

(zone-create-refusal object)

Undocumented: this exported symbol needs a docstring.

zone-create-reply

(zone-create-reply object)

Undocumented: this exported symbol needs a docstring.

Functions

commit-cutover-transition

(commit-cutover-transition origin to-state my-generation)

Commit an operator cutover flip of the zone at canonical ORIGIN to TO-STATE (:answer-as-secondary | :primary) — an observable substrate-level state transition. runciter's pure cutover-transition-legal-p decides legality (through the valis-owned serving seam); an illegal flip (or no held anchor to flip) signals illegal-cutover-transition and persists nothing.

A flip to :answer-as-secondary additionally REQUIRES a populated, non-expired persisted expiredeadline: an answering secondary must carry a live SOA expiry from its last successful transfer. Without one (absent or already past the live clock) the flip is refused with secondary-timer-not-ready and persists nothing — a secondary can never be made answerable with a stale or absent timer.

A legal flip persists the new cutoverstate on the ndbentry anchor inside a fenced transaction (assert-fence-touch FIRST — a superseded instance flips nothing); a promotion to :primary additionally flips authoritystate to primary, valis becoming the system of record.

valis maintains no serving view of its own, so the commit reloads nothing: after the durable commit the in-process zone-change signal fires (origin, current serial) so the c3po-dns wire feed and runciter's lazy pull observe the change. Runs inside the :names connection seam. Returns TO-STATE.

commit-zone-create

(commit-zone-create payload my-generation owner-did)

Create the domain PAYLOAD describes and enrol its shared secondary as ONE act, under OWNER-DID and the store write-epoch MY-GENERATION. Returns (values CANONICAL-ORIGIN SERIAL RECORD-COUNT PEER KEY-NAME SECRET-BASE64 MASTER-ADDRESS UNSERVED-REASON) for the reply. The zone rows and the secondary's two allowlist rows share one transaction, so a failure anywhere leaves neither: an allowlist row authorising a peer to pull a zone that does not exist is the residue this ordering exists to prevent. The TSIG custody file is deliberately OUTSIDE that transaction, because a file write cannot be rolled back; the correct state after a failed create is therefore no zone, no allowlist rows, and an orphaned key, and a re-run reuses that key rather than minting a second one.

make-names-cert-dir

(make-names-cert-dir)

Construct the axis-level cert control directory child.

make-names-cert-obtain-file

(make-names-cert-obtain-file)

Construct the axis-level cert obtain /ctl node. The staging base fences on a generation-reader it never consults here (an obtain does not fence against the store epoch), so a constant reader is passed.

make-names-dir-root

(make-names-dir-root &key (generation-reader (constantly 0)))

Construct the :names axis root. GENERATION-READER is a thunk returning the live store write-epoch this instance holds; the fabric passes a reader over the durable head so every commit / delete fences against the current generation. root.lisp mounts the result under :names as a /mail sibling in the owner's canonical frame.

make-names-records-dir

(make-names-records-dir origin generation-reader)

Construct the per-zone structured record directory for canonical ORIGIN over the live GENERATION-READER.

make-names-zone-control-dir

(make-names-zone-control-dir generation-reader)

Construct the axis-level zone control directory over the live GENERATION-READER.

make-names-zone-create-file

(make-names-zone-create-file generation-reader)

Construct the axis-level zone create door over the live GENERATION-READER. Unlike the cert obtain door this one fences: a create is a mutating write into operator state, so it asserts the current store write-epoch and a superseded instance creates nothing.

make-names-zone-master-node

(make-names-zone-master-node origin)

Construct the per-zone flat master-file read node for canonical ORIGIN.

Variables

*max-zone-master-bytes*

The upper bound on a staged zone master file, in bytes. node-write accumulates octets across arbitrarily many Twrite frames into one fid's submission buffer before the clunk commits; seven's per-frame oversize guard bounds a single frame but not the running total, so without this ceiling an authenticated writer could stream unbounded data into one fid and grow image memory without limit. 16 MiB is generous for the largest legitimate zone — a fully DNSSEC-signed zone with many records runs to a few MiB — while foreclosing the unbounded-accumulation abuse.

*names-dir-root*

The :names axis node. Set by the fabric at start-fabric when an operator-state pool is configured; nil before the fabric is up, after teardown, or when no operator-state pool is present. root.lisp's node-walk walks :names through this variable, so a nil value means the axis is absent (sovereignty-as-absence) — the DNS management surface only exists where there is a PostgreSQL seam to write into.

*names-with-connection*

The connection seam the :names commit / read / delete paths run their PG work through. In production it is the default that wraps with-operator-state-connection (acquire-late / release-early, on the serve/worker thread — never the epoll listener). A PG acceptance test binds it to a pass-through that runs the thunk on the ambient disposable-schema connection, so the same node path the operator drives is exercised end to end against a throwaway schema.

Package valis/src/namespace/projection

Classes

read-only-open-wrapper

Wraps an inner open-object after a read-mode open on a projection. seven binds this as the fid's open-object; all subsequent dispatches (node-read, node-write, node-close, node-iounit) go here first. Reads and closes delegate to the inner open-object; writes are denied unconditionally, closing the bypass path that would otherwise let a read-mode Topen on a writable inner node escape the projection.

read-only-projection-node

Deep read-only proxy. Wraps a backend-node subtree exposing walk/read/stat only; write/create/remove/wstat signal nine-p-error. Children walked through a projection are themselves wrapped in fresh projections (lazy, avoids pre-building the whole subtree). QID passes through to the inner node.

NOT a backend-node subclass — node-qid passes through the inner node's QID to preserve resource identity on the wire. A projection wraps a view, not an object.

node-open returns a read-only-open-wrapper rather than the raw inner open-object so that seven's post-open node-write dispatches still reach the deny implementation — the wrapper is the enforcement carrier for the full open lifetime.

Generic functions

projection-inner

(projection-inner object)

Undocumented: this exported symbol needs a docstring.

read-only-open-wrapper-inner-open-obj

(read-only-open-wrapper-inner-open-obj object)

Undocumented: this exported symbol needs a docstring.

Functions

make-projection

(make-projection inner)

Wrap INNER in a read-only-projection-node.

Package valis/src/namespace/proto

Classes

proto-dir

The /proto directory node. node-entries and node-walk call registered-protocols fresh on every invocation; opening /proto in a 9P client snapshots the result at that moment.

Functions

make-proto-dir

(make-proto-dir)

Construct a fresh proto-dir node.

Package valis/src/namespace/pub

Classes

pub-dir-root

The /pub directory node. node-entries and node-walk query the store on every invocation — never a snapshot stored at construction time. A nil pub-store means the store is not yet up; both methods return nil/empty safely rather than signalling.

Functions

make-pub-dir-root

(make-pub-dir-root)

Construct a fresh pub-dir-root node.

Variables

*pub-dir-root*

The /pub axis node. Set by start-fabric; nil before the fabric is up or after stop-fabric. root.lisp's node-walk walks /pub through this variable.

Package valis/src/namespace/root

Classes

dev-auth-node

Development credential stub for the auth seam. Any Twrite completes the dev auth conversation. The live fabric uses a real Noise/factotum credential check (noise-auth-node) in its place.

valis-root

The valis 9P attach root. seven's server hands this node to each Tattach; node-walk dispatches the three top-level axes (/proto, /bus, /id) to the module-level seam variables the fabric controller wires at startup.

Functions

attach-handshake

(attach-handshake principal)

Return the auth conversation PRINCIPAL was admitted through, or nil when none was recorded: the unauthenticated path, or a principal built outside an attach.

current-principal

(current-principal)

Return the resolved principal for the request currently being served.

Reads the opaque identity seven recorded on the 9P session at Tattach via node-attach-identity, surfaced through seven/src/server:current-identity for the dynamic extent of request dispatch. Returns a keyed principal for a session admitted by NoiseXX, or the anonymous sentinel for a NOFID attach. Never returns nil within a request — if the identity slot is empty (called outside dispatch, or on a session whose backend recorded nil), this collapses to the anonymous sentinel so callers can treat the return value uniformly through principal-p / anonymous-p.

Dynamic-extent boundary: current-identity resolves only on the session thread inside %dispatch (see seven/src/server). A standard file node's node-read runs synchronously on that thread, so current-principal is correct during node-open / node-read / node-write. A backend that overrides node-read-async to park off-thread (the /bus pattern) must capture the principal at the synchronous call site and close over it for delivery — current-principal at the delivery site is outside the dynamic extent and will collapse to anonymous.

make-valis-root

(make-valis-root)

Construct a fresh valis-root node.

note-attach-handshake

(note-attach-handshake principal handshake)

Record that PRINCIPAL was admitted through HANDSHAKE, and return PRINCIPAL so the caller can wrap the value it was already producing. A nil HANDSHAKE records nothing: the unauthenticated path has no conversation to name, and a nil row would make every anonymous attach look like the same one.

Variables

*base-view-fn*

Callback set by the namespace assembler to build-base-view. Wired at assembler load time to break the circular package dependency: assembler imports root (for valis-root and %walk-designation), so root cannot import assembler at compile time. When nil (assembler not loaded, unit tests that do not stand up the full fabric), node-attach-root's plain branch returns an empty view — fail-closed: nobody receives an ambient namespace by accident.

*bearer-view-decorate-fn*

A function of (view-root auth-identity grant-string) called on each view-root built for a VERIFIED bearer-name attach; returns the view to bind (normally the same object). Set by start-fabric to the assembler's decorate-bearer-view, which stamps the grant hash on the view's mount entries, adds the per-view ctl door for phase-two mount/unmount, and weak-registers the view for revocation eviction; cleared by stop-fabric. Nil binds bearer views bare — correct outside a running fabric. A function-valued hook because the assembler imports this package, so this package cannot import the assembler back.

*edge-dir*

The /edge status directory node (the live edge controller projection) for this valis image. Set by the fabric controller at start-fabric time; read by valis-root's node-walk / node-entries and mounted into the owner's canonical frame by the assembler. When nil (no fabric started, or a teardown window), the /edge walk misses and the axis is simply absent.

Owned here rather than in src/namespace/edge.lisp to break a load cycle: edge.lisp pulls in the edge controller, which transitively reaches the assembler, which imports this package — so root cannot import edge back. The node class and its constructor live in edge.lisp (which root never imports); the seam variable lives upstream here, and the fabric — downstream of both — calls make-edge-dir to fill it. The same upstream-variable / downstream- constructor split the other axis seam variables use.

*factotum*

The factotum directory node (the live /id subtree) for this valis image. Set by the fabric controller at start-fabric time; read by valis-root's node-walk / node-entries. When set, takes precedence over id-stub under the /id axis; when nil (no fabric started, or unit tests touching the root directly), node-walk falls through to id-stub so the axis remains traversable for tests that do not stand up the full fabric.

*id-stub*

The /id stub directory node for this valis image. Set by the fabric controller at start-fabric time.

*proto-dir*

The /proto directory node for this valis image. Set by the fabric controller at start-fabric time; read by valis-root's node-walk / node-entries.

*valis-bus*

The /bus directory node (seven's bus-dir) for this valis image. Set by the fabric controller at start-fabric time.

Package valis/src/namespace/session-door

Classes

session-ctl-node

The /id/session-ctl file. One command line per write:

fence SESSION-ID

Fencing empties that session's namespace, so it can name nothing until it authenticates again. Fencing the session that issued the command is allowed and takes effect at once: the result stays readable on the handle already open, and nothing else is reachable afterwards.

Unknown verbs are ignored, because a control file must not become an eval surface. A malformed argument to a known verb produces an "error …" read response and never a signal into the 9P layer.

sessions-node

The /id/sessions file. Read-only; one line per live session giving its id, the principal it was admitted as, when it attached, when it was last used, and whether it has been fenced.

The id in the first column is what an operator writes to /id/session-ctl. It exists because the registry is keyed by an object no one outside the image can name, and an operator looking at a session they want stopped has to have something they can type.

Functions

make-session-ctl-node

(make-session-ctl-node)

Construct a fresh /id/session-ctl command node.

make-sessions-node

(make-sessions-node)

Construct a fresh /id/sessions listing node.

Variables

*session-descriptor-fn*

Returns the live sessions as a list of plists carrying :ID, :PRINCIPAL, :ADMITTED-AT, :LAST-ACTIVITY and :FENCED-AT.

Nil when no fabric is running, in which case the listing reads as empty rather than failing. That is the truthful answer: with no fabric there are no sessions.

Installed by start-fabric and cleared by stop-fabric. The registry lives downstream of this file and cannot be imported back into it, which is why the connection is made at start time rather than at compile time.

*session-fence-fn*

Fences the session named by its one argument, and returns true when a live session carried that id.

Nil when no fabric is running; a fence attempted then reports the session as absent, which is accurate. Installed and cleared alongside SESSION-DESCRIPTOR-FN.

Package valis/src/namespace/union-node

Classes

union-node

An ordered union of backend-node directories. Implements 9Front bind semantics: the first member whose subtree contains a name wins on walk; all members' entries are concatenated without deduplication on read.

Each member tracks its own grant hash and its own rights bitmask so revocation sweeps can remove individual members without over-evicting sibling grants, and so the union entry's rights-bits can be recomputed from survivors after each per-member eviction.

Generic functions

union-node-member-grant-hashes

(union-node-member-grant-hashes object)

Undocumented: this exported symbol needs a docstring.

union-node-member-rights-bits

(union-node-member-rights-bits object)

Undocumented: this exported symbol needs a docstring.

union-node-members

(union-node-members object)

Undocumented: this exported symbol needs a docstring.

union-node-name

(union-node-name object)

Undocumented: this exported symbol needs a docstring.

Functions

make-union-node

(make-union-node members &key (name "") (member-grant-hashes nil) (member-rights-bits nil))

Construct a union-node with MEMBERS (an ordered list of backend-nodes, first member searched first on walk). NAME is the leaf name reported by node-stat; defaults to the empty string. MEMBER-GRANT-HASHES is an optional parallel list of grant hash octet vectors (or nils) in 1-to-1 correspondence with MEMBERS; when omitted, all hashes default to nil (no revocable grant for any member). MEMBER-RIGHTS-BITS is an optional parallel list of integer rights bitmasks in 1-to-1 correspondence with MEMBERS; when omitted, all rights default to 0.

union-node-evict-member-by-hash

(union-node-evict-member-by-hash union hash)

Remove all members of UNION whose grant hash equals HASH (byte-equalp). Returns three values: the updated UNION, T if at least one member was removed (NIL if no member matched), and the bitwise OR of the surviving members' rights bitmasks (0 when the union is now empty). The caller should update the enclosing mount-entry's rights-bits to this third value so the entry never advertises rights from a revoked grant.

HASH comparison uses EQUALP on octet vectors. A nil member-grant-hash means that member has no revocable grant and is never removed here.

union-node-evict-write-members

(union-node-evict-write-members union)

Remove every capability-backed, write-capable member of UNION. A member is capability-backed when its grant hash is non-nil; it is write-capable when its rights bitmask carries the write right. Members with no grant hash are base-policy and are never removed here.

Returns two values: T if at least one member was removed, and the bitwise OR of the surviving members' rights bitmasks (0 when the union is now empty). The caller updates the enclosing mount-entry's rights-bits to the second value so the entry never advertises rights from a swept grant.

union-node-member-count

(union-node-member-count union)

Return the number of members in UNION.

Package valis/src/namespace/view-ctl

Classes

view-ctl-node

The /ctl file in an assembled view. node-open mints a fresh view-ctl-conversation; node-write parses a mount/unmount command; node-read returns the result. mode #o600 — only the session holder should write it.

Functions

make-view-ctl-node

(make-view-ctl-node &key view)

Construct a view-ctl-node whose :view slot points to VIEW (a view-root). VIEW may be NIL at construction time; node-open guards against a nil view.

Package valis/src/namespace/view-root

Classes

mount-entry

One row in a view-root's mount table. NAME is the leaf name under which NODE is reachable; GRANT-HASH is the SHA-256(canonical-bytes || signature) of the capability grant that produced this entry (nil for base-policy entries created at connect-time, which are unaffected by the revocation eviction sweep); RIGHTS-BITS is the integer bitmask from the grant's mount-directive; BIND-FLAG is :replace, :before, or :after (default :after, per 9Front bind semantics).

view-root

A per-attach 9P root whose children are the mounted grants for one session. Returned by node-attach-root on valis-root; seven binds it as the session's attach fid. Mount-table entries are mount-entry structs.

Generic functions

view-root-mount-table

(view-root-mount-table object)

Undocumented: this exported symbol needs a docstring.

view-root-session-entry

(view-root-session-entry object)

Undocumented: this exported symbol needs a docstring.

Functions

%make-mount-entry

(%make-mount-entry &key ((:name name) "") ((:node node) nil) ((:grant-hash grant-hash) nil) ((:rights-bits rights-bits) 0) ((:bind-flag bind-flag) :after))

Undocumented: this exported symbol needs a docstring.

make-view-root

(make-view-root &key (mount-table (quote nil)))

Construct a view-root carrying MOUNT-TABLE, a list of mount-entry structs. An empty list is valid — the session is admitted but can reach nothing.

mount-entry-bind-flag

(mount-entry-bind-flag instance)

Undocumented: this exported symbol needs a docstring.

mount-entry-grant-hash

(mount-entry-grant-hash instance)

Undocumented: this exported symbol needs a docstring.

mount-entry-name

(mount-entry-name instance)

Undocumented: this exported symbol needs a docstring.

mount-entry-node

(mount-entry-node instance)

Undocumented: this exported symbol needs a docstring.

mount-entry-rights-bits

(mount-entry-rights-bits instance)

Undocumented: this exported symbol needs a docstring.

Variables

*session-activity-fn*

A function of one argument (the view-root) called on each session operation that reaches this view: a walk from the session root, or a listing of it. It stamps the session's last-activity mark and, when the deployment configures an idle bound, empties an over-idle session's view before the operation resolves, so an abandoned session cannot be picked up and used.

Nil means no session bookkeeping, which is the correct state outside a running fabric: a unit test that builds a view-root directly gets today's behavior unchanged. Installed by start-fabric and cleared by stop-fabric, the same downstream-installs-the-hook arrangement the rest of the namespace seams use, and for the same reason: the session registry lives downstream of this file and cannot be imported back into it.