feat(bridge): protocol 5 — configuration from the site, and the reload that undoes itself #5

Merged
whitlocktech merged 1 commits from feat/phase-7b-config into edge 2026-09-22 10:01:47 -05:00
Member

Phase 7b, the plugin half of R18. Spec: docs/rust-link/PROTOCOL.md §11; as built: PLAN.md §21 (docs PR alongside).

Three verbs

  • config.list — a recursive walk rooted at Interface.Oxide.ConfigDirectory (so oxide/config on Oxide, carbon/configs on Carbon, and wherever an operator moved it), plus every loaded plugin so the website can offer a reload target. It hashes nothing: a version comes from config.read, on the one file somebody opened, because hashing 500 files would be up to 128 MB of reads in a frame.
  • config.read — one file's text and its version.
  • config.write — a set of files and one reload target.

DataDirectory is never walked. It holds live state and both frameworks' permission stores, which is protocol 4's mirror one directory over.

The write, and why the last step is the feature

Resolve, version-check and parse-check everything before the first byte lands (the perm.sync posture: a refusal that has touched nothing has nothing to unwind), then back the set up, write it, reload through the framework, and wait four seconds for OnPluginLoaded. If it never arrives, restore every file, reload again, and report the failure with the tail of the newest log file.

Without that this is a web form that takes a required plugin off a production server one typo at a time — and R6/R17 make four of them required.

Four seconds is arithmetic: the worst path is two windows while a caller holds the sidecar's 10s RPC budget.

Two refusals worth reading

  • reload-self — reloading this plugin would close the link carrying the answer and leave the rollback with nothing watching it.
  • Anything outside the config root — canonicalise, assert under the root, refuse absolute paths, drive letters, .. and reparse points. Protocol 4 addressed things by name; this addresses them by path, which is the change that introduces the bug class.

Proven

rg.config on the live Oxide rig answers protocol=5 framework=oxide root=/home/container/oxide/config — 1,050 new lines compiled in 0 ms and loaded, with the framework detected at runtime rather than by conditional compilation. The Carbon rig is the other half of R19 and is booting.

The in-game leg (a setting changed on the site taking effect) needs the sidecar and the game on one host; it is written down in PLAYER_WALK.md.

  • AI-assisted: Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01PMH6bw1jXMgbyF3ZWGEzSM

Phase 7b, the plugin half of R18. Spec: `docs/rust-link/PROTOCOL.md` §11; as built: `PLAN.md` §21 (docs PR alongside). ## Three verbs - `config.list` — a **recursive** walk rooted at `Interface.Oxide.ConfigDirectory` (so `oxide/config` on Oxide, `carbon/configs` on Carbon, and wherever an operator moved it), plus every loaded plugin so the website can offer a reload target. It hashes **nothing**: a version comes from `config.read`, on the one file somebody opened, because hashing 500 files would be up to 128 MB of reads in a frame. - `config.read` — one file's text and its version. - `config.write` — a **set** of files and one reload target. `DataDirectory` is never walked. It holds live state and both frameworks' permission stores, which is protocol 4's mirror one directory over. ## The write, and why the last step is the feature Resolve, version-check and parse-check everything **before the first byte lands** (the `perm.sync` posture: a refusal that has touched nothing has nothing to unwind), then back the set up, write it, reload through the framework, and **wait four seconds for `OnPluginLoaded`**. If it never arrives, restore every file, reload again, and report the failure with the tail of the newest log file. Without that this is a web form that takes a required plugin off a production server one typo at a time — and R6/R17 make four of them required. Four seconds is arithmetic: the worst path is two windows while a caller holds the sidecar's 10s RPC budget. ## Two refusals worth reading - **`reload-self`** — reloading this plugin would close the link carrying the answer and leave the rollback with nothing watching it. - **Anything outside the config root** — canonicalise, assert under the root, refuse absolute paths, drive letters, `..` and reparse points. Protocol 4 addressed things by name; this addresses them by path, which is the change that introduces the bug class. ## Proven `rg.config` on the live Oxide rig answers `protocol=5 framework=oxide root=/home/container/oxide/config` — 1,050 new lines compiled in 0 ms and loaded, with the framework detected at runtime rather than by conditional compilation. The Carbon rig is the other half of R19 and is booting. The in-game leg (a setting changed on the site taking effect) needs the sidecar and the game on one host; it is written down in `PLAYER_WALK.md`. - [x] AI-assisted: Claude Code 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01PMH6bw1jXMgbyF3ZWGEzSM
wtclaude added 1 commit 2026-09-22 08:56:16 -05:00
feat(bridge): protocol 5 — configuration from the site, and the reload that undoes itself
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in 10s
48eeb56300
R18. Three request/reply verbs — `config.list`, `config.read`, `config.write` —
and the first command on this bridge that writes to the game host's filesystem.

The walk is rooted at `Interface.Oxide.ConfigDirectory`, never a literal, so it
is right on Oxide, on Carbon and on a server whose operator moved it; the data
directory is never walked, because it holds live state and both frameworks'
permission stores, which is protocol 4's mirror one directory over.

A write is resolved, version-checked and parse-checked before the first byte
lands, then backed up, written and reloaded — and the reload is WATCHED. If
`OnPluginLoaded` does not arrive within four seconds the whole set is restored,
reloaded again, and reported with the tail of the newest log file. Without that
this is a web form that takes a required plugin off a production server one typo
at a time.

Four seconds is arithmetic, not taste: the worst path is two windows while a
caller holds the sidecar's ten-second RPC budget.

This plugin will not reload itself — the reload would close the link carrying
the answer — and the site composes the file's bytes, so nothing here has an
opinion about content beyond "it parses".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMH6bw1jXMgbyF3ZWGEzSM
whitlocktech merged commit c62c4d7033 into edge 2026-09-22 10:01:47 -05:00
whitlocktech deleted branch feat/phase-7b-config 2026-09-22 10:01:48 -05:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/Rust-Plugins#5
No description provided.