fix(bridge): protocol 13 opens — UTF-8 from the site, a reload that fails on evidence (F15, F9, F10) #16

Merged
whitlocktech merged 1 commits from fix/protocol-13-config-reload into edge 2026-09-26 17:22:11 -05:00
Member

Step 1 of docs/modules/rust/PLAN_FIXES.md §6, on edge per D177 (Rust-Plugins, Rust-Link and Module-Rust release protocol 13 together). Decisions: docs#285. Spec: docs#286 (PROTOCOL.md §19).

edge was re-created from main (it had been deleted after the phase-18 cutover), so this diff is protocol 13 only.

F15 — UTF-8 from the site

ReadLoop cast each byte to char, which is Latin-1, so every non-ASCII character from the site was mangled: announcements, titles, kit and zone names, and saved config files. Lines are now split as bytes (UTF-8 never uses 0x0A inside a character) and each finished line is decoded as UTF-8, so a character split across two reads survives. MaxInboundLineBytes now counts bytes.

F9 / F10 — config.write answers first (D178)

  • The reply comes as soon as the files are written: pending: true, writeId, reload, ceilingMs: 30000. No-reload, not-loaded and reload-failed answer as before.
  • A pending reload reads the framework log once a second from where it stood. A line naming the target as a whole word beside a failure phrase ("error while compiling", "failed to initialize", …) rolls back at once. The bridge's own lines are skipped.
  • Ceiling, 30 s per phase, judged by what is loaded: loaded and seen unloading means applied (the hook was missed); loaded and never unloaded means the file stands and applies at the next load; not loaded means rolled back.
  • A rollback waits for the restore's own reload, so the outcome says restored: true/false.
  • The outcome is a config.outcome event (the sidecar files it like any other event). rg.config shows the phase and seconds.
  • ProtocolVersion and overlay.toml are both 13.

Choices I made inside D178, for review

  1. Never unloaded but still loaded at the ceiling → keep the file, don't restore. The old instance is still running, so nothing is down.
  2. The outcome waits for the restore's reload rather than being sent at restore time. That's up to ~60 s in the worst case, and the site's settle_by covers it.
  3. The failure phrases include Carbon guesses: "failed compiling", "failed initializing", "failed loading", "unable to load". The Carbon re-walk pins the real wording.
  4. IsPluginLoaded is plugins.Find(name) != null. I didn't use Plugin.IsLoaded because it isn't proven on Carbon.

Checks

  • node scripts/checkPlugin.js passes: protocol 13, 32 hooks, all void and listed.

  • Not compiled or run yet. The plugin only builds on a Rust server. The rig walk is PLAYER_WALK.md configuration steps 2, 2a, 2b and 4, on Oxide and Carbon.

  • AI-assisted: Claude Code (Claude Opus 5.5)

🤖 Generated with Claude Code

https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY

Step 1 of `docs/modules/rust/PLAN_FIXES.md` §6, on `edge` per **D177** (Rust-Plugins, Rust-Link and Module-Rust release protocol 13 together). Decisions: docs#285. Spec: docs#286 (PROTOCOL.md §19). **`edge` was re-created from `main`** (it had been deleted after the phase-18 cutover), so this diff is protocol 13 only. ### F15 — UTF-8 from the site `ReadLoop` cast each byte to `char`, which is Latin-1, so every non-ASCII character from the site was mangled: announcements, titles, kit and zone names, **and saved config files**. Lines are now split as bytes (UTF-8 never uses `0x0A` inside a character) and each finished line is decoded as UTF-8, so a character split across two reads survives. `MaxInboundLineBytes` now counts bytes. ### F9 / F10 — `config.write` answers first (D178) - The reply comes as soon as the files are written: `pending: true`, `writeId`, `reload`, `ceilingMs: 30000`. No-reload, not-loaded and `reload-failed` answer as before. - A pending reload **reads the framework log once a second** from where it stood. A line naming the target as a whole word beside a failure phrase ("error while compiling", "failed to initialize", …) rolls back at once. The bridge's own lines are skipped. - **Ceiling, 30 s per phase, judged by what is loaded:** loaded and seen unloading means applied (the hook was missed); loaded and never unloaded means the file stands and applies at the next load; not loaded means rolled back. - **A rollback waits for the restore's own reload**, so the outcome says `restored: true/false`. - The outcome is a **`config.outcome` event** (the sidecar files it like any other event). `rg.config` shows the phase and seconds. - `ProtocolVersion` and `overlay.toml` are both 13. ### Choices I made inside D178, for review 1. **Never unloaded but still loaded at the ceiling** → keep the file, don't restore. The old instance is still running, so nothing is down. 2. **The outcome waits for the restore's reload** rather than being sent at restore time. That's up to ~60 s in the worst case, and the site's `settle_by` covers it. 3. **The failure phrases include Carbon guesses**: "failed compiling", "failed initializing", "failed loading", "unable to load". The Carbon re-walk pins the real wording. 4. `IsPluginLoaded` is `plugins.Find(name) != null`. I didn't use `Plugin.IsLoaded` because it isn't proven on Carbon. ### Checks - `node scripts/checkPlugin.js` passes: protocol 13, 32 hooks, all `void` and listed. - **Not compiled or run yet.** The plugin only builds on a Rust server. The rig walk is PLAYER_WALK.md configuration steps 2, 2a, 2b and 4, on Oxide and Carbon. - [x] AI-assisted: Claude Code (Claude Opus 5.5) 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
wtclaude added 1 commit 2026-09-26 17:19:49 -05:00
fix(bridge): protocol 13 opens — UTF-8 from the site, a reload that fails on evidence (F15, F9, F10)
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in 20s
042727e5fe
F15: the read loop cast each byte to a char, decoding the site's UTF-8 as
Latin-1, so every non-ASCII announcement, title, kit name and saved config
file arrived mangled. Lines are now split as bytes and decoded whole, which
keeps a character that straddles two reads intact.

F9/F10 (D177, D178): config.write answers at once with pending, writeId and
ceilingMs, and the outcome follows as a config.outcome event. A pending
reload reads the framework log each second and rolls back the moment the
target fails to compile or initialise; a slow compile is waited for, under
a 30 s ceiling per phase. At the ceiling the plugin looks at what is loaded
before restoring anything, and a rollback waits for the restore's own
reload so the outcome says whether the plugin is back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
whitlocktech merged commit 5de406f356 into edge 2026-09-26 17:22:11 -05:00
whitlocktech deleted branch fix/protocol-13-config-reload 2026-09-26 17:22:11 -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#16
No description provided.