Add wiki article drafts, session memory tools, reminders, and security updates #2

Merged
rbrooks merged 37 commits from wiki-article-editor into main 2026-05-11 20:25:55 +00:00
Owner

This branch adds the wiki article editor workflow, including article drafts, draft review, wiki link suggestions, and structured character visibility controls. It also improves session workflows with session memory search, proposed-session bot delivery, optional fourth reminders, and automatic reminders for party members who have not voted within three days of voting opening.

It also includes production-readiness fixes found during validation: restored session confirmation notifications, legacy import compatibility for older campaign exports, safer test database guards, updated dev auth/dev-server behavior, and dependency security patches across the backend, bot, and frontend.

Validation completed:

Backend tests: 284 passed
Bot tests: 135 passed
Frontend tests: 64 passed
Frontend build: passed
Backend, bot, and frontend dependency audits: clean
Dev server rebuilt and checked healthy before merge prep

This branch adds the wiki article editor workflow, including article drafts, draft review, wiki link suggestions, and structured character visibility controls. It also improves session workflows with session memory search, proposed-session bot delivery, optional fourth reminders, and automatic reminders for party members who have not voted within three days of voting opening. It also includes production-readiness fixes found during validation: restored session confirmation notifications, legacy import compatibility for older campaign exports, safer test database guards, updated dev auth/dev-server behavior, and dependency security patches across the backend, bot, and frontend. Validation completed: Backend tests: 284 passed Bot tests: 135 passed Frontend tests: 64 passed Frontend build: passed Backend, bot, and frontend dependency audits: clean Dev server rebuilt and checked healthy before merge prep
- New WikiNewEntry page at /campaigns/:id/wiki/new: full-page article
  creation with type, title, pronouns, body, GM notes, private notes,
  structured sidebar and timeline (player_character), and link suggestions
- WikiArticle edit mode gains link suggestions (refresh, apply one, apply
  all, dismiss) using the existing wikiLinkSuggestions utility
- CampaignWiki "New entry" button replaced with a Link to /wiki/new;
  inline create form and its state removed
- CampaignLore.jsx and CampaignLore.test.jsx deleted
- /campaigns/:id/lore redirects to /wiki (no AuthGuard needed on redirect)
- /campaigns/:id/wiki/entries redirect simplified to same helper
- SessionDetail "Review proposals" link updated from /lore to /wiki
- App.test.jsx updated: remove CampaignLore mock, add WikiNewEntry mock,
  add two new route tests for /lore redirect and /wiki/new

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add gm_notes and player_private_notes to edit form state and UI;
  both fields were missing, meaning saves would silently wipe GM notes
- Fix pronouns field condition: was npc-only, now also shows for player_character
- Save payload now sends editable gm_notes (GM only) and player_private_notes
  (can_view_private_notes) rather than passing them through unchanged

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both boxes were display-only and hid themselves when empty, giving no
affordance to add notes without navigating to the full article edit route.
They now always show when the user has permission, with an Add/Edit button
that opens an inline textarea and saves directly without leaving the page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents lore proposal queue regression, session summary Discord repost
failure, and vote-mode session proposal not posting to Discord.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add react-markdown dependency; replace plain-text BodyWithLinks with a
  full Markdown renderer that also handles [[Entry Title]] wiki-link syntax
  via a wiki-link: URI preprocessor and custom <a> component
- Add FormatToolbar above the body textarea in article edit mode: bold,
  italic, underline, H1/H2/H3, bullet list, numbered list, external link,
  inline image, and table insertion; wraps/inserts at the current cursor
  position and restores selection after each action
- Gate private character notes (edit textarea and PrivateNotesBox in read
  mode) on entry_type === player_character; previously appeared on any
  entry where can_view_private_notes was true
- Move Wiki Editing UX roadmap item to ROADMAP-COMPLETED.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove max-w-5xl cap from the article+infobox flex container so the
  page uses full screen width instead of ~50% on wide monitors
- Break the body field out of the two-column label grid so the toolbar
  and textarea span the full article column width; increase default rows
  from 18 to 24 for more writing space
- Rename "Title" label to "Name" in both WikiArticle and WikiNewEntry
  edit forms to better reflect the field's actual purpose

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- postcss 8.5.8 -> 8.5.14 (GHSA-qx2v-qp2m-jg93, moderate XSS in CSS stringifier)
- vite 8.0.0 -> 8.0.10 (GHSA-4w7w-66w2-5vf9, GHSA-v2wj-q39q-566r, GHSA-p9ff-h696-f583,
  path traversal and arbitrary file read in dev server)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The bot proposal review UI was lost when CampaignLore.jsx was deleted
and the code that was moved to CampaignWiki.jsx was never routed.

- Move entry and relationship proposal state, API calls, and handlers
  into CampaignStoryline (the active /campaigns/:id/wiki landing)
- Add ProposalEditForm and TypeBadge sub-components to CampaignStoryline
- Render entry proposals (amber) and relationship proposals (violet)
  below the storyline body, GM-only
- Delete CampaignWiki.jsx — now fully dead code with no remaining callers

The "Review proposals →" link in SessionDetail already pointed to
/campaigns/:id/wiki so no change needed there.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All five multi-pass lore pipeline tasks used asyncio.new_event_loop() /
loop.run_until_complete() / loop.close() instead of asyncio.run(). In a
forked Celery worker the SQLAlchemy/asyncpg connection pool is bound to the
parent event loop; using a new loop causes 'Future attached to a different
loop' errors, causing the entire pipeline to silently stall after the first
retry (leaving sessions stuck in 'extracting' status indefinitely).

Convert generate_lore_proposals, lore_chunk_extract, lore_deduplicate_extracts,
lore_match_category, and lore_consolidate_proposals (including its
MaxRetriesExceededError handler) to asyncio.run(), matching every other
async Celery task in this file.

Also reset the one session stuck in 'extracting' directly in the DB so
it can be re-triggered without a data fix migration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All 5 multi-pass lore pipeline tasks (generate_lore_proposals,
lore_chunk_extract, lore_deduplicate_extracts, lore_match_category,
lore_consolidate_proposals) were using AsyncSessionLocal, whose connection
pool is created in the parent Celery process and bound to the parent's
event loop. When tasks run in forked workers under asyncio.run(), the
inherited connections fail with "Future attached to a different loop".

task_session() creates a fresh NullPool engine per call, avoiding all
cross-process connection reuse.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Proposals moved from the bottom of the Campaign Story page to a new
dedicated page at /campaigns/:id/wiki/proposals. The wiki sidebar shows
an "AI Proposals" link (GM only) with a count badge when proposals exist.

The approval overwrite bug is fixed: when approving an update proposal
(proposed_for_entry_id set), the new bot-extracted content is now
appended to the existing entry body rather than replacing it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When approving an update proposal (proposed_for_entry_id set), the backend
now calls the LLM to intelligently merge the new session-extracted content
into the existing entry body. The LLM incorporates genuinely new information,
discards duplicates, and writes in the same voice as the existing entry.

Falls back to plain append if LLM config is not set or the call fails.
New entries (no proposed_for_entry_id) are unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a red Delete button in the article header (read mode only, GM only).
Confirms with the entry title before proceeding, then calls the existing
DELETE /campaigns/:id/lore/:entryId endpoint and navigates back to the wiki.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Nest title, summary, campaign_name, and summary_discord_message_id under
extra in the session_summary_approved payload. The bot dispatcher reads
only payload[extra] and discards top-level keys, so the handler was
falling back to empty defaults and posting a blank embed.

Add test asserting the extra shape so this class of payload mismatch is
caught before it reaches the bot again.

Also updates ENHANCEMENTS.md with execution order table and detailed root
cause / investigation notes for each near-term roadmap item.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GM-triggered "Rephrase with LLM" button on each article and bot proposal
approval (for merge cases) now route through a new draft-review page where
the GM can edit inline, send back to the LLM with comments for another
iteration, approve, or discard before any LLM output replaces the article.
Approve snapshots a LoreEntryVersion via the existing update_lore_entry path.
Both the rephrase and merge prompts now explicitly require preservation of
[[wiki-link]] and markdown formatting.

- New lore_entry_drafts table (one draft per entry, unique constraint)
- 6 new endpoints under /api/campaigns/{cid}/lore/{entry_id}/drafts
- generate_lore_entry_draft Celery task with testable core
- WikiDraftReview page (polling, autosave, iterate, approve, discard)
- WikiProposals + CampaignDetail merge-style approvals route through the draft
  pipeline; new-entry proposals still approve directly
- Legacy approve_lore_proposal merge branch retained as a direct-API fallback

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The LLM call in generate_lore_entry_draft raises before any draft mutation,
so rolling back the session was a no-op in production but cleared test
setup data when the worker's error path was driven inside a per-test
transactional session. Just record the failure on the already-loaded
draft and commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Local reasoning models can consume the entire output budget on
chain-of-thought tokens before producing any visible output, which surfaces
as finish_reason='length' with empty content and a 'LLM returned an empty
response' error. The rephrase pass was hardcoded to max_tokens=4096, which
isn't enough headroom for those models.

- generate_structured_text accepts max_tokens=None to skip the caller-imposed
  cap. OpenAI / llama.cpp omit the field; Anthropic falls back to 16384
  since the API requires the field.
- rephrase_lore_entry_body passes max_tokens=None.
- merge_lore_entry_body left at 2048 — already in production with no reports.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bump cryptography security patch
Some checks failed
CI / Frontend tests (pull_request) Failing after 3s
CI / Backend tests (pull_request) Failing after 2s
5290067ad4
rbrooks self-assigned this 2026-05-11 20:12:27 +00:00
Move CI automation to Forgejo
Some checks failed
CI / Frontend tests, audit, and build (pull_request) Failing after 1s
CI / Backend migration, tests, and audit (pull_request) Failing after 2s
CI / Bot tests and audit (pull_request) Failing after 1s
603643c716
rbrooks deleted branch wiki-article-editor 2026-05-11 20:25:55 +00:00
Sign in to join this conversation.
No description provided.