Store category prompts as EXACT split legacy text, no boilerplate

The per-category prompt editor showed English machine boilerplate
("Role: description. Build JSON …", schema intro, {{var}} context lines)
because seed/sync baked the render framing into categories.prompt. Now the
stored overlay is exactly the legacy wp_product_categories.sql content,
split into the three sections a user would type themselves:

  --- Title ---        Slovenian naming formula
  --- Description ---  legacy <H2>/<p>/<ul> body structure
  --- Meta ---         legacy metaDescription instruction

Schema, role framing, and Name/Description/Category/Attrs product context
stay render-time only (system template + ensureCategoryEnhanceUserContext),
where they already existed.

- SplitLegacyCombinedEnhancePrompt: non-legacy input now returns "" —
  categories without seed/legacy content get their override CLEARED
  (company default) instead of being stuffed with the canonical template
  (e.g. parent categories like "Bela tehnika" absent from the SQL).
- CategoryEnhancePromptNeedsRepair flags stored boilerplate ("parsed as
  JSON", "Build JSON", retired Attributes section) so Sync rewrites old
  data to the clean shape; repair supports clearing (prompt = '{}').
- seed-a1 apply-category-prompts skips instead of writing template text.
- Web editor compose stores only the user's section text: empty sections
  keep bare markers, default bodies and the default preamble are never
  persisted (DEFAULT_SECTION_BODIES removed).
- Verified locally: apply rewrote 238 A1+Demo categories (216 exact
  splits, 22 cleared), zero boilerplate matches in DB, idempotent re-run
  (would_update=0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 00:53:26 +02:00
co-authored by Claude Fable 5
parent 0eef202f56
commit 9a839d6d13
13 changed files with 182 additions and 157 deletions
+7 -3
View File
@@ -188,7 +188,8 @@ func applyCategoryPrompts(ctx context.Context, pg *pgxpool.Pool, companyID uuid.
byNorm := make(map[string]string, len(file.Entries))
byUnique := make(map[string]string, len(file.Entries))
// Overlay: split each legacy combined Name+Description prompt into role-sectioned
// enhance USER text (Title / Description / Meta / Attributes). Unique title /
// enhance USER text (Title / Description / Meta) holding exactly the legacy
// per-category text — no schema/role boilerplate. Unique title /
// description / meta formulas stay in title_template / description_template.
// Stored under "sl" + "*" so prompt->>'sl' and LangPromptAny both resolve;
// language stays via {{language}}.
@@ -207,10 +208,13 @@ func applyCategoryPrompts(ctx context.Context, pg *pgxpool.Pool, companyID uuid.
}
if aiprompts.IsLegacyCombinedEnhancePrompt(raw) {
canonical = prepareCategoryPrompt(aiprompts.SplitLegacyCombinedEnhancePrompt(raw))
} else if aiprompts.CategoryEnhanceHasRoleSections(raw) {
} else if aiprompts.CategoryEnhanceHasRoleSections(raw) && !aiprompts.CategoryEnhancePromptNeedsRepair(raw) {
canonical = prepareCategoryPrompt(raw)
} else {
canonical = prepareCategoryPrompt(aiprompts.CategoryEnhanceUserTemplate)
// No usable per-category content — never store template boilerplate;
// the category keeps the company default.
out.Skipped++
continue
}
if canonical == "" {
out.Skipped++