W6.1: batch-narrate all 122 documents + magazine titles from body H1
Some checks failed
CI / Web — typecheck + lint + build (push) Failing after 31s
CI / Scripts — Python smoke (push) Failing after 5s
CI / Web — npm audit (push) Failing after 36s
CI / Retrieval — golden set (Recall@5 + MRR) (push) Failing after 3s

User wants every case in the archive documented in the narrated format.
Queued a case_report for all 122 documents (slug = doc_id, scoped to that
doc's chunks). The LISTEN worker drains 2 at a time (~5h, ~$18 OAuth).
5 reports already existed; ~122 new jobs queued, skipping any already
queued/running/complete by slug.

Title rendering: the batch seeds `topic` from the auto-derived
canonical_title ("Doc 18 100754 General 1946 7 Vol 2"), which is ugly as a
headline. The narrator writes a proper magazine H1 in the body, so:
  - /c/[slug]: extract the two body H1s (EN + PT-BR), use the locale one
    as the headline, strip both leading H1s from the rendered body so the
    title isn't duplicated. Falls back to frontmatter topic.
  - case-library.tsx + featured-case.tsx: same H1 extraction for card
    titles, so /bureau and the homepage show real titles not "Doc 18…".
  - featured-case: pin the flagship (green-fireballs-narrative, which has
    a curated hero painting) to the featured slot instead of most-recent,
    so the batch's random completions don't take over the homepage hero.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Luiz Gustavo 2026-05-25 03:54:35 -03:00
parent 0b39495954
commit c1260cfa68
3 changed files with 26 additions and 6 deletions

View file

@ -121,9 +121,18 @@ export default async function CaseReportPage({
const locale = (await getLocale()) === "en" ? "en" : "pt-br"; const locale = (await getLocale()) === "en" ? "en" : "pt-br";
const c = await loadCase(slug); const c = await loadCase(slug);
if (!c) notFound(); if (!c) notFound();
const { fm, body } = c; const { fm } = c;
const title = locale === "pt-br" ? (fm.topic_pt_br ?? fm.topic ?? slug) : (fm.topic ?? slug); // The narrator writes two H1s in the body: "# <Title EN>" then
// "# <Título PT-BR>". Prefer those over the generic frontmatter topic
// (which is often an auto-derived "Doc 18 100754 …"). Pick by locale and
// strip BOTH leading H1s from the body so the headline isn't duplicated.
const h1s = [...c.body.matchAll(/^#\s+(.+)$/gm)].map((m) => m[1].trim());
const bodyTitle = locale === "pt-br" ? (h1s[1] ?? h1s[0]) : h1s[0];
// Strip H1 lines ("# Title") — the "## section" headers survive since the
// regex requires whitespace after a single #. Avoids duplicating the title.
const body = c.body.replace(/^#\s+.+$\n?/gm, "").replace(/^\s+/, "");
const title = bodyTitle ?? (locale === "pt-br" ? (fm.topic_pt_br ?? fm.topic ?? slug) : (fm.topic ?? slug));
const dateLabel = fm.created_at ? new Date(fm.created_at).toLocaleDateString(locale === "pt-br" ? "pt-BR" : "en-US", { day: "numeric", month: "long", year: "numeric" }) : null; const dateLabel = fm.created_at ? new Date(fm.created_at).toLocaleDateString(locale === "pt-br" ? "pt-BR" : "en-US", { day: "numeric", month: "long", year: "numeric" }) : null;
const canonical = `${SITE_URL}/c/${slug}`; const canonical = `${SITE_URL}/c/${slug}`;
const lead = pickLead(body, locale).slice(0, 280); const lead = pickLead(body, locale).slice(0, 280);

View file

@ -93,10 +93,15 @@ async function loadCases(locale: "pt-br" | "en"): Promise<CaseFile[]> {
const md = await readFile(full, "utf-8"); const md = await readFile(full, "utf-8");
const st = await stat(full); const st = await stat(full);
const { fm, body } = parseFrontmatter(md); const { fm, body } = parseFrontmatter(md);
// Prefer the narrator's body H1 (magazine title) over the generic
// auto-derived frontmatter topic. Two H1s: EN then PT-BR.
const h1s = [...body.matchAll(/^#\s+(.+)$/gm)].map((m) => m[1].trim());
const enTitle = h1s[0] ?? fm.topic ?? f;
const ptTitle = h1s[1] ?? h1s[0] ?? fm.topic_pt_br ?? fm.topic ?? f;
items.push({ items.push({
slug: f.replace(/\.md$/, ""), slug: f.replace(/\.md$/, ""),
topic: fm.topic ?? f, topic: enTitle,
topic_pt_br: fm.topic_pt_br ?? null, topic_pt_br: ptTitle,
opening: pickOpening(body, locale), opening: pickOpening(body, locale),
mtimeMs: st.mtimeMs, mtimeMs: st.mtimeMs,
}); });

View file

@ -81,10 +81,11 @@ async function loadFeatured(locale: "pt-br" | "en"): Promise<FeaturedCaseData |
const { fm, body } = parseFrontmatter(md); const { fm, body } = parseFrontmatter(md);
const docRef = extractFirstDocRef(body); const docRef = extractFirstDocRef(body);
const slug = f.replace(/\.md$/, ""); const slug = f.replace(/\.md$/, "");
const h1s = [...body.matchAll(/^#\s+(.+)$/gm)].map((m) => m[1].trim());
items.push({ items.push({
slug, slug,
topic: fm.topic ?? f, topic: h1s[0] ?? fm.topic ?? f,
topic_pt_br: fm.topic_pt_br ?? null, topic_pt_br: h1s[1] ?? h1s[0] ?? fm.topic_pt_br ?? null,
opening: pickOpening(body, locale), opening: pickOpening(body, locale),
hero_doc_id: docRef?.doc_id ?? null, hero_doc_id: docRef?.doc_id ?? null,
hero_page: docRef?.page ?? null, hero_page: docRef?.page ?? null,
@ -92,6 +93,11 @@ async function loadFeatured(locale: "pt-br" | "en"): Promise<FeaturedCaseData |
mtimeMs: st.mtimeMs, mtimeMs: st.mtimeMs,
}); });
} }
// Pin a flagship to the featured slot (it has a curated hero painting).
// Falls back to most-recent if the flagship isn't present.
const FLAGSHIP = "green-fireballs-narrative";
const flagship = items.find((i) => i.slug === FLAGSHIP);
if (flagship) return flagship;
items.sort((a, b) => b.mtimeMs - a.mtimeMs); items.sort((a, b) => b.mtimeMs - a.mtimeMs);
return items[0] ?? null; return items[0] ?? null;
} catch { } catch {