- Category enhance prompts (Sync A1 / seed-a1 / repair) now use the same three role sections as the rest of the platform: Title / Description / Meta. The retired "--- Attributes ---" role section is removed from the canonical template, the legacy-split overlay, and the web prompt editor; Category/Attrs stay as plain product-context lines (attribute extraction remains pipeline-level via AppendAttributeConstraints). - Stored prompts still carrying an attributes section are detected by CategoryEnhancePromptNeedsRepair and rewritten on the next Sync. - Legacy wp_product_categories.sql splits now also seed a default Slovenian metaTitle rule (dumps only carried <metaDescription>), so every A1 category gets all four prompt areas: title formula, description sections, meta title, meta description. - Role-sectioned prompts no longer imply the A1 SEO-omit cohort (CompanyOmitsSEOMeta): sectioned prompts are the canonical prompt-editor output for every tenant, and the sniff silently disabled SEO meta for any company that saved a category prompt. - Verified locally: repair-category-prompts -apply updated 238 A1 + Platform Demo categories from scripts/seed/wp_product_categories.sql (216 legacy splits), idempotent on re-run, zero attributes sections left in DB. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
90 lines
2.9 KiB
Go
90 lines
2.9 KiB
Go
// Command repair-category-prompts rewrites A1 / Platform Demo categories.prompt
|
|
// values into aiprompts role-sectioned overlays (Title / Description / Meta).
|
|
// Prefers wp_product_categories.sql (SEED_A1_WP_CATEGORIES /
|
|
// scripts/seed) as source of truth, else a1-category-prompts.json. Legacy combined
|
|
// Slovenian name+description blobs are split so naming rules land under Title
|
|
// and HTML under Description; otherwise CategoryEnhanceUserTemplate is used.
|
|
// Also repairs empty or brand-only title_template and empty description_template
|
|
// from legacy <name> / HTML / meta rules (never brand-only).
|
|
//
|
|
// Usage (from apps/api):
|
|
//
|
|
// go run ./cmd/repair-category-prompts -dry-run
|
|
// go run ./cmd/repair-category-prompts -apply
|
|
// go run ./cmd/repair-category-prompts -apply -wp-categories ../../scripts/seed/wp_product_categories.sql
|
|
// go run ./cmd/repair-category-prompts -apply -prompts ../../scripts/seed/a1-category-prompts.json
|
|
//
|
|
// DATABASE_URL / -postgres required. Default is dry-run (count only).
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/descrybe/descrybe-v2/apps/api/internal/catalog"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
func main() {
|
|
postgresURL := flag.String("postgres", os.Getenv("DATABASE_URL"), "Postgres URL (DATABASE_URL)")
|
|
dryRun := flag.Bool("dry-run", true, "count rows that would update (default true)")
|
|
apply := flag.Bool("apply", false, "write updates (implies not dry-run)")
|
|
promptsPath := flag.String("prompts", "", "path to a1-category-prompts.json (optional fallback)")
|
|
wpPath := flag.String("wp-categories", os.Getenv("SEED_A1_WP_CATEGORIES"), "path to wp_product_categories.sql (preferred source of truth)")
|
|
flag.Parse()
|
|
|
|
if strings.TrimSpace(*postgresURL) == "" {
|
|
log.Fatal("-postgres / DATABASE_URL is required")
|
|
}
|
|
doDryRun := *dryRun
|
|
if *apply {
|
|
doDryRun = false
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
|
defer cancel()
|
|
|
|
pg, err := pgxpool.New(ctx, *postgresURL)
|
|
if err != nil {
|
|
log.Fatalf("postgres: %v", err)
|
|
}
|
|
defer pg.Close()
|
|
|
|
opts := catalog.RepairA1DemoOptions{
|
|
SeedPromptsPath: strings.TrimSpace(*promptsPath),
|
|
WPCategoriesPath: strings.TrimSpace(*wpPath),
|
|
}
|
|
|
|
// Always print dry-run counts first when applying, so operators see the delta.
|
|
preview, err := catalog.RepairA1DemoCategoryEnhancePromptsWithOptions(ctx, pg, true, opts)
|
|
if err != nil {
|
|
log.Fatalf("dry-run: %v", err)
|
|
}
|
|
printResult("dry-run", preview)
|
|
|
|
if doDryRun {
|
|
return
|
|
}
|
|
|
|
res, err := catalog.RepairA1DemoCategoryEnhancePromptsWithOptions(ctx, pg, false, opts)
|
|
if err != nil {
|
|
log.Fatalf("apply: %v", err)
|
|
}
|
|
printResult("apply", res)
|
|
}
|
|
|
|
func printResult(phase string, res catalog.RepairCategoryEnhancePromptsResult) {
|
|
b, err := json.MarshalIndent(res, "", " ")
|
|
if err != nil {
|
|
log.Printf("%s: %+v", phase, res)
|
|
return
|
|
}
|
|
fmt.Printf("%s:\n%s\n", phase, string(b))
|
|
}
|