refactor(chat): render rectification activity through the shared step timeline

The rectification surface had its own activity pipeline: a trace panel
with a 20px canvas orb clipped inside a 14px marker, a list that never
collapsed, a second receipt disclosure under every reply, an inline
failure banner and a staged label while regenerating. Its trace and
receipt are now projected onto ConsultationTimelineRow so both surfaces
render one ConsultationRunTimeline with one live marker and one settled
summary; receipt methods become source chips on the last completed row.
The unreachable sections-report/step-tree path, the trace panel, the
receipt component and the thinking-orbs dependency are removed. The
server-side drop of rectification thinking deltas is untouched.

BUG-476

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
This commit is contained in:
Jesse_Chen
2026-09-02 04:02:15 +00:00
co-authored by Claude Fable 5.1
parent be5e810ac9
commit ccdae76dd3
17 changed files with 313 additions and 819 deletions
@@ -44,10 +44,6 @@ const progressLabels = readFileSync(
new URL("../src/lib/rectification-activity-labels.ts", import.meta.url),
"utf8",
);
const completedActivityReceipt = readFileSync(
new URL("../src/components/completed-activity-receipt.tsx", import.meta.url),
"utf8",
);
const choiceCardComponent = readFileSync(
new URL("../src/components/rectification-choice-card.tsx", import.meta.url),
"utf8",
@@ -344,9 +340,10 @@ test("rectification keeps receipts for the varga sentence and shows live tool pr
const replyIndex = messageRender.indexOf("<ChatMessageRow");
assert.ok(replyIndex >= 0);
assert.doesNotMatch(messageRender, /<RectificationHouseTableView/);
assert.match(completedActivityReceipt, /<details className=/);
assert.doesNotMatch(completedActivityReceipt, /<details[^>]*\sopen/);
assert.match(completedActivityReceipt, /本轮完成 · \$\{stepLabels\.length\} 个步骤 · \$\{receipt\.methods\.length\} 项计算依据/);
// Former locks on `completed-activity-receipt.tsx` (`<details>`, never open, the "本轮完成 · N 个
// 步骤" summary): that was a second collapsed block under every settled rectification reply.
// Its methods now sit as source chips on the shared timeline's calculate row (BUG-476).
assert.match(chat, /completedReceipt/);
for (const genericCopy of ["开始本轮执行", "正在加载专用方法", "专用方法已加载", "本轮做了什么"]) {
assert.doesNotMatch(chat, new RegExp(genericCopy));
}
@@ -360,7 +357,10 @@ test("rectification keeps receipts for the varga sentence and shows live tool pr
assert.doesNotMatch(chat, /本轮处理未完成,已保留服务端记录的执行进度/);
assert.match(chat, /startActivityTraceStep/);
assert.match(chat, /completeActivityTraceStep/);
assert.match(activityStatus, /activityTrace/);
// Former lock: `activityStatus` contained `activityTrace` — the rectification-only trace panel.
// The trace is now projected onto the shared timeline rows (BUG-476); the panel is a fallback.
assert.match(chat, /rectificationTimelineRows/);
assert.doesNotMatch(activityStatus, /activityTrace/);
assert.match(activityStatus, /className="message-thinking"/);
assert.match(activityStatus, />思考</);
assert.match(activityStatus, /userOpen \?\? !hasAnswer/);