feat(rectification): 区间常驻条补代表分钟与已答题数,盘面五段折叠收成两段
Independent Staging Quality Gate / validate (push) Canceled after 3m14s
Independent Staging Quality Gate / publish (push) Canceled after 0s

R7 / 决策 D10。任务书 docs/tasks/TASK-cend-surfaces-claude-alignment-20260916.md。

T7.1 常驻条。任务书 E9 说区间只在盘面标题行,实际读代码:对话区顶部
已有常驻条 RectificationTimeline 且已显示区间与宽度,窄屏 .is-compact 下
也可见。真正只存在于 .rectification-board__clock 的是代表分钟——窄屏盘面
是默认关闭的 overlay,代表分钟就此看不见。所以没有另造第二条(会撞固定条
高这条正确性约束),而是在既有条上补齐缺的两项:

  05:07–05:09 · 3 分钟 · 代表分钟 05:08 · 已答 6 题

代表分钟与盘面标题行是同一次 workingRectificationTime(result) 调用,一个
值两处用,不是两条推导路径。已答题数逐字读服务端的
inference_state.answered_probe_count,投影没给就整项不显示,不补「已答 0 题」。
条上不写确认,边界句仍只在交付/采用旁白里出现一次。读数只增宽不增高:条高
在滚动容器外,变高会让贴底读者的内容无声滑出视野。

收窄进度未做,触发让步顺序第 5 条。没有这个字段(服务端只把这句话拼进旁白
正文),且前端自己减会算错——candidate_range 是当前窗口且会放宽(BUG-572),
拿它当「最初」相减会把一次放宽报成一次收窄。缺口与解除条件写进 BLOCKED.md。

T7.2 盘面折叠。实际有 8 个 details(任务书记的五处漏了交界节奏、错标了两块),
按内容归成「候选分钟」(换升时刻 + 次级候选)与「参数与口径」(宫位表、确认门、
本轮技法、两段本命上升、经历与大运对照含双轨一致性、交界节奏)。每块保留原有
渲染条件,engineMeaningToDisplayCopy() 仍是 5 处,逐分钟行的 is-changed /
当前时间 一字未改。共享组件 technique-audit-disclosure.tsx 未动。

顺带修掉一个静默失效的断言:rectification-agentic-entry 用
board.slice(indexOf(A), indexOf(B)),B 改名后 indexOf 返回 -1,slice(i, -1)
会悄悄退化成几乎整份文件,底下四条 doesNotMatch 照样绿。已换成带越界断言的
sliceBetween()。两处改动的断言都在测试里写了原值/新值/原因。

tsc 0 错;lint 0 error / 118 warning(同基线);npm test 3350 → 3360,失败
仍是 31 条无 Docker 用例且与基线逐条一致;next build exit 0,/ 仍 ○ Static;
产物 CSS gzip 39,017 → 38,973 B(−0.11%)。

窄屏 .is-compact 下常驻条的实际可见性无 Chrome 无法验证,已按任务书写成环境
缺口,未标通过;CSS 上已确认无任何规则在该状态下隐藏该条,并写成测试断言。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
This commit is contained in:
Jesse_Chen
2026-09-16 06:44:49 +00:00
co-authored by Claude Opus 5
parent a1a78c7ebc
commit ca0204984b
13 changed files with 751 additions and 72 deletions
+56 -1
View File
@@ -2523,6 +2523,11 @@ button.nav-rail-identity:hover { background: var(--sidebar-accent); }
grid-template-columns: minmax(0, 1fr);
grid-template-rows: minmax(0, 1fr);
}
/* Both take the single cell and stack. The chat keeps its three rows here, so
the range bar is on screen at every width — the overlay only covers it while
the board is deliberately open, and it is closed by default. Nothing below
may hide `.rectification-timeline` under `.is-compact`: on a narrow viewport
that bar is the only place the range and the working minute appear (D10). */
.rectification-workspace.is-compact .rectification-workspace__chat,
.rectification-workspace.is-compact .rectification-board-overlay {
grid-area: 1 / 1;
@@ -2562,11 +2567,19 @@ button.nav-rail-identity:hover { background: var(--sidebar-accent); }
border-bottom: 1px solid var(--color-border);
overflow: hidden;
}
/* One line, always. The bar's height is fixed on purpose (see above), so the
readout may grow wider but never taller; wrapping would push the axis out of
a box nothing is observing. Four short items clear 375px with room to spare,
and the bar's own `overflow: hidden` clips rather than reflows if they ever
do not. */
.rectification-timeline__readout {
margin: 0;
display: flex;
align-items: baseline;
gap: var(--space-2);
flex-wrap: nowrap;
gap: var(--space-2) var(--space-3);
min-width: 0;
white-space: nowrap;
font-size: 13px;
line-height: 1.2;
}
@@ -2578,6 +2591,22 @@ button.nav-rail-identity:hover { background: var(--sidebar-accent); }
.rectification-timeline__width {
color: var(--color-ink-secondary);
}
/* The working minute reads at the same weight as the range: on a compact
viewport the board is a closed overlay, so this is the only place it shows. */
.rectification-timeline__working {
font-variant-numeric: tabular-nums;
font-weight: 500;
color: var(--color-ink);
}
/* Last in the row and first to be clipped: the count is context, not the
answer, and it is the only item the reader can do without. */
.rectification-timeline__answered {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
color: var(--color-ink-secondary);
font-variant-numeric: tabular-nums;
}
.rectification-timeline__axis {
position: relative;
height: 26px;
@@ -2832,6 +2861,22 @@ button.nav-rail-identity:hover { background: var(--sidebar-accent); }
padding-top: 0;
border-top: 0;
}
/* The board folds to two sections, so most disclosures are now nested one level
inside 候选分钟 or 参数与口径. The reset above strips every separator, which
left the nested rows flush against each other; the rhythm inside an open
section is restored here rather than by relaxing that reset, which the
top-level sections still want. */
.rectification-board .technique-audit > .technique-audit,
.rectification-board .technique-audit > .technique-audit-panel,
.rectification-board .technique-audit > .rectification-board__group,
.rectification-board .technique-audit > .rectification-board__minutes,
.rectification-board .technique-audit > .rectification-board__disclosure {
margin-top: var(--space-4);
}
/* A label sits closer to the list it names than to the block before it. */
.rectification-board .technique-audit > .rectification-board__group + .rectification-board__minutes {
margin-top: var(--space-2);
}
.rectification-board__section {
display: grid;
gap: var(--space-3);
@@ -2843,6 +2888,16 @@ button.nav-rail-identity:hover { background: var(--sidebar-accent); }
font-weight: 600;
letter-spacing: -.2px;
}
/* Names the list that follows it now that 换升时刻 is a group inside 候选分钟
rather than a fold of its own. Not a <summary>: this content is always open
once its section is, so a second disclosure to click would be one more step
to the same place. */
.rectification-board__group {
margin: 0;
color: var(--color-ink-secondary);
font-size: var(--type-caption);
font-weight: 600;
}
.rectification-board__minutes {
display: grid;
gap: var(--space-3);