Fix Indonesian newsletters delivering raw JSON and add language preview tabs - #1055
Merged
Merged
Conversation
…ew tabs Point length was a hard document rule, so a translated point over 100 characters invalidated the whole body. Delivery then fell through the template's legacy plain-text branch and mailed the JSON blob while still reporting success. Format is now the contract and length is generation-time guidance: the schema validates structure only, the translation prompt tags each point with its budget, translateNewsletter validates what it rebuilds, and delivery skips a translation that fails validation instead of mailing it. Adds badged per-language Email Preview tabs to the newsletter detail page, backed by two generic table-v1 features: tab badges and visibleWhen. Closes #1054
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
Indonesian subscribers were receiving the raw JSON newsletter document instead of a formatted email. A translated summary point that ran past 100 characters invalidated the entire body, and the template's legacy plain-text fallback then mailed the blob verbatim while delivery still recorded success. This separates format from length, and adds badged per-language Email Preview tabs to the newsletter detail page so the translated rendering is visible in Hermes.
Related issues
Closes #1054
Important changes
MAX_POINT_LENGTHno longer invalidates a document.newsletterDocumentSchemanow checks format only: version, canonical section keys, non-empty strings, http(s) URLs, points-per-article, articles-per-section. The per-point character cap moves out. A slightly long point is a wording problem, not a corrupt body, and no longer costs a subscriber their newsletter.translateNewsletternow runs the rebuilt document throughnewsletterDocumentSchemaand throwsTranslateNewsletterErrorwith the failing paths, so a malformed translation cannot reach the database. It also tags each point in the prompt with(max 100 chars)and tells the model Indonesian runs longer, so length stays steered where the model can act on it. Titles stay untagged since the schema does not cap them.skipped_invalid_translationand logs a warning. Behaviour for a missing translation is unchanged, and English is still never substituted for anidsubscriber.table-v1contract features.detailBlockTabSchemagains an optionalbadge(label plus variant) andvisibleWhen, a rule in the existingsectionRule.whenlanguage. Both are domain-agnostic, so any manifest can use them. AvisibleWhenthat fails to parse leaves the tab visible, so a bad expression never silently hides content.Email Previewbadgedenandid. Theidtab renders the IndonesianNewsletterTranslationand appears only when one exists, viavisibleWhen: "present(emailPreviewHtmlIndonesian)".Other changes
sections.0.articles.0.url: URL must use http or https.renderEmailPreviewaccepts alanguageand passes it to the email template, so theidpreview renders with Indonesian chrome rather than English.map-badge-variant.ts.Key files to review
packages/shared/email-templates/src/newsletter/newsletter-document.ts- the format/length split.MAX_POINT_LENGTHis still exported and still used, just not as a validation rule.apps/mediapulse/agents/content-generation/src/translate-newsletter.ts- prompt budget tags and the pre-persist validation gate.apps/mediapulse/agents/delivery/src/deliver-newsletter.ts- the invalid-translation skip. Worth confirming the skip is the right call versus falling back to English.packages/hermes/domain-contract/src/detail-blocks.ts-badgeandvisibleWhenon the tab schema.apps/hermes/dashboard/components/detail-blocks/detail-block-tabs.tsx- tab filtering and the active-index clamp when a tab disappears.apps/mediapulse/domain-api/src/resources/newsletters/build-translation-preview.ts- returnsnullwhen no translation exists, which is what drives tab visibility.How to test
pnpm code-qualityfrom the repo root. All 108 tasks pass, Prettier clean.user_ticker.language = 'id'for a ticker with a generated newsletter.Email PreviewenandEmail Previewid; theidtab renders a formatted Indonesian email, not a JSON dump.entab is present.urltojavascript:alert(1). The preview should name the failing field, and delivery should skip that recipient withskipped_invalid_translation.