feat(bridge): protocol 9 — the world verbs, and the phase-7 owner fix (phase 13a) #9

Merged
whitlocktech merged 3 commits from feat/phase-13a-world into edge 2026-09-24 05:08:47 -05:00

3 Commits

Author SHA1 Message Date
0a7ad570f7 fix(bridge): refuse world commands until the world has loaded
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in -1m29s
The link starts in Init, before the save loads. The phase 13a walk restarted
the rig mid-run: the website saw the new boot id at once, asked world.owned
into an empty world, and the plugin — finding no entity behind any net id —
pruned three live crates from its own registry. They stayed in the world,
owned by nothing, and a revert would have refused them.

world.owned, world.revert, world.monuments and every world write now answer
`not-ready` until OnServerInitialized, zones are not re-created before it,
and server.hello carries `worldReady` so the website can hold its reconcile
until the world it would be asking about exists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-09-24 02:16:03 -05:00
bbaa7f346e feat(bridge): protocol 9 — the world verbs events place and give back (phase 13a)
world.monuments, world.zone, world.place, world.revert and world.owned
(PLAN.md §28, D86-D96):

- Zones through ZoneManager's temporary zones, owned by the bridge, with a
  required duration the plugin enforces itself (D96) and re-created from the
  bridge's own registry on every load and every ZoneManager reload (D92),
  because ZoneManager erases a plugin's zones when that plugin unloads.
- Crates and NPCs from a plugin-held allowlist (D88) at a monument by kind
  and instance, or at raw coordinates (D87, D93), bounded 25/20 per step (D95).
- A registry file keyed by the website's idempotency key, since this bridge
  has no at-most-once store: a repeat answers with the first call's ids.
- world.owned LOOKS by net id: crates survive a restart, NPCs do not, so a
  boot id proves nothing. A wipe drops the registry whole.
- EventsEnabled gates every world write; revert, owned and monuments never
  (D94). Revert refuses only a thing that exists and is not this run's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-09-24 01:22:06 -05:00
c106ba826b fix(bridge): grant with a null owner and read every grant back (D85)
EnsureGrant and EnsureGroupPermission passed `this` as the owner. Given an
owner, Oxide first asks PermissionExists(perm, owner) — whether THAT plugin
registered the name — and returns silently when it did not, so every
site-authored grant of another plugin's permission was a no-op on Oxide that
the report counted as applied (PLAN.md §27.6).

Both now pass null and read the store back. A grant the store does not hold
afterwards is reported in the new `notLanded` list instead of counted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-09-24 00:37:45 -05:00