feat(webapp): the wiki's links, references, names, one Save, and who may edit (lane 8 PR 2a) — stacked on #864 #874
Loading…
Reference in a new issue
No description provided.
Delete branch "build/lane8-2a-links"
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?
Lane 8 (#734), wave 1, PR 2a. Stacked on the second merge train, on top of #864. It builds on PR 1's
wiki_textandwiki_audience.What's built
Migration
8b2c3d4e5f6a(on10c3). It adds:lore_linksandlore_references, backfilled from every page;lore_name_targets(D72);lore_entries.version_id;campaigns.wiki_edit_mode;wiki_templatesandreputation_levels;Its downgrade turns relationships narrower than the table into proposals, so nothing becomes public in the old schema.
wiki_links.py:[[Name]],[[Name#Section|shown]],![[embed]], and typed footnotes;by-namelookup, and the rename rewrite, which also follows:::forcharacter names.wiki_edit.py, who may edit (own_pages,everyoneorsuggest), enforced on every write:suggest, a player's page becomes a proposal and their edit becomes a draft, merged as them when a GM accepts it;One Save:
base_version_idgets a 409, carrying the current page and who saved it;Settings → Wiki's API: the edit mode (audited), reputation levels, templates (rendered per reader), suggestions, name targets and by-name.
Export and import carry all of it. Links are re-read from the text on import.
Tests
test_wiki_links,test_wiki_links_api,test_wiki_edit_apiandtest_wiki_links_migration. The last checks that the migration's frozen parser matches the app's, and runs the backfill on real rows.test_discussions_no_ai, fixed by moving the thread lookup intodiscussion_service; then 455 passed acrosstests/wikiandtests/discussions.Owner questions (W15, W16), on the questions page
Decided in-lane
:::for @Playerblock doesn't follow a rename of their display name yet. That's a follow-up.Merge note: #871 (lane 10 PR 3) also adds a migration on
10c3. Whichever merges second is re-chained.🤖 Generated with Claude Code
The page at /campaigns/:id/safety (CAMP-18): lines and veils for everyone; for a GM, Edit, Remove with Undo (D12), "+ Add", and the waiting queue with Add as a veil / Add as a line (in the GM's wording) and Dismiss. A player gets the anonymous suggest card with the drawn words (T3(a)) and every GM named (T10(a)), and IS-017's Sent card. The flag dialog, "Flag something to Dana", behind four doors: This week's card (IS-205, about no session), the foot of a live or played session's page (T2(a), IS-210), and Table mode's players' face ("Flag something quietly"). The GM's Table-mode face gets the quiet "N waiting in Table rules & safety" in its place, polled from GET …/safety/waiting (T4(a)). The Contents gains the Table rules & safety entry, with the GM's count (IS-204, IS-212); a player is never asked for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"Make it canon" on a party thread wrote the answer, unblocked, into a wiki page the whole table reads, so members outside the party read it there (found by the lane 8 survey). CANON_AUDIENCES is ("table",) until lane 8's party and visibility blocks (IS-148) can carry the thread's audience into the article; a party answer is now a 422, like a narrower one. The thread page follows: no "Make it canon" on a party thread. Tests hold both sides; API.md and the CHANGELOG say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>The bot's half is tested: /record/test announces "Recording a test" before it captures (and records anyway if the post fails, D171), captures with the same sink into audio_temp/tests/{id}/ with absolute placement intact, hands over through POST /api/bot/recording-tests/{id}/audio, deletes the audio if the handoff does not land (D150), and crash recovery and the startup sweep never take tests/ for a session. The session page's SSE keys a test's "other" by its own id. API.md documents the routes; the changelog says it. Closes #824. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Server and bot halves together; no pages. - Discord DMs (D152): `notification_dm` on the durable stream, claimed before publish, the bell's line + link + time for session news only; sent only to a bot whose GET /identity lists "dm" in its new `features`. The bot's handler is exempt from the channel check and reports refusals to the new POST /api/bot/users/discord/{id}/dm-status (closed | no_shared_server | ok); the settings carry a `warning` beside the DM column until the next DM lands. - The GM's warnings (D151): session_at_risk and audio_deletion_pending are GM-only bell rows, DM'd per the GM's grid (GM tasks x DM on by default), and posted to the channel only when no GM is reachable by DM. The at-risk poller runs for campaigns without a guild. - A group without Discord (D153, #840): session news is emailed to every member unless Sessions email is explicitly off; the from-address email backends are retired. Reminders are `session_reminder` rows per member (only the last in the bell), reading the reader's RSVP. - The reader's time: users.timezone, else the campaign's, else UTC, with the abbreviation, in notification emails and calendar invites. - One star, one wish (D161): `feedback_requested`, written on completion for the players Home asks, never in the bell. - D159: campaigns.voice_channel_id, stored and shown to GMs. - PUT notification-settings writes only cells that change and never refuses an unchanged echo, so the page's whole-grid save keeps the defaults. - Migration 10a1b2c3d4e5 on c4e6a8b0d2f1: the kind CHECK is the union with lane 9 A's and lane 7's kinds; notifications.in_bell; platform_links dm_failed_at/dm_failed_reason; campaigns.voice_channel_id. Bot contract unchanged (additive). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Admin becomes a place with sections in Home's Contents rather than a page of ten tabs, reusing the same shape lane 3 gave Settings: - adminSections.js (16 sections, the survey's addresses); ADMIN_SECTIONS' `built` flag follows settingsSections.js's own rollout rule — three sections with no legacy screen at all (Content notices, Instance health, Plans & entitlements) stay unmounted for their own PR (4c/4d). - /admin/* routes; `?tab=` redirects to the new address (paths are contracts, R1-8); `bot` (ambiguous) goes to AI models. - Home's Contents "This instance" group, the crumb ("Admin › <section>"), and IS-377's Stop for a non-administrator (AdminDoc.jsx). - The index (GET /admin/overview, already on this branch from lane 9 A): grouped status lines, D142's quiet leftovers box, and D141's accept/ decline banner for an offered server. - ADMIN-15 About this server: the admin GET/PUT this lane's server work added, now with a form. - ADMIN-1 Users: the owner's chip, "Hand the server on…" (an offer, D68), Make/Remove administrator (a dialog, then an undo), delete with the typed name and the blocked-by-campaigns state, and D56's search-scope radio cards (new GET endpoint — the setter existed, nothing read it back). - ADMIN-2 Campaigns: the instance-wide list, and an immediate (never an offer) hand-on for a campaign whose owner is unreachable or just moved on — the admin's own recovery path either way. - D141's server-scoped attention item: AttentionItem.campaign_id/ campaign_name become optional for the one kind that isn't a campaign's (server_owner_offer), checked ahead of the membership scope so it reaches an administrator with no campaigns of their own. - Every other built section keeps working at its new address by mounting pages/Admin.jsx's existing component unchanged (the tab bar is gone); AI models and Discord share one interim mount until page 4c splits BotSettings along the new addresses — a documented departure. - J1's Admin leg walked for real: the leftovers list, Backup's own heading and Contents-current row, a whole-page axe scan (no longer scoped to [role="alert"]), the desktop project settling the step, and the keyboard project reaching Admin through the account menu and its Contents sub-list. A new IS-377 journey test (Priya, stopped, axed). Backend: GET /api/admin/settings/member-search-scope (D56's setter has existed since #855; nothing read it back before this). Not in this PR (see the survey's §7 row 4a and the file's own notes): AI models/AI usage & speed/Discord's real split, Recording & retention, Backup, Content packs, Content notices, Audit log's names/categories, and Plans & entitlements — pages 4b/4c/4d. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>