Merge remote-tracking branch 'origin/main' into refactor/task-15f-full-guide-restore

This commit is contained in:
Marcos Paulo
2026-09-06 00:11:17 +00:00
2 changed files with 25 additions and 6 deletions
+24 -3
View File
@@ -2,6 +2,7 @@
// Compare the *rendered* text of a legacy page against its Astro replacement. // Compare the *rendered* text of a legacy page against its Astro replacement.
// //
// node .agents/scripts/rendered-text-diff.mjs full-guide // node .agents/scripts/rendered-text-diff.mjs full-guide
// node .agents/scripts/rendered-text-diff.mjs full-guide --pt
// //
// Why this exists: scripts/verify.mjs reads the legacy files, so a migrated // Why this exists: scripts/verify.mjs reads the legacy files, so a migrated
// page can drop half its content and still pass the gate. Task 15d shipped // page can drop half its content and still pass the gate. Task 15d shipped
@@ -26,9 +27,15 @@ import { chromium } from 'playwright';
// directory of its own, so it needs a different path on the legacy side. // directory of its own, so it needs a different path on the legacy side.
const route = process.argv[2]; const route = process.argv[2];
if (!route) { if (!route) {
console.error('usage: rendered-text-diff.mjs <route> e.g. full-guide, or index'); console.error('usage: rendered-text-diff.mjs <route> [--pt] e.g. full-guide, or index');
process.exit(2); process.exit(2);
} }
// `--pt` clicks the language toggle on both pages first. English parity is
// only half the contract: a page can render every English string and still
// leave a restored block untranslated, because the Portuguese half is a
// separate set of nodes. Only /full-guide/ and /rules/ have a toggle.
const portuguese = process.argv.includes('--pt');
const legacyPath = route === 'index' ? 'index.html' : `${route}/index.html`; const legacyPath = route === 'index' ? 'index.html' : `${route}/index.html`;
const astroPath = route === 'index' ? '' : `${route}/`; const astroPath = route === 'index' ? '' : `${route}/`;
@@ -74,6 +81,12 @@ try {
// The islands hydrate and render their initial panel on load; without this // The islands hydrate and render their initial panel on load; without this
// every panel's copy reads as missing. // every panel's copy reads as missing.
await page.waitForTimeout(1200); await page.waitForTimeout(1200);
if (portuguese) {
const toggle = await page.$('[data-lang="pt"]');
if (!toggle) throw new Error(`no language toggle on ${url}`);
await toggle.click();
await page.waitForTimeout(1200);
}
const spans = await page.evaluate(visibleText); const spans = await page.evaluate(visibleText);
await page.close(); await page.close();
return spans; return spans;
@@ -86,11 +99,19 @@ try {
const rendered = new Set(astro); const rendered = new Set(astro);
const missing = legacy.filter((span) => !rendered.has(span)); const missing = legacy.filter((span) => !rendered.has(span));
// Both directions. A string the Astro page paints and the legacy page does
// not is just as wrong: it means a translation was invented, or an English
// string was left standing where the legacy page swaps it.
const legacySpans = new Set(legacy);
const extra = astro.filter((span) => !legacySpans.has(span));
const mode = portuguese ? 'pt' : 'en';
console.log( console.log(
`legacy ${legacy.length} spans · astro ${astro.length} spans · missing ${missing.length}`, `${mode} · legacy ${legacy.length} spans · astro ${astro.length} spans · missing ${missing.length} · extra ${extra.length}`,
); );
for (const span of missing) console.log(` - ${span}`); for (const span of missing) console.log(` - ${span}`);
process.exitCode = missing.length === 0 ? 0 : 1; for (const span of extra) console.log(` + ${span}`);
process.exitCode = missing.length === 0 && extra.length === 0 ? 0 : 1;
} finally { } finally {
stop(); stop();
} }
+1 -3
View File
@@ -56,7 +56,6 @@
"skillReadSkill": "READ SKILL ↗", "skillReadSkill": "READ SKILL ↗",
"skillReadSkillPt": "LER SKILL ↗", "skillReadSkillPt": "LER SKILL ↗",
"skillTriggerLabel": "TRIGGER", "skillTriggerLabel": "TRIGGER",
"skillTriggerLabelPt": "GATILHO",
"copyStatus": "Prompt copied.", "copyStatus": "Prompt copied.",
"copyStatusPt": "Prompt copiado.", "copyStatusPt": "Prompt copiado.",
"copyFallback": "Select the text manually.", "copyFallback": "Select the text manually.",
@@ -118,8 +117,7 @@
"stageOpenSourcePt": "ABRIR FONTE ↗", "stageOpenSourcePt": "ABRIR FONTE ↗",
"skillReadSkill": "LER SKILL ↗", "skillReadSkill": "LER SKILL ↗",
"skillReadSkillPt": "LER SKILL ↗", "skillReadSkillPt": "LER SKILL ↗",
"skillTriggerLabel": "TRIGGER", "skillTriggerLabel": "GATILHO",
"skillTriggerLabelPt": "GATILHO",
"copyStatus": "Prompt copied.", "copyStatus": "Prompt copied.",
"copyStatusPt": "Prompt copiado.", "copyStatusPt": "Prompt copiado.",
"copyFallback": "Select the text manually.", "copyFallback": "Select the text manually.",