diff --git a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-progress.css b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-progress.css index aa4ced86f7..9c805f1343 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-progress.css +++ b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-progress.css @@ -68,10 +68,10 @@ .research-effect-citations button:hover { text-decoration: underline; } .research-native-results { border-block-start: 1px solid var(--pw-line); margin-block-start: 16px; padding-block-start: 16px; } .research-native-results h4 { margin: 0; font-size: var(--text-body); font-weight: 600; } -.research-native-results > p { margin-block: 8px; } -.research-native-reading { display: flex; align-items: center; flex-wrap: wrap; gap: 16px 48px; margin-block: 16px; } -.research-native-best { min-width: 0; } -.research-native-reading dl { margin: 0; } +.research-native-heading { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 16px; } +.research-native-reading { display: flex; align-items: baseline; flex-wrap: wrap; gap: 12px 32px; margin-block: 12px 4px; } +.research-native-reading > div { min-width: 0; max-width: 100%; } +.research-native-reading > .research-native-best { margin-inline-end: 24px; } .research-native-reading dt { font-size: var(--text-body); color: var(--pw-muted); } .research-native-reading dd { margin: 4px 0 0; } .research-native-reading dd button { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 8px; max-width: 100%; min-height: 44px; padding: 0; font: inherit; background: none; border: 0; color: var(--pw-text); text-align: start; cursor: pointer; } @@ -79,12 +79,14 @@ .research-native-reading dd button svg { align-self: center; flex-shrink: 0; color: var(--pw-muted); } .research-native-reading dd button:hover strong { text-decoration: underline; } .research-native-reading dd button:focus-visible { outline: 2px solid var(--pw-blue); outline-offset: 2px; } -.research-native-reading strong { font-weight: 600; font-variant-numeric: tabular-nums; font-size: var(--text-lead); } -.research-native-best strong { font-size: var(--text-display); line-height: var(--leading-title); } +.research-native-reading strong { font-weight: 600; font-variant-numeric: tabular-nums; font-size: var(--text-title); line-height: var(--leading-title); } +.research-native-best strong { font-size: var(--text-display); } .research-native-unit { font-size: var(--text-body); color: var(--pw-muted); } -.research-native-best > p { margin: 4px 0 0; font-size: var(--text-body); } -.research-native-context { display: flex; align-items: baseline; flex-wrap: wrap; gap: 12px 32px; } -.research-native-context > div { min-width: 0; } +.research-progress .research-native-metric { margin: 0; font-size: var(--text-body); } +.research-native-footer { display: flex; align-items: flex-start; flex-wrap: wrap; gap: 0 24px; } +.research-native-footer .research-native-scope { align-items: center; min-height: 44px; } +.research-native-footer .research-native-basis { min-width: 0; } +.research-native-footer .research-native-basis[open] { flex-basis: 100%; } .research-native-unknown { display: inline-block; padding-block: 10px; font-size: var(--text-body); color: var(--pw-muted); } .research-native-scope { display: flex; flex-wrap: wrap; gap: 4px 16px; color: var(--pw-muted); font-size: var(--text-body); } .research-native-basis dd { margin: 4px 0 12px; } @@ -131,8 +133,8 @@ .research-progress select { max-width: 100%; } .research-effect-metrics { gap: 8px; } .research-assessment > summary { gap: 8px; } - .research-native-reading { align-items: flex-start; flex-direction: column; gap: 20px; } - .research-native-context { gap: 12px 24px; } + .research-native-reading { gap: 12px 16px; } + .research-native-reading > .research-native-best { flex-basis: 100%; margin-inline-end: 0; } .research-progress-values { grid-template-columns: 1fr; gap: 16px; } .research-request-values { grid-template-columns: 1fr; } .research-usage-basis { grid-template-columns: 1fr; gap: 4px; } diff --git a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-progress.tsx b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-progress.tsx index 1210ffdf9f..31620438bd 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-progress.tsx +++ b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-progress.tsx @@ -143,23 +143,21 @@ function NativeResults({native, zh, onCitation}: {native: ResearchProgressPack[" ...(new Date(outcomes.start).getUTCFullYear() !== new Date(outcomes.end).getUTCFullYear() ? {year: "numeric"} : {})}); const value = ([key, cn, en]: typeof points[number]) => { const point = outcomes[key]; - return
{zh ? cn : en}
{point ? + return
{zh ? cn : en}
{point ? : {zh ? "未知" : "Unknown"}{key === "best_valid" ? · {outcomes.metric.unit} : null}}
; }; return
-

{historical ? (zh ? "历史原生测量" : "Historical native measurements") : (zh ? "原生测量" : "Native measurements")}

{historical ? (zh ? "历史原生测量" : "Historical native measurements") : (zh ? "原生测量" : "Native measurements")}

{historical ?

{zh ? "来源已变化或不可读;以下仅为历史捕获,当前结果未核验。" : "The source changed or is unavailable. These are historical captures; current results are unverified."}

: null}

{zh ? "最佳只限本次捕获窗口;原生保留与最后提交可能不同。未采集的值保留未知,不记零。" : "Best is limited to this capture; retained and final submissions can differ. Uncaptured values remain unknown, not zero."}

{zh ? "检验过收益、采用了证据及原目标达成各需各自证据,不能由这些数值推断。" : "Utility testing, evidence adoption and original-objective success each need their own evidence; these values cannot establish them."}

-
-
{value(points[0])}

{outcomes.metric.name} · {outcomes.metric.higher_is_better ? (zh ? "越高越好" : "higher is better") : (zh ? "越低越好" : "lower is better")}

-
{points.slice(1).map(value)}
-
-
{outcomes.valid_count} / {outcomes.sample_count} {zh ? "项有效结果" : "valid results"} +

{outcomes.metric.name} · {outcomes.metric.higher_is_better ? (zh ? "越高越好" : "higher is better") : (zh ? "越低越好" : "lower is better")}

+
{points.map(value)}
+
{outcomes.valid_count} / {outcomes.sample_count} {zh ? "项有效结果" : "valid results"} {period.formatRange(new Date(outcomes.start), new Date(outcomes.end))} UTC {!outcomes.complete ? {zh ? "部分窗口 · 起点未知" : "Partial window · initial unknown"} : null}
@@ -173,7 +171,7 @@ function NativeResults({native, zh, onCitation}: {native: ResearchProgressPack[" return point ?
{zh ? cn : en}
{String(point.value)} {outcomes.metric.unit}
{point.candidate_ref}
{zh ? "提交" : "Submission"} {point.submission_index} · {zh ? "提交时间" : "Submitted at"}: {point.submitted_at ?? (zh ? "未知" : "Unknown")}
{zh ? "收到结果" : "Result received"}: {point.observed_at}
: null; })}
    {outcomes.limitations.map((line, i) =>
  • {line}
  • )}
- +
; } diff --git a/examples/personal-workspace-browser/evidence/research-summary/after-desktop.png b/examples/personal-workspace-browser/evidence/research-summary/after-desktop.png new file mode 100644 index 0000000000..16652f4e0c Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/after-desktop.png differ diff --git a/examples/personal-workspace-browser/evidence/research-summary/after-phone.png b/examples/personal-workspace-browser/evidence/research-summary/after-phone.png new file mode 100644 index 0000000000..34802be5a3 Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/after-phone.png differ diff --git a/examples/personal-workspace-browser/evidence/research-summary/before-desktop.png b/examples/personal-workspace-browser/evidence/research-summary/before-desktop.png new file mode 100644 index 0000000000..f034c7cbe6 Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/before-desktop.png differ diff --git a/examples/personal-workspace-browser/evidence/research-summary/before-phone.png b/examples/personal-workspace-browser/evidence/research-summary/before-phone.png new file mode 100644 index 0000000000..e46015cd40 Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/before-phone.png differ diff --git a/examples/personal-workspace-browser/evidence/research-summary/first-desktop.png b/examples/personal-workspace-browser/evidence/research-summary/first-desktop.png new file mode 100644 index 0000000000..f5f05f37c4 Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/first-desktop.png differ diff --git a/examples/personal-workspace-browser/evidence/research-summary/first-phone.png b/examples/personal-workspace-browser/evidence/research-summary/first-phone.png new file mode 100644 index 0000000000..1fec0878dc Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/first-phone.png differ diff --git a/examples/personal-workspace-browser/evidence/research-summary/long-unit-200-phone.png b/examples/personal-workspace-browser/evidence/research-summary/long-unit-200-phone.png new file mode 100644 index 0000000000..83fee4df23 Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/long-unit-200-phone.png differ diff --git a/examples/personal-workspace-browser/evidence/research-summary/sources-desktop.png b/examples/personal-workspace-browser/evidence/research-summary/sources-desktop.png new file mode 100644 index 0000000000..cbb2947f6e Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/sources-desktop.png differ diff --git a/examples/personal-workspace-browser/evidence/research-summary/sources-phone.png b/examples/personal-workspace-browser/evidence/research-summary/sources-phone.png new file mode 100644 index 0000000000..390619a8b4 Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/sources-phone.png differ diff --git a/examples/personal-workspace-browser/evidence/research-summary/unknown-assessment-phone.png b/examples/personal-workspace-browser/evidence/research-summary/unknown-assessment-phone.png new file mode 100644 index 0000000000..813848575f Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/unknown-assessment-phone.png differ diff --git a/examples/personal-workspace-browser/evidence/research-summary/unknown-native-desktop.png b/examples/personal-workspace-browser/evidence/research-summary/unknown-native-desktop.png new file mode 100644 index 0000000000..ac2cd8e39a Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/unknown-native-desktop.png differ diff --git a/examples/personal-workspace-browser/evidence/research-summary/unknown-native-phone.png b/examples/personal-workspace-browser/evidence/research-summary/unknown-native-phone.png new file mode 100644 index 0000000000..76a1194b75 Binary files /dev/null and b/examples/personal-workspace-browser/evidence/research-summary/unknown-native-phone.png differ diff --git a/examples/personal-workspace-browser/research-history-backend.py b/examples/personal-workspace-browser/research-history-backend.py index 029d679bfd..d9528a98f5 100644 --- a/examples/personal-workspace-browser/research-history-backend.py +++ b/examples/personal-workspace-browser/research-history-backend.py @@ -79,6 +79,8 @@ def main(): original[registry] = registry.read_bytes() # Optional synthetic analysis uses the real pack verifier, process/job # owner and HTTP reader. It never enables model dispatch from the page. + fixture_config = {**DEFAULT_CONFIG, "research_synthesis": False} + fixture_config.pop("research_synthesis_revision", None) for capture in captures: for index, analysis in enumerate(capture.get("analyses", [])): source_root = root / f"analysis-{capture['goal_id']}-{index}" @@ -91,7 +93,7 @@ def main(): input_path.write_text(json.dumps(analysis["input"], ensure_ascii=False)) scope = dict(runtime_root=runtime, owner_goal_id=capture["goal_id"]) registered = register_pack(**scope, input_path=input_path, source_root=source_root, title=analysis["title"], - config=analysis.get("config", {**DEFAULT_CONFIG, "research_synthesis": False}), + config=analysis.get("config", fixture_config), native_outcomes_json=analysis.get("native_outcomes_json")) for language, output in analysis["outputs"].items(): provider = root / f"analysis-provider-{index}-{language}" diff --git a/examples/personal-workspace-browser/research-native-reading.mjs b/examples/personal-workspace-browser/research-native-reading.mjs index db8d99fd30..6bea96cc7f 100644 --- a/examples/personal-workspace-browser/research-native-reading.mjs +++ b/examples/personal-workspace-browser/research-native-reading.mjs @@ -103,6 +103,13 @@ export const researchNativeReadingScenario = { assert.match(await native.locator(".research-native-best .research-native-unit").textContent(), new RegExp(c.unit ?? "points"), "The raw unit remains visible even when no valid measurement exists"); assert.match(await native.locator(".research-native-scope").innerText(), new RegExp(`${c.values.filter(v => v !== null).length} / ${c.values.length}.*有效结果`)); if (c.partial) assert.match(await native.innerText(), /部分窗口 · 起点未知/); + if (c.id === "invalid-first") { + const best = await native.locator('[data-native-point="best_valid"]').boundingBox(); + const retained = await native.locator('[data-native-point="retained"]').boundingBox(); + assert(best.width > retained.width + 8, "An unknown retained result must not reserve an equal primary column beside the best valid measurement"); + await native.evaluate(e => e.scrollIntoView({block: "start"})); + await page.screenshot({path: resolve(outputDir, "research-native-unknown-desktop.png"), animations: "disabled"}); + } await page.setViewportSize({width: 390, height: 844}); const details = native.locator(".research-native-basis"); if (await details.evaluate(e => e.open)) await details.locator(":scope > summary").click(); @@ -122,6 +129,7 @@ export const researchNativeReadingScenario = { await page.screenshot({path: resolve(outputDir, "research-native-source-tail-phone.png"), animations: "disabled"}); } await details.locator(":scope > summary").tap(); + if (c.id === "invalid-first") await page.screenshot({path: resolve(outputDir, "research-native-unknown-phone.png"), animations: "disabled"}); if (c.id === "lower-negative") { const retained = native.getByRole("button", {name: /原生保留结果.*查看原始证据/}); await retained.focus(); await retained.press("Enter");