feat(seed): realistic seed content for Pages, plus BlogPosts/BlogTopics seed generators - #43
Merged
Merged
Conversation
The access.delete function queried BlogPosts for a 'tags' field that doesn't exist (only 'topics' does) — the query threw, was silently caught, and delete access was always granted regardless of whether the topic was still referenced. Corrected the field name.
deletedPages only made sense for Pages. Renamed to deleted and added skipped, so the same channel type and admin-panel toast summary work for cleanPosts/cleanTopics (added in later tasks) without inventing a new field name per collection. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Ported verbatim (same node shapes, same deterministic-random helpers) into src/lib/seed/lexical.ts so Pages, BlogPosts, and BlogTopics' seed generators can share one implementation instead of each carrying its own copy. Added test coverage the original script never had. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Flagged by Task 3's review — imported but never referenced. No italic-specific test coverage was planned; IS_BOLD already exercises the format bitmask structurally.
lexical.ts's link() was ported from scripts/seed-blog.ts, whose claimed field shape (nested under a 'link' key with a 'type' discriminator) no longer matches this project's actual LinkField (flat fields, no 'type' field at all — removed in an earlier refactor). Every link insertion into a rich-text field threw a deterministic ValidationError. Verified the fix against the real Payload validator, not just the unit test. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Replaced the generic 'Seeded Dummy Page N' title and single boilerplate paragraph with a realistic title pool and 2-4 blocks per page (One-Column, Two-Column, Code, Link Group), each with real prose generated via the shared src/lib/seed/lexical builders. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Follows the seedPages/cleanPages shape exactly. cleanTopics' one new behavior: it never deletes a seeded topic a non-seeded (real) post still references, relying on the corrected topics.contains query from the BlogTopics access-check fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Ports scripts/seed-blog.ts's lexicalArticle generator onto the shared src/lib/seed/lexical builders. seedPosts resolves 1-2 topic ids per post, creating its own seeded topics via seedTopics when too few exist rather than requiring seedTopics to run first. cleanPosts cascade-deletes hero images with the same live-flag-recheck safety property cleanPages already has, and does not touch BlogTopics. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
seedTopics is idempotent-by-slug, not "create N more" — it skips pool slots that already exist. A naive shortfall calculation could silently under-fulfill the requested count. resolveTopicIds now loops until it actually has `count` ids (bounded, since topicFor's cycling suffixes make running out of the pool practically impossible for realistic seed sizes). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Extends the single 'pages'-only branch to also handle 'posts' and 'topics', each calling the matching seedX/cleanX pair from Tasks 5-6. Same task, same channel, same mode-parameterized shape. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Registers the existing, unmodified SeedActions component on both collections, matching Pages' registration exactly — no component changes needed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Superseded by seed:posts and seed:topics (src/lib/seed/posts.ts, src/lib/seed/topics.ts), which cover the same content generation via the shared src/lib/seed/lexical module, plus the seeded-dummy tagging and admin-panel action seed-blog.ts never had. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
…-returns resolveTopicIds was being called fresh for every seeded post, causing redundant queries and giving every post the same leading 1-2 topics instead of a spread across the pool. Hoisted resolution to run once per seedPosts call, rotating which topics each post gets by index. Also logs when the bounded retry loop can't reach the requested count, since a silent short-return now affects every post in a run instead of just one. Also: dropped the vestigial type:'custom' field from pages.ts's linkGroupBlock (inconsistent with lexical.ts's corrected link() shape), replaced two inline text-node literals with the shared text() helper, and restored the spec's videoIds parity branch in lexicalArticle (dead but present, matching the design doc's explicit instruction). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
The final-review fix hoisted resolveTopicIds out of seedPosts' loop but requested only MAX_TOPICS_PER_POST (2), so the whole corpus rotated between just 2 topics regardless of how many were seeded — the review's re-verification flagged this as a residual realism gap versus the retired script's full-pool rotation. Pool size is now min(count, MAX_TOPIC_POOL_SIZE=6), floored at 2, so a larger seed run spreads posts across more topics. Updated two tests whose mocks assumed a fixed 2-topic pool request to match the wider, count-scaled request.
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
Extends the fixture-seeding infrastructure (previously Pages-only) to cover
BlogPostsandBlogTopics, and upgrades Pages' seeded content from generic placeholder text to realistic, varied content.BlogTopics' delete-access check queried a nonexistenttagsfield instead oftopics, silently granting delete access to referenced topics.SeedTaskProgress's success payload from Pages-specific (deletedPages) to collection-agnostic (created/deleted/deletedMedia/skipped).src/lib/seed/lexical.ts) from the oldscripts/seed-blog.ts, fixing a real bug in the portedlink()builder along the way — its field shape didn't match this project's actualLinkFieldconfig and would deterministically fail validation on every use.seedTopics/cleanTopicsforBlogTopicsandseedPosts/cleanPostsforBlogPosts(ports the old article generator onto the shared Lexical builders, adds hero-image download, topic resolution, cascade-delete).pnpm seed:topics/seed:posts+:cleanvariants), and admin-panelSeed…/Cleanactions.scripts/seed-blog.tsand its oldpnpm seed/seed:blog/seed:blog:cleancommands.Process
Built via Subagent-Driven Development: 11 planned tasks, each implemented and reviewed independently (spec compliance + code quality gates), followed by a final whole-branch review. One real bug was caught and fixed mid-plan (a
link()field-shape mismatch that would fail validation on every use); the final whole-branch review caught and fixed a topic-resolution performance/realism issue inseedPosts(redundant per-post queries, insufficient topic variety across the seeded corpus).Verification
pnpm typecheck— cleanpnpm vitest run— 75 files, 654 tests passingpnpm build— succeeds, all pages generateNon-goals (per the design spec)
No changes to the Resume collections, no BlogTopics hero image, no changes to Pages' cascade-delete safety property, no internal-relationship links in seeded LinkGroupBlock entries, no global
cleanAllcommand.🤖 Generated with Claude Code