valis / Understanding the system
The DSMR Constellation: Architecture of Record & SDLC Orientation
This is the canonical responsibility map for the whole constellation of repos that make up the DSMR system. It exists so that a change always lands in the right repo and the right layer, and so that a reader (developer or agent) who is unsure where a piece of behaviour belongs has one authoritative place to settle it.
Read this first, before placing any new behaviour. If a change seems to put protocol service logic into the substrate, or sockets into the protocol library, or answer semantics anywhere but the service module, stop. It is against this document, and this document is the architecture of record. (For valis's own internal shape see ARCHITECTURE.org; this file is the layer above that: how the repos divide the world.)
Terms
These terms recur below with exactly these meanings:
- owner
- whoever holds a node's identity (its owner key) and the authority rooted in it. The owner decides what the node serves and delegates capabilities to others.
- operator
- whoever runs a node, by a capability its owner delegates. The owner and the operator may be the same person; where they differ, the operator acts only within what the owner delegated.
- served set
- the ports a node's owner has chosen for the node to serve. It is owner configuration held in valis, and a change to it takes effect without a restart. By default it is 53 (DNS) and 80 (the node's manual), and the owner can remove either, so a node may serve other ports only, or none at all.
- admitted set
- the ports valis asks fulcrum's default-deny firewall to accept from the public network: the served set, as fulcrum last applied it. valis sends fulcrum the served set at start and on every change, and fulcrum's firewall accepts exactly that set, so the two differ only while a change is being applied or after fulcrum has failed to apply one. The firewall also accepts the edge and owner ports that fulcrum's launch configuration opens; those are not in the admitted set.
- launch port list
- the ports fulcrum's launch configuration names (its
:designated-portskey) and passes to valis at every start. valis records the list as the served set at the node's first boot, records the default served set when the list is empty, and ignores the list at every later boot. fulcrum binds the:53UDP and TCP sockets at start only when 53 is in the list, and hands them to valis. The list and the served set are separate, so after first boot they can differ: valis serves DNS on sockets handed down this way only while 53 is in the served set, and closes them as it boots when 53 is not. - the director
- fulcrum's eBPF
sk_lookupprogram. It funnels every inbound TCP connection in the node's network namespace, loopback included, into valis's single listening socket, whatever the port, so each connection is handed to valis in valis's own execution context; fulcrum accepts none of those connections itself. Connections to the TCP ports fulcrum binds for valis (:53, the edge port, and the owner port) are funnelled too while the director is attached, and valis routes each by the port the client dialled. The public network reaches only the ports in the admitted set and the edge and owner ports fulcrum's launch configuration opens. The funnel carries TCP only. The kernel runs the director for UDP lookups as well, and a UDP datagram is expected to fall through to the kernel's own socket lookup; that is reasoned, not measured (see ARCHITECTURE.org). UDP needs a socket of its own in any case, because a UDP reply must leave from the socket the client addressed. UDP:53is the one exception to the rule that every connection arrives on the single listening socket: fulcrum binds a UDP socket for it and passes that socket to valis. A protocol that needs a socket of its own would be a further exception to that rule. - control connection
- the local socket valis opens to fulcrum at start and holds
while valis runs, separate from the enrolment intake (see fulcrum, below). The 9P
session valis runs over it is the control session. valis sends its listening
descriptor and the served set over it, and fulcrum sends back a descriptor valis
requests while running (today, the UDP
:53socket).
The one-sentence shape
fulcrum, the privileged host agent, uses its director to funnel every inbound TCP
connection in the node's network namespace, loopback included, into valis, the
userland Lisp machine that holds the owner's data, the object-capability system, and
every process not delegated to a sister. UDP :53, which the funnel does not carry,
arrives on a socket fulcrum binds and passes to valis. valis multiplexes each connection
to a registered service module; each module speaks its protocol through a shared
protocol-definition library and answers from valis's data. No layer reaches across
another's responsibility.
The actors
| Actor | One responsibility | Repo |
|---|---|---|
| fulcrum | Privileged host-agent. Runs the director, its eBPF sk_lookup program, and accepts none of the connections the director funnels - valis accepts each on its own socket, which is what makes sk_lookup a selection rather than a proxy. valis sends fulcrum the listening descriptor it owns, once, over SCM_RIGHTS; once the sockmap carries it the kernel selects valis's socket directly and fulcrum is off the data path. Separately it does bind :53 UDP+TCP when 53 is in the launch port list, the edge port when its launch configuration names one (:443 on a public node), and optionally the owner port, inside the namespace before the privilege drop, and valis inherits those descriptors at start - socket activation, whose descriptors travel the opposite way from the listening descriptor valis sends for the director. While the director is attached, connections to those TCP ports are funnelled like every other TCP connection, so only the UDP :53 socket serves on its own. When 53 is in the served set and valis holds no UDP socket for it, at boot or after a change, fulcrum binds one at valis's request and passes the descriptor to valis over the control connection. Also owns the default-deny ruleset that is the real public-surface control (the director widens, the firewall narrows), the namespace and public interface, and the privilege drop. Owns privileged inbound transport, and (at the same host boundary) the host-local enrolment intake: a root-only, AF_LOCAL, never-network-reachable channel that delivers owner-equivalent enrolment material up to valis, mirroring the inherited-descriptor handoff. It stamps that material with an un-forgeable host-local provenance and owns only that channel: no auth-mint policy. |
fulcrum |
| Whistler | Compiles the director, fulcrum's eBPF sk_lookup program, from Lisp. Produces what fulcrum runs. |
Whistler |
| valis | The heart of the Lisp machine being reified, and the default home for every process not delegated to a sister below. Owns the object-capability (OCAP) system; manages all of the owner's data (the ndb - zones, identity, operator-state - is one axis of it); and multiplexes that data to the network service modules (the service-module registry + connection dispatch, over a capability-gated 9P namespace). Governs access and holds data and capabilities; holds no protocol service logic. Is the fail-closed dispatcher of the :53 descriptors fulcrum hands it (inherited at start, or sent over the control connection while valis runs) into the serving path, and sends its own listening descriptor to fulcrum over SCM_RIGHTS for the director, and owns the transfer-peer allowlist as capability-mediated operator-state together with the transfer authorizer that gates who may pull a zone. |
valis |
| service modules | One per protocol service. Each owns the transport for its connections (inbound fd dispatched by valis, which either received it from fulcrum (inherited at start, or sent over the control connection while running) or owns the single listening socket the director funnels into; outbound via valis's dial seam), drives c3po's codec client over that transport, and implements the service logic of its protocol. Registered into valis. | per protocol |
| runciter | The DNS service module, the logical nameserver. The canonical example of a service module. Owns nameserver answer logic (authority, RFC 2308 negatives, CNAME chase, wildcard synthesis), resolver policy, BIND zone-file parsing, the DNS resource-record/rdata model, and the in-memory serving index it builds from valis's data and keeps current by pull. Also serves zone transfer (emitting a zone only after authorizing the requesting peer, and sending NOTIFY when the serial advances) and drives outbound resolution over an authenticated TLS stream (DNS-over-TLS). Reads zone data from valis's ndb; speaks the wire through c3po's codec. ⚠ Every one of those outbound paths (the transfer pull, the NOTIFY it sends, the resolution it drives) originates through valis's dial seam: runciter composes and signs, valis carries the bytes. It opens no socket and binds no source address (rule 3). | runciter |
| c3po | Protocol definitions + transport-agnostic codec clients. Encode/decode/framing for DNS, HTTP, SMTP, Gopher, … over an injected stream. The DNS codec now also frames zone transfer (AXFR/NOTIFY) and the DNS-over-TLS wire, still reading and writing an injected stream and still owning no socket. Never binds or owns a socket, never serves a port, never holds service logic or answer semantics. The library every service module speaks through. Also homes the multiformats leaf, the generic base-N codec layer (base58 / unsigned-varint / multicodec-prefixing), a standalone package with no protocol-module or iolib dependency, that higher marshalling layers build on. |
c3po |
| hekate | Crypto-free marshalling, the Plan 9 libauthsrv analog. Owns the structure↔bytes wire codecs for identity and capability: the did:key codec, the capability-token wire codec (a single token, and the token chain a publisher's module vouch travels as), the capability-name wire codec, the codec for a publisher's signed revocation list, and the node-pins codec and store. The store is hekate's one file layer: the client file valis and ubik share, recording which node identity the owner expects at each name. The signed codecs lay out canonical bytes alongside an opaque signature they never compute: mercer signs, valis verifies and attenuates, ubik decodes. Depends on the c3po multiformats leaf for the base58/varint mechanics; touches no crypto and no socket, and never reaches into valis internals. A pure library, and its own repo only because it earns it: ≥2 modules already link it. |
hekate |
| mercer | The factotum / credential authority. Holds the credentials a node's services use (the publisher's subordinate signing key among them) but not the node's own seed: valis custody holds that seed as the owner's key, holds the X25519 transport key derived from it, and derives the publisher's creating identity from it on each use. Owns the transport cipher and per-session sealing; certificate custody and ACME lifecycle. Supplies the authenticated TLS transport (the DNS-over-TLS stream a resolver rides, fail-closed on any certificate-verification failure) and holds the TSIG (HMAC-SHA256) transfer-authentication keys, signing and verifying the digest that gates zone transfer and NOTIFY. | mercer |
| seven | The 9P2000 library, the fabric and bus transport valis's namespace is served over. | seven |
| ubik | The owner-facing viewer, a CLIM application (McCLIM over the clim-clog backend) that mounts valis's owner-proven management view as a 9P client and renders each namespace axis (/pub /id /cap /edge /bus) as live, operable presentations: mint/attenuate/delegate/revoke a capability, publish an item, watch the edge, retire a key and show the host command that enrols one, and manage the node's configuration, served set, restart, and certificates through typed panels. It attaches with a device key of its own, never the node's own key. A client, never in the serving path; it holds no authority the owner's key did not grant, names only what its session mounts, and drives the substrate solely through the same ctl / verify file operations every module uses. Depends on seven, mercer + hekate, never on valis internals. |
ubik |
| clim-clog | The McCLIM backend ubik draws through. It renders a CLIM application's panes to an HTML5 canvas in a web browser over a CLOG websocket and carries pointer and keyboard input back. It runs inside ubik's process, so the browser connection it serves belongs to ubik and never to a node, and it contains no 9P, capability, or namespace code. Our fork of a third-party upstream (parenworks), kept under the BSD-3-Clause licence it came with. |
clim-clog |
| dsmr | The private Quicklisp distribution manager. Pins the constellation's whole dependency closure to exact commits in local checkouts and generates a valid Quicklisp dist from them: a tarball per release plus the distinfo / releases.txt / systems.txt indexes, read back and structurally validated before anything is served. The indexes come from walking the real ASDF graph out of the delivery roots, so package-inferred sub-systems map to their releases and the dist carries what a delivered image needs to run and what a test harness needs to run a suite against it. A subscriber installs by pointing a Quicklisp client at one stable pointer, which publish rewrites as it replaces the serving host's docroot with the validated tree; publication is fail-closed on the audit, refusing a tree whose verdict is missing, damaged, failing, or recorded for a different dist or version. Owns reproducible provisioning and none of the source it ships: trees are pinned, packaged and pin-audited here, never authored or patched here, and the delivery app's own source is walked to build the graph and then withheld, as is any release held back from serving. Holds no protocol logic, no key material, no capability, and sits in no serving path. Names no deployment internally and administers no host: serving host, docroot and dist name come only from a flag, the persisted store or an environment seed. |
dsmr |
| cl-kademlia | The Kademlia distributed hash table: the XOR-metric routing table and the lookup that finds which nodes hold a key in a 256-bit keyspace. Locates a module by its Kademlia key, the SHA-256 of the module's identity (a multihash over its sorted path, size and file-hash entries), which is where IPFS looks for it. Holds no key material (mercer's) and admits nothing (valis's): a lookup says where a module's bytes are, never whether to admit them. Like every sister it opens no socket of its own; its traffic goes through valis's dial seam (rule 3). | cl-kademlia |
| ekphrasis | UI verification, a development tool. You describe a view as Lisp data (its elements, their labels, their order, and their states), and ekphrasis renders a McCLIM pane headlessly and reports each element that is missing, mislabelled, out of order, in the wrong state, or too faint to see. It checks CLIM interfaces in general, and ubik is its first client. It sits in no serving path, no node or ubik build depends on it, and it holds no key or capability. | ekphrasis |
valis is the centre; the sisters are delegations out of it. Everything not named in a row above lives in valis: the rows are responsibilities split off from the Lisp machine (privileged funnelling, protocol definitions, a protocol's service, key custody, the 9P fabric), each because it earns its own boundary. When in doubt about where a non-protocol process belongs, it belongs in valis; a sister is the exception that must justify itself.
ubik is a different kind of member: a consumer, not a delegation. Where fulcrum/runciter/c3po/mercer/seven are responsibilities carved out of the substrate, ubik sits outside and above it, an owner-facing client that only ever sees what the owner's key mounts into its session, exactly as any other 9P viewer would, with no privileged side-channel. Sovereignty is the absence of a name, and ubik does not get to cheat it.
dsmr is a third kind of member: supply, beside the constellation rather than inside it. It is neither a responsibility carved out of the substrate nor a client of it. Nothing it produces serves a request, and it holds no part of the owner's data. What it owns is the constellation's dependency closure - what every repository here is to be built from - which is why its boundary is drawn in terms of what it pins and publishes rather than what it answers. ⚠ Its absence would stop the constellation being reproducible, never stop it running - the opposite failure from every row that answers a request, and the reason it is easy to leave out of a map like this one. ⇒ A change belongs here when it is about pinning or shipping what the other repos are built from, never about what they do: source is authored in the repo that owns it and only packaged here.
clim-clog sits with ubik, on the owner's side of the namespace; ekphrasis is development tooling beside both. Neither is a delegation out of valis. clim-clog is the drawing layer under ubik, a library ubik loads, with no more standing in the substrate than ubik has. ekphrasis checks what a CLIM interface draws against what it should show, and nothing it does reaches a running node. A change belongs in either only when it is about how a CLIM interface is drawn or checked.
The layering
the wire (a TCP or UDP port)
│
┌─────────────────────────────────────┐
│ fulcrum: runs the director (sk_lookup). │ privileged
│ Accepts no funnelled connection. │ (Whistler compiles the program)
│ Binds :53 if the launch port list │
│ names it (UDP :53 also on request); │
│ the edge and owner ports if │
│ configured. │
└─────────────────────────────────────┘
▲ valis's LISTENING fd, once, over SCM_RIGHTS
│ (the :53 socket travels the other way: fulcrum binds it, and valis
│ inherits it at start or receives it while running)
│
│ then the kernel selects valis's socket directly
┌─────────────────────────────────────┐
│ valis - substrate + ndb DATA │ userland
│ • connection dispatch (9P/seven) │
│ • service-module registry + seams │
│ • authoritative zone/operator data │
│ (no serving cache, no answers) │
└─────────────────────────────────────┘
│ dispatch by port/protocol
┌─────────────────────────────────────┐
│ service module (e.g. runciter = DNS) │ the protocol's service
│ • owns this connection's transport │
│ • SERVICE logic (answers, policy) │
│ • in-memory serving index, pull-fed │
│ • reads valis ndb data via a seam │
└─────────────────────────────────────┘
│ encode/decode over an injected stream
┌─────────────────────────────────────┐
│ c3po - protocol definition + codec │ pure wire framing
│ client (no socket, no logic) │
└─────────────────────────────────────┘
mercer (keys/cipher/custody) and seven (9P fabric) are cross-cutting, consumed by valis.
Plan 9 lineage
The split mirrors Plan 9 / 9front, which is the design ground:
- valis = ndb, the network database. It holds the facts (zones, hosts, services, operator state) and answers data questions. It does not interpret a protocol.
- runciter = ndb/dns, the logical nameserver that reads ndb and applies nameserver semantics: authority, negative-answer composition, CNAME, wildcards, resolver policy. It holds the in-memory serving index built from that data; valis keeps no serving cache.
- c3po = the protocol grammar/codec: how a DNS message (or HTTP request, …) is laid out on the wire. Definition, not service.
- fulcrum = the privileged network front: what binds the sockets valis cannot bind itself and funnels every inbound TCP connection in the node's network namespace, loopback included, into userland.
- hekate = libauthsrv, Plan 9's dedicated auth-marshalling library, which lays out the wire form of authentication structures and is linked by factotum rather than embedded in it. hekate is its cleaner descendant: because our capability token is signed, not encrypted, she marshals structure to bytes and never touches crypto at all: every linker composes her instead of hand-copying the formats.
- ubik = acme / rio, the interactive viewer onto the namespace, not a new model of the world. It renders and operates what valis already exposes and holds no authority of its own.
Canonical flows
Inbound: serving DNS on :53
A node serves DNS on :53 only while 53 is in its served set. A new node's served set
holds 53 by default, and the owner can remove 53.
- fulcrum's director funnels a TCP
:53connection into valis's single listening socket; a UDP:53query arrives on the socket fulcrum bound and valis holds. - valis dispatches the query, which arrives as a UDP datagram or over a TCP stream, to the registered DNS service module (runciter).
- runciter drives c3po's DNS codec client over that datagram or stream to decode the query.
- runciter computes the authoritative answer (RFC 2308 NXDOMAIN/NODATA/NOERROR, apex SOA on negatives, CNAME chase, wildcard synthesis) over valis's ndb zone data (read through the data seam valis implements).
- runciter encodes the response through c3po's codec and returns it out through valis.
The nameserver (runciter) is in the serving path. c3po frames bytes; it does not decide answers.
Outbound: resolving a recipient MX
- runciter (resolver policy) obtains mercer's authenticated TLS stream (the
DNS-over-TLS transport) and drives c3po's codec over it; a bare outbound socket via
iolibis the non-TLS fallback. - It drives c3po's DNS codec client over that transport to query upstream.
- It applies resolver policy (MX preference, budget, TTL cache, temperror/permerror) and returns preference-sorted targets, never losing mail on a transient failure.
- A substrate consumer (e.g. valis's
/mailoutbound drain) calls runciter for this; valis itself holds no resolver logic.
Zone transfer: serving a secondary (AXFR/NOTIFY)
Enrolling a secondary (valis zone secondary) mints a TSIG key into mercer custody,
records the (zone, peer, key-name) allowlist row and the also-notify recipient, and
prints the ready-to-paste BIND snippet.
⚠ This section is the shape of the exchange, not evidence that it verifies end to end. It describes which repo authorizes and which emits. The signing itself lives on the far side of the seam, in mercer, and whether a signed response verifies against a real secondary is a property of that crossing rather than of this map. Do not read this section as covering that half. TODO.org records what has actually been driven.
The shape:
- valis dispatches the transfer connection into the serving path, fail-closed, exactly
as it dispatches
:53traffic. - runciter authorizes the requesting peer against valis's capability-mediated transfer-peer allowlist - TSIG-verified through mercer (HMAC-SHA256), and serial-monotonic so a stale serial never replaces a fresh one - emitting the zone only once the peer is authorized.
- runciter emits the zone's records through c3po's transfer framing (AXFR), out through valis.
- On a committed serial advance, runciter NOTIFYs the recipient set so each secondary knows to pull the fresh zone.
Authorization precedes emission: an unauthorized or TSIG-unverified peer is refused before a single record leaves.
Responsibility boundaries (the rules)
- Protocol service logic lives only in the service module. Answer semantics, resolver policy, protocol state machines: runciter for DNS, the HTTP module for HTTP, etc. Never in valis (substrate) and never in c3po (codec).
- Authoritative data lives only in valis (the ndb). Service modules read it through a
seam valis implements (for DNS, runciter authors the
zone-data-sourceread protocol and valis implements it over PostgreSQL). A module never owns the authoritative data. Transport ownership: privileged inbound = fulcrum (port bind + funnel). Everything client-based or outbound originates through valis's dial seam, without exception: a service module composes and interprets, valis carries the bytes. A module opens no socket of its own, binds no source address, and resolves no name on the way out. Where a connection must be authenticated, the (DNS-over-TLS) outbound stream is supplied by mercer over that same seam and the module drives its codec across it. c3po never owns a socket: it operates on an injected stream. valis routes connections but does not interpret their bytes.
This is settled architecture, not a preference, and the reasoning is written up in full in outbound-dial.org. The short form: a capability model with several ways out is decorative. valis is built to run code its operator did not author, so a subsystem that decides for itself how to reach the network is a second door, and hosted code reaching the network however it likes cannot be found by reading the tree at all. The seam's job is not to forbid the shortcut but to leave it nothing to offer.
⚠ The trap is that every step toward a second door is locally reasonable. The founding defect was valis's own notify-the-secondaries path: a socket opened in the file, names resolved with a library already close to hand, and passing tests. On a live node inside a network namespace it could resolve nothing, and it surfaced as a complaint about polling a descriptor, so nothing in the failure said the word "name".
- c3po is definition + transport-agnostic codec client. It frames what the service module hands it and parses what the module reads; it derives no policy and composes no answer. (Where a codec needs the typed data model or grammar - e.g. the DNS resource-record model, rdata text↔typed, name canonicalization - c3po delegates to the owning service module; today c3po's DNS codec calls into runciter for exactly these.)
- Access is gated by valis's OCAP system; keys live only in mercer. valis owns the object-capability system: capability tokens and names mediate every access to the owner's data. The key material that backs identity and the transport cipher live only in mercer. A capability is not a key: valis decides what may be reached, mercer holds what proves who you are. No other repo holds either.
Adding a new protocol service (the pattern)
- Define the protocol in c3po: a codec client (encode/decode/framing) over an injected stream. No sockets, no service logic.
- Build the service module: owns its transport (inbound fd from valis dispatch; outbound
through valis's dial seam, never a socket of its own), drives c3po's codec, implements the
service logic, reads any authoritative data it needs through a valis-implemented seam. The
shape that satisfies this is an injected connector: the module takes a function that opens
the stream and a source address to originate from, and returns a refusal when it is handed
neither. runciter's
transfer-sink.lispandtransfer-notify.lispare the worked examples. - Register the module into valis's service seam so valis dispatches the protocol's connections to it.
- Make it reachable from off-host. The director funnels every inbound TCP connection in
the node's network namespace, loopback included, into valis's single listening socket, so
registration in valis (step 3) is what dispatches the protocol, but the reachable
public surface is bounded separately by fulcrum's default-deny firewall, which accepts
the ports in the admitted set and, beyond those, only the edge and owner ports fulcrum's
launch configuration opens. The firewall's rules are fulcrum's alone and nothing a
module does can reach them, so a module can never widen the ruleset; the membership of
the admitted set follows the served set, which valis sends to fulcrum, and registering a
module adds nothing to it: the protocol becomes reachable when the node's owner adds the
protocol's port to the served set. See
the firewall-ruleset invariant for
which half is whose. A UDP protocol cannot be made reachable by these steps alone. It
needs a socket of its own, because a UDP reply must leave from the socket the client
addressed, and fulcrum binds such a socket only for
:53: at start when 53 is in the launch port list, or at valis's request, a path that accepts 53/udp only.:53is the one exception to the rule that every connection arrives on the single listening socket; another UDP protocol would need an exception of its own, and a change to fulcrum, not an application of this step.
runciter (DNS) is the worked example of all four steps.
Anti-patterns (the landmines)
These are the specific confusions that have actually occurred. Each is a boundary violation above; they are called out because they read as plausible until checked against this map.
- Answer semantics in the substrate. Putting NXDOMAIN/NODATA determination, apex-SOA-on- negatives, CNAME chase, or wildcard synthesis in valis. → It belongs in the service module (runciter). valis holds the zone data, not the DNS answer.
- Answer semantics in the codec. Putting RFC 2308 negative composition or negative-cache TTL policy in c3po's handler. → c3po frames the SOA/TTL the nameserver hands it; it does not reason about authority.
- Binding the service seam to the codec, skipping the module. Wiring valis's service seam directly to c3po (or to a substrate-resident lookup), so the service module (runciter) is not in the serving path. → The registered handler is the service module; it drives the codec.
- Sockets/ports in c3po. Giving c3po a
:53serving loop, UDP/TCP listeners, or a socket- owning resolver client. → Inbound transport is fulcrum's; outbound goes through valis's dial seam; c3po only ever sees an injected stream. - A second door out. Any subsystem opening its own outbound socket, binding its own source address, or resolving a name on the way out, however respectable the library and however local the reasoning. → It originates through valis's dial seam. See rule 3 and outbound-dial.org. ⚠ This one is listed because it is the anti-pattern that is hardest to see: the alternative is always nearer to hand, the tests pass, and the failure appears only on a live node, in language that names something other than the network.
- Resolver/service policy in c3po. MX preference, lookup budget, caching. → The module's.
- Duplicate protocol parsers across layers. One grammar/parser, owned by one layer (the DNS master-file/rdata grammar is runciter's; the wire framing is c3po's; they do not overlap).
- Duplicate marshalling across layers (resolved). The identity and capability wire codecs
(
did:key, the token wire, the bearer-name wire) once lived as a valis copy and a hand-copied client-side decoder that could silently drift apart. They now rest once, in hekate, and every linker composes that one codec over a clean API instead of hand-copying it, so valis and its clients decode the identical bytes because they run the identical code. The base-N mechanics beneath them rest once too, in the c3po multiformats leaf. This is the marshalling case of the one-parser-per-layer rule, and the drift hazard it names is closed. - Reducing valis to "seam + controller" with no data-owner role. valis is the ndb; its authoritative-data ownership is a first-class responsibility, not an afterthought.
SDLC notes: how development honours this map
- Each repo runs its own development lifecycle: discuss, plan, execute, verify. Cross-repo work is coordinated between the repos; merges and tags to a repo's default branch stay operator-gated.
- A seam between two repos is fixed before either side builds against it: versioned and fail-closed (the symmetric idiom used by valis's service-adapter seam and runciter's resolve-over-wire consumer seam). The freeze is the contract; a seam evolves additively, never by breaking a version already in use.
- When unsure where a piece belongs, this document settles it. If it cannot, the boundary is underspecified. Surface it and amend this document rather than drifting past it. This file is amended deliberately, not drifted.
Cross-references
- ARCHITECTURE.org - valis's internal architecture (the layer below this map).
- SEAM-CONTRACTS.org - the versioned interface contract for the cross-repo seams, A through F: runciter↔c3po, c3po↔mercer, the valis↔mercer server-TLS termination, valis↔ACME zone-write, consumer↔hekate marshalling, consumer↔c3po multiformats, and the valis outbound connector the sisters dial through.
- deployment/host-deployment-contract.org - how a valis node comes up on a real host: the fulcrum-privileged (below) → valis-condense (above) bring-up, framed as deploy == condense-from-genesis. The privileged substrate is fulcrum's; the condense that stands the node up is valis's.
- proving-ground/ - the migration-thesis regression harness (deploy / evacuate / restore over one mechanism) that validates that bring-up against a two-location Debian topology.
- TODO.org - where valis stands and the delivery order.
- The sister repos carry this same map in their own
docs/per the shared documentation pattern.