# 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// 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//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-/`. 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- ``` 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/`. 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.