diff --git a/apps/presentation/dashboard/src/features/personal-workspace/explore-finding-copy.ts b/apps/presentation/dashboard/src/features/personal-workspace/explore-finding-copy.ts new file mode 100644 index 0000000000..1c15bd7e53 --- /dev/null +++ b/apps/presentation/dashboard/src/features/personal-workspace/explore-finding-copy.ts @@ -0,0 +1,13 @@ +/** Source-reported finding meaning, shared by history and saved-result readers. + * These labels do not classify evidence or schedule verification. */ +export function exploreFindingCopy(zh: boolean) { + return zh ? { + labels: {tentative: "暂定结论", confirmed: "来源记为确认", refuted: "已反驳"}, + help: "结论状态说明", + meaning: "暂定结论表示来源尚未确认或反驳该结论,可能已有观测与证据;不表示有检查任务排队。确认与反驳也仅表示来源在所述适用范围内的判断,不等于独立验证或目标完成。研究问题是否收束、下一步继续或转向,分别记录。", + } : { + labels: {tentative: "Tentative", confirmed: "Recorded confirmation", refuted: "Refuted"}, + help: "About finding states", + meaning: "Tentative means the source has not confirmed or refuted the finding; observations and evidence may already exist. It does not mean a check is queued. Confirmation and refutation are source judgments within the stated scope, not independent verification or Goal completion. Question closure and the decision to continue or replan are recorded separately.", + }; +} diff --git a/apps/presentation/dashboard/src/features/personal-workspace/goal-explore-results.tsx b/apps/presentation/dashboard/src/features/personal-workspace/goal-explore-results.tsx index caf263094c..33691654da 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/goal-explore-results.tsx +++ b/apps/presentation/dashboard/src/features/personal-workspace/goal-explore-results.tsx @@ -1,3 +1,4 @@ +import {exploreFindingCopy} from "./explore-finding-copy"; import {useEffect, useRef, useState} from "react"; import {ChevronRight, RefreshCw} from "lucide-react"; import {fetchExploreResults, readTodoRequest, type ExploreResultPage} from "../../data/chat"; @@ -59,9 +60,10 @@ export function GoalExploreResults({goalId, zh, active = true, readSourceUrl}: { }, [goalId, cursor, revision, active, readSourceUrl]); const selected = page?.items.find(item => item.finding_id === selectedId); const sections = selected ? parseExploreFindingSections(selected.summary) : null; + const findingCopy = exploreFindingCopy(zh); const statuses: Record = zh - ? {tentative: "待检查", confirmed: "来源记为确认", refuted: "已反驳", open: "未完成", done: "已完成", blocked: "受阻", deferred: "已延后"} - : {tentative: "Tentative", confirmed: "Recorded confirmation", refuted: "Refuted", open: "Open", done: "Done", blocked: "Blocked", deferred: "Deferred"}; + ? {...findingCopy.labels, open: "未完成", done: "已完成", blocked: "受阻", deferred: "已延后"} + : {...findingCopy.labels, open: "Open", done: "Done", blocked: "Blocked", deferred: "Deferred"}; const outcomes: Record = zh ? {replan: "转向", continue: "继续", stop: "停止", wait: "等待", no_change: "无变化", ask_human: "请人决定"} : {replan: "Replan", continue: "Continue", stop: "Stop", wait: "Wait", no_change: "No change", ask_human: "Ask human"}; @@ -81,6 +83,7 @@ export function GoalExploreResults({goalId, zh, active = true, readSourceUrl}: {

{zh ? "已保存的结论" : "Saved findings"}

{zh ? "来源记录的观察与结论,保存不代表已经验证或被后续决策采用。关联任务是原记录的显式关联。" : "Source-recorded observations and conclusions. Saving does not establish validation or adoption. Linked tasks are explicit source relationships."}

+

{findingCopy.meaning}

{busy ?

{zh ? "正在读取证据…" : "Reading evidence…"}

: null} diff --git a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.tsx b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.tsx index 61acc09efe..4552545bf7 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.tsx +++ b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.tsx @@ -1,3 +1,4 @@ +import {exploreFindingCopy} from "./explore-finding-copy"; import {AlertCircle, ArrowLeft, ArrowRight, Circle, CircleHelp, FlaskConical, GitBranch, RefreshCw, Search} from "lucide-react"; import {Fragment, useEffect, useId, useLayoutEffect, useMemo, useRef, useState} from "react"; import {defaultParseSearch} from "@tanstack/react-router"; @@ -106,7 +107,8 @@ export function GoalResearchHistory({goalId, active, zh, refreshRevision = 0, re }; // Labels reuse Explore's existing vocabulary; they confer no verification state. const kindLabels: Record = zh ? {question: "问题", hypothesis: "假设", experiment: "尝试", artifact: "产物", area: "路线"} : {question: "Question", hypothesis: "Hypothesis", experiment: "Attempt", artifact: "Artifact", area: "Route"}; - const stateLabels: Record = zh ? {open: "待探索", exploring: "探索中", blocked: "受阻", resolved: "已收束", dead_end: "已排除", tentative: "待检查", confirmed: "来源记为确认", refuted: "已反驳"} : {open: "Open", exploring: "Exploring", blocked: "Blocked", resolved: "Resolved", dead_end: "Ruled out", tentative: "Tentative", confirmed: "Recorded confirmation", refuted: "Refuted"}; + const findingCopy = exploreFindingCopy(zh); + const stateLabels: Record = zh ? {open: "待探索", exploring: "探索中", blocked: "受阻", resolved: "已收束", dead_end: "已排除", ...findingCopy.labels} : {open: "Open", exploring: "Exploring", blocked: "Blocked", resolved: "Resolved", dead_end: "Ruled out", ...findingCopy.labels}; const relationLabels: Record = zh ? {subtopic_of: "属于", depends_on: "依赖", answers: "回答", supports: "支持", refutes: "反驳", leads_to: "引向"} : {subtopic_of: "Part of", depends_on: "Depends on", answers: "Answers", supports: "Supports", refutes: "Refutes", leads_to: "Leads to"}; const kindLabel = (kind: string) => kindLabels[kind] ?? kind; const stateLabel = (state: string) => stateLabels[state] ?? state; @@ -464,7 +466,7 @@ export function GoalResearchHistory({goalId, active, zh, refreshRevision = 0, re
-

{kindLabel(selected.latest.node_kind)} · {stateLabel(selected.latest.status)}

+
{kindLabel(selected.latest.node_kind)} · {stateLabel(selected.latest.status)}

{findingCopy.meaning}

{selected.findings.length > 1 && findingExceptions ?

{findingExceptions}

: null}
{selected.findings.length ? selectedFinding?.title !== selected.latest.title ?
setQuestionExpanded(event.currentTarget.open)}> diff --git a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-timeline.tsx b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-timeline.tsx index ffb4354ba0..e9c40c0cba 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-timeline.tsx +++ b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-timeline.tsx @@ -1,3 +1,4 @@ +import {exploreFindingCopy} from "./explore-finding-copy"; import {CircleHelp} from "lucide-react"; import {useLayoutEffect, useRef, useState, type CSSProperties} from "react"; import type {ExploreTimeline, TimelineFinding, TimelineNode, TimelinePhase} from "../../../../../../loopx/control_plane/presentation/explore_timeline.js"; @@ -32,6 +33,7 @@ export function GoalResearchTimeline({timeline, zh, selectedIds, selectedDay, da observer.observe(element); return () => observer.disconnect(); }, [timeline.start, timeline.end]); + const findingCopy = exploreFindingCopy(zh); const copy: Copy = zh ? { early: "前段", middle: "中段", late: "后段", items: "研究项", findings: "结论", decisions: "显式决策", none: "未记录显式决策", changed: "变化", stopped: "停止", retained: "保留", @@ -40,7 +42,7 @@ export function GoalResearchTimeline({timeline, zh, selectedIds, selectedDay, da routes: "研究路线", routeHint: "仅由显式关联或父子分组相连", singles: "未关联研究项", trail: "决策轨迹", more: "显示更多决策", all: "全部时段", span: "记录跨度", start: "起点", end: "末端", replan: "转向", continue: "继续", stop: "停止", wait: "等待", no_change: "无变化", ask_human: "请人决定", - confirmed: "来源记为确认", refuted: "已反驳", tentative: "待检查", unlabeled: "无结论", phaseNote: "按记录时间三等分,仅为阅读分组,不是预声明的评估窗口。", + ...findingCopy.labels, unlabeled: "无结论", phaseNote: "按记录时间三等分,仅为阅读分组,不是预声明的评估窗口。", noTime: "没有可用的记录时间,无法放上时间轴;下方记录仍可完整阅读。", } : { early: "Early", middle: "Middle", late: "Late", items: "Research items", findings: "Findings", @@ -50,7 +52,7 @@ export function GoalResearchTimeline({timeline, zh, selectedIds, selectedDay, da routes: "Research routes", routeHint: "Connected only by recorded relationships or parent grouping", singles: "Unlinked research items", trail: "Decision history", more: "Show more decisions", all: "Whole history", span: "Recorded span", start: "Start", end: "End", replan: "Replan", continue: "Continue", stop: "Stop", wait: "Wait", no_change: "No change", ask_human: "Ask human", - confirmed: "Recorded confirmation", refuted: "Refuted", tentative: "Tentative", unlabeled: "No finding", phaseNote: "Equal thirds of record time, for reading only; not a pre-declared evaluation window.", + ...findingCopy.labels, unlabeled: "No finding", phaseNote: "Equal thirds of record time, for reading only; not a pre-declared evaluation window.", noTime: "No usable record time; the history cannot be placed on a time axis. All records remain readable below.", }; const {start, end} = timeline; @@ -115,7 +117,7 @@ export function GoalResearchTimeline({timeline, zh, selectedIds, selectedDay, da

{zh ? "未关联问题按首次记录 UTC 日期收纳,不推断路线或因果。决策轨迹保留各轮显式决策,最新记录在前。" : "Unlinked questions group by first-record UTC date, without inferring a route or cause. Decision history retains each explicit decision, newest record first."}

{timeline.phases.map(item =>
{phaseName(item)}
{phaseDescription(item)}
)}
{phase !== null ? : null}
- {LABELS.map(key =>