feat(sidecar)!: guild rosters on the guild board, and a way to migrate the store #31
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/teams-phase1-guild-roster"
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?
Teams Phase 1, sidecar half. Targets
edge;edge→mainis the v4 cutover.Spec:
docs/link/v4.md· pairs with servuo-plugins #12The board
guild.rosterwrites amemberscolumn, not a field insidejson. That column holds the verbatimguild.updateline, and a roster written into it would clobber the snapshot — name, abbr, leader, online — thatguild.updateowns. Two writers across two columns keeps both as plain upserts: neither reads the other first, so there is no read-modify-write and either kind can arrive first.GET /guildsfolds the roster back in at read time.guild.leavegets no board arm. The sidecar persists and broadcasts it like any event; the roster self-corrects on the nextguild.roster. Keeping the delta out of the projection is what keeps this a forwarder rather than a thing that maintains state.A guild with an update but no roster yet has no
rosterkey — distinct from an empty one, so a reader can't render "not known" as "known to be empty".The migration — the part worth the most review
This repo has no schema-migration mechanism.
SCHEMAisCREATE TABLE IF NOT EXISTS, which adds a table but cannot add a column to one that exists. Every change up to Protocol 3.0 happened to add whole tables, soALTER TABLEappears nowhere in this repo's history and the gap was invisible.guilds.membersis the first column added to an existing table: without a mechanism it would never reach an installed sidecar and every roster write would fail.Settled by the org lead:
PRAGMA user_versionstepped migrations — an integer in the database header, so no extra table and it cannot drift from the file it describes. Each step is transactional with the bump recording it.sqlx::migrate!: its per-file checksums hard-fail startup if a released migration is ever edited.Second commit: chunk reassembly (a real bug, caught live)
The shard splits a large roster across frames. The board upsert wrote whichever array it got, so each frame overwrote the last — a live 155-member guild, split 50/50/50/5, landed on the board with 5 members while
guild.updatecorrectly reported 155 beside it.Every unit test passed through this, because they all exercised single-frame rosters. Only the live rig caught it.
Frames are now reassembled in memory and written once. Appending per frame was rejected twice over: it would make the write a read-modify-write, and it would publish a torn roster to anyone hitting
GET /guildsmid-sequence.Tests
store.rshad none before this. 13 added across both files:duplicate column nameand, since failure aborts startup, brick the sidecar after its first upgraderosterkeycargo fmt/clippy -D warnings/testall green (39 passed). This PR also gates PRs intoedge, not justmain— ten phases land there and gating only themainhop would first run these checks at the cutover; the precedent is already in installer's copy of the workflow.AI-assisted: written with Claude Code. Commits carry
Co-Authored-By: Claude <noreply@anthropic.com>.