Per-tag wiki prompts - #228
Merged
Merged
Conversation
A tag can now carry its own wiki generation/update prompts, resolved
tag → global setting → built-in default at the single strategy-context
funnel, so both strategies and the incremental-update path inherit the
override with no changes. Prompts stay off the Tag payload (the tree
ships hundreds of rows; prompts run to kilobytes) and are fetched on
demand by the new GET/PUT /api/tags/{id}/wiki-prompts routes and the
tag context menu's Wiki Prompt modal. SQLite V25 + Postgres 026 add
the columns; migrate push copies them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Migration V25 wraps its two ALTERs and version stamp in one transaction (a crash between autocommitted ALTERs re-entered past the single-column guard and stranded the schema at 25 without wiki_update_prompt); a debug_assert now pins user_version to LATEST_VERSION after the ladder. The SQLite prompt read moves off the write mutex onto the read pool. Update-prompt resolution gains the tag's generation prompt as its middle term so a deliberately-shaped article keeps its shape through incremental updates, and the agentic research phase now sees the override it was curating against. The modal keys its load state by tag id so a failed fetch can never render one tag's prompts under another's title, and Save is gated on a successful load. CI newly executes e2e_wiki, e2e_tags_settings, and migrate_tests under Postgres (all dormant arms verified green against pg16 first) and typechecks the frontend. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tag tree's context menu was the only way in. Article and suggestion cards gain a hover/touch ⋮ menu (the suggestion case matters: shaping an article before its first generation is the primary flow), and the reader header gets a Prompt button beside Regenerate — deliberately not gated on version-viewing, since reading a bad version is a common reason to go edit the instructions. The card ⋮ also makes the feature reachable on touch for the first time. WikiHeader turned out to be dead code (nothing renders it — the reader's titleActions cluster is the real header) and is deleted rather than maintained as a phantom twin. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The menu portals its DOM to <body>, but React events bubble along the component tree — a caller rendering the menu inside a clickable card or row (WikiCard, latently ReportRow) had item clicks also fire the card's own onClick, opening the reader over the just-opened modal. Stopping propagation at the menu root fixes every inline caller at once. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The most-repeated community request (asked 5× on Discord): a tag can now carry its own wiki generation/update prompts, overriding the global Settings → Prompts values for that tag's article only. Right-click a tag → Wiki Prompt… — the named use cases (a "Todo Summary" wiki over unchecked tasks, a "Diary" wiki over daily notes, per-meeting summary wikis) all work by writing one prompt on one tag.
Design
build_wiki_strategy_context(the single funnel both strategies and the update path already flow through): tag override → global custom prompt → built-in default. The update chain takes the tag's generation prompt as its middle term so a deliberately-shaped article keeps its shape through incremental updates.Tagpayload (the tree ships hundreds of rows; prompts run to kilobytes) — fetched on demand viaGET/PUT /api/tags/{id}/wiki-prompts, blank-clears-override normalization server-side.tags— SQLite V25 (transactional, crash-safe) + Postgres 026 (additive, fleet-gated).migrate pushcopies them. On Postgres the columns aredb_id-scoped, i.e. genuinely per-tenant.Adversarial review
Four independent review passes (migrations/storage, wiki semantics, API/frontend, test adequacy) ran against the feature commit; every confirmed finding is fixed in the second commit. Highlights:
debug_assertpinninguser_versiontoLATEST_VERSIONafter the ladder.e2e_wiki,e2e_tags_settings, ormigrate_tests— their_postgresarms reported ok without executing. All three are now in the workflow; every previously-dormant arm was verified green against a real pg16 first. The frontend job also gainstsc --noEmit.db_idfencing, route auth, and 404-body consistency are each pinned by new tests; whitespace-only global prompts no longer shadow the built-in default.Known limitations (deliberate)
deny_unknown_fields.Test plan
cargo test -p atomic-core -p atomic-server— 36 suites green (SQLite).npm test(87) andnpx tsc --noEmitclean.🤖 Generated with Claude Code