# CUBELinux-2 system integration (`cubesys`) This crate is the composition layer the PDF implies but does not name as a "Package 6". It binds Packages 3-5 (cubefs, cubecode, cubecrypt) into one running system over a **single shared `CubeStore`**, which is the literal CUBELinux premise: *data addressed by coordinate, not path.* ## The one invariant > The cube is the single source of truth. cubefs is a *view* of it, cubecode > is a *kind* of record in it, cubecrypt is a *transform* applied to records > in it. None of them own storage. That is what makes the integration real instead of three crates side by side: every layer operates on the same backend, so a write through one is visible to the others at the same coordinate. ## What binds to what | Layer | Role in the system | Shares via | |--------------|------------------------------------------------------|----------------------------------| | `cubefs` | POSIX namespace; a path `C/Z/Y/X` is a coordinate | `CubeStore`, `path_to_czyx` | | `cubecode` | code cells stored *as records*; VM runs them | `CubeStore`, `CodeCell` | | `cubecrypt` | seals records under a `CubeEnv`; key in Null cubes | `CubeStore`, `CubeEnv` | Two primitives in this crate do the binding: * `path_to_czyx(path)` — the single bijection (re-exported from `cubefs`) so path and coordinate never disagree. * `load_code_cell(store, path)` — reads the record at a path's coordinate and decodes it as cubevm bytecode. A cubefs file **is** a runnable VM cell. ## End-to-end properties proved by the tests 1. **A path is a function.** Writing bytecode at `/c012/z001/y001/x021` makes cubefs list it as a file *and* the VM run it at `Czyx::new(12,1,1,21)` — same coordinate, two views. (Note: an axis value of `0` is Null control space and is rejected as a path component, so every user path maps to a coordinate with all axes in `1..=255`; keys and metadata live in Null space and are addressed directly by `C.Z.Y.X`.) 2. **Seal then run is the same record.** `CubeEnv::put_encrypted` at a coordinate leaves the cube carrying an encrypted body (encrypted flag set); the raw body no longer decodes as bytecode. To *execute* a sealed record the system decrypts it back into a plaintext record at the same coordinate, then runs the VM (the VM runs code located by coordinate; reading the envelope directly would fail decode). `open` + `CodeCell::from_record` + `Vm::run` recovers and executes it on the *same* store. ## Bugs found and fixed while integrating (real, cross-crate) Building the integration turned up two latent cross-crate bugs that the per-package test suites never exercised: * **`CubeHeader::refresh_flags()` dropped out-of-band flag bits.** It recomputed `flags` only from structured fields (bits 0–7), so `cubecrypt`'s `HEADER_FLAG_ENCRYPTED` (bit 12), which is set out-of-band, was wiped on every refresh. `put_encrypted` calls `refresh_flags` before storing, so an encrypted record lost its flag. Fixed by preserving spare bits (8..=15) in `refresh_flags`. (`cubecoords`) * **The record codec never serialized `flags`.** `record_codec::encode_header` wrote only structured fields, and `decode_header` rebuilt `flags` from them — so even a correctly-set encrypted bit was lost on the store round-trip. Added tag `12` (raw flag bits) to the TLV codec so out-of-band bits survive. (`cubestore`) Both are now guarded by `cubesys` integration tests. ## Why this, and not a "Package 6" The PDF arc ends at cubecrypt; the only named next package is `cubeai`, which the directive explicitly excluded (hardware cannot run it). Integration is the honest completion: it turns five isolated crates into the coherent coordinate-addressed system the design describes, without inventing a package the spec never defined. ## Binaries * `cube-demo` — self-contained tour (write two linked cells, run; seal a record, reopen + run). Prints evidence at each step. * `cube` — CLI: `write`, `run`, `ls`, `stat`, `seal`, `open` over one store, interactively (`repl`), from a file (`script`), or as the demo (`demo`). * `cube-server` — long-lived daemon: holds ONE `CubeStore` for its whole lifetime and serves the same command language over a Unix-domain socket. Snapshots the store to a JSON file on every request so the cube survives restarts (see below). * `cubec` — client for `cube-server`: one-shot (`cubec prog ...`) or REPL (`cubec` with stdin), talking the framed Unix socket. ## The daemon: `cube-server` + `cubec` The directive asked for "a cube systemd service that holds the store and exposes the CLI over a socket." That is `cube-server` + `cubec`: * **One store, one process.** The daemon owns a single [`Session`] (one `CubeStore`) and serves requests sequentially. Every front-end — `cube`, `cubec`, the daemon — executes the *identical* command interpreter (`cubesys::commands::Session::exec`), so behavior cannot drift. * **Socket transport** (`cubesys::net`): each request is one frame (`[u32 len][utf8 command line]`), one reply frame. No delimiters, no partial reads. Default socket is `$XDG_RUNTIME_DIR/cube/cube.sock`. * **Persistence** (`cubesys::persist`): every record is serialized to a JSON snapshot (`$XDG_STATE_HOME/cube/cube-store.json`) after each mutating command (atomic temp-write + rename). On startup the daemon replays the snapshot so sealed/encrypted state survives a restart. Verified: a record sealed, then the service restarted, then `open`+run still halts with the original value. * **systemd unit** (`/etc/systemd/system/cube.service`): runs as `luulu`, `Restart=on-failure`, `ProtectSystem=strict`, `RestrictAddressFamilies=AF_UNIX` (socket only), writes confined to `/home/luulu/.cubelinux` and the runtime dir. Enabled + running. ```sh # daemon already running via systemd; talk to it: cubec prog /c005/z001/y001/x007 const 7 halt cubec run /c005/z001/y001/x007 cubec seal /c005/z001/y001/x007 0.1.0.1 gcm cubec open /c005/z001/y001/x007 0.1.0.1 gcm cubec ls / ``` **Caveat (inherited from the CLI):** `open` decrypts a sealed record and writes the plaintext back to the same coordinate before running, so the encrypted state is replaced by plaintext after one `open`. That is the original `cube`/`cubesys` behavior and is acceptable for a demo/control socket; a read-only "open" (decrypt into a scratch coordinate, run, leave the sealed record intact) would be the fix if sealed-at-rest must be preserved across reads. ## Building / testing ```sh cd /home/CUBELinux/CUBELinux-2 ./check quick # fmt + clippy -D warnings + tests (the gate) ./check mount # also builds cubefs --features mount (FUSE adapter) cargo run -p cubesys --bin cube-demo cargo run -p cubesys --bin cube -- repl # local in-process REPL # daemon mode: systemctl status cube.service cubec --socket /run/user/1000/cube/cube.sock ls /