feat(sidecar): protocol 13, the egg with RunicNPC and the banner, edge → main (runicnpc 9e step 3, merge 2 of 3) #23

Merged
whitlocktech merged 11 commits from edge into main 2026-10-09 07:21:03 +00:00
Member

What & why

Merge 2 of 3, together with Rust-Plugins' and installer's cutovers. PROTOCOL_VERSION 13, RunicNPC forwarding (stage 4), POST /permissions/inventory, the egg installing every plugin file and RunicNPC from the bundle, and the PopupNotifications banner (D327, D328).

  • Releases v0.2.0 (from v0.1.3): both sidecar binaries, with-sidecar.sh, the egg JSON, SHA256SUMS.
  • Its protocol must equal the bridge's (13) or the bundle's Gate 1 refuses the pair — hence the same window as Rust-Plugins.

The order (docs/runicnpc/PLAN.md, 9e step 3)

  1. runicnpc-rust edge → main — after runicnpc-rust#18 (the feat!:) has merged into edge. Releases v1.0.0.
  2. Rust-Plugins, Rust-Link and installer edge → main, together — after I have checked v1.0.0 (checksums, manifest api 6). The bridge and the sidecar both move protocol 12 → 13, and the bundle's Gate 1 refuses a pair that disagrees, so one without the other leaves a bundle that cannot compose.
  3. I check those three releases and that v2/rust/current.json on installer's bundles branch moves to protocol 13 with RunicNPC 1.0.0 in it (dispatching bundle.yml if a compose run lost the race).
  4. Module-Rust edge → main — last, once a server can actually get RunicNPC from a bundle.

Please leave edge standing (untick "delete branch" on merge): later work lands there.

After the merges: the installer's RunicNPC path and the egg's banner from the real bundle (the row the walk left for this step), then the docs PR recording step 3.

How it was tested

Each change on edge came in by its own PR with its own checks and rig walk (stages 4–9, the 9d player session, 9e steps 1–2). edge is 0 commits behind main, so this merges clean; this PR's checks are the run against the merged tree.

Checklist

  • I have read CONTRIBUTING.md.
  • The change builds and existing tests/checks pass locally.
  • I have added or updated tests/docs where it makes sense.
  • My commits are reasonably scoped with clear messages.

AI-assisted contributions (required)

  • No AI tools were used to produce this contribution.
  • AI tools were used. Tool(s): Claude Code (Claude Opus 5.5). I have reviewed and understand
    every change, and take responsibility for it. AI-authored commits are
    marked with a Co-Authored-By / Assisted-By trailer.

License

  • I agree that my contribution is licensed under this project's license
    (GNU GPL v3.0 or later), and I have the right to contribute it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY

## What & why **Merge 2 of 3, together with Rust-Plugins' and installer's cutovers.** `PROTOCOL_VERSION` 13, RunicNPC forwarding (stage 4), `POST /permissions/inventory`, the egg installing every plugin file and RunicNPC from the bundle, and the PopupNotifications banner (D327, D328). - **Releases v0.2.0** (from v0.1.3): both sidecar binaries, `with-sidecar.sh`, the egg JSON, `SHA256SUMS`. - Its protocol must equal the bridge's (13) or the bundle's Gate 1 refuses the pair — hence the same window as Rust-Plugins. ## The order (docs/runicnpc/PLAN.md, 9e step 3) 1. **runicnpc-rust** `edge` → `main` — after runicnpc-rust#18 (the `feat!:`) has merged into `edge`. Releases **v1.0.0**. 2. **Rust-Plugins**, **Rust-Link** and **installer** `edge` → `main`, **together** — after I have checked v1.0.0 (checksums, manifest `api` 6). The bridge and the sidecar both move protocol 12 → 13, and the bundle's Gate 1 refuses a pair that disagrees, so one without the other leaves a bundle that cannot compose. 3. I check those three releases and that `v2/rust/current.json` on `installer`'s `bundles` branch moves to protocol 13 with RunicNPC 1.0.0 in it (dispatching `bundle.yml` if a compose run lost the race). 4. **Module-Rust** `edge` → `main` — last, once a server can actually get RunicNPC from a bundle. **Please leave `edge` standing** (untick "delete branch" on merge): later work lands there. After the merges: the installer's RunicNPC path and the egg's banner from the real bundle (the row the walk left for this step), then the docs PR recording step 3. ## How it was tested Each change on `edge` came in by its own PR with its own checks and rig walk (stages 4–9, the 9d player session, 9e steps 1–2). `edge` is 0 commits behind `main`, so this merges clean; this PR's checks are the run against the merged tree. ## Checklist - [x] I have read [CONTRIBUTING.md](CONTRIBUTING.md). - [x] The change builds and existing tests/checks pass locally. - [x] I have added or updated tests/docs where it makes sense. - [x] My commits are reasonably scoped with clear messages. ## AI-assisted contributions (required) - [ ] No AI tools were used to produce this contribution. - [x] AI tools were used. Tool(s): `Claude Code (Claude Opus 5.5)`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` / `Assisted-By` trailer. ## License - [x] I agree that my contribution is licensed under this project's license (**GNU GPL v3.0 or later**), and I have the right to contribute it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
wtclaude added 11 commits 2026-10-09 07:15:45 +00:00
fix(sidecar): protocol 13 — a configuration write no longer waits for its reload (F9)
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 3m48s
522187ddd1
The plugin now answers config.write once the files are on disk and reports
the reload as a config.outcome event, which this process files and feeds by
its type like any other event. The reload window no longer has to fit
inside REPLY_TIMEOUT, so CONFIG_RELOAD_WINDOW and the test that asserted
the pairing are gone, and the 504 body stops pointing at a rollback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Reviewed-on: #18
feat(egg): install every plugin file the release lists, helpers included (D182)
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 1m58s
fe7b2822c5
Rust-Plugins now releases a ZoneManager helper, RunicGatewayZones.cs, beside
the bridge (docs/modules/rust/PLAN_FIXES.md D181, D182), installed by default.
The egg copied only RunicGateway.cs out of the tarball.

It now takes every .cs the plugin manifest lists in `files`, checks each
against its own sha256 before anything is placed (the bridge's own checksum
was never checked by the egg before), and refuses a name that is not a plain
<Name>.cs. A release older than helpers lists only the bridge and installs
exactly what it did before. Exercised in an Alpine shell against both, a
tampered helper, a missing one, `../evil.cs` and `evil.dll`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Reviewed-on: #19
feat(sidecar): POST /permissions/inventory forwards the plugin's store read
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 1m40s
3662363caf
Protocol 13, the permission manager (PLAN_REDESIGNS section 1): one more
opaque forward. The body is {snapshotId?, page?}; paging is the plugin's
and the website's, and no page is kept here.

Refs RunicGateway/Module-Rust#21

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Reviewed-on: #20
GET and POST /npc/profiles, GET /npc/placements and POST /npc/placement:
four thin forwards of the plugin's npc.* commands, stamped like every other.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
feat(egg): install RunicNPC when the bundle carries it (runicnpc stage 4, D224)
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 1m53s
10221b7e20
The install script fetches RunicNPC's tarball with the rest, checks it against
the bundle's sha256, its API against the bundle and its file against its own
manifest, and places RunicNPC.cs before the bridge. Its data directory is left
for RunicNPC to make (runicnpc PLAN.md §1.5). rust-link/bundle.json names it.
Walked against a mock Gitea with and without RunicNPC.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Reviewed-on: #21
feat(egg): write the recommended PopupNotifications banner (runicnpc 9e, D327, D328)
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 4m43s
4eee1fbe17
The install writes PopupNotifications.json into oxide/config or
carbon/configs as a banner across the top of the screen, by the installer's
rule: only where the file is missing or every setting is still the plugin's
own default (the Version aside). Anything else is kept whole. The plugin's
Version is written or kept, because PopupNotifications resets a config
without one. A failed write is said in the console and does not fail the
install: it is a look, not the bridge.

Tested in ghcr.io/ptero-eggs/installers:debian: missing, the rig's defaults,
defaults from a later release (version kept), four kinds of change, not
JSON, an existing banner, and an unmakeable directory. egg/build.sh builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Reviewed-on: #22
whitlocktech merged commit 703245455b into main 2026-10-09 07:21:03 +00:00
whitlocktech deleted branch edge 2026-10-09 07:21:07 +00: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-Link#23
No description provided.