From 7e82ca346bca3d3d2278e3fcd74214144f37837c Mon Sep 17 00:00:00 2001 From: Cobb04 <134911580+Cobb04@users.noreply.github.com> Date: Tue, 25 Aug 2026 22:44:16 +0800 Subject: [PATCH] fix(reporting): use host-neutral portable HTML copy Replace Codex-specific header, footer, and copy-success text in the shared portable HTML renderer with host-neutral English and Chinese wording. Add generated DSH and cross-host control coverage for Bug #115. Validated with the literal npm run check gate on Node 24.15.0 and the focused renderer suites on Node 22.20.0 and Node 24.15.0. Co-authored-by: Codex (GPT 5.6 Sol) --- .../renderers/html-interactions.mjs | 4 +- scripts/harness-analysis/renderers/html.mjs | 4 +- .../harness-report-render-cli.test.mjs | 56 +++++++++++++++++++ .../html-report-interactions.test.mjs | 4 +- 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/scripts/harness-analysis/renderers/html-interactions.mjs b/scripts/harness-analysis/renderers/html-interactions.mjs index 0faf02ea..33494e74 100644 --- a/scripts/harness-analysis/renderers/html-interactions.mjs +++ b/scripts/harness-analysis/renderers/html-interactions.mjs @@ -265,14 +265,14 @@ export function renderHtmlInteractionScript(language) { ? { copy: "复制 AI 修复", copied: "已复制", - copySuccess: "已复制,请粘贴到 Codex 输入框。", + copySuccess: "已复制,请粘贴到当前 Coding Agent 输入框。", manualCopy: "自动复制被阻止,请手动复制已选中的提示词。", missingPrompt: "这个问题没有可用的 AI 修复提示词。", } : { copy: "Copy AI Fix", copied: "Copied", - copySuccess: "Copied. Paste into the Codex input.", + copySuccess: "Copied. Paste into your coding agent input.", manualCopy: "Automatic copy was blocked. Copy the selected prompt manually.", missingPrompt: "No AI Fix prompt is available for this finding.", }; diff --git a/scripts/harness-analysis/renderers/html.mjs b/scripts/harness-analysis/renderers/html.mjs index 6d1453cd..1eb3d40b 100644 --- a/scripts/harness-analysis/renderers/html.mjs +++ b/scripts/harness-analysis/renderers/html.mjs @@ -580,7 +580,7 @@ function renderHtmlBody(reportData) { return `
- ${renderVisibleText(copy(language, "Harness Insights · Codex HTML", "Harness 洞察 · Codex HTML"), language)} + ${renderVisibleText(copy(language, "Harness Insights · Portable HTML", "Harness 洞察 · 便携式 HTML"), language)}

${renderVisibleText(projectName, language)}

${renderVisibleText(overview, language)}

${renderVisibleText(summary.modelId ?? "Harness", language)}${renderVisibleText(copy(language, "Evidence-bound", "证据有界"), language)}
@@ -656,7 +656,7 @@ export function renderHtml(reportData, actionContext) {
${renderHtmlBody(reportData)} -
${renderVisibleText(copy(reportData.language, "Generated from one reviewed Harness source · self-contained Codex HTML", "由同一份已复核 Harness source 生成 · 自包含 Codex HTML"), language)}
+
${renderVisibleText(copy(reportData.language, "Generated from one reviewed Harness source · self-contained portable HTML", "由同一份已复核 Harness source 生成 · 自包含便携式 HTML"), language)}
diff --git a/test/reporting/harness-report-render-cli.test.mjs b/test/reporting/harness-report-render-cli.test.mjs index 31b932d0..96613c4a 100644 --- a/test/reporting/harness-report-render-cli.test.mjs +++ b/test/reporting/harness-report-render-cli.test.mjs @@ -202,6 +202,14 @@ function embeddedJson(html, id) { return JSON.parse(payload); } +function visibleHtmlText(html) { + return String(html) + .replace(/<(?:script|style)\b[^>]*>[\s\S]*?<\/(?:script|style)>/giu, " ") + .replace(/<[^>]+>/gu, "") + .replace(/\s+/gu, " ") + .trim(); +} + function reviewedTaskLoopSource() { const source = buildTaskLoopSourceCandidate({ scope: { platform: "qoder", workspace: "/tmp/render-source-project" }, @@ -1224,6 +1232,49 @@ test("DSH reuses portable HTML report data, target root, and exact artifact cont }); }); +test("generated DSH HTML uses host-neutral visible copy in both locales", async () => { + await withTempDir("better-harness-dsh-portable-copy-", async (root) => { + const findingsPath = path.join(root, "reviewed.findings.json"); + await writeJson(findingsPath, dshReviewedFindings()); + + for (const row of [{ + language: "en", + eyebrow: "Harness Insights · Portable HTML", + footer: "Generated from one reviewed Harness source · self-contained portable HTML", + copySuccess: "Copied. Paste into your coding agent input.", + oldCopySuccess: "Copied. Paste into the Codex input.", + }, { + language: "zh-CN", + eyebrow: "Harness 洞察 · 便携式 HTML", + footer: "由同一份已复核 Harness source 生成 · 自包含便携式 HTML", + copySuccess: "已复制,请粘贴到当前 Coding Agent 输入框。", + oldCopySuccess: "已复制,请粘贴到 Codex 输入框。", + }]) { + const result = runNode([ + renderPath, + "--findings", findingsPath, + "--mode", "html", + "--platform", "dsh", + "--target", root, + "--run-dir", `copy-${row.language}`, + "--language", row.language, + "--validate", + "--json", + ], { cwd: root }); + + assert.equal(result.status, 0, `${row.language}: ${result.stderr || result.stdout}`); + const payload = parseRun(result.stdout); + const html = readFileSync(path.join(payload.runDir, "report.html"), "utf8"); + const visibleText = visibleHtmlText(html); + assert.equal(visibleText.includes(row.eyebrow), true, row.language); + assert.equal(visibleText.includes(row.footer), true, row.language); + assert.equal(visibleText.includes("Codex"), false, row.language); + assert.equal(html.includes(row.copySuccess), true, row.language); + assert.equal(html.includes(row.oldCopySuccess), false, row.language); + } + }); +}); + test("render routes html output by host id and fails closed on unknown platforms", async () => { await withTempDir("better-harness-render-platform-", async (root) => { const findingsPath = path.join(root, "input.findings.json"); @@ -1238,6 +1289,11 @@ test("render routes html output by host id and fails closed on unknown platforms const payload = parseRun(routed.stdout); assert.equal(payload.outputLocation.requestedOut, `.${platform}/better-harness`); assert.equal(payload.runDir.includes(path.join(`.${platform}`, "better-harness")), true); + const html = readFileSync(path.join(payload.runDir, "report.html"), "utf8"); + const visibleText = visibleHtmlText(html); + assert.equal(visibleText.includes("Harness Insights · Portable HTML"), true, platform); + assert.equal(visibleText.includes("Codex HTML"), false, platform); + assert.equal(html.includes("Paste into the Codex input"), false, platform); } const rejected = runNode( diff --git a/test/reporting/html-report-interactions.test.mjs b/test/reporting/html-report-interactions.test.mjs index 4e02d03d..12f3157d 100644 --- a/test/reporting/html-report-interactions.test.mjs +++ b/test/reporting/html-report-interactions.test.mjs @@ -49,7 +49,7 @@ const ACTION_PROMPT = actionPrompt(); const LABELS = { copy: "Copy AI Fix", copied: "Copied", - copySuccess: "Copied. Paste into the Codex input.", + copySuccess: "Copied. Paste into your coding agent input.", manualCopy: "Automatic copy was blocked. Copy the selected prompt manually.", missingPrompt: "No AI Fix prompt is available for this finding.", }; @@ -421,6 +421,6 @@ test("rendered interaction controller localizes labels without host coupling", ( assert.match(script, /id="harness-report-interactions"/u); assert.match(script, /复制 AI 修复/u); - assert.match(script, /已复制,请粘贴到 Codex 输入框。/u); + assert.match(script, /已复制,请粘贴到当前 Coding Agent 输入框。/u); assert.doesNotMatch(script, /window\.openai|codex:\/\/|chatgpt:\/\//iu); });