Skip to content

Commit d944ec4

Browse files
authored
fix: tighten zh operator copy on critical surfaces (#163)
1 parent 7e59717 commit d944ec4

5 files changed

Lines changed: 75 additions & 12 deletions

File tree

apps/dashboard/app/command-tower/page.tsx

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,49 @@ type CommandTowerHomeState = {
2727
hasLiveData: boolean;
2828
};
2929

30+
function buildCommandTowerWarningSummary({
31+
locale,
32+
overviewWarning,
33+
sessionsWarning,
34+
hasLiveData,
35+
}: {
36+
locale: UiLocale;
37+
overviewWarning: string | null;
38+
sessionsWarning: string | null;
39+
hasLiveData: boolean;
40+
}): string {
41+
if (!overviewWarning && !sessionsWarning) {
42+
return "";
43+
}
44+
45+
if (locale === "zh-CN") {
46+
if (overviewWarning && sessionsWarning) {
47+
return "指挥塔总览与 PM 会话列表当前都不可用。请稍后再试。";
48+
}
49+
if (overviewWarning) {
50+
return hasLiveData
51+
? "指挥塔总览暂时不可用。当前页面只显示部分快照,继续操作前请直接核对运行记录或工作流案例。"
52+
: "指挥塔总览暂时不可用。请稍后再试。";
53+
}
54+
return hasLiveData
55+
? "PM 会话列表暂时不可用。当前页面只显示部分快照,继续操作前请直接核对运行记录或工作流案例。"
56+
: "PM 会话列表暂时不可用。请稍后再试。";
57+
}
58+
59+
if (overviewWarning && sessionsWarning) {
60+
return "Command Tower overview and PM session list are temporarily unavailable. Try again later.";
61+
}
62+
if (overviewWarning) {
63+
return hasLiveData
64+
? "Command Tower overview is temporarily unavailable. The page is showing a partial snapshot, so verify runs or Workflow Cases directly before you act."
65+
: "Command Tower overview is temporarily unavailable. Try again later.";
66+
}
67+
return hasLiveData
68+
? "The PM session list is temporarily unavailable. The page is showing a partial snapshot, so verify runs or Workflow Cases directly before you act."
69+
: "The PM session list is temporarily unavailable. Try again later.";
70+
}
71+
3072
async function loadCommandTowerHomeState(locale: UiLocale): Promise<CommandTowerHomeState> {
31-
const commandTowerCopy = getUiCopy(locale).dashboard.commandTowerPage;
3273
const fallbackOverview: CommandTowerOverviewPayload = {
3374
generated_at: new Date().toISOString(),
3475
total_sessions: 0,
@@ -72,11 +113,16 @@ async function loadCommandTowerHomeState(locale: UiLocale): Promise<CommandTower
72113
const sessions = sessionsResult.data;
73114
const overviewWarning = overviewResult.warning;
74115
const sessionsWarning = sessionsResult.warning;
75-
const warning = [overviewWarning, sessionsWarning].filter(Boolean).join(" ");
76116
const hasLiveData =
77117
(overview.total_sessions || 0) > 0 ||
78118
(overview.active_sessions || 0) > 0 ||
79119
(sessions?.length || 0) > 0;
120+
const warning = buildCommandTowerWarningSummary({
121+
locale,
122+
overviewWarning,
123+
sessionsWarning,
124+
hasLiveData,
125+
});
80126

81127
return {
82128
overview,
@@ -190,7 +236,7 @@ export function CommandTowerPageIntro({
190236
<p id="command-tower-page-subtitle" className="page-subtitle">
191237
{recoveryMode
192238
? locale === "zh-CN"
193-
? "指挥塔当前拿不到 live 总览。先确认只读真相,再走一条恢复路径。"
239+
? "指挥塔当前拿不到实时总览。先确认只读真相,再走一条恢复路径。"
194240
: "Command Tower cannot read the live overview right now. Verify the read-only truth first, then take one recovery path."
195241
: partialMode
196242
? commandTowerCopy.partialNextAction
@@ -238,7 +284,7 @@ export function CommandTowerPageIntro({
238284
? commandTowerCopy.partialBadge
239285
: commandTowerCopy.partialBadge
240286
: locale === "zh-CN"
241-
? "先看 live"
287+
? "先看实时态"
242288
: "Live first"}
243289
</Badge>
244290
</div>
@@ -247,13 +293,13 @@ export function CommandTowerPageIntro({
247293
<>
248294
<div className="home-briefing-signal">
249295
<span className="cell-sub mono muted">{locale === "zh-CN" ? "当前状态" : "Current state"}</span>
250-
<strong>{locale === "zh-CN" ? "live 总览暂时不可读" : "The live overview is temporarily unavailable"}</strong>
296+
<strong>{locale === "zh-CN" ? "实时总览暂时不可读" : "The live overview is temporarily unavailable"}</strong>
251297
<p>{locale === "zh-CN" ? "这不是正常驾驶舱读面。先恢复主面,再继续值班。" : "This is not a normal cockpit read. Restore the surface first, then resume operator work."}</p>
252298
</div>
253299
<div className="home-briefing-signal">
254300
<span className="cell-sub mono muted">{locale === "zh-CN" ? "仍然成立的真相" : "What still holds"}</span>
255301
<strong>{locale === "zh-CN" ? "只读入口与证明室仍可用" : "The read-only rooms still work"}</strong>
256-
<p>{locale === "zh-CN" ? "你仍然可以回 PM、Runs 和 Workflow Cases,但不要把当前页面当成 live cockpit。 " : "You can still use PM, Runs, and Workflow Cases, but do not treat this page as a live cockpit right now."}</p>
302+
<p>{locale === "zh-CN" ? "你仍然可以回 PM 入口、运行记录和工作流案例,但不要把当前页面当成实时驾驶舱。 " : "You can still use PM, Runs, and Workflow Cases, but do not treat this page as a live cockpit right now."}</p>
257303
</div>
258304
<div className="home-briefing-signal">
259305
<span className="cell-sub mono muted">{locale === "zh-CN" ? "恢复动作" : "Recovery move"}</span>
@@ -266,11 +312,11 @@ export function CommandTowerPageIntro({
266312
<div className="home-briefing-signal">
267313
<span className="cell-sub mono muted">{locale === "zh-CN" ? "当前状态" : "Current state"}</span>
268314
<strong>{commandTowerCopy.partialTitle}</strong>
269-
<p>{locale === "zh-CN" ? "你现在看到的是部分可读的值班面,不是完整 live cockpit。首屏要先承认降级,再继续分诊。" : "You are looking at a partially readable operator surface, not a full live cockpit. The first screen should acknowledge degradation before continuing triage."}</p>
315+
<p>{locale === "zh-CN" ? "你现在看到的是部分可读的值班面,不是真正完整的实时驾驶舱。首屏要先承认降级,再继续分诊。" : "You are looking at a partially readable operator surface, not a full live cockpit. The first screen should acknowledge degradation before continuing triage."}</p>
270316
</div>
271317
<div className="home-briefing-signal">
272318
<span className="cell-sub mono muted">{locale === "zh-CN" ? "仍然成立的真相" : "What still holds"}</span>
273-
<strong>{locale === "zh-CN" ? "可见 board 只算部分快照" : "The visible board only counts as a partial snapshot"}</strong>
319+
<strong>{locale === "zh-CN" ? "可见面板只算部分快照" : "The visible board only counts as a partial snapshot"}</strong>
274320
<p>{commandTowerCopy.partialNextAction}</p>
275321
</div>
276322
<div className="home-briefing-signal">

apps/dashboard/components/DashboardHomeStorySections.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ export default function DashboardHomeStorySections({
191191
locale === "zh-CN"
192192
? [
193193
{
194-
kicker: "当前 live",
194+
kicker: "当前实况",
195195
value: hasRunHistory ? String(runningCount) : "0",
196196
detail: hasRunHistory ? "先读指挥塔,再下钻明细" : "先起第一条任务,系统才会亮起来",
197197
},
@@ -202,7 +202,7 @@ export default function DashboardHomeStorySections({
202202
},
203203
{
204204
kicker: "真相路径",
205-
value: hasRunHistory ? "Workflow + Proof" : "Start in PM",
205+
value: hasRunHistory ? "工作流 + 证明" : "先从 PM 开始",
206206
detail: hasRunHistory ? "首页只负责导向,不负责替代证明室" : "先写请求,再让真相面出现",
207207
},
208208
]

apps/dashboard/tests/command_tower_page_render.test.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ describe("command tower page render", () => {
174174
expect(screen.getByText("Partial truth / live surface degraded")).toBeInTheDocument();
175175
expect(screen.getByText("Command Tower is running with partial truth")).toBeInTheDocument();
176176
expect(screen.getByText("Partial context")).toBeInTheDocument();
177+
expect(
178+
screen.getByText(
179+
"Command Tower overview is temporarily unavailable. The page is showing a partial snapshot, so verify runs or Workflow Cases directly before you act."
180+
)
181+
).toBeInTheDocument();
177182
expect(screen.getByRole("link", { name: "Reload Command Tower" })).toHaveAttribute("href", "/command-tower");
178183
expect(screen.getByRole("link", { name: "View runs" })).toHaveAttribute("href", "/runs");
179184
expect(screen.queryByTestId("ct-callout")).toBeNull();
@@ -203,6 +208,10 @@ describe("command tower page render", () => {
203208
expect(screen.getByText("部分真相 / live 面当前降级")).toBeInTheDocument();
204209
expect(screen.getByText("指挥塔当前只提供部分真相")).toBeInTheDocument();
205210
expect(screen.getByText("上下文不完整")).toBeInTheDocument();
211+
expect(screen.getByText("可见面板只算部分快照")).toBeInTheDocument();
212+
expect(
213+
screen.getByText("指挥塔总览暂时不可用。当前页面只显示部分快照,继续操作前请直接核对运行记录或工作流案例。")
214+
).toBeInTheDocument();
206215
expect(screen.getByRole("status")).toHaveTextContent("正在加载指挥塔实时总览...");
207216
expect(screen.getByRole("link", { name: "重载指挥塔" })).toHaveAttribute("href", "/command-tower");
208217
expect(screen.getByRole("link", { name: "查看运行记录" })).toHaveAttribute("href", "/runs");
@@ -220,6 +229,9 @@ describe("command tower page render", () => {
220229
expect(
221230
screen.getByText("Command Tower cannot read the live overview right now. Verify the read-only truth first, then take one recovery path."),
222231
).toBeInTheDocument();
232+
expect(
233+
screen.getByText("Command Tower overview and PM session list are temporarily unavailable. Try again later.")
234+
).toBeInTheDocument();
223235
expect(screen.getByRole("link", { name: "Reload Command Tower" })).toHaveAttribute("href", "/command-tower");
224236
expect(screen.getByRole("link", { name: "Start from PM" })).toHaveAttribute("href", "/pm");
225237
expect(screen.queryByTestId("ct-live-client")).toBeNull();
@@ -236,7 +248,9 @@ describe("command tower page render", () => {
236248
render(await CommandTowerPage());
237249

238250
expect(screen.getByText("恢复模式 / 当前主面不可用")).toBeInTheDocument();
239-
expect(screen.getByText("指挥塔当前拿不到 live 总览。先确认只读真相,再走一条恢复路径。")).toBeInTheDocument();
251+
expect(screen.getByText("指挥塔当前拿不到实时总览。先确认只读真相,再走一条恢复路径。")).toBeInTheDocument();
252+
expect(screen.getByText("实时总览暂时不可读")).toBeInTheDocument();
253+
expect(screen.getByText("指挥塔总览与 PM 会话列表当前都不可用。请稍后再试。")).toBeInTheDocument();
240254
expect(screen.getByRole("link", { name: "重载指挥塔" })).toHaveAttribute("href", "/command-tower");
241255
expect(screen.getByRole("link", { name: "回到 PM 入口" })).toHaveAttribute("href", "/pm");
242256
expect(screen.queryByTestId("ct-live-client")).toBeNull();

apps/dashboard/tests/home_page.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ describe("dashboard home run-summary clarity", () => {
272272
expect(screen.getAllByText("只读 MCP 快速入口").length).toBeGreaterThan(0);
273273
expect(screen.getAllByText("API 与契约快速入口").length).toBeGreaterThan(0);
274274
expect(screen.getByText("显示四步首跑流程")).toBeInTheDocument();
275+
expect(screen.getByText("当前实况")).toBeInTheDocument();
276+
expect(screen.getByText("先从 PM 开始")).toBeInTheDocument();
277+
expect(screen.queryByText("Start in PM")).not.toBeInTheDocument();
275278
});
276279

277280
it("maps latest failure category to semantic label and provides governance link", async () => {

packages/frontend-shared/uiCopy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2698,7 +2698,7 @@ const UI_COPY: Record<UiLocale, UiCopy> = {
26982698
unavailableBadge: "实时数据缺失",
26992699
partialTitle: "指挥塔当前只提供部分真相",
27002700
partialNextAction:
2701-
"当前可见总览只能算部分快照。做审批、回滚或发布判断前,先直接核对 Runs 或 Workflow Cases。",
2701+
"当前可见总览只能算部分快照。做审批、回滚或发布判断前,先直接核对运行记录或工作流案例。",
27022702
partialBadge: "上下文不完整",
27032703
actions: {
27042704
reload: "重载指挥塔",

0 commit comments

Comments
 (0)