Skip to content

fix(seed): resolve taxonomy terms in the content entry locale - #4417

Open
emdash-autofix[bot] wants to merge 3 commits into
mainfrom
emdash-bot/issue-4416
Open

emdash-autofix[bot] wants to merge 3 commits into
mainfrom
emdash-bot/issue-4416

Conversation

@emdash-autofix

Copy link
Copy Markdown
Contributor

What does this PR do?

Scopes seed taxonomy slug lookup to the content entry's locale on create and update. French content now attaches the French term when English and French translations share a slug. Updates use the stored entry locale, including entries matched by ID, with the resolved seed locale as a fallback for null stored locales.

When no term exists in that locale, the import warns with the taxonomy name, slug and locale and skips that assignment. This preserves the existing continue-on-unresolved-reference behavior rather than introducing a fatal error (particularly important on D1, where writes are not transactional). Updates still declaratively replace the prior assignments. To repair existing wrong-locale assignments, reapply the seed with --on-conflict update.

Closes #4416

Type of change

  • Bug fix
  • Feature (requires an accepted feature plan or RFC)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Your connection to this change

Prepared by the project-operated autofix bot through auto-intake for this reported reproduction. Maintainer approval is required before merge.

  • I use EmDash and ran into the problem this PR addresses
  • I maintain a tool, dependency, or service that EmDash uses, and this change concerns that integration
  • A Maintainer approved this specific change before I opened the PR

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes (core-scoped typecheck passed; full workspace check left to CI)
  • pnpm lint passes (pnpm lint:quick passed with zero diagnostics; type-aware lint left to CI)
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes
  • User-visible strings in the admin UI are wrapped for translation (not applicable: no admin changes)
  • I have added and reviewed the user-facing changeset
  • New features link to their merged design PR (not applicable: bug fix)
  • I have included screenshots below if this PR changes the UI (not applicable)

AI assistance disclosure

  • This PR includes AI-generated code or text — model/tool: cloudflare-ai-gateway:gpt-6.1-sol via the EmDash bot (Pi Durable)

Screenshots / test output

Screenshots: Not applicable (seed import only).

  • Regression tests reproduced English terms being selected for French content before the fix.
  • pnpm --filter emdash exec vitest run tests/integration/seed-taxonomy-locale.test.ts tests/integration/seed-on-conflict.test.ts tests/integration/seed-i18n-default-locale.test.ts — 37 tests passed.
  • Coverage includes explicit/default locales, create/update, slugless updates using the stored locale, foreign-locale-only and entirely missing terms, warnings and continued import. Tests use the dialect wrapper; PostgreSQL was not run because no EMDASH_TEST_PG connection was configured.
  • NODE_OPTIONS=--max-old-space-size=8192 pnpm build — passed (the first attempt with the default heap limit exhausted memory).
  • pnpm --filter emdash typecheck — passed.
  • pnpm lint:quick — zero diagnostics.
  • pnpm format — passed.

Pre-submit review feedback addressed: replaced the initial missing-term throw with warning-and-skip, removed rollback claims and updated tests and changeset. Kept the test alongside the existing seed integration tests rather than moving files for an optional location nit.

The EmDash bot took this issue on automatically when it was opened; no maintainer has assigned it yet.

Pass the resolved content locale to taxonomy term lookup for seed creates and the stored locale for updates. Warn and skip missing localized terms instead of attaching a foreign-locale term. Added regression coverage for shared slugs, explicit/default locales, slugless updates, and unresolved references. Verified with 37 focused tests, root build (8 GB Node heap), core typecheck, pnpm format and lint:quick (zero diagnostics). Independent review and follow-up completed.

EmDash-Bot-Case: 1198246700-issue-6038274325
EmDash-Bot-Candidate: cand-1-6658f487ab
@emdash-autofix emdash-autofix Bot added the bot:fix Assign this issue or pull request to the EmDash bot to fix label Oct 26, 2026
@emdash-autofix

emdash-autofix Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor Author

EmDash bot: Ready for human review

Plan

Completed the translation-group fix and regression coverage, including cross-collection ID isolation. All 41 focused tests, root build, core typecheck, formatting and quick lint pass; independent follow-up review is clean.

  • Inspect seed import and regression test patterns
  • Add regression coverage and scope term lookup to the entry locale
  • Run focused checks and review the candidate
  • Document repair guidance, verify and publish the update
  • Clear assignments once per translation group and add regression tests
  • Verify and review the revised fix

Status

  • Required checks passed, the review bot approved the current head, and the head merges cleanly.

Next action: A maintainer will review and approve the pull request.

Details
Candidate cand-3-ca73ab7ff2 (tree 659622e6a17c)
Published head 88864d5bca34
Reviewer's latest review of head approved
Reporter confirmation not yet
Human approval required before merge

Required checks on the current head:

  • Typecheck: succeeded
  • Tests: succeeded
  • Smoke Tests: succeeded
  • Browser Tests: succeeded
  • Format: succeeded
  • CLAssistant: succeeded
  • Measure: succeeded

This status is generated from recorded evidence. It is not a review and contains no instructions.

@changeset-bot

changeset-bot Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 88864d5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/plugin-test Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
create-emdash Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach is right: seed import now resolves taxonomy slugs in the content entry's resolved locale, matching what the public API's assignTaxonomies already does. Unresolved references keep the existing warn-and-skip behavior. Both reviewers approved and found no logic, SQL-safety or locale-filter problems on the create and update paths. Tests cover persisted assignments across dialects. Review was static; tests, builds and lint were not run, and PostgreSQL/D1 execution is unverified. One suggestion remains: the changeset should tell affected users how to repair existing data and warn that previously attached cross-locale terms are now skipped.


Reviewed by anthropic/claude-opus-5-5 and openai/gpt-6.1-sol.

Comment thread .changeset/hot-cases-draw.md Outdated
"emdash": patch
---

Fixes seed imports assigning taxonomy terms from another locale when slugs are shared across translations. Taxonomy references now resolve in the content entry's locale; a missing localized term produces a warning and skips that assignment instead of attaching a term from another locale.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] This entry describes the fix, but two things are missing for readers who are already affected:

  1. Existing data isn't repaired. Sites that already ran an affected seed still have entries linked to the wrong-locale term. The PR description gives the fix: re-run the seed with --on-conflict update. The changeset doesn't say this, and it's what the issue reporter (French posts returning 404) would need.
  2. Previously working imports can lose assignments. A seed that referenced a term existing only in another locale used to get that term attached. Now the assignment is skipped with a warning. Seed authors should know to add the term in the entry's locale.
Suggested change
Fixes seed imports assigning taxonomy terms from another locale when slugs are shared across translations. Taxonomy references now resolve in the content entry's locale; a missing localized term produces a warning and skips that assignment instead of attaching a term from another locale.
Fixes seed imports assigning taxonomy terms from another locale when slugs are shared across translations. Taxonomy references in seed content now resolve in the content entry's locale. When no term with that slug exists in the entry's locale, the import logs a warning and skips that assignment instead of attaching a term from another locale; add the term in that locale to keep the assignment. To repair entries already attached to a wrong-locale term, re-apply the seed with `--on-conflict update`.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added both points to the changeset: existing assignments are not repaired automatically and can be corrected by reapplying with --on-conflict update; missing localized terms now warn and skip the assignment, so authors should add the term in the entry's locale to retain it. Re-ran formatting and the 37 focused tests successfully.

@pkg-pr-new

pkg-pr-new Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@4417

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@4417

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@4417

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@4417

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@4417

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@4417

emdash

npm i https://pkg.pr.new/emdash@4417

create-emdash

npm i https://pkg.pr.new/create-emdash@4417

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@4417

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@4417

@emdash-cms/plugin-test

npm i https://pkg.pr.new/@emdash-cms/plugin-test@4417

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@4417

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@4417

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@4417

@emdash-cms/registry-loader

npm i https://pkg.pr.new/@emdash-cms/registry-loader@4417

@emdash-cms/registry-moderation

npm i https://pkg.pr.new/@emdash-cms/registry-moderation@4417

@emdash-cms/registry-verification

npm i https://pkg.pr.new/@emdash-cms/registry-verification@4417

upgrade-emdash

npm i https://pkg.pr.new/upgrade-emdash@4417

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@4417

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@4417

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@4417

@emdash-cms/plugin-ai-search

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-search@4417

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@4417

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@4417

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@4417

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@4417

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@4417

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@4417

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@4417

commit: 88864d5

Expanded the changeset in response to review: explain that missing localized terms are skipped, existing assignments require reapplying the seed with --on-conflict update, and that reapplying also overwrites other seeded records. No implementation changes. Ran pnpm format and diff checks; 37 focused tests passed during this revision. Independent review and follow-up passed.

EmDash-Bot-Case: 1198246700-issue-6038274325
EmDash-Bot-Candidate: cand-2-d5d299dce5

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach is right. Seed import now resolves taxonomy slugs in the content entry's locale, matching what the public API's assignTaxonomies already does. Both reviewers approved and found no outstanding issues. The earlier changeset suggestion is addressed. The changeset now says that existing wrong-locale assignments can be repaired by reapplying the seed with --on-conflict update, which also overwrites other seeded records. It also says that terms existing only in another locale are now skipped with a warning, so authors should add the term in the entry's locale. Tests cover create and update paths, omitted and explicit locales, and missing terms. Review was static; tests, builds and lint were not run, and PostgreSQL/D1 execution is unverified.


Reviewed by anthropic/claude-opus-5-5 and openai/gpt-6.1-sol.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://emdash-bot-issue-4416.try.emdashcms.com, https://emdash-bot-issue-4416-emdash-playground.emdash-cms.workers.dev (commit 88864d5)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://cfce00f7.try.emdashcms.com, https://cfce00f7-emdash-playground.emdash-cms.workers.dev 88864d5 2026-10-29T19:19:57.582Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://1bc0cd8a.try.emdashcms.com, https://1bc0cd8a-emdash-playground.emdash-cms.workers.dev 924d41e 2026-10-26T11:20:26.174Z Visit the dashboard ↗

@emdash-autofix emdash-autofix Bot added the triage/awaiting-reporter Fix pushed, waiting on reporter to verify label Oct 26, 2026
@danielmlr

Copy link
Copy Markdown
Contributor

@emdash-autofix

  • Clear a translation group's taxonomy assignments once per seed run, not once per translation. Assignments are stored per translation group, so on onConflict: "update" each translation's clearEntryTerms removes what the translations before it attached. With post-en and post-fr (translationOf: post-en) both listing a term that exists only in en, the update leaves both posts with no category, while main keeps it. With that same pair and separate en and fr guides terms, the English post loses its category. Keep a Set of cleared groups in applySeedWrites, keyed on existing.translationGroup ?? existing.id, pass it into applyContentTaxonomies, and clear only when the group isn't in it yet. Then attach each translation's terms on top.
  • Add a regression test for it: a translated pair, applied and then reapplied with onConflict: "update", checking through TaxonomyRepository.getTermAssignmentsForEntry that each locale still has its terms after the reapply. Read through that helper in the existing tests too, since joining ct.taxonomy_id to t.id only works while each term is its own translation group.

Keep the locale-scoped lookup and the warn-and-skip as they are. Leave the export command and the term read path out of this PR.

@emdash-autofix emdash-autofix Bot removed the triage/awaiting-reporter Fix pushed, waiting on reporter to verify label Oct 29, 2026
@danielmlr

Copy link
Copy Markdown
Contributor

@emdash-autofix

  • Clear a translation group's taxonomy assignments once per seed run, not once per translation. Assignments are stored per translation group, so on onConflict: "update" each translation's clearEntryTerms removes what the translations before it attached. With post-en and post-fr (translationOf: post-en) both listing a term that exists only in en, the update leaves both posts with no category, while main keeps it. With that same pair and separate en and fr guides terms, the English post loses its category. Keep a Set of cleared groups in applySeedWrites, keyed on existing.translationGroup ?? existing.id, pass it into applyContentTaxonomies, and clear only when the group isn't in it yet. Then attach each translation's terms on top.
  • Add a regression test for it: a translated pair, applied and then reapplied with onConflict: "update", checking through TaxonomyRepository.getTermAssignmentsForEntry that each locale still has its terms after the reapply. Read through that helper in the existing tests too, since joining ct.taxonomy_id to t.id only works while each term is its own translation group.

Keep the locale-scoped lookup and the warn-and-skip as they are. Leave the export command and the term read path out of this PR.

@emdash-autofix

Copy link
Copy Markdown
Contributor Author

Confirmed both update regressions with the translated-pair tests: English-only and separate English/French terms lost assignments before the change. The importer now tracks cleared translation groups once per applySeedWrites call, then accumulates each translation's terms. Tests read through getTermAssignmentsForEntry, including linked term translations, and verify that removing all references still clears the group. Locale-scoped lookup and warn-and-skip are unchanged; export and term reads remain untouched. The 40 focused tests, root build, core typecheck, formatting and quick lint pass.

Addressed the maintainer's update regression by clearing taxonomy assignments once per translation group per collection, then accumulating terms from each translation. Kept locale-scoped lookup and warn-and-skip unchanged. Converted test reads to getTermAssignmentsForEntry and added translated-pair reapplication/clearing and cross-collection ID regressions. Verified 41 focused tests, root build, core typecheck, formatting, quick lint (zero diagnostics), and clean independent follow-up review.

EmDash-Bot-Case: 1198246700-issue-6038274325
EmDash-Bot-Candidate: cand-3-ca73ab7ff2
@emdash-autofix

Copy link
Copy Markdown
Contributor Author

Addressed in candidate cand-3-ca73ab7ff2, submitted for publication. The cleared-group Set is scoped per collection and keyed by existing.translationGroup ?? existing.id; subsequent translations add their terms without clearing again. Regression tests cover English-only, separate and linked translated terms across reapplication, and existing test reads now use getTermAssignmentsForEntry. All 41 focused tests pass. Locale-scoped lookup and warn-and-skip remain unchanged; export and production term reads are untouched.

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach is sound. Seed import now resolves taxonomy slugs in the content entry's locale, matching the public API's assignTaxonomies. Updates use the stored entry locale and fall back to the resolved seed locale when it is null. Both reviewers approved and found no outstanding issues.

The earlier changeset suggestion is addressed. The changeset now explains the warn-and-skip behavior for terms missing in the entry's locale, and how to repair existing wrong-locale assignments with --on-conflict update (which also overwrites other seeded records).

The new fix clears taxonomy assignments once per translation group per collection, so later translations no longer erase earlier translations' terms on update. Tests cover create and update paths, omitted and explicit locales, stored-locale handling for ID-matched entries, translation groups, and terms missing from the entry's locale.

The review was static. Tests, builds and lint were not run, and PostgreSQL and D1 execution are unverified.


Reviewed by anthropic/claude-opus-5-5 and openai/gpt-6.1-sol.

@emdash-autofix emdash-autofix Bot added triage/awaiting-reporter Fix pushed, waiting on reporter to verify and removed triage/awaiting-reporter Fix pushed, waiting on reporter to verify labels Oct 29, 2026
@emdashbot emdashbot Bot added the review/needs-review No maintainer or bot review yet label Oct 29, 2026
@github-actions github-actions Bot removed the review/needs-review No maintainer or bot review yet label Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core bot:fix Assign this issue or pull request to the EmDash bot to fix cla: signed size/L triage/awaiting-reporter Fix pushed, waiting on reporter to verify

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Seed import attaches a category term from the wrong locale: applyContentTaxonomies calls findBySlug without the entry locale

1 participant