v0.154.0 — Map building: Inherited roles
Map building's tenth milestone (M10, the program plan's M5): a GM decides what each campaign role gets on the campaign's maps, tokens, characters, parties, factions, channels and timed effects, separately from the role on the campaign itself. Nothing changes for anyone until a GM changes something: every existing grant becomes rows that give exactly the same answers as before, checked on a copy of production (7,589 user × entity pairs, 0 differences). The program's documents are in docs/programs/map-building/; this milestone's tasks, decisions and test script are in docs/programs/map-building/m10-inherited-roles.md.
Access, per campaign
- [x] Edit Campaign → Access is a grid: for each campaign role, what it gets on the campaign's maps, tokens and characters (and, under More, parties, factions, channels and effects). A cell reads "same" when it gives the role itself. Each row fills from a preset (Player, Co-GM, Spectator).
- [x] Changes are previewed before they apply: who gains or loses what, by type ("Pat loses play on maps"). Taking access away asks first.
- [x] A new campaign's grid comes from the presets, and can be changed at creation.
- [x] The Players toggles ("edit each other's maps / characters") are two of the grid's cells; turning one off returns that type to Collaborators' own role.
- [x] On maps, tokens, characters, channels and effects a cell gives at least Viewer; "none" is offered for parties and factions only.
Sharing, per player
- [x] In Share, one player can be given something different per type ("On its maps: Collaborator"). Changing their role on the campaign asks about the types that read "same", and Keep holds them.
- [x] Edit Map → Sharing: a map's own sharing, for whoever may share it, with per-player rows for its tokens, channels and effects.
- [x] The Effective tab names the row that decided: "Collaborators' default on maps, on Campaign X", "granted to Pat on Campaign X, covering maps", or "granted here".
- [x] New members get offers Player, Co-GM and Spectator.
Under the hood
- [x] Every check that judged something inside a campaign by the campaign alone (factions, a campaign's characters, timed effects, channels, the chat, copying a map, and more) now asks about the thing itself. A guard test keeps new code from going round it.
- [x] A
.catimport gives the campaigns it makes their grid. A.catexport made by someone other than the owner leaves out what they can't read. - [x] Fixed on the way: replacing a custom role that someone held beside its replacement failed with an error.
The data migration
- At boot, once (
inherited-roles-0085indata_migrations), in one transaction: every campaign gets its grid, every map its channel rows, and every user grant on a map the rows that keep its answers. A failure stops the server rather than run half-migrated. The schema change (migration 0085) shipped in v0.153.0. - Before deploying, a database snapshot (see the release's merge task). On SQLite the migration keeps a copy,
<db>.pre-0085.sqlite.
Known leftovers
- A map's Sharing → Who has access starts empty: players reach the map through the campaign.
- The Effective view says "on Campaign
"; a long preview can say "loses play" twice; names truncate in the narrow sidebar. - A
.catbackup doesn't carry a custom grid yet (the.catprogram will add it).