mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
1229 lines
37 KiB
Markdown
1229 lines
37 KiB
Markdown
# Embedded Node Surface Specification
|
|
|
|
**Version:** 0.1
|
|
**Status:** Draft for reusable deployment
|
|
**Target nodes:** Racknerd, Netcup, Architect, Hutter, local edge nodes
|
|
**Protocol reference:** `docs/specs/OMNITOKEN_GCL_REDESIGN.md`
|
|
**GCL revision reference:** `docs/specs/GCL_TOPOLOGY_REVISION_SPEC.md`
|
|
**Principle:** A node is a small observer chart, not a full general-purpose stack.
|
|
The kernel contract is a GCL nanokernel; Linux is only one possible carrier.
|
|
|
|
---
|
|
|
|
## Purpose
|
|
|
|
This spec defines a reusable embedded surface for low-resource nodes. The node
|
|
keeps only the local machinery required to join the atlas, expose a minimal API,
|
|
recover itself, and mount external state. Bulk data, datasets, archives, and
|
|
large working sets are provided by Google Drive topological storage through an
|
|
ENE-managed mount.
|
|
|
|
The surface does not require Linux as its conceptual kernel. The portable
|
|
kernel contract is the GCL nanokernel: the smallest executable transition unit
|
|
that admits work, routes state, checks recovery transitions, emits receipts, and
|
|
exposes the node as an observer chart. Linux, LFS, NixOS, unikernels,
|
|
bare-metal firmware, or a VM monitor may host that contract, but they are
|
|
substrate choices rather than the mathematical center.
|
|
|
|
The intended result is a small, repeatable node shape:
|
|
|
|
```text
|
|
GCL nanokernel + read-only carrier + tiny writable state + compressed API + recovery
|
|
```
|
|
|
|
This avoids deploying the full Research Stack onto nodes that are better used as
|
|
lightweight coordinate charts. RackNerd is the first `GCL-Edge`: a constrained
|
|
edge node whose primary job is to host the GCL nanokernel, expose recovery and
|
|
health, and carry topology phases without running the full research stack.
|
|
Operationally, RackNerd is an appliance server: it has a narrow managed surface,
|
|
bounded local state, explicit update channels, and no expectation that operators
|
|
log in to run arbitrary workloads.
|
|
|
|
Builder, Warden, and Judge behavior are not deployed as separate software
|
|
layers. They are topology phases carried by the general node surface:
|
|
|
|
1. Builder is the topology's constructive/forward phase.
|
|
2. Warden is the topology's inhibitory/verification phase.
|
|
3. Judge is the topology's adjudication/settlement phase.
|
|
|
|
Historical builder, warden, and judge state, receipts, and validation routines
|
|
are topology artifacts. A node may expose these phases through topology
|
|
capabilities, but there is no standalone Builder, Warden, or Judge runtime
|
|
boundary in the embedded profile.
|
|
|
|
---
|
|
|
|
## Design Constraints
|
|
|
|
Every conforming node MUST:
|
|
|
|
1. Preserve SSH or recovery console access during upgrades.
|
|
2. Boot without Google Drive being available.
|
|
3. Treat the GDrive mount as optional external state, never as the root of trust.
|
|
4. Expose a plain recovery health endpoint even if the compressed API fails.
|
|
5. Keep writable local state small, explicit, and backed up.
|
|
6. Admit work through RGFlow/compression policy before local execution.
|
|
7. Support atomic image or service rollback.
|
|
|
|
Every conforming node SHOULD:
|
|
|
|
1. Use a compressed read-only root or read-only service bundle.
|
|
2. Use tmpfs for transient logs and scratch.
|
|
3. Store persistent node identity under a single state directory.
|
|
4. Keep large data in mounted topological storage.
|
|
5. Prefer push/pull artifacts over building locally.
|
|
|
|
---
|
|
|
|
## Appliance Server Model
|
|
|
|
An appliance server is a node operated as a sealed function rather than as a
|
|
general-purpose host. The RackNerd `GCL-Edge` appliance exposes only the surface
|
|
needed to join the atlas, emit receipts, answer health/status probes, carry
|
|
topology phases, and recover itself.
|
|
|
|
Appliance invariants:
|
|
|
|
1. The primary runtime is `rs-surface-api.service`.
|
|
2. Builder, Warden, and Judge are topology phases inside the surface.
|
|
3. Legacy full-stack services remain masked unless a rescue procedure explicitly
|
|
says otherwise.
|
|
4. Local mutation is restricted to `/var/lib/rs-surface`, bounded spools,
|
|
rollback slots, and explicit topology artifacts.
|
|
5. Software changes enter through in-place nanokernel updates, A/B release
|
|
updates, or provider rescue pivots.
|
|
6. The node is not a build worker, dataset host, database server, or ad hoc
|
|
shell box.
|
|
|
|
The appliance may still use Debian, systemd, SSH, and Tailscale as carrier
|
|
facilities. Those facilities serve the appliance contract; they do not redefine
|
|
the node as a general VM.
|
|
|
|
---
|
|
|
|
## Surface Layers
|
|
|
|
```text
|
|
+------------------------------------------------------------+
|
|
| Atlas clients / controller |
|
|
+------------------------------------------------------------+
|
|
| Compressed WebSocket API + plain /health fallback |
|
|
+------------------------------------------------------------+
|
|
| Admission layer: RGFlow, compression policy, attestation |
|
|
+------------------------------------------------------------+
|
|
| MNN routing: adaptive path formation (local/atlas/reject) |
|
|
+------------------------------------------------------------+
|
|
| Topology phases: builder, warden, judge |
|
|
+------------------------------------------------------------+
|
|
| Local actions: route, attest, compress, status, recovery |
|
|
+------------------------------------------------------------+
|
|
| State: /var/lib/rs-surface + optional GDrive mount |
|
|
+------------------------------------------------------------+
|
|
| Carrier: Linux, LFS, Nix, unikernel, firmware, VM monitor |
|
|
+------------------------------------------------------------+
|
|
```
|
|
|
|
The MNN (Morphic Neural Network) routing layer sits between admission and local actions. It uses:
|
|
- Goal-aware routing (health, attest, compress, route, recover)
|
|
- State-constrained decisions (memory, CPU, recovery mode, trust score)
|
|
- Carrier-agnostic adaptation (works with any shell)
|
|
- Cost-aware optimization (energy, time, bandwidth)
|
|
- Historical learning (adaptive morphic topology)
|
|
|
|
See `docs/specs/MORPHIC_NEURAL_NETWORK_ROUTING_SPEC.md` for the complete MNN specification.
|
|
|
|
The surface is intentionally carrier-agnostic. Debian can host it first; later
|
|
nodes may boot directly into an embedded image or a GCL-native runtime. The
|
|
important object is the topological substrate: the set of admitted primitives
|
|
that the GCL nanokernel can expose safely on a given carrier.
|
|
|
|
### Topological Substrate Primitive Exposure
|
|
|
|
A node does not need KVM to become a topological device. KVM, QEMU, Linux
|
|
processes, unikernels, firmware loops, and serial controllers are all carriers.
|
|
The GCL nanokernel is responsible for exposing the primitive vocabulary that
|
|
matters to the atlas.
|
|
|
|
Every appliance SHOULD expose a primitive descriptor:
|
|
|
|
```text
|
|
GET /primitives
|
|
WS op 10: primitives
|
|
```
|
|
|
|
The descriptor names:
|
|
|
|
1. The substrate class.
|
|
2. The carrier used to host the substrate.
|
|
3. Whether primitives are exposed through the kernel surface.
|
|
4. Compute slots and memory reserve.
|
|
5. Primitive names, such as `attest`, `compress`, `rgflow`, `route`,
|
|
`plan_route`, `vector_filter`, `delta_batch`, `merkle_mmr`,
|
|
`content_chunk`, `wiki`, `fractal_fold`, `meta_autotype`, and `receipt`.
|
|
6. Optional accelerators, such as AVX-512, BF16, VNNI, VAES, VPCLMULQDQ, or
|
|
SHA-NI.
|
|
|
|
The primitive descriptor is descriptive, not a permission grant. Admission,
|
|
topology phases, and receipt checks still decide whether a requested transition
|
|
is lawful.
|
|
|
|
### Nanokernel Route Planning Primitive
|
|
|
|
The nanokernel route planner is a bounded pre-admission selector:
|
|
|
|
```text
|
|
WS op 11: plan_route
|
|
```
|
|
|
|
It applies:
|
|
|
|
```text
|
|
payload
|
|
-> metaprobe payload signature
|
|
-> MS3C/S3C shell codon
|
|
-> sequence/GCL motif/informaton surface selection
|
|
-> RGFlow persistence check
|
|
-> compression route tuple
|
|
```
|
|
|
|
The returned tuple has:
|
|
|
|
```text
|
|
surface
|
|
motif
|
|
witness
|
|
compressor
|
|
```
|
|
|
|
This tuple is not execution authority. It is a route-prior hint consumed by
|
|
GCL admission. The required gate remains:
|
|
|
|
```text
|
|
OBSERVE -> BIND -> ROUTE -> SIGMA_CHECK -> POLICY_CHECK -> DAG_CHECK -> VERIFY -> RECEIPT
|
|
```
|
|
|
|
If FAMM marks the shell region as saturated failure, the planner SHOULD downrank
|
|
or refuse similar route teeth before local execution.
|
|
|
|
The typed Lean vocabulary for this contract lives in:
|
|
|
|
```text
|
|
0-Core-Formalism/lean/Semantics/Semantics/GCLTopologyRevision.lean
|
|
```
|
|
|
|
That module fixes the distinction between route hints and authority: a
|
|
`RouteHint` cannot directly authorize execution, even if it comes from MS3C,
|
|
metaprobe, RGFlow, Sparkle, or a node primitive.
|
|
|
|
### ENE Wiki Primitive
|
|
|
|
The ENE wiki primitive is a MediaWiki-like knowledge surface without a full
|
|
MediaWiki runtime:
|
|
|
|
```text
|
|
WS op 12: wiki
|
|
```
|
|
|
|
It supports compact JSON requests:
|
|
|
|
```json
|
|
{"op":"put","title":"GCL","text":"See [[MS3C]] [[Category:Topology]]"}
|
|
{"op":"get","title":"GCL"}
|
|
{"op":"search","query":"topology"}
|
|
{"op":"backlinks","title":"MS3C"}
|
|
{"op":"recent","limit":20}
|
|
```
|
|
|
|
The implementation is `infra/ene_wiki_layer.py`. It stores revision history,
|
|
links, categories, backlinks, and recent changes in SQLite. Every write emits:
|
|
|
|
1. an ENE `BaseArchiveRecord`-style object using `source_type=json_catalog`;
|
|
2. a Unified JSON-L event using `src=ene` and `op=upsert`;
|
|
3. a deterministic receipt hash;
|
|
4. a schema-compatible `packages` upsert.
|
|
|
|
This keeps the wiki layer inside the ENE substrate instead of creating a
|
|
separate application authority.
|
|
|
|
### ENE Fractal Fold Primitive
|
|
|
|
The fractal fold primitive is the canonical ENE surface for self-similar
|
|
recursive storage and retrieval:
|
|
|
|
```text
|
|
WS op 13: fractal_fold
|
|
```
|
|
|
|
It supports compact JSON requests:
|
|
|
|
```json
|
|
{"op":"put","name":"payload","text":"...","chunk_size":4096,"branching_factor":4}
|
|
{"op":"put_graphml","name":"research_graph","data_b64":"..."}
|
|
{"op":"navigate","root_hash":"...","leaf_index":31}
|
|
{"op":"proof","root_hash":"...","leaf_index":31}
|
|
{"op":"verify","root_hash":"..."}
|
|
{"op":"graph_entity","root_hash":"...","graph_node_id":"n31"}
|
|
{"op":"graph_neighbors","root_hash":"...","graph_node_id":"n31"}
|
|
```
|
|
|
|
The implementation is `infra/ene_fractal_fold.py`. It stores a recursive hash
|
|
tree in SQLite. Leaves use Gray-code folded addresses; navigation projects
|
|
folded addresses onto a golden-spiral chart and descends by manifold-distance
|
|
pruning. With fixed branching factor, entity retrieval is `O(log n)` in the
|
|
number of leaves. Damage is detectable because leaves and parents are checked
|
|
through fractal parent/child hash consistency.
|
|
|
|
GraphML is treated as a concept surface. Each GraphML node becomes one fractal
|
|
leaf carrying `graph_node_id`, `name`, `family`, `domain`, folded address,
|
|
golden-spiral coordinate, and outgoing neighbors. This lets ENE retrieve graph
|
|
concepts by the same fractal path used for raw payload chunks.
|
|
|
|
### ENE Meta-Autotype Primitive
|
|
|
|
The meta-autotype primitive handles unknown or fragmented ingestion surfaces:
|
|
|
|
```text
|
|
WS op 14: meta_autotype
|
|
```
|
|
|
|
It supports:
|
|
|
|
```json
|
|
{"name":"unknown_payload","text":"..."}
|
|
{"name":"unknown_payload","data_b64":"..."}
|
|
```
|
|
|
|
The implementation is `infra/ene_meta_autotype.py`. It deterministically emits
|
|
contingent fields with inferred type, confidence, extraction rule, bind class,
|
|
and receipt. These fields are not authority; they are provisional topology
|
|
until a defined ingestion surface binds them through the normal GCL gate.
|
|
|
|
### Bind Policy
|
|
|
|
The profile's `api.bind` field is normative:
|
|
|
|
| `api.bind` | Runtime bind host |
|
|
|------------|-------------------|
|
|
| `localhost` | `127.0.0.1` |
|
|
| `tailscale` | `api.tailscale_ip` or top-level `tailscale_ip` |
|
|
| `public` | `0.0.0.0` |
|
|
|
|
`RS_SURFACE_HOST` may override this during smoke tests, but production units
|
|
SHOULD omit it so the profile controls exposure. If `api.bind` is `tailscale`
|
|
and no Tailscale IP is present, the surface MUST fail closed rather than bind
|
|
publicly.
|
|
|
|
### KVM Carrier Addressing
|
|
|
|
Most deployment nodes are themselves virtual machines, so KVM must be treated as
|
|
an optional nested carrier rather than assumed bare metal. A node with no KVM
|
|
can still be a first-class topological substrate by exposing primitives directly
|
|
through the GCL nanokernel.
|
|
|
|
KVM addressing has three separate layers:
|
|
|
|
```text
|
|
host virtual pointer -> KVM memslot -> guest physical address -> guest CS:RIP
|
|
```
|
|
|
|
The guest physical address is not host physical memory. It is an address in a
|
|
userspace-owned memslot registered with `KVM_SET_USER_MEMORY_REGION`.
|
|
|
|
Minimal KVM surfaces MUST record:
|
|
|
|
1. Whether `/dev/kvm` exists and is openable.
|
|
2. Whether `KVM_CREATE_VM`, `KVM_CREATE_VCPU`, and `KVM_RUN` succeed.
|
|
3. The memslot number.
|
|
4. The guest physical base.
|
|
5. The guest entry address.
|
|
6. The I/O or MMIO pulse channel used for recovery output.
|
|
|
|
Carrier classification:
|
|
|
|
| Class | Meaning | Required behavior |
|
|
|-------|---------|-------------------|
|
|
| `kvm_native` | Hardware virtualization is directly available | Run KVM carrier |
|
|
| `kvm_nested` | KVM works inside a VM | Run KVM carrier with slower-exit budget |
|
|
| `kvm_unavailable` | `/dev/kvm` missing or denied | Fall back to QEMU TCG or hosted process |
|
|
| `kvm_restricted` | VM starts but required exits fail | Refuse or quarantine carrier |
|
|
|
|
KVM MUST NOT become the root of trust. It is only a carrier for admitted GCL
|
|
state. If KVM is unavailable, the node should expose the recovery surface and
|
|
topological primitives through another carrier.
|
|
|
|
---
|
|
|
|
## GCL Nanokernel Contract
|
|
|
|
GCL is the nanokernel of a node: the smallest trusted control surface that can
|
|
perform a bounded transition and produce a receipt. It is not required to be the
|
|
hardware kernel in the Unix sense. It is the invariant-preserving layer that
|
|
decides what the carrier is allowed to do.
|
|
|
|
Local repo usage treats a nanokernel as:
|
|
|
|
1. A tiny executable unit.
|
|
2. Local state.
|
|
3. Message passing.
|
|
4. Bounded transition.
|
|
5. Receipt.
|
|
|
|
For morphic topology, the nanokernel also assigns candidate niches for morphic
|
|
scalars. Assignment is a measurement hypothesis, not final permission; the
|
|
topology phases and AngrySphinx-style checks still decide whether collapse is
|
|
admissible.
|
|
|
|
GCL MUST provide:
|
|
|
|
1. Node identity and local observer-frame metadata.
|
|
2. Admission control for requested operations.
|
|
3. RGFlow/compression policy hooks.
|
|
4. Route selection or local execution refusal.
|
|
5. Attestation of state transitions.
|
|
6. Recovery transition checks.
|
|
7. A plain health signal independent of the compressed API.
|
|
|
|
GCL SHOULD be small enough to port across carriers. A Linux-hosted daemon, an
|
|
initramfs recovery binary, a unikernel service, a microcontroller firmware, or a
|
|
tiny VM monitor shim can all be valid GCL nanokernel carriers if they satisfy
|
|
the same contract.
|
|
|
|
The carrier MAY provide:
|
|
|
|
1. Process isolation.
|
|
2. Filesystems and mounts.
|
|
3. TCP/IP, WireGuard, Tailscale, or serial transport.
|
|
4. Timers and watchdogs.
|
|
5. Hardware drivers.
|
|
|
|
The carrier MUST NOT be the root of trust for atlas decisions. Those decisions
|
|
belong to GCL.
|
|
|
|
---
|
|
|
|
## Layer 0 Handoff Target
|
|
|
|
The long-term target is for the GCL nanokernel to become Layer 0: the first
|
|
meaningful runtime after firmware/provider boot. In that mode, Linux is no
|
|
longer the node's operating environment. Linux is only a bootstrap loader,
|
|
hardware discovery tool, artifact fetcher, and emergency recovery substrate.
|
|
|
|
The intended destructive handoff is:
|
|
|
|
```text
|
|
provider firmware / VPS boot
|
|
-> minimal Linux loader
|
|
-> verify signed Layer 0 image + last-good receipt
|
|
-> kexec handoff
|
|
-> GCL nanokernel Layer 0
|
|
-> topology primitives, receipts, recovery pulse
|
|
```
|
|
|
|
After handoff, the current Linux userspace may be intentionally discarded. That
|
|
is the point: legacy services, model routers, ad hoc shell state, package
|
|
sprawl, and ordinary daemon assumptions should not survive into Layer 0.
|
|
|
|
### Kexec Role
|
|
|
|
`kexec` is the preferred bridge when the provider requires a normal Linux boot
|
|
but the node wants to replace Linux without a full firmware reboot. The loader
|
|
kernel prepares memory, validates the Layer 0 artifact, then transfers control
|
|
to the GCL image.
|
|
|
|
The Layer 0 image may initially be a tiny Linux/initramfs appliance, unikernel,
|
|
or purpose-built kernel. What matters is not the implementation label; what
|
|
matters is that the GCL nanokernel owns the primitive boundary and emits
|
|
receipts before admitting work.
|
|
|
|
### Layer 0 Gates
|
|
|
|
A node MUST NOT perform a destructive handoff until all gates pass:
|
|
|
|
1. Provider rescue console or reinstall path is confirmed.
|
|
2. A rollback boot entry or previous working image exists.
|
|
3. The Layer 0 image is signed or hash-pinned.
|
|
4. The loader can emit a pre-handoff receipt.
|
|
5. The Layer 0 image can emit a console, serial, or provider-visible health
|
|
pulse without Tailscale.
|
|
6. The Layer 0 image can answer `/health` or the Omnitoken recovery equivalent.
|
|
7. Node identity and topology artifacts are preserved or intentionally sealed.
|
|
8. The operator has an out-of-band recovery window.
|
|
|
|
Until those gates exist, `destructive_handoff_allowed` MUST remain `false` in
|
|
node profiles. Hosted `rs-surface-api.service` remains the safe Phase 0
|
|
appliance.
|
|
|
|
Profiles SHOULD make the handoff mechanically checkable by declaring:
|
|
|
|
```json
|
|
{
|
|
"layer0_image": {
|
|
"path": "/boot/gcl/layer0-netcup.img",
|
|
"sha256": "TBD",
|
|
"signature": "/boot/gcl/layer0-netcup.img.sig",
|
|
"public_key": "/etc/rs-surface/layer0.pub",
|
|
"cmdline": "console=ttyS0 gcl.node=netcup-router gcl.mode=layer0"
|
|
},
|
|
"rollback": {
|
|
"boot_entry": "debian-loader-last-good",
|
|
"previous_image": "/boot/gcl/layer0-netcup.previous.img",
|
|
"provider_rescue": "netcup-rescue-console"
|
|
}
|
|
}
|
|
```
|
|
|
|
`sha256: "TBD"` is valid only while `destructive_handoff_allowed` is `false`.
|
|
Before enabling destructive handoff, the image digest and signature path MUST
|
|
refer to real artifacts.
|
|
|
|
### Preservation Set
|
|
|
|
Even when the Linux userspace is wiped, these concepts survive the handoff:
|
|
|
|
1. Node identity.
|
|
2. Last-good receipt.
|
|
3. Recovery pulse.
|
|
4. Topology artifacts such as `judge.tardy`, MMR roots, and node profile.
|
|
5. Primitive descriptor.
|
|
6. Provider recovery instructions.
|
|
|
|
Everything else is disposable unless the profile explicitly preserves it.
|
|
|
|
---
|
|
|
|
## JupiterBox and Omnitoken Carrier
|
|
|
|
For constrained nodes, the preferred GCL carrier envelope is JupiterBox and the
|
|
preferred wire/codon layer is Omnitoken.
|
|
|
|
JupiterBox provides the box boundary:
|
|
|
|
1. A bounded execution envelope.
|
|
2. A small routing identity.
|
|
3. A multiplexing slot for swarm traffic.
|
|
4. A place to attach recovery and last-good metadata.
|
|
5. A carrier abstraction that can run over Linux, serial, Tailscale, I2P, or a
|
|
future non-Linux substrate.
|
|
|
|
Omnitoken provides the packet language:
|
|
|
|
1. Finite operation names instead of open strings.
|
|
2. Small typed fields for value, timestamp, tags, and checksum.
|
|
3. Fragmentation/reassembly for larger payloads.
|
|
4. A bridge into existing swarm transport and MIMO routing.
|
|
5. A natural path to codon compression on tiny RAM targets.
|
|
|
|
The normal embedded surface can expose WebSocket for compatibility, but the
|
|
inner frame SHOULD be Omnitoken-compatible:
|
|
|
|
```text
|
|
carrier transport
|
|
-> JupiterBox envelope
|
|
-> Omnitoken/GCL frame
|
|
-> operation payload
|
|
```
|
|
|
|
On large carriers, the stack may be:
|
|
|
|
```text
|
|
WebSocket or Tailscale TCP -> JupiterBox -> Omnitoken -> GCL op
|
|
```
|
|
|
|
On tiny carriers, the stack may collapse to:
|
|
|
|
```text
|
|
serial frame -> Omnitoken codon -> GCL op
|
|
```
|
|
|
|
Or, on an IBM-II-class software Ethernet surface:
|
|
|
|
```text
|
|
Ethernet-looking shell -> 2-byte Omnitoken scalar/LUT selector -> GCL op
|
|
```
|
|
|
|
The Ethernet controller does not need to implement IP. It only validates the
|
|
local shell boundary, extracts the invariant `(domain, scalar)` pair, and lets
|
|
GCL decide admission.
|
|
|
|
This is how the same node surface can scale from Racknerd down toward an 8 KB
|
|
RAM target. The carrier changes; the GCL operation vocabulary does not.
|
|
|
|
### 8 KB RAM Shape
|
|
|
|
At the smallest target, JupiterBox is not a container in the Linux sense. It is a
|
|
fixed memory envelope:
|
|
|
|
```text
|
|
RX frame 512 B
|
|
TX frame 512 B
|
|
GCL registers 512 B
|
|
route table 1 KB
|
|
compression 1 KB
|
|
recovery log 1 KB
|
|
stack 512 B
|
|
free margin 3 KB
|
|
```
|
|
|
|
The tiny target MUST NOT require JSON, HTTP, WebSocket, TLS, malloc, a
|
|
filesystem, or dynamic loading. It only needs enough Omnitoken/GCL vocabulary to
|
|
say:
|
|
|
|
```text
|
|
health
|
|
status
|
|
attest
|
|
rgflow-admit
|
|
compress
|
|
route
|
|
snapshot
|
|
recover
|
|
```
|
|
|
|
---
|
|
|
|
## Filesystem Contract
|
|
|
|
### Required Local Paths
|
|
|
|
| Path | Mode | Purpose |
|
|
|------|------|---------|
|
|
| `/opt/rs-surface` | read-only preferred | Surface daemon, static assets, API schema |
|
|
| `/etc/rs-surface/node.json` | read-only or managed | Node identity and role profile |
|
|
| `/var/lib/rs-surface` | persistent writable | Identity, tokens, last-good marker, tiny state |
|
|
| `/var/log/rs-surface` | tmpfs or capped persistent | Ring logs and boot reports |
|
|
| `/run/rs-surface` | tmpfs | Sockets, pid files, ephemeral cache |
|
|
| `/mnt/topological-storage` | optional mount | GDrive/rclone topological storage |
|
|
|
|
### Required Persistent State
|
|
|
|
```text
|
|
/var/lib/rs-surface/
|
|
node-id
|
|
authorized_keys
|
|
api-token.hash
|
|
ed25519-node.key
|
|
last-good.json
|
|
boot-count
|
|
state.sqlite optional, small
|
|
recovery/
|
|
last-failure.log
|
|
rollback-target
|
|
```
|
|
|
|
Persistent state MUST stay small enough to archive and restore quickly.
|
|
|
|
### External State
|
|
|
|
Google Drive topological storage SHOULD be mounted at:
|
|
|
|
```text
|
|
/mnt/topological-storage
|
|
```
|
|
|
|
Recommended remote layout:
|
|
|
|
```text
|
|
gdrive:topological_storage/
|
|
nodes/<node-id>/
|
|
inbox/
|
|
outbox/
|
|
artifacts/
|
|
snapshots/
|
|
logs/
|
|
shared/
|
|
datasets/
|
|
models/
|
|
manifests/
|
|
dictionaries/
|
|
```
|
|
|
|
Nodes MUST tolerate the mount being absent. On mount failure, the node remains in
|
|
normal mode with degraded storage, or enters recovery mode only if local state is
|
|
also invalid.
|
|
|
|
---
|
|
|
|
## Runtime Modes
|
|
|
|
### Normal Mode
|
|
|
|
Normal mode runs the compressed API and the minimal local action set.
|
|
|
|
Required services:
|
|
|
|
```text
|
|
rs-surface-api
|
|
rs-surface-heartbeat
|
|
rs-storage-mount optional/degraded if unavailable
|
|
```
|
|
|
|
Allowed operations:
|
|
|
|
```text
|
|
health
|
|
status
|
|
metrics
|
|
attest
|
|
compress
|
|
rgflow
|
|
route
|
|
mount-status
|
|
snapshot
|
|
enter-recovery
|
|
```
|
|
|
|
### Recovery Mode
|
|
|
|
Recovery mode is deliberately boring. It MUST NOT depend on custom compression,
|
|
RGFlow, GDrive, or the normal API.
|
|
|
|
Required recovery services:
|
|
|
|
```text
|
|
dropbear or sshd
|
|
plain HTTP /health
|
|
rollback command
|
|
mount inspection
|
|
log dump
|
|
authorized_keys restore
|
|
```
|
|
|
|
Allowed operations:
|
|
|
|
```text
|
|
GET /health
|
|
GET /boot-report
|
|
POST /rollback
|
|
POST /mark-good
|
|
POST /reboot-normal
|
|
```
|
|
|
|
Recovery mode MUST be able to run with only local disk and network.
|
|
|
|
---
|
|
|
|
## API Contract
|
|
|
|
### Plain HTTP Fallback
|
|
|
|
Every node MUST expose:
|
|
|
|
```text
|
|
GET /health
|
|
```
|
|
|
|
Minimal response:
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"node": "racknerd-510bd9c",
|
|
"mode": "normal",
|
|
"surface_version": "0.1",
|
|
"storage": "mounted|degraded|absent",
|
|
"last_good": true
|
|
}
|
|
```
|
|
|
|
### Compressed WebSocket Endpoint
|
|
|
|
Normal mode SHOULD expose:
|
|
|
|
```text
|
|
GET /ws
|
|
```
|
|
|
|
The WebSocket transport carries custom binary frames. The custom layer is inside
|
|
WebSocket for compatibility with browsers, proxies, and standard debugging
|
|
tools.
|
|
|
|
Frame format:
|
|
|
|
```text
|
|
byte 0 version currently 1
|
|
byte 1 flags bitfield
|
|
byte 2 codec 0 none, 1 zstd, 2 lz4, 3 hutter, 4 rgflow-zstd
|
|
byte 3 op finite operation id
|
|
u32le 4..7 request_id
|
|
u32le 8..11 payload_len
|
|
u32le 12..15 crc32_payload
|
|
bytes 16..N payload
|
|
bytes N..M optional ed25519 signature when flags.sig = 1
|
|
```
|
|
|
|
Operation IDs:
|
|
|
|
| ID | Operation | Notes |
|
|
|----|-----------|-------|
|
|
| 0 | `health` | same meaning as `/health` |
|
|
| 1 | `status` | node status and local budgets |
|
|
| 2 | `metrics` | capped telemetry |
|
|
| 3 | `attest` | hash/sign payload |
|
|
| 4 | `compress` | run compression policy |
|
|
| 5 | `rgflow` | admission/classification |
|
|
| 6 | `route` | forward or queue task |
|
|
| 7 | `mount_status` | report external storage state |
|
|
| 8 | `snapshot` | write tiny local snapshot |
|
|
| 9 | `enter_recovery` | authenticated only |
|
|
|
|
Payloads are canonical JSON unless the operation explicitly declares a binary
|
|
body. Binary bodies MUST include a JSON envelope with content hash, codec, and
|
|
size.
|
|
|
|
---
|
|
|
|
## Compression Policy
|
|
|
|
Compression is not automatic for every frame. The node chooses the cheapest
|
|
lawful path:
|
|
|
|
| Payload | Codec |
|
|
|---------|-------|
|
|
| Tiny control frames | `none` |
|
|
| Repeated telemetry | `zstd` with shared dictionary |
|
|
| Hot local API frames | `lz4` or `none` |
|
|
| Attestation bundles | `zstd` |
|
|
| Semantic or dataset payloads | RGFlow admission, then `zstd` |
|
|
| Unknown/high entropy payloads | reject, route, or store externally |
|
|
|
|
No node should spend more CPU compressing a payload than it saves in network,
|
|
memory, or storage cost. On tiny nodes, the first optimization is often to avoid
|
|
local work and route it elsewhere.
|
|
|
|
---
|
|
|
|
## GDrive Mount Contract
|
|
|
|
The mount provider SHOULD be `rclone`, managed by ENE credentials.
|
|
|
|
Recommended mount command shape:
|
|
|
|
```bash
|
|
rclone mount Gdrive:topological_storage /mnt/topological-storage \
|
|
--read-only \
|
|
--vfs-cache-mode minimal \
|
|
--dir-cache-time 5m \
|
|
--poll-interval 1m \
|
|
--buffer-size 4M \
|
|
--vfs-read-chunk-size 4M \
|
|
--vfs-read-chunk-size-limit 32M
|
|
```
|
|
|
|
Tiny nodes SHOULD default to read-only mounts. Writes go through an explicit
|
|
outbox path or a controller-mediated upload:
|
|
|
|
```text
|
|
/mnt/topological-storage/nodes/<node-id>/outbox/
|
|
```
|
|
|
|
If write support is required, use a bounded local spool:
|
|
|
|
```text
|
|
/var/lib/rs-surface/spool/
|
|
```
|
|
|
|
The spool MUST have a byte cap and MUST degrade gracefully when full.
|
|
|
|
---
|
|
|
|
## Node Profile
|
|
|
|
Each node has a small JSON profile:
|
|
|
|
```json
|
|
{
|
|
"surface_version": "0.1",
|
|
"node_id": "racknerd-510bd9c",
|
|
"role": "gcl-edge",
|
|
"mode_default": "normal",
|
|
"operational_model": "appliance",
|
|
"memory_budget_mb": 715,
|
|
"disk_budget_gb": 9,
|
|
"local_state_budget_mb": 128,
|
|
"api": {
|
|
"plain_health_port": 8080,
|
|
"websocket_port": 8080,
|
|
"bind": "tailscale",
|
|
"tailscale_ip": "100.103.54.58"
|
|
},
|
|
"storage": {
|
|
"provider": "gdrive",
|
|
"mount_point": "/mnt/topological-storage",
|
|
"remote": "Gdrive:topological_storage",
|
|
"required_for_boot": false,
|
|
"write_mode": "outbox",
|
|
"spool_budget_mb": 128
|
|
},
|
|
"capabilities": [
|
|
"health",
|
|
"status",
|
|
"metrics",
|
|
"attest",
|
|
"compress",
|
|
"rgflow",
|
|
"route",
|
|
"nanokernel",
|
|
"topology",
|
|
"builder",
|
|
"warden",
|
|
"judge",
|
|
"mount_status",
|
|
"snapshot",
|
|
"recovery"
|
|
],
|
|
"disabled": [
|
|
"full_git_checkout",
|
|
"local_training",
|
|
"local_build",
|
|
"large_database",
|
|
"legacy_warden_service",
|
|
"legacy_tardy_service",
|
|
"legacy_substrate_index_service",
|
|
"legacy_compression_gateway_service"
|
|
]
|
|
}
|
|
```
|
|
|
|
Profiles are deployable across nodes by changing only identity, budgets, and
|
|
capabilities.
|
|
|
|
---
|
|
|
|
## Upgrade and Rollback
|
|
|
|
The surface supports both in-place nanokernel updates and A/B-style deployment
|
|
even when hosted on Debian. RackNerd as `GCL-Edge` SHOULD use the smallest safe
|
|
upgrade path:
|
|
|
|
- **In-place nanokernel upgrade:** routine changes to the GCL control surface,
|
|
profile, topology phase wiring, or small service-unit corrections.
|
|
- **In-place carrier kernel upgrade:** routine Linux kernel package updates on
|
|
the Debian carrier when SSH/Tailscale and provider rescue fallback are ready.
|
|
- **A/B release upgrade:** larger release bundles, carrier changes, storage
|
|
layout changes, or updates where the previous release must remain bootable.
|
|
- **Rescue pivot:** host repair, root filesystem work, SSH/Tailscale recovery,
|
|
or anything that might make the node unreachable.
|
|
|
|
### In-Place Nanokernel Upgrade
|
|
|
|
The in-place path keeps the running OS, SSH access, Tailscale identity, topology
|
|
state, and legacy-service masks intact. It updates only the GCL nanokernel
|
|
carrier files:
|
|
|
|
```text
|
|
/opt/rs-surface/current/server.py
|
|
/etc/rs-surface/node.json
|
|
/var/lib/rs-surface/last-good.json
|
|
```
|
|
|
|
Operator entrypoint:
|
|
|
|
```bash
|
|
sudo infra/embedded_surface/gcl_edge_in_place_upgrade.sh upgrade \
|
|
/tmp/rs-surface-upgrade/server.py \
|
|
/tmp/rs-surface-upgrade/node.json
|
|
```
|
|
|
|
In-place upgrade steps:
|
|
|
|
1. Stage the new `server.py` and `node.json` outside the live paths.
|
|
2. Compile-check Python and parse-check JSON.
|
|
3. Start the candidate server on a temporary localhost port.
|
|
4. Run `/health` against the candidate.
|
|
5. Copy current live files into
|
|
`/var/lib/rs-surface/rollback/inplace-<timestamp>/`.
|
|
6. Install the candidate files atomically into the live paths.
|
|
7. Run `systemctl daemon-reload` and restart `rs-surface-api.service`.
|
|
8. Run post-start `/health`.
|
|
9. Mark `last-good.json` only after health succeeds.
|
|
|
|
If restart or health fails, restore the rollback copy, restart the service, and
|
|
health-check again:
|
|
|
|
```bash
|
|
sudo infra/embedded_surface/gcl_edge_in_place_upgrade.sh rollback \
|
|
/var/lib/rs-surface/rollback/inplace-<timestamp>
|
|
```
|
|
|
|
An in-place update MUST NOT repartition disks, format filesystems, replace the
|
|
bootloader, alter SSH authorization, reset Tailscale identity, or unmask the
|
|
legacy Builder/Warden/Judge runtimes. Builder, Warden, and Judge are topology
|
|
phases of the GCL nanokernel surface; they are not restored as standalone
|
|
services.
|
|
|
|
### In-Place Carrier Kernel Upgrade
|
|
|
|
When "kernel" means the Linux carrier kernel rather than the GCL nanokernel,
|
|
RackNerd MAY still update in place, but only as a controlled reboot operation.
|
|
This path is for normal Debian security/kernel package updates, not topology
|
|
rewrites.
|
|
|
|
Carrier kernel in-place steps:
|
|
|
|
1. Confirm provider rescue mode is available and SSH authorization is intact.
|
|
2. Capture current boot state:
|
|
`uname -a`, `lsblk -f`, `findmnt /`, `systemctl is-enabled rs-surface-api.service`.
|
|
3. Confirm `/boot` has enough free space and keep at least one previous kernel.
|
|
4. Apply the kernel package update without removing old kernels.
|
|
5. Run `update-grub` or the carrier's bootloader refresh command.
|
|
6. Reboot during a maintenance window.
|
|
7. Verify SSH/Tailscale, `/health`, and `rs-surface-api.service` after boot.
|
|
8. Only then prune stale kernels.
|
|
|
|
If the node fails to return, use provider rescue mode and the saved boot state
|
|
to restore the previous kernel entry or pivot back to the last-good surface.
|
|
Carrier kernel updates MUST NOT unmask legacy services or convert Builder,
|
|
Warden, or Judge back into standalone processes.
|
|
|
|
### A/B Release Upgrade
|
|
|
|
For larger upgrades, use release directories:
|
|
|
|
```text
|
|
/opt/rs-surface/releases/
|
|
surface-20260425T170000/
|
|
surface-20260425T180000/
|
|
current -> releases/surface-20260425T180000
|
|
previous -> releases/surface-20260425T170000
|
|
```
|
|
|
|
A/B upgrade steps:
|
|
|
|
1. Upload new release to `/opt/rs-surface/releases/<version>`.
|
|
2. Verify hashes and required files.
|
|
3. Start new API on a temporary port.
|
|
4. Run local health and atlas health probes.
|
|
5. Move `current` symlink.
|
|
6. Restart normal service.
|
|
7. Mark last-good only after post-start health succeeds.
|
|
|
|
A/B rollback steps:
|
|
|
|
1. Stop current service.
|
|
2. Move `current` to `previous`.
|
|
3. Restart service.
|
|
4. Enter recovery mode if rollback health fails.
|
|
|
|
Bootable embedded images use the same logic with `surface-A.squashfs` and
|
|
`surface-B.squashfs`.
|
|
|
|
---
|
|
|
|
## Minimal Deployment Phases
|
|
|
|
### Phase 0: Debian-Hosted Surface
|
|
|
|
Use the existing host OS as the recovery substrate.
|
|
|
|
```text
|
|
Debian
|
|
systemd service: rs-surface-api
|
|
optional rclone mount
|
|
disabled legacy services
|
|
```
|
|
|
|
This is the safest first target for RackNerd and Netcup.
|
|
|
|
### Phase 1: Compressed Service Bundle
|
|
|
|
Package `/opt/rs-surface/current` as a compressed artifact and deploy the same
|
|
bundle across nodes.
|
|
|
|
### Phase 2: Embedded Root Surface
|
|
|
|
Move to read-only root or squashfs image, with local writable overlay for
|
|
`/var/lib/rs-surface`.
|
|
|
|
### Phase 3: Boot Pivot
|
|
|
|
Only after recovery mode is proven, the node may boot directly into the embedded
|
|
surface.
|
|
|
|
### Phase 4: Layer 0 Kexec Handoff
|
|
|
|
Use Linux only as a loader. The loader verifies the signed Layer 0 GCL image,
|
|
emits a pre-handoff receipt, then uses `kexec` to transfer control to the
|
|
nanokernel-owned runtime. This phase may wipe the old userspace assumptions, so
|
|
it is gated by provider rescue, rollback image, and Layer 0 health pulse.
|
|
|
|
---
|
|
|
|
## Racknerd Initial Profile
|
|
|
|
Observed on 2026-04-25:
|
|
|
|
```text
|
|
host: racknerd-510bd9c
|
|
os: Debian GNU/Linux 13 trixie
|
|
cpu: 1 vCPU
|
|
memory: 715 MiB
|
|
swap: 767 MiB
|
|
root disk: 9.1 GiB, about 6.8 GiB free
|
|
tailscale: 100.103.54.58
|
|
```
|
|
|
|
RackNerd SHOULD run Phase 0 first as `GCL-Edge`:
|
|
|
|
```text
|
|
disable: warden.service, tardy.service, substrate-index.service, compression-gateway.service
|
|
keep: SSH, Tailscale, recovery shell
|
|
add: rs-surface-api, rs-surface-heartbeat, optional rclone mount
|
|
avoid: local builds, full Research Stack checkout, large local databases
|
|
```
|
|
|
|
`GCL-Edge` means:
|
|
|
|
1. GCL nanokernel carrier is the primary runtime.
|
|
2. Builder/Warden/Judge exist only as topology phases.
|
|
3. SSH, Tailscale, and recovery health are preserved above everything else.
|
|
4. Full-stack services are not restored on the node.
|
|
|
|
Recommended Racknerd budgets:
|
|
|
|
```text
|
|
api RSS budget: 32-64 MiB
|
|
mount/cache budget: 64 MiB
|
|
local state budget: 128 MiB
|
|
spool budget: 128 MiB
|
|
free disk floor: 1 GiB
|
|
```
|
|
|
|
---
|
|
|
|
## Netcup Appliance Profile
|
|
|
|
Observed on 2026-04-27:
|
|
|
|
```text
|
|
host: netcup-router
|
|
os: Debian GNU/Linux 13 trixie
|
|
kernel: 6.12.74+deb13+1-amd64
|
|
cpu: 2 vCPU AMD EPYC-Genoa, AVX-512 available
|
|
memory: 3.8 GiB
|
|
swap: none
|
|
root disk: 125 GiB, about 87 GiB free
|
|
tailscale: 100.85.1.50
|
|
public ip: 46.232.249.226
|
|
kvm: unavailable
|
|
```
|
|
|
|
Netcup SHOULD run as a `mirror` appliance rather than a general shell host:
|
|
|
|
```text
|
|
keep: SSH, Tailscale, qemu-guest-agent, fail2ban, rs-surface-api
|
|
disable: tardy.service, openwebui-moe-router.service
|
|
stop: topology_node.py, swarm_surface.py
|
|
avoid: local builds, local training, unbounded web/router services, large databases
|
|
```
|
|
|
|
The Netcup appliance role is to keep the mirror/relay/storage chart available
|
|
while freeing CPU and memory for admitted computation. The surface itself should
|
|
remain tiny: health/status/metrics, topology phase receipts, RGFlow admission,
|
|
and bounded outbox storage. Compute work is admitted through the surface and
|
|
should run as explicit bounded jobs, not as always-on stack services.
|
|
|
|
Recommended Netcup budgets:
|
|
|
|
```text
|
|
api RSS budget: 32-64 MiB
|
|
relay/spool budget: 512 MiB
|
|
local state budget: 512 MiB
|
|
admitted compute: up to 2 vCPU / 3 GiB when idle
|
|
free disk floor: 10 GiB
|
|
```
|
|
|
|
Netcup does not need `/dev/kvm` to be useful. Its best use is a hosted
|
|
topological substrate: the GCL nanokernel exposes primitive operations directly
|
|
on the Debian carrier, and AVX-512 accelerates admitted vector transitions.
|
|
|
|
### EPYC Genoa Topological Device Notes
|
|
|
|
Netcup's EPYC Genoa carrier deserves special handling. It exposes a small but
|
|
high-value vector topology:
|
|
|
|
```text
|
|
cpu topology: 2 vCPU, 1 NUMA node
|
|
per-vCPU cache: 32 KiB L1d, 32 KiB L1i, 1 MiB L2, 32 MiB L3
|
|
vector width: AVX-512
|
|
useful extensions: AVX-512 VNNI, BF16, VBMI/VBMI2, VPOPCNTDQ, VAES, VPCLMULQDQ, SHA-NI
|
|
carrier limit: no /dev/kvm
|
|
```
|
|
|
|
Treat this as an `epyc-genoa-vector-substrate`: a topological device optimized
|
|
for wide deterministic transforms over compact batches. The appliance surface
|
|
should advertise Genoa as primitive substrate capacity without letting vector
|
|
jobs become resident daemons.
|
|
|
|
Kernel-exposed primitives:
|
|
|
|
```text
|
|
attest
|
|
compress
|
|
rgflow
|
|
route
|
|
snapshot
|
|
vector_filter
|
|
delta_batch
|
|
merkle_mmr
|
|
content_chunk
|
|
receipt
|
|
```
|
|
|
|
Preferred admitted work:
|
|
|
|
1. RGFlow vector filtering over batches.
|
|
2. Delta-GCL compression and dictionary scoring.
|
|
3. Structural attestation, Merkle/MMR receipt generation, and SHA-heavy scans.
|
|
4. Content-defined chunking and mirror deduplication.
|
|
5. BF16/VNNI experiments that fit under the appliance memory cap.
|
|
|
|
Scheduling rules:
|
|
|
|
1. Keep `rs-surface-api.service` small and latency-stable.
|
|
2. Reserve at least 768 MiB for the carrier, SSH/Tailscale, cache, and rollback.
|
|
3. Admit at most two CPU slots by default.
|
|
4. Prefer short batch jobs with explicit receipts over long-lived compute
|
|
daemons.
|
|
5. Pin or shard jobs by vCPU when testing cache-sensitive kernels, because the
|
|
observed L3 slices are not shared across the two exposed vCPUs.
|
|
6. Do not require KVM for substrate work; route only VM-specific experiments
|
|
away from Netcup unless `/dev/kvm` appears in a future provider
|
|
configuration.
|
|
|
|
---
|
|
|
|
## Acceptance Checks
|
|
|
|
A node conforms to this spec when:
|
|
|
|
1. `/health` works without GDrive mounted.
|
|
2. `/ws` accepts `health`, `status`, and `mount_status`.
|
|
3. The node can enter and leave recovery mode.
|
|
4. GDrive mount failure does not break SSH or `/health`.
|
|
5. Local persistent state remains below its budget.
|
|
6. Legacy heavyweight services are absent or disabled on constrained nodes.
|
|
7. An upgrade can be rolled back without manual file editing.
|
|
|
|
Layer 0 handoff adds stricter acceptance checks:
|
|
|
|
1. The loader can boot normally and refuse an unsigned Layer 0 image.
|
|
2. The loader can `kexec` into a non-production test image and return through
|
|
provider rescue.
|
|
3. The Layer 0 image emits a recovery pulse without Linux userspace.
|
|
4. The Layer 0 image exposes the primitive descriptor.
|
|
5. The old Linux userspace can be discarded without losing node identity,
|
|
last-good receipt, or topology artifacts.
|
|
|
|
---
|
|
|
|
## Non-Goals
|
|
|
|
This surface does not provide:
|
|
|
|
1. Full Git hosting.
|
|
2. Local model training.
|
|
3. Local large dataset storage.
|
|
4. Local package builds on tiny nodes.
|
|
5. Recovery that depends on custom compression or GDrive.
|
|
|
|
Those functions belong on larger atlas points or in topological storage.
|