feat(store): persist world.ruleset and serve it from GET /ruleset #17
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/ruleset-endpoint"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Protocol 3.0 order 2 —
docs/link/v3.md§5. Sidecar half of a four-repo change.This is the first PR into the new
edgebranch in this repo (cut frommain);edge→mainis the v3 cutover.What
The shard publishes one
world.rulesetframe per connect describing how it is configured. The sidecar folds it into a singleton row and serves it back:store.rs— arulesettable withid INTEGER PRIMARY KEY CHECK (id = 1), so the singleton is enforced by the schema and an upsert can targetid = 1unconditionally.main.rs— one more arm in the board-projection match, keyed on nothing (there is only ever one row); it keepsrevalongside the JSON.web.rs—GET /ruleset, behind the samegateas every other protected route.Why store-backed rather than an RPC
Same reason as
/guildsand/houses(PROTOCOL_2.md§12.2): a rules page that goes blank while the shard restarts is worse than one that is briefly stale. Verified below withplugin_connected: false.{"ruleset": null}distinguishes "the shard has never published one" — an older plugin, orBridge.RulesetEnabled=false— from a published ruleset. The website renders those differently, so it is deliberately not smoothed into{}.rev(the shard's FNV-1a of the body) is kept so a reader can tell "same ruleset, re-sent on reconnect" from "the operator changed something" without diffing the JSON.PROTOCOL_VERSIONstays 2The 2→3 bump is an operator-visible hard cutover —
web.rs::gate409s every protected route on mismatch and the website's WS closes on thews.hellomismatch — so it happens exactly once, at the end of v3 (§4), not per phase.INTEGRATION.md§2 now documents what that means for consumers during this window.Verification
cargo buildandcargo clippy --all-targetsclean.Smoke-tested on loopback against a fake shard (ports 17788/18080, isolated config + DB):
GET /rulesetbefore any frame{"ruleset":null}plugin_connected: false(the outage path)X-UOLink-Version: 1409Authorization401Then end to end into the website: backfill snapshot on WS connect, live SSE delivery of a changed ruleset, and the REST read reflecting the overwrite — see the website PR.
Sibling PRs
BridgeRuleset.csemitter/site/rulesINTEGRATION.mdcatalog +GET /ruleset,v3.mdprogress🤖 Generated with Claude Code
https://claude.ai/code/session_01U7CBg11prhLimL9iHSX1bP
Protocol 3.0 §5 (docs/link/v3.md). The shard publishes one world.ruleset frame per connect describing how it is configured; the sidecar folds it into a singleton row and serves it back. Store-backed rather than an RPC, for the same reason /guilds and /houses are (PROTOCOL_2.md §12.2): a rules page that goes blank while the shard restarts is worse than one that is briefly stale. `{"ruleset": null}` distinguishes "the shard has never published one" — an old plugin, or Bridge.RulesetEnabled=false — from a published ruleset, which the website renders differently. `rev` (the shard's FNV-1a of the body) is kept alongside the JSON so a reader can tell "same ruleset, re-sent on reconnect" from "the operator changed something" without diffing. PROTOCOL_VERSION stays 2. The 2→3 bump is a hard operator-visible cutover and happens exactly once, at the end of v3 (§4), not per phase. Smoke-tested against a fake shard on loopback: frame ingested, GET /ruleset returns it with plugin_connected=false (outage path), and the route sits behind the gate (409 on a version mismatch, 401 unauthenticated). cargo build + clippy clean. Co-Authored-By: Claude <noreply@anthropic.com>