Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@
.research-effect-evidence article > span { font-size: var(--text-caption); }
.research-effect-citations { display: flex; flex-wrap: wrap; gap: 4px; }
.research-effect-citations button { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; font: inherit; font-size: var(--text-caption); background: transparent; border: 1px solid var(--pw-line); border-radius: 6px; padding: 4px 8px; color: var(--pw-text); }
.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-caption); font-weight: 600; }
.research-native-results > p { margin-block: 8px; }
.research-native-values { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px 16px; margin-block: 12px; }
.research-native-values > div { min-width: 0; }
.research-native-values dt, .research-native-values dd > span { font-size: var(--text-caption); color: var(--pw-muted); }
.research-native-values dd { margin: 0; }
.research-native-values dd button { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0; font: inherit; background: none; border: 0; color: var(--pw-text); cursor: pointer; }
.research-native-values dd button:hover { text-decoration: underline; }
.research-native-values dd button:focus-visible { outline: 2px solid var(--pw-blue); outline-offset: 2px; }
.research-native-basis dd { margin: 4px 0 12px; }
.research-native-values strong { font-size: var(--text-body); font-weight: 600; font-variant-numeric: tabular-nums; }
.research-native-values small { display: block; }
.research-native-basis { font-size: var(--text-caption); }
.research-progress-basis > dl, .research-usage-basis { display: grid; grid-template-columns: 120px minmax(0, 1fr); gap: 8px 16px; font-size: var(--text-caption); }
.research-progress-basis dt, .research-usage-basis dt { color: var(--pw-muted); }
.research-progress-basis dd, .research-usage-basis dd { margin: 0; }
Expand All @@ -35,6 +49,7 @@
.research-progress label { flex-direction: column; align-items: stretch; width: 100%; }
.research-progress select { max-width: 100%; }
.research-effect-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 16px; }
.research-native-values { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.research-progress-values { grid-template-columns: 1fr; }
.research-progress-basis > dl, .research-usage-basis { grid-template-columns: 1fr; gap: 4px; }
.research-progress-basis dd, .research-usage-basis dd { margin-bottom: 8px; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,39 @@ export function verdictLabel(metric: TrajectoryMetric, verdict: AssessmentVerdic
return verdict === "yes" ? (zh ? "有依据" : "Supported") : (zh ? "未建立" : "Not established");
}

// Format the native owner's existing projection, without deriving a gain,
// deciding adoption, or borrowing values from another pack.
function NativeResults({native, zh, onCitation}: {native: ResearchProgressPack["native_outcomes"]; zh: boolean; onCitation: (citation: AssessmentCitation, origin?: HTMLButtonElement) => void}) {
const outcomes = native?.projection;
if (!native || !outcomes) return <p className="research-native-empty">{zh ? "原生测量:尚无同范围捕获;分析器判读不能补成实际收益。" : "Native measurements: no capture for this scope. Analyzer judgments cannot supply realized utility."}</p>;
const historical = native.applicability === "historical";
const points = [["initial", "首次提交", "Initial submission"], ["best_valid", "窗口内最佳有效值", "Best valid in capture"], ["retained", "原生保留结果", "Native retained result"], ["final_valid", "最后有效提交", "Final valid submission"]] as const;
return <section className="research-native-results" aria-label={zh ? "原生测量" : "Native measurements"}>
<h4>{historical ? (zh ? "历史原生测量" : "Historical native measurements") : (zh ? "原生测量" : "Native measurements")}</h4>
{historical ? <p className="research-progress-warning" role="status">{zh ? "来源已变化或不可读;以下仅为历史捕获,当前结果未核验。" : "The source changed or is unavailable. These are historical captures; current results are unverified."}</p> : null}
<p>{outcomes.metric.name} · {outcomes.metric.unit} · {outcomes.metric.higher_is_better ? (zh ? "越高越好" : "higher is better") : (zh ? "越低越好" : "lower is better")} · {outcomes.valid_count} / {outcomes.sample_count} {zh ? "项有效结果" : "valid results"}</p>
<p>{outcomes.complete ? (zh ? "声明为完整前缀" : "Declared complete prefix") : (zh ? "部分窗口,起点未知" : "Partial window; initial unknown")} · <time dateTime={outcomes.start}>{outcomes.start}</time> — <time dateTime={outcomes.end}>{outcomes.end}</time></p>
<dl className="research-native-values">{points.map(([key, cn, en]) => {
const point = outcomes[key];
return <div key={key} data-native-point={key}><dt>{zh ? cn : en}</dt><dd>{point ? <>
<button type="button" onClick={event => onCitation(point.citation, event.currentTarget)} aria-label={`${zh ? cn : en}: ${String(point.value)} · ${zh ? "查看原始证据" : "Read original evidence"}`}><strong>{String(point.value)}</strong><ArrowUpRight size={13} aria-hidden/></button>
<small>{zh ? "提交" : "Submission"} {point.submission_index}</small>
</> : <span>{zh ? "— 未知,不记零" : "— Unknown, not zero"}</span>}</dd></div>;
})}</dl>
<p>{zh ? "最佳只限上述窗口;原生保留与最后提交可能不同。检验过收益、采用了证据及原目标达成各需各自证据,不能由这些数值推断。" : "Best is limited to this capture; retained and final submissions can differ. Utility testing, evidence adoption and original-objective success each need their own evidence."}</p>
<details className="research-native-basis"><summary>{zh ? "测量来源与限制" : "Measurement sources and limits"}</summary>
<p>{native.artifact}<br/><code>{native.artifact_sha256}</code></p>
<dl>{points.map(([key, cn, en]) => {
const point = outcomes[key];
return point ? <div key={key}><dt>{zh ? cn : en}</dt><dd><code>{point.candidate_ref}</code><br/>{zh ? "提交" : "Submitted"}: {point.submitted_at}<br/>{zh ? "收到结果" : "Result received"}: {point.observed_at}</dd></div> : null;
})}</dl>
<ul>{outcomes.limitations.map((line, i) => <li key={i}>{line}</li>)}</ul>
</details>
</section>;
}

export function ResearchProgress({pack: p, packs, selectedId, error, zh, onSelect, onCitation}: {pack: ResearchProgressPack | null; packs: Pick<ResearchProgressPack, "pack_id" | "title">[]; selectedId: string; error: string; zh: boolean; onSelect: (id: string) => void; onCitation: (citation: AssessmentCitation, origin?: HTMLButtonElement) => void}) {
const measured = p?.solver_usage, usage = measured?.projection, result = p?.result;
const native = p?.native_outcomes, outcomes = native?.projection;
const number = (n: number) => new Intl.NumberFormat(zh ? "zh-CN" : "en", {maximumFractionDigits: 1}).format(n);
const percent = (n: number) => new Intl.NumberFormat(zh ? "zh-CN" : "en", {style: "percent", maximumFractionDigits: 0}).format(n);
const duration = (s: number) => `${number(s / 60)} ${zh ? "分钟" : "min"}`;
Expand Down Expand Up @@ -70,21 +100,12 @@ export function ResearchProgress({pack: p, packs, selectedId, error, zh, onSelec
</div>
<p>{zh ? "六项分别判断,不合成总分、成功率或原生收益。" : "Six separate judgments, not a total score, success rate or native utility."}</p>
</div> : <p className="research-effect-empty" role="status">{zh ? "此范围尚无分析器判读。已有用量不能替代效果;按需深度分析后在此展示。" : "No analyzer judgments exist for this scope. Usage is not effectiveness; requested deep analysis will appear here."}</p>}
<NativeResults native={p.native_outcomes} zh={zh} onCitation={onCitation}/>
<details className="research-progress-basis"><summary>{zh ? "来源、方法与覆盖" : "Sources, method and coverage"}</summary><dl>
<dt>{zh ? "题目 / 运行" : "Case / run"}</dt><dd>{p.scope.case_id}<br/>{p.scope.run_id}</dd><dt>{zh ? "证据窗口" : "Evidence window"}</dt><dd>{p.scope.window}</dd><dt>{zh ? "取样规则" : "Selection rule"}</dt><dd>{p.selection.rule}</dd>
<dt>{zh ? "总体研究片段数" : "Population of episodes"}</dt><dd>{p.selection.population_episodes == null ? (zh ? "未知" : "Unknown") : number(p.selection.population_episodes)}</dd>
{result ? <><dt>{zh ? "分析方法" : "Analysis method"}</dt><dd>{result.method_version} · {zh ? "Agent 判读未校准" : "Uncalibrated Agent judgment"}</dd><dt>{zh ? "结果标识" : "Result key"}</dt><dd><code>{result.analysis_key}</code></dd><dt>{zh ? "分析限制" : "Limitations"}</dt><dd>{result.limitations.map((line, i) => <p key={i}>{line}</p>)}</dd></> : null}
<dt>{zh ? "来源版本" : "Source revision"}</dt><dd><code>{p.scope.revision}</code></dd>
<dt>{zh ? "原生结果" : "Native outcomes"}</dt><dd>{outcomes ? <>
<p>{outcomes.metric.name} · {outcomes.metric.unit} · {outcomes.metric.higher_is_better ? (zh ? "越高越好" : "higher is better") : (zh ? "越低越好" : "lower is better")}</p>
<p>{outcomes.start} — {outcomes.end} · {outcomes.complete ? (zh ? "声明为完整前缀" : "Declared complete prefix") : (zh ? "部分窗口,起点未知" : "Partial window; initial unknown")} · {outcomes.valid_count} / {outcomes.sample_count} {zh ? "项有效结果" : "valid results"}</p>
<dl>{([ ["initial", "首次提交", "Initial submission"], ["best_valid", "窗口内最佳有效值", "Best valid in capture"], ["retained", "原生保留结果", "Native retained result"], ["final_valid", "最后有效提交", "Final valid submission"] ] as const).map(([key, cn, en]) => {
const point = outcomes[key];
return <div key={key}><dt>{zh ? cn : en}</dt><dd>{point ? <>{String(point.value)} · {point.candidate_ref} <button type="button" onClick={event => onCitation(point.citation, event.currentTarget)}>{zh ? "查看原始证据" : "Read original evidence"}</button></> : (zh ? "— 未知,不记零" : "— Unknown, not zero")}</dd></div>;
})}</dl>
{native?.applicability === "historical" ? <p role="status">{zh ? "原生来源已变化或不可读;仅保留历史捕获,当前结果未核验。" : "Native source changed or is unavailable; retained historical capture, current results unverified."}</p> : null}
<p>{zh ? "原生测量与分析器判断分开。有效性和保留选择来自提供方,不认证研究因果收益;用量窗口独立,不补算达标成本或全程账单。" : "Native measurements are separate from analyzer judgments. Validity and retention are provider-recorded, not causal benefit. Usage has its own window; threshold and total-study costs are not inferred."}</p>
</> : (zh ? "— 尚无同范围的原生结果捕获;不能从分析器判断或用量补算。" : "— No native capture for this scope; analyzer judgments and usage cannot supply it.")}</dd>
</dl></details>
<details className="research-usage"><summary>{zh ? "用量与成本" : "Usage and cost"}{usage ? ` · ${zh ? "捕获跨度" : "Captured elapsed"} ${duration(usage.elapsed_seconds)}` : ` · ${zh ? "尚无完整用量捕获" : "No complete usage capture"}`}{measured?.applicability === "historical" ? (zh ? " · 历史捕获" : " · Historical capture") : ""}</summary>
<p>{zh ? "只读捕获,窗口可能与以上判读片段及下方 Explore 历史不同。" : "Read-only capture; its window can differ from the judgments above and Explore history below."}</p>
Expand Down
36 changes: 24 additions & 12 deletions examples/personal-workspace-browser/research-history.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function analysisReadback(selected = "a") {
...(["a", "b", "d"].includes(selected) ? {native_outcomes: {artifact: "native-outcomes.json", artifact_sha256: "9".repeat(64),
applicability: selected === "b" ? "historical" : "current", reason_code: selected === "b" ? "source_changed" : null,
projection: {method: "source_bound_native_outcomes_v1", scope, start: "2026-01-01T00:00:00Z", end: "2026-01-01T00:10:00Z",
complete: true, metric: {name: "error", unit: "points", higher_is_better: false}, sample_count: 3, valid_count: 2,
complete: selected !== "d", metric: {name: "error", unit: "points", higher_is_better: false}, sample_count: 3, valid_count: 2,
...Object.fromEntries(["initial", "best_valid", "retained", "final_valid"].map(key => [key, {submission_index: key === "initial" ? 1 : 3,
result_id: key === "initial" ? "native-initial" : "native-final", candidate_ref: key === "initial" ? "candidate-first" : "candidate-retained",
submitted_at: "2026-01-01T00:01:00Z", observed_at: "2026-01-01T00:02:00Z", value: key === "initial" ? 7 : 3,
Expand All @@ -46,7 +46,13 @@ function analysisReadback(selected = "a") {
{metric: 'redundancy', verdict: 'no', reason: 'Synthetic evidence records a new question rather than repeating a settled result.'}
].map(item => ({...item, episode_id: 'episode', citations: [{source_id: 'source', first_line: 1, last_line: 2}]}))]},
}};
if (selected === "d") {snapshot.pack.result = null; snapshot.pack.job = null;}
if (selected === "b") {
snapshot.pack.native_outcomes.projection.sample_count = 4;
snapshot.pack.native_outcomes.projection.valid_count = 3;
snapshot.pack.native_outcomes.projection.final_valid = {...snapshot.pack.native_outcomes.projection.final_valid,
submission_index: 4, result_id: "native-later", candidate_ref: "candidate-later", value: 5};
}
if (selected === "d") {snapshot.pack.result = null; snapshot.pack.job = null; snapshot.pack.native_outcomes.projection.initial = null;}
return snapshot;
}

Expand Down Expand Up @@ -333,20 +339,21 @@ Path(sys.argv[1]).write_text(json.dumps({'goal_id':goal,'display_name':'Syntheti
assert.match(await progress.innerText(), /更早失败.*恢复.*评测/s);
await progress.locator('.research-usage > summary').click();
const basis = progress.locator('.research-progress-basis');
await basis.locator('summary').click();
assert.match(await basis.innerText(), /首次提交.*7.*candidate-first/s);
assert.match(await basis.innerText(), /原生保留结果.*3.*candidate-retained/s);
await basis.getByRole('button', {name: '查看原始证据', exact: true}).first().scrollIntoViewIfNeeded();
assert.equal(await basis.evaluate(e => e.open), false);
const nativeResults = progress.getByRole('region', {name: '原生测量', exact: true});
assert.match(await nativeResults.innerText(), /首次提交.*7.*提交 1/s, 'Native measurements need no disclosure before reading');
assert.match(await nativeResults.innerText(), /原生保留结果.*3.*提交 3/s);
assert.match(await nativeResults.innerText(), /越低越好/);
await nativeResults.getByRole('button', {name: /首次提交.*查看原始证据/}).scrollIntoViewIfNeeded();
assert(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1), 'Native details remain readable on a narrow screen');
await page.screenshot({path: resolve(outputDir, "research-native-outcomes-mobile.png"), animations: "disabled"});
await page.setViewportSize({width:1280,height:900});
await page.screenshot({path: resolve(outputDir, "research-native-outcomes-desktop.png"), animations: "disabled"});
await basis.getByRole('button', {name: '查看原始证据', exact: true}).first().click();
await nativeResults.getByRole('button', {name: /首次提交.*查看原始证据/}).click();
await citedOriginal.waitFor();
assert.match(await citedOriginal.innerText(), /Synthetic original evidence/);
await citedOriginal.press('Escape');
await history.getByRole('button', {name: '关闭分析', exact: true}).click();
await basis.locator('summary').click();
await benefitMetric.locator('summary').click();
assert.match(await progress.innerText(), /0 \/ 1/);
assert.match(await progress.innerText(), /1 \/ 2/);
Expand All @@ -373,6 +380,9 @@ Path(sys.argv[1]).write_text(json.dumps({'goal_id':goal,'display_name':'Syntheti
await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))));
assert.equal(await analysis.locator("header p").first().textContent(), "Synthetic analysis B", "A delayed same-Goal read cannot undo a pack selection");
assert.match(await progress.innerText(), /历史捕获|historical/i);
assert.match(await nativeResults.innerText(), /历史原生测量.*当前结果未核验/s, 'Stale measurements never appear current');
assert.match(await nativeResults.locator('[data-native-point="retained"]').innerText(), /3.*提交 3/s);
assert.match(await nativeResults.locator('[data-native-point="final_valid"]').innerText(), /5.*提交 4/s, 'The last submission is not silently presented as retained or best');
await page.reload({waitUntil: "networkidle"});
await analysis.locator("header p").first().filter({hasText: /^Synthetic analysis B$/}).waitFor();
await page.setViewportSize({width: 390, height: 844});
Expand Down Expand Up @@ -422,6 +432,8 @@ Path(sys.argv[1]).write_text(json.dumps({'goal_id':goal,'display_name':'Syntheti
assert.equal(await analysis.count(), 0, "Changing a factual scope preserves the closed analysis panel");
assert.match(await progress.innerText(), /不适用|N\/A/);
assert.doesNotMatch(await progress.innerText(), /0%/);
assert.equal(await nativeResults.count(), 0, 'A missing native capture cannot borrow the previous scope');
assert.match(await progress.innerText(), /尚无同范围捕获/);
await history.getByRole("button", {name: "查看分析", exact: true}).click();
await analysis.locator("header p").first().filter({hasText: /^Synthetic analysis C$/}).waitFor();
await analysis.press('Escape');
Expand All @@ -430,14 +442,14 @@ Path(sys.argv[1]).write_text(json.dumps({'goal_id':goal,'display_name':'Syntheti
assert.match(await progress.innerText(), /此范围尚无分析器判读/);
assert.equal(await progress.locator('.research-effect-metrics').count(), 0, 'An unanalysed cost pack never borrows another pack’s judgments');
assert.equal(await analysis.count(), 0, 'Choosing an unanalysed source never requests analysis');
await basis.locator('summary').click();
assert.match(await basis.innerText(), /原生保留结果.*candidate-retained/s, 'Native facts do not require an analyzer result');
const nativeCitation = basis.getByRole('button', {name: '查看原始证据', exact: true}).first();
assert.match(await nativeResults.innerText(), /原生保留结果.*3.*提交 3/s, 'Native facts do not require an analyzer result or disclosure');
assert.match(await nativeResults.innerText(), /部分窗口,起点未知/);
assert.match(await nativeResults.locator('[data-native-point="initial"]').innerText(), /未知,不记零/);
const nativeCitation = nativeResults.getByRole('button', {name: /原生保留结果.*查看原始证据/});
await nativeCitation.focus(); await nativeCitation.press('Enter');
await citedOriginal.waitFor();
await citedOriginal.press('Escape');
await history.getByRole('button', {name: '关闭分析', exact: true}).click();
await basis.locator('summary').click();
// Analysis sources do not require an Explore log. The real read-only
// backend must keep their measurements discoverable with zero events.
const emptyFixture = resolve(temporary, "empty.json");
Expand Down
Loading