Просмотр исходного кода

docs(web): record implemented trajectory attachment presentation

Refs #4356
sjw1231 2 недель назад
Родитель
Сommit
f176327afc

+ 6 - 0
.agents/notes/implemented/bug-fix/2026-09-15-trajectory-attachment-presentation.i18n.yaml

@@ -0,0 +1,6 @@
+# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
+# side as of the last confirmed-consistent state. Both languages carry equal authority;
+# after editing either side, bring the other along and re-record with:
+#   pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-09-15-trajectory-attachment-presentation.md
+2026-09-15-trajectory-attachment-presentation.md: 4a1528a230c0ded38d26d0859a181ebaa208180d
+2026-09-15-trajectory-attachment-presentation.zh.md: e6accddb292613d9688b66847b6d6834ad6636c6

+ 55 - 0
.agents/notes/implemented/bug-fix/2026-09-15-trajectory-attachment-presentation.md

@@ -0,0 +1,55 @@
+# Agent Note: Consistent Trajectory attachment presentation
+
+Status: implemented
+
+English | [中文](2026-09-15-trajectory-attachment-presentation.zh.md)
+
+## Problem
+
+A user message can contain text, images, and ordinary files. Trajectory omitted image counts beside text, left ordinary files out of Preview, and mixed file JSON with rendered images in Raw. Readers could not identify the complete attachment set consistently across the ledger and inspector (Issue #4356).
+
+## Decision
+
+Trajectory presents every attachment occurrence while keeping visual inspection separate from inspection of recorded fields.
+
+| Location | Behavior |
+|---|---|
+| Ledger | Separate nonzero image and ordinary-file counts accompany the text excerpt, including messages without text. Each record stays on one compact line. |
+| Summary and Preview | Message text precedes one ordered attachment list. Both tabs use the same renderer; Summary retains its compact spacing and scroll container. |
+| Attachment list | Equal-width compact rows share spacing and corners. A file-type icon or contained image thumbnail accompanies the recorded name and available metadata. Repeated references retain their occurrence order. |
+| Image interaction | The complete image fits inside a 48px square thumbnail without cropping. Activation opens the existing image viewer, with keyboard access, loading feedback, and retry after a failed read. |
+| Raw | Image and file blocks use initially collapsed metadata disclosures with complete recorded fields. Original content-block order and unrendered text remain intact; generated display labels do not enter raw fields. |
+
+Recorded filenames take precedence over localized numbered image labels. Metadata comes from recorded fields or the filename extension; zero-byte sizes remain visible. Visually truncated names retain their complete accessible text and tooltip. Messages without text still expose all attachments inside the inspector's scroll area.
+
+### Ownership
+
+[ui-trajectory](../../../../packages/client/ui-trajectory/README.md) owns counts, ordered attachment projection, and inspector composition. Its view data carries typed image and file references separately from the serialized content used by Raw, so display code does not recover file metadata by parsing JSON.
+
+[ui-attachment](../../../../packages/client/ui-attachment/README.md) owns image loading and the viewer through the existing image slot. [ui-conversation](../../../../packages/client/ui-conversation/README.md) owns the per-session image cache: Chat and Trajectory share one authorized read and browser URL per attachment. Thumbnail sizing and optional display labels affect presentation only; loading still receives the original reference. Chat and tool-result gallery sizing retain their existing behavior.
+
+This decision uses existing durable attachment references without changing upload, storage, model requests, or the Session format. Ordinary files expose metadata without a content viewer or download action. Product labels use typed locale dictionaries, and styles use the existing semantic tokens.
+
+The [generic file upload decision](../feature/2026-08-26-generic-file-upload.md) owns upload, storage, admission, and ordered message attachments; this record owns Trajectory presentation. The [unreadable attachment quarantine proposal](../../proposed/bug-fix/2026-08-20-attachment-read-quarantine.md) concerns model-request recovery independently of thumbnail loading feedback.
+
+## Alternatives considered
+
+**Keep large inline images as the default inspector presentation.** This makes one image immediately readable, but a tall image displaces attachment names and message text in the narrow inspector. Compact rows with explicit image activation provide a consistent overview of mixed attachments.
+
+**Use two-column attachment cards.** A grid can make thumbnails more prominent on wide panels, but it leaves less room for long filenames and requires a different narrow-panel arrangement. A single equal-width list accommodates both panel widths.
+
+**Keep file JSON and image previews together in Raw.** This assigns different meanings to the same tab for two attachment kinds. Metadata disclosures let readers inspect recorded fields while Preview owns visual image presentation.
+
+## Consequences
+
+The shared attachment renderer keeps names, order, metadata, and image actions consistent between Summary and Preview. Grouping attachments after message text makes the complete set easy to scan; Raw preserves interleaving when readers need the original block sequence. Repeated references remain separate rows even when image loading shares a cache entry. Selecting another record resets Raw attachment disclosures; updates to the selected record, including loading older history, preserve their state.
+
+Compact thumbnails require opening the viewer to read detailed diagrams. Missing metadata stays absent, and image-read failures retain a retry control without hiding ordinary files. Changes to the shared image slot also affect Chat and tool results, so their gallery behavior and cache reuse remain regression requirements.
+
+## Verification
+
+[Projection tests](../../../../packages/client/ui-trajectory/tests/layout.client.spec.tsx) cover mixed, attachment-only, empty-text, and repeated occurrences. [Inspector tests](../../../../packages/client/ui-trajectory/tests/table.client.spec.tsx) cover both locales, unnamed images, long filenames, zero-byte files, ordered lists, complete Raw fields, and disclosure state across record selection and history updates. [Image tests](../../../../packages/client/ui-attachment/tests/message-image.client.spec.tsx) cover thumbnail labels, loading, retry, and the existing viewer.
+
+The recorded [mixed-upload browser scenario](../../../../apps/web/tests/file-upload-round.e2e.ts) compares Summary and Preview, verifies keyboard activation and focus restoration, checks collapsed and expanded Raw content, and repeats inspection after reload. Its [Trajectory expectation](../../../../snapshots/web/file-upload-round/trajectory.expected.md) accompanies the unchanged Session fixture. The [assembled image-cache test](../../../../apps/web/tests/trajectory-image-display.expected.e2e.ts) also checks reuse between Chat and Trajectory.
+
+Layout acceptance covers narrow and wide panels, both themes and locales, complete thumbnail containment, and reachable final attachments. The [GIF workflow](../../../skills/record-browser-gif/SKILL.md) requires review evidence from a clean committed tree and one real-server, real-model session showing mixed submission, ledger counts, Summary, Preview image activation, and expanded Raw metadata. Issue #4356 and its linked PR track executed checks and demonstration evidence.

+ 55 - 0
.agents/notes/implemented/bug-fix/2026-09-15-trajectory-attachment-presentation.zh.md

@@ -0,0 +1,55 @@
+# Agent Note: 统一 Trajectory 附件展示
+
+Status: implemented
+
+[English](2026-09-15-trajectory-attachment-presentation.md) | 中文
+
+## 问题
+
+用户消息可以包含文本、图片和普通文件。Trajectory 曾在文本旁省略图片数量,在预览中遗漏普通文件,并在原始内容中混排文件 JSON 与渲染后的图片。读者无法在列表和详情面板中一致地确认完整附件集合(Issue #4356)。
+
+## 决定
+
+Trajectory 展示每次附件出现的记录,并分别提供视觉预览与已记录字段检查。
+
+| 位置 | 行为 |
+|---|---|
+| 列表 | 文本摘要旁分别显示非零的图片数量与普通文件数量,无正文的消息也显示计数。每条记录保持为紧凑单行。 |
+| 概述与预览 | 消息正文之后展示一个有序附件列表。两个标签页使用相同的渲染器;概述保留紧凑间距和滚动容器。 |
+| 附件列表 | 等宽的紧凑行使用一致的间距和圆角。文件类型图标或完整缩放的图片缩略图旁展示已记录的名称与可用元数据。重复引用保留各次出现的顺序。 |
+| 图片交互 | 图片完整缩放到 48px 方形缩略图内,不裁剪。激活时打开现有图片查看器,保留键盘访问、加载反馈和读取失败后的重试。 |
+| 原始内容 | 图片块和文件块使用默认收起的元数据折叠区,包含完整记录字段。原始内容块顺序与未渲染文本保持完整;生成的显示标签不进入原始字段。 |
+
+已记录文件名优先于本地化的编号图片标签。元数据来自记录字段或文件扩展名,零字节大小仍然可见。视觉上截断的名称保留完整的无障碍文本和工具提示。无正文的消息仍在详情面板滚动区域内展示全部附件。
+
+### 职责
+
+[ui-trajectory](../../../../packages/client/ui-trajectory/README.zh.md)负责计数、有序附件投影和详情面板组合。其视图数据将带类型的图片与文件引用和原始内容使用的序列化文本分别保存,展示代码因此无需解析 JSON 来恢复文件元数据。
+
+[ui-attachment](../../../../packages/client/ui-attachment/README.zh.md)通过现有图片 slot 负责图片加载与查看器。[ui-conversation](../../../../packages/client/ui-conversation/README.zh.md)拥有会话级图片缓存:Chat 与 Trajectory 对每个附件共享一次授权读取和一个浏览器 URL。缩略图尺寸和可选显示标签只影响展示,加载仍接收原始引用。Chat 和工具结果图库保留现有的尺寸行为。
+
+本决定使用现有持久附件引用,不改变上传、存储、模型请求或会话格式。普通文件展示元数据,不提供内容查看器或下载操作。产品标签使用带类型的本地化字典,样式使用现有语义 token。
+
+[通用文件上传决定](../feature/2026-08-26-generic-file-upload.zh.md)负责上传、存储、准入和有序消息附件;本记录负责 Trajectory 展示。[不可读附件隔离提案](../../proposed/bug-fix/2026-08-20-attachment-read-quarantine.zh.md)处理模型请求恢复,与缩略图加载反馈相互独立。
+
+## 考虑过的替代方案
+
+**默认在详情面板中内联展示大图。** 这样可以立即阅读单张图片,但高图片会在窄面板中挤走附件名称和消息正文。紧凑行加显式图片激活入口能一致地概览混合附件。
+
+**使用双列附件卡片。** 网格能在宽面板上突出缩略图,但会压缩长文件名空间,并要求窄面板采用不同排布。单列等宽列表适用于两种面板宽度。
+
+**在原始内容中混排文件 JSON 和图片预览。** 这让同一个标签页对两种附件具有不同含义。元数据折叠区用于检查已记录字段,预览负责图片的视觉展示。
+
+## 影响
+
+共享附件渲染器使概述与预览中的名称、顺序、元数据和图片操作保持一致。将附件集中在消息正文之后便于浏览完整集合;需要原始块顺序时,原始内容保留交错关系。即使图片加载共享缓存项,重复引用仍各占一行。选择另一条记录时,原始内容中的附件折叠区恢复收起状态;当前记录更新时,包括加载更早历史时,折叠状态保持不变。
+
+紧凑缩略图需要打开查看器才能阅读详细图表。缺失的元数据保持缺失,图片读取失败保留重试控件,并且不隐藏普通文件。共享图片 slot 的修改也会影响 Chat 和工具结果,因此其图库行为和缓存复用仍需回归验证。
+
+## 验证
+
+[投影测试](../../../../packages/client/ui-trajectory/tests/layout.client.spec.tsx)覆盖混合附件、纯附件、空文本和重复引用。[详情面板测试](../../../../packages/client/ui-trajectory/tests/table.client.spec.tsx)覆盖两种语言、无名称图片、长文件名、零字节文件、有序列表、完整的原始字段,以及记录切换和历史更新时的折叠状态。[图片测试](../../../../packages/client/ui-attachment/tests/message-image.client.spec.tsx)覆盖缩略图标签、加载、重试和现有查看器。
+
+已录制的[混合上传浏览器场景](../../../../apps/web/tests/file-upload-round.e2e.ts)比较概述与预览,验证键盘激活和焦点恢复,检查原始内容收起与展开状态,并在刷新后重复检查。其 [Trajectory 预期输出](../../../../snapshots/web/file-upload-round/trajectory.expected.md)配合未改动的会话 fixture(测试前置数据)使用。[组装应用图片缓存测试](../../../../apps/web/tests/trajectory-image-display.expected.e2e.ts)也检查 Chat 与 Trajectory 之间的复用。
+
+布局验收覆盖窄版与宽版面板、两种主题和语言、缩略图完整缩放及末尾附件可达性。[GIF 工作流](../../../skills/record-browser-gif/SKILL.md)要求评审证据基于干净的已提交代码树,在同一个真实服务、真实模型会话中展示混合提交、列表计数、概述、预览中的图片激活和展开的原始元数据。Issue #4356 及其关联 PR(Pull Request)记录已执行的检查和演示证据。

+ 2 - 2
.agents/notes/implemented/feature/2026-08-26-generic-file-upload.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-08-26-generic-file-upload.md
-2026-08-26-generic-file-upload.md: bda96caa36f27a2270971127b5e3635a7fec9fcd
-2026-08-26-generic-file-upload.zh.md: 2ddfd48f1ea04ba6cfbff10224444de8d37d7a8a
+2026-08-26-generic-file-upload.md: ddaf92a396ade59d65a81300531be9bce2aeeaba
+2026-08-26-generic-file-upload.zh.md: 27a73536ec3632f40ee49a59d932406e77b5591d

+ 1 - 1
.agents/notes/implemented/feature/2026-08-26-generic-file-upload.md

@@ -51,4 +51,4 @@ Unit and integration coverage pins verbatim and streamed storage, name sanitizat
 
 ## Related
 
-The [Trajectory attachment presentation proposal](../../proposed/bug-fix/2026-09-15-trajectory-attachment-presentation.md) covers ledger counts and inspector attachment layouts.
+The [Trajectory attachment presentation decision](../bug-fix/2026-09-15-trajectory-attachment-presentation.md) owns ledger counts and inspector attachment layouts.

+ 1 - 1
.agents/notes/implemented/feature/2026-08-26-generic-file-upload.zh.md

@@ -51,4 +51,4 @@ Status: implemented
 
 ## 相关记录
 
-[Trajectory 附件展示提案](../../proposed/bug-fix/2026-09-15-trajectory-attachment-presentation.zh.md)涵盖列表计数与详情面板附件布局。
+[Trajectory 附件展示决定](../bug-fix/2026-09-15-trajectory-attachment-presentation.zh.md)负责列表计数与详情面板附件布局。

+ 0 - 6
.agents/notes/proposed/bug-fix/2026-09-15-trajectory-attachment-presentation.i18n.yaml

@@ -1,6 +0,0 @@
-# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
-# side as of the last confirmed-consistent state. Both languages carry equal authority;
-# after editing either side, bring the other along and re-record with:
-#   pnpm run verify-translation-pairing --write .agents/notes/proposed/bug-fix/2026-09-15-trajectory-attachment-presentation.md
-2026-09-15-trajectory-attachment-presentation.md: 23ce4145f0a90e0e03a90ca4c335bb2cb3598785
-2026-09-15-trajectory-attachment-presentation.zh.md: cbd507235e28a523360bd47a105acbb59963418f

+ 0 - 89
.agents/notes/proposed/bug-fix/2026-09-15-trajectory-attachment-presentation.md

@@ -1,89 +0,0 @@
-# Agent Note: Consistent Trajectory attachment presentation
-
-Status: proposed
-
-English | [中文](2026-09-15-trajectory-attachment-presentation.zh.md)
-
-## Problem
-
-A user message can contain text, images, and ordinary files, but Trajectory exposes different subsets of that message across its ledger and inspector. The [ledger projection](../../../../packages/client/ui-trajectory/src/client/layout.ts) omits the image count when text is present. The [inspector renderer](../../../../packages/client/ui-trajectory/src/client/TrajectoryTable.tsx) displays images without ordinary file cards in Preview and mixes file JSON with rendered images in Raw. Readers cannot reliably identify the complete attachment set without switching views.
-
-The Summary tab embeds `MarkdownRecordContent` with compact presentation, while Preview uses the same component without that option. Attachment changes must preserve that shared renderer so both entry points expose the same content and actions.
-
-## Proposal
-
-Deliver one Trajectory presentation change covering the ledger, Summary, Preview, and Raw. The proposed behavior is not implemented by this document; Issue #4356 and its linked PR track execution status and completed evidence.
-
-### Display behavior
-
-| Location | Proposed behavior |
-|---|---|
-| Ledger | Show separate nonzero image and ordinary-file counts beside the text excerpt, including messages that contain text. Keep each record on one compact line. |
-| Summary and Preview | Render the message text followed by one ordered attachment list. Use the same attachment renderer in both tabs; Summary may retain its compact spacing and scroll container. |
-| Attachment list | Use equal-width compact rows with consistent height, spacing, and corners. Place a file-type icon or contained image thumbnail on the left and the recorded name and available metadata on the right. Preserve attachment occurrence order, including repeated references. |
-| Image interaction | Fit the whole image inside its thumbnail without cropping. Open the existing large-image viewer on activation; preserve keyboard access, loading feedback, and retry after a failed read. |
-| Raw | Preserve original content-block order and boundaries. Give image and file blocks consistent, initially collapsed metadata disclosures, with complete recorded fields available on expansion. Keep text blocks as unrendered text; generated display labels do not become raw fields. |
-
-Use the recorded filename when available and a localized numbered image label otherwise. Show type and size only when supported by the recorded data; preserve zero-byte sizes. Long names may truncate visually, but the full name must remain available through accessible text and a tooltip. A message without text still exposes every attachment. Multiple attachments remain reachable inside the inspector's existing scroll area.
-
-### Implementation ownership
-
-[ui-trajectory](../../../../packages/client/ui-trajectory/README.md) owns the counts, ordered attachment projection, and inspector composition. Carry typed image and file references through its view data rather than recovering file metadata by parsing JSON prepared for display. Keep complete recorded attachment fields available to Raw.
-
-[ui-attachment](../../../../packages/client/ui-attachment/README.md) retains image loading and viewer behavior, using the Conversation-owned per-session cache. Compose cross-package UI through slots and reuse suitable static controls from [ui-primitives](../../../../packages/client/ui-primitives/README.md), following the [client rules](../../../../packages/client/AGENTS.md). Update all consumers of any changed shared props. Keep the containment treatment specific to the requested attachment presentation so existing Chat and tool-image sizing remains covered by regression checks.
-
-This scope uses existing durable attachment references. It introduces no upload, storage, model-request, or Session-format change, and no ordinary-file content viewer or download action. Styles follow [Web styling](../../../../docs/web-styling.md); display text, accessibility labels, and tooltips use typed locale dictionaries.
-
-### Existing decisions
-
-The [generic file upload decision](../../implemented/feature/2026-08-26-generic-file-upload.md) remains authoritative for upload, storage, admission, and ordered message attachments. This proposal revises only its Trajectory presentation and does not fully supersede that record. The [unreadable attachment quarantine proposal](2026-08-20-attachment-read-quarantine.md) concerns model-request recovery and remains independent of thumbnail loading feedback.
-
-## Implementation plan
-
-The steps below define the delivery sequence and completion evidence. They are not a record of commands already run. Use the current [development guide](../../../../docs/development.md), [testing policy](../../../../docs/testing.md), and linked workflows when executing them.
-
-| Step | Work | Completion evidence |
-|---|---|---|
-| 1. Establish the baseline | Verify the internal repository, live base, clean worktree, dependencies, and applicable rules; use an isolated feature branch. | The repository, branch, and base are identified and unrelated changes are excluded. |
-| 2. Associate an Issue | Find the existing task or create its Issue with reproduction, scope, native Type, applicable Project fields, and the acceptance criteria below. | A real Issue owns progress and provides the PR reference. |
-| 3. Map consumers | Trace Trajectory attachment data, Summary/Preview composition, Raw serialization, image slots, and any shared props. | Every affected consumer and test owner is identified before interfaces change. |
-| 4. Implement presentation | Preserve typed attachment data, fix counts, introduce the shared attachment list, and align Raw disclosures in that order. | All four locations expose the specified information without changing durable message data. |
-| 5. Add behavior evidence | Extend projection and component tests, then the recorded mixed-upload browser scenario; cover both inspector entry points and image interactions. | Assertions reject the missing-file, missing-count, ordering, and layout regressions. |
-| 6. Update documentation | Update affected README pairs, JSDoc, and the owning decision records with the implementation; record bilingual consistency. | Documentation describes the implemented behavior, and this proposal is rewritten for its final lifecycle when implementation is complete. |
-| 7. Validate the outgoing diff | Apply the [pre-push check workflow](../../../skills/dsh-pre-push-checks/SKILL.md) and the client check ladder; inspect the complete diff and changed expected outputs. | Relevant local checks pass, with commands and limitations recorded accurately. |
-| 8. Commit and demonstrate | Review hook changes, commit normally, build the clean committed tree, and record one isolated real-server, real-model flow under the [GIF workflow](../../../skills/record-browser-gif/SKILL.md). Push normally and verify the remote head. | The reviewed GIF names the demonstrated commit and serving conditions, and the remote branch contains that commit. |
-| 9. Publish and review | Fill the [PR template](../../../../.github/pull_request_template.md), link the Issue, select live kind/area labels, and attach evidence. Check the PR preview and CI; address review on the same branch. | The current head has reviewable evidence; fixes update affected checks and the GIF when its demonstrated commit changes. |
-| 10. Merge and follow up | After review, satisfy live approval and merge rules, then follow mainline checks and Issue state. | The authorized merge is verified and any remaining work has an owner; release publication follows its separate workflow. |
-
-### Verification coverage
-
-| Layer | Planned coverage |
-|---|---|
-| Projection | Text with one image and one file; images only; files only; attachment-only mixed messages; empty text; multiple and repeated attachment occurrences. Counts and raw fields match the input. |
-| Components | Summary and Preview show the same attachment names, order, metadata, and activation behavior. Raw preserves block order and complete fields. Cover absent image names, zero-byte files, long filenames, loading, failure, and retry. |
-| Assembled application | Extend [file-upload-round](../../../../apps/web/tests/file-upload-round.e2e.ts) and its [recorded scenario](../../../../snapshots/web/file-upload-round/snapshot.yml) to inspect Summary, Preview, and Raw after the mixed upload and after reopening history. Keep the [shared image-cache check](../../../../apps/web/tests/trajectory-image-display.expected.e2e.ts). |
-| Browser layout and accessibility | Verify narrow and wide inspector widths, light and dark themes, both locales, complete thumbnail containment, reachable final attachments, and keyboard activation and viewer dismissal. Keep geometry expectations beside their test owner under the [snapshot placement rules](../../../../snapshots/AGENTS.md). |
-| Local checks | Run focused tests during implementation, then the required GUI and browser replay checks from the client rules, locale verification, documentation checks, and lint. Normal pre-push runs typecheck; CI owns exhaustive coverage and platform checks. |
-| Demonstration | Record mixed submission, the ledger counts, Summary, Preview with image activation, and expanded Raw metadata from one real model session. Keep media outside the feature branch and attach it according to the GIF workflow. |
-
-## Alternatives considered
-
-**Keep large inline images as the default inspector presentation.** This makes one image immediately readable, but a tall image displaces attachment names and message text in the narrow inspector. Compact rows with explicit image activation provide a consistent overview of mixed attachments.
-
-**Use two-column attachment cards.** A grid can make thumbnails more prominent on wide panels, but it leaves less room for long filenames and requires a different narrow-panel arrangement. A single equal-width list is the proposed default.
-
-**Keep file JSON and image previews together in Raw.** This preserves the existing rendering, but assigns different meanings to the same tab for two attachment kinds. Consistent metadata disclosures let readers inspect recorded fields while Preview owns the visual image presentation.
-
-## Acceptance criteria
-
-- A message containing text, one image, and one ordinary file shows both counts in the ledger and both attachments in Summary and Preview.
-- Summary and Preview share one attachment renderer; each provides the same ordered attachments and image actions despite their different spacing and containers.
-- Attachment-only messages, repeated references, unnamed images, zero-byte files, and long filenames remain identifiable without invented metadata.
-- Images fit completely inside compact thumbnails. Keyboard and pointer users can open and dismiss the existing image viewer; a failed image load remains visible and retryable.
-- Raw preserves every original content block and its order. Image and file disclosures expose all recorded attachment fields without replacing them with generated labels or downloaded file contents.
-- Narrow panels, both themes, and both locales remain usable. Existing Chat/tool-image behavior and per-session image cache reuse retain regression coverage.
-- The implementation includes corresponding tests, reviewed keyless browser expectations, paired documentation, and a real-model GIF tied to the demonstrated PR head.
-
-## Risks
-
-Adding file references to view data can accidentally route them through image-only consumers or lose raw fields. Trace every affected discriminant and verify mixed and repeated occurrences. Compact thumbnails reduce immediate readability of diagrams, so full-image activation must remain discoverable. Shared renderer changes can affect Chat and tool results, while Summary's scroll container can hide final rows; both need assembled-browser checks. Missing recorded metadata must remain visibly absent, and image-read failures must not hide unrelated files. Unavailable model credentials block the real-model demonstration and must be reported rather than replaced with fixture footage.

+ 0 - 89
.agents/notes/proposed/bug-fix/2026-09-15-trajectory-attachment-presentation.zh.md

@@ -1,89 +0,0 @@
-# Agent Note: 统一 Trajectory 附件展示
-
-Status: proposed
-
-[English](2026-09-15-trajectory-attachment-presentation.md) | 中文
-
-## 问题
-
-用户消息可以包含文本、图片和普通文件,但 Trajectory 列表与详情面板展示的消息内容并不完整一致。[列表投影](../../../../packages/client/ui-trajectory/src/client/layout.ts)在消息含有文本时省略图片数量。[详情渲染器](../../../../packages/client/ui-trajectory/src/client/TrajectoryTable.tsx)在预览中展示图片而不展示普通文件卡片,在原始内容中又把文件 JSON 与渲染后的图片混排。读者需要切换视图才能确认完整的附件集合。
-
-概述标签页通过紧凑展示选项嵌入 `MarkdownRecordContent`,预览标签页使用同一组件,但不启用该选项。附件调整必须保留这一共享渲染器,使两个入口展示相同的内容和操作。
-
-## 提案
-
-交付一项覆盖列表、概述、预览和原始内容的 Trajectory 展示调整。本文不实现所提议的行为;执行状态和已完成的验证证据由 Issue #4356 及其关联 PR(Pull Request)记录。
-
-### 展示行为
-
-| 位置 | 提议的行为 |
-|---|---|
-| 列表 | 在文本摘要旁分别显示非零的图片数量与普通文件数量,包含有文本的消息。每条记录保持为紧凑单行。 |
-| 概述与预览 | 消息正文之后展示一个有序附件列表。两个标签页使用相同的附件渲染器;概述可以保留紧凑间距和滚动容器。 |
-| 附件列表 | 使用等宽的紧凑行,统一行高、间距和圆角。左侧放文件类型图标或完整缩放的图片缩略图,右侧放已记录的名称与可用元数据。保留每次附件出现的顺序,包括重复引用。 |
-| 图片交互 | 图片完整缩放到缩略图内,不裁剪。激活时打开现有大图查看器;保留键盘访问、加载反馈和读取失败后的重试。 |
-| 原始内容 | 保留原始内容块顺序与边界。图片块和文件块使用一致、默认收起的元数据折叠区,展开后显示完整记录字段。文本块保持未渲染文本;生成的显示标签不进入原始字段。 |
-
-有已记录文件名时使用文件名,否则为图片使用本地化的编号标签。类型与大小只在已记录数据支持时显示;保留零字节大小。长名称可以在视觉上截断,但完整名称必须能通过无障碍文本和工具提示获取。没有正文的消息仍须展示每个附件。多个附件在详情面板现有滚动区域内保持可达。
-
-### 实现职责
-
-[ui-trajectory](../../../../packages/client/ui-trajectory/README.zh.md)负责计数、有序附件投影和详情面板组合。通过其视图数据传递带类型的图片与文件引用,不从为展示准备的 JSON 中反向解析文件元数据。为原始内容保留完整的已记录附件字段。
-
-[ui-attachment](../../../../packages/client/ui-attachment/README.zh.md)继续负责图片加载和查看器行为,使用 Conversation 拥有的会话级缓存。通过 slot 组合跨包 UI,并复用 [ui-primitives](../../../../packages/client/ui-primitives/README.zh.md) 中适用的静态控件,遵循[客户端规则](../../../../packages/client/AGENTS.md)。共享属性发生变化时,更新全部消费方。完整缩放处理限定于本次附件展示,并通过回归检查覆盖现有 Chat 和工具图片尺寸行为。
-
-本次范围使用现有持久附件引用,不改变上传、存储、模型请求或会话格式,也不增加普通文件内容查看器或下载操作。样式遵循 [Web 样式规范](../../../../docs/web-styling.zh.md);显示文字、无障碍标签和工具提示使用带类型的本地化字典。
-
-### 现有决定
-
-[通用文件上传决定](../../implemented/feature/2026-08-26-generic-file-upload.zh.md)继续负责上传、存储、准入和有序消息附件。本提案只调整其中的 Trajectory 展示,并不完整取代该记录。[不可读附件隔离提案](2026-08-20-attachment-read-quarantine.zh.md)处理模型请求恢复,与缩略图加载反馈相互独立。
-
-## 实施计划
-
-以下步骤定义交付顺序与完成证据,不代表命令已经执行。执行时使用当前[开发指南](../../../../docs/development.zh.md)、[测试策略](../../../../docs/testing.zh.md)和所链接的工作流。
-
-| 步骤 | 工作 | 完成证据 |
-|---|---|---|
-| 1. 确定基线 | 核对内部仓库、实时基线、干净的 worktree、依赖和适用规则;使用隔离的功能分支。 | 仓库、分支和基线明确,未混入无关修改。 |
-| 2. 关联 Issue | 查找现有任务或创建 Issue,写明复现、范围、原生 Type、适用的 Project 字段和下列验收标准。 | 真实 Issue 负责进度,并作为 PR 的引用。 |
-| 3. 梳理消费方 | 跟踪 Trajectory 附件数据、概述与预览组合、原始内容序列化、图片 slot 和共享属性。 | 接口修改前,已明确全部受影响消费方与测试归属。 |
-| 4. 实现展示 | 依次保留带类型的附件数据、修正计数、引入共享附件列表、统一原始内容折叠区。 | 四处位置均展示规定信息,持久消息数据不变。 |
-| 5. 补行为证据 | 扩展投影与组件测试,再扩展已录制的混合上传浏览器场景;覆盖两个详情入口和图片交互。 | 断言能够检出文件遗漏、计数遗漏、顺序及布局回归。 |
-| 6. 更新文档 | 随实现更新受影响的 README 双语文件、JSDoc 和所属决定记录,并记录双语一致性。 | 文档描述已实现行为,完整实现后按最终生命周期改写本提案。 |
-| 7. 验证待提交差异 | 应用[推送前检查工作流](../../../skills/dsh-pre-push-checks/SKILL.md)和客户端检查层级;检查完整差异与变化的预期输出。 | 相关本地检查通过,准确记录命令与限制。 |
-| 8. 提交与演示 | 检查 hook 修改,正常提交,构建干净的已提交代码树,并按 [GIF 工作流](../../../skills/record-browser-gif/SKILL.md)录制一次隔离的真实服务、真实模型流程。正常推送并核对远端提交。 | 已检查的 GIF 标明演示提交和服务条件,远端分支包含该提交。 |
-| 9. 发布与评审 | 填写 [PR 模板](../../../../.github/pull_request_template.md),关联 Issue,选择当前 kind/area 标签并附证据。检查 PR 预览和 CI;在同一分支处理评审。 | 当前提交具有可评审证据;修复后更新受影响检查,演示提交变化时更新 GIF。 |
-| 10. 合并与跟进 | 评审后满足实时审批与合并规则,再跟进主线检查和 Issue 状态。 | 已核实获授权的合并,剩余工作有明确归属;发行走独立流程。 |
-
-### 验证覆盖
-
-| 层级 | 计划覆盖 |
-|---|---|
-| 投影 | 文本加一张图片与一个文件、只有图片、只有文件、无正文的混合附件、空文本、多个附件与重复附件。计数和原始字段与输入一致。 |
-| 组件 | 概述与预览显示相同的附件名称、顺序、元数据与激活行为。原始内容保留块顺序和完整字段。覆盖图片无名称、零字节文件、长文件名、加载、失败与重试。 |
-| 组装应用 | 扩展 [file-upload-round](../../../../apps/web/tests/file-upload-round.e2e.ts) 及其[录制场景](../../../../snapshots/web/file-upload-round/snapshot.yml),在混合上传后和重新打开历史后检查概述、预览与原始内容。保留[共享图片缓存检查](../../../../apps/web/tests/trajectory-image-display.expected.e2e.ts)。 |
-| 浏览器布局与无障碍 | 验证窄版与宽版详情面板、浅色与深色主题、两种语言、缩略图完整缩放、末尾附件可达,以及键盘激活和关闭查看器。按[快照存放规则](../../../../snapshots/AGENTS.md),把几何预期留在所属测试旁。 |
-| 本地检查 | 实现期间运行针对性测试,然后执行客户端规则要求的 GUI 与浏览器回放检查、本地化验证、文档检查和 lint。正常 pre-push 执行类型检查;CI 负责全量覆盖率与平台检查。 |
-| 演示 | 在同一个真实模型会话中录制混合提交、列表计数、概述、预览中的图片激活,以及展开的原始元数据。媒体保存在功能分支之外,按 GIF 工作流附到 PR。 |
-
-## 考虑过的替代方案
-
-**默认在详情面板中内联展示大图。** 这样可以立即阅读单张图片,但高图片会在窄面板中挤走附件名称和消息正文。紧凑行加显式图片激活入口能一致地概览混合附件。
-
-**使用双列附件卡片。** 网格能在宽面板上突出缩略图,但会压缩长文件名空间,并要求窄面板采用不同排布。提案默认使用单列等宽列表。
-
-**在原始内容中继续混排文件 JSON 和图片预览。** 这保留了现有渲染,却让同一个标签页对两种附件具有不同含义。一致的元数据折叠区用于检查已记录字段,图片视觉展示由预览负责。
-
-## 验收标准
-
-- 同时包含文本、一张图片和一个普通文件的消息,在列表显示两种数量,在概述和预览显示两个附件。
-- 概述与预览共用一个附件渲染器;即使间距和容器不同,也提供相同的有序附件和图片操作。
-- 纯附件消息、重复引用、无名称图片、零字节文件和长文件名保持可识别,不编造元数据。
-- 图片完整缩放到紧凑缩略图内。键盘和指针用户均可打开并关闭现有图片查看器;图片加载失败时仍有可见反馈并可重试。
-- 原始内容保留每个原始内容块及其顺序。图片与文件折叠区展示全部已记录附件字段,不以生成标签或下载的文件内容替代。
-- 窄面板、两种主题和两种语言下均可使用。现有 Chat/工具图片行为和会话级图片缓存复用保留回归覆盖。
-- 实现包含相应测试、经审阅的无密钥浏览器预期输出、双语文档,以及与演示 PR 当前提交对应的真实模型 GIF。
-
-## 风险
-
-在视图数据中加入文件引用,可能误将文件传给只接受图片的消费方,或丢失原始字段。需要跟踪每个受影响的类型标记,并验证混合与重复附件。紧凑缩略图降低了图表的直接可读性,因此大图激活入口必须容易发现。共享渲染器改动可能影响 Chat 和工具结果,概述滚动容器也可能遮挡末尾行;两者都需要组装浏览器检查。缺失的记录元数据必须保持明确缺失,图片读取失败不能隐藏其他文件。模型凭证不可用时,真实模型演示会受阻,必须如实说明,不能用 fixture(测试前置数据)录屏替代。

+ 2 - 2
packages/client/ui-trajectory/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write packages/client/ui-trajectory/README.md
-README.md: f11bfa3188ce616e392158f9f2cf33920edea8ba
-README.zh.md: 53672cc8e4c8891ff6ea9b985b4efafc0368e1bf
+README.md: 1ddfe6198d37b8e61b44507ab02cbe5a08cafc40
+README.zh.md: 68ea4d7fa8711296407b3881300c7343514a62cc

+ 2 - 0
packages/client/ui-trajectory/README.md

@@ -35,6 +35,8 @@ Selection, timeline navigation, folding, and search cover the React-visible wind
 
 Summary and Preview share one ordered attachment list after the message text, preserving repeated references. Each row shows a contained image thumbnail or file-type icon, the recorded filename (a localized numbered label for unnamed images), and recorded size, type, and image dimensions where available. Zero-byte files retain their size, and truncated filenames expose the full name in a tooltip. Images open the existing lightbox. Raw keeps content-block order and unrendered text, with images and files in initially collapsed disclosures containing their complete recorded fields.
 
+Selecting another record resets its Raw attachment disclosures to collapsed. Updates to the selected record, including loading older history, preserve its disclosure state.
+
 ### The timing overview
 
 Historical replies retain TTFT, generation duration, and throughput when their recorded streams contain token timestamps. TTFT measures from the Step start to its first token, including output from an earlier retry attempt; an unloaded Step start or a stream without tokens leaves the corresponding metric unavailable.

+ 2 - 0
packages/client/ui-trajectory/README.zh.md

@@ -35,6 +35,8 @@ Trajectory 标签页让你以按轮次组织的事件记录表和交互式时间
 
 概述与预览共用正文之后的有序附件列表,保留重复引用。每行展示完整缩放的图片缩略图或文件类型图标、已记录的文件名(未命名图片使用本地化的编号名称),以及可用的已记录大小、类型和图片尺寸。零字节文件保留大小显示,截断的文件名通过提示显示完整名称。图片打开现有灯箱。原始内容保留内容块顺序和未渲染文本,图片与文件使用默认折叠的展开项,包含完整的已记录字段。
 
+选择另一条记录时,其原始内容中的附件折叠区恢复收起状态。当前记录更新时,包括加载更早历史时,折叠状态保持不变。
+
 ### 时间概览
 
 当记录的流包含 token 时间戳时,历史回复会保留 TTFT、生成耗时与吞吐量。TTFT 从步骤开始计量到首个 token,包括更早重试尝试中的输出;步骤起点尚未加载或流中没有 token 时,对应指标保持不可用。