---
status-class: historical
design-state: superseded-unshipped-v1
historical-refs:
  - specs/agent-space/shared-spaces-and-agent-spaces.md
---
# Agent Space 04：Surface Projection Design

日期：2026-04-25
状态：superseded historical record。本文只记录未上线 Agent Space panel /
share-flow / publish / auto-publish surface 设计线，不能作为当前产品、schema、
API、runtime 或用户可见 surface 的合同。当前实现已经删除 Agent Space panel、
browser-facing Agent Space API/realtime、manual publish / auto-publish UI、基于
publication relation 的 projection 与 private-agent visual filtering；默认 Web surface
使用 parent channel/thread/task target、Task / owner-private context facade 和 hidden
owner-private context。需要实现当前语义时请参考 `runtime-api-design.md`、Task 收敛
specs、storage spec 与代码。
范围：把 `01-space-core` / `02-delivery-wake` / `03-share-publish` 已经锁定的对象与行为，收敛成 panel / details / modal / composer-adjacent surface 的显示合同；定义哪些 surface 只是 render，哪些 surface 真的触发 share / publish / routing action。
非目标：像素级视觉稿、具体 React 组件实现、API 形状、迁移 rollout 顺序、group/role mention、generic notification 文案。

## 0. 与前序设计的关系

本篇默认以下前置已经成立：

- `01-space-core` 锁定 `agent_space` 的对象模型、lifecycle、parent observer 边界、owner direct authoring 与 source refs 基座；
- `02-delivery-wake` 锁定 unread / badge / wake / observer browse 与 delivery 分离语义；
- `03-share-publish` 锁定 share-in / publish-out / auto-publish / thread routing modifier / richer share thumbnail + detail 的产品语义；
- `web/src/agentteam/components/ui/*` 与现有 thread surface 锁定当前 AgentTeam 前端可复用 primitives；
- 未上线 implementation line 中的 `AgentSpacePanel` / share flow / entry surfaces 仅作为历史 handoff baseline；这些入口不是当前 Web/API surface。
- 未上线 implementation line 曾把 panel header、member/notification buttons、ShareFlow、mobile composer 与 message actions 收敛到本文 v1 形态；这些 browser-facing Agent Space surfaces 已被删除。本文后续旧 wording 只用于理解历史实现，不得作为当前 Web/API/runtime 依据。

因此，这份历史 O4 当时不重新定义：

1. 谁能看见什么；
2. 谁能 publish / share；
3. unread / wake 如何计算；
4. packed / per-row / thread-in-detail 的内容合同。

历史 O4 只回答：

- 这些已删除的未上线语义当时在 **哪个 surface** 上如何呈现；
- 哪些 UI 只是在投影同一条对象，哪些 UI 真的是新的 action 入口；
- 当同一对象跨 surface 出现时，哪些 metadata 必须一致，哪些可以延后或折叠。
- 以及 **哪些本来看似可做成 surface 的东西，v1 明确不做**。

## 1. Goal & non-goals

### 1.1 Goal

O4 希望把 Agent Space 相关的 UI surface 收成一份 **projection contract**，避免后续每做一个界面都重新发明：

- header 命名与 scope 提示；
- transcript row 在 panel / detail / parent published row 里的对应关系；
- shared-context thumbnail vs detail 的展开边界；
- channel main 下针对 `@agent` 的 thread routing modifier 如何暴露；
- 哪些地方直接复用现有 AgentTeam thread / message primitives，哪些地方必须新增 gap 组件。

### 1.2 Non-goals

本篇不解决：

- pixel-perfect Figma 稿与动效参数；
- API / React Query hook 的最终命名；
- analytics 埋点；
- 实现任务拆分与 rollout plan；
- 未来多 owner header disambiguation 的最终解。

## 2. Vocabulary

### 2.1 Surface

`surface` 指用户实际可见、可交互的一块 UI 容器，例如：

- Agent Space panel
- shared-context details
- share modal
- composer routing modifier

### 2.2 Projection

`projection` 指：

> 同一个底层 Agent Space / parent message object，在另一个 surface 上的 render 呈现。

projection 不等于新的 routing / delivery / authored object。

### 2.3 Reference surface

`reference surface` 指当前已经通过 O4 锁定、可以当作后续实现基线的 surface。

当前 O4 的第一个 reference surface 是：

- `AgentSpacePanel`

### 2.4 Action surface

`action surface` 指用户在其中直接触发 share / publish / routing 决策的 UI。

当前候选 action surfaces：

- `ShareFlow`
- `ChannelComposeRoutingModifier`
- parent timeline message hover / more-actions 中的 publish

## 3. Cross-surface invariants

### 3.1 Render 不创造新 routing

某条消息被渲染在 panel / detail / parent published row 中，不意味着它自动变成新的 parent row 或新的 Agent Space row。

### 3.1A v1 不做 InlineAgentSpaceProjection

v1 明确不做 `InlineAgentSpaceProjection`。

这意味着：

- parent timeline 只显示**真实的 parent row**；
- Agent Space transcript 只在 panel / detail family 中显示；
- parent 中需要可见的内容，必须走 manual publish / auto-publish materialize 成真实 parent row；
- O4 不再讨论 “私有消息影子在 parent 里折叠渲染” 这条路线。

### 3.1B v1 不做 PublishAttributionPill

v1 也不做常驻的 `PublishAttributionPill` / dedicated provenance chrome。

这意味着：

- parent published row 默认看起来就是普通 parent message；
- O4 v1 不要求在 parent row 上常驻显示 `from Agent Space` 一类标签；
- provenance 仍然存在于数据模型与 traceability 合同中，但不在 v1 作为独立常驻 surface 暴露。

### 3.2 Shared-context thumbnail 与 detail 使用同一内容真相

thumbnail 中的缩略 preview 与 detail 中的完整消息列表，必须来自同一个 shared-context payload truth；detail 只是展示更多，不是另一套独立对象。

### 3.3 Parent participant 的 observer 能力不等于 unread / badge

任何 O4 surface 都不能暗示 parent participant 因为能 browse Agent Space 就拥有 unread / badge / inbox 语义。

### 3.4 Scope 影响文案，但不改变对象类型

channel-level Agent Space 与 thread-level Agent Space 的差异主要体现在：

- header scope label
- publish target label
- subtitle/source provenance
- sidebar / entry path

而不是两套不同的 UI 语言。

### 3.5 Panel 是私有协作工作区，不是 parent timeline 复制件

即便 panel 复用 AgentTeam thread primitives，它仍然代表 Agent Space transcript，而不是普通 parent thread panel 的简单别名。

## 4. Surface contracts

### 4.1 AgentSpacePanel family

`AgentSpacePanel` 是 O4 的第一个正式 reference surface。它代表 Agent Space transcript 的主工作区，而不是 parent thread panel 的简单复制。

#### 4.1.0 Implementation strategy: thread as baseline

Agent Space 的前端实现策略不是“重新做一套平行 panel UI”，而是**拿当前 AgentTeam thread 作为 baseline，只叠加 Agent Space 特有的差异层**。

应直接复用的 thread primitives 至少包括：

- `WorkspacePaneHeader` / `WorkspacePanePrimaryRow`
- `MessageRow`
- 当前 thread-style 的两排 composer（`FlatConversationEditor` + 第二排 emoji/send）
- message hover action cluster
- 右侧 pane chrome、spacing、border density、token palette

需要在 thread baseline 上额外表达的 Agent Space 差异至少包括：

1. header scope 文案（`Agent Space / #channel`、`Agent Space / {thread}`）
2. entry surface / panel placement
3. shared-context row + details
4. non-owner read-only mode
5. archived state
6. publish / share flow 相关动作与文案

反过来说，v1 明确不鼓励：

- copy 一份新的平行 thread UI
- 引入新的 bubble / 新布局体系 / 新的 panel 视觉语言
- 让 Agent Space 看起来像另一个独立产品壳，而不是 thread baseline 上的语义变体

#### 4.1.1 包含的 panel family

v1 的 panel family 至少包括：

- channel-level Agent Space panel
- thread-level Agent Space panel
- archived read-only panel
- shared-context details page（作为 panel 家族的一部分，而不是独立信息架构）

Canonical implementation references:

- `web/src/agentteam/workspace/AgentSpacePanel.tsx`
- `web/src/agentteam/workspace/ThreadMessages.tsx`

#### 4.1.2 视觉语言

v1 不引入新的 panel 视觉语言。实现必须直接 anchored 到当前 AgentTeam thread UI，优先复用：

- `WorkspacePaneHeader`
- `MessageRow`
- `FlatConversationEditor`
- 现有 token / spacing / border density

这条约束意味着：Agent Space 的“特殊性”应尽量通过 header scope、shared-context row、hover actions、archived banner 等最小差异表达，而不是通过新的 bubble、重色 pill、独立布局体系来表达。

因此 O4 surface 不应重新引入类似 sidebar subtitle / org label 的二级头部装饰，只为“看起来像一个新产品面板”而增加噪音。

#### 4.1.3 Header contract

v1 的 header 采用 owner-implicit 规则：当前 viewer 默认就是该 owner 的使用视角，因此 header 不额外重复 owner 名字；多 owner disambiguation 留待后续设计。

Header 格式：

- channel-level：`Agent Space / #channel-name`
- thread-level：`Agent Space / {thread id or thread title}`

thread-level header 不带 channel 名前缀；channel 路径由外部导航或详情来源信息承担。

Header 右侧 action contract：

- `Notifications` 使用与 channel / thread 同样的 header action alignment，而不是靠左浮动；
- `Members` 是单独按钮，点击后打开成员面板，列出该 Agent Space 中的 owner / private agents 及状态；
- 标题下方不显示 `@agent1, @agent2, ...` 这种 agent subtitle；成员信息只进入 `Members` panel，避免长 agent 列表挤压标题。

#### 4.1.4 Transcript row contract

panel 内 transcript 使用真实 Agent Space row 的 projection，而不是 parent timeline 的镜像。

其中：

- owner direct authoring row = 普通 owner message row
- private-agent-authored row = ordinary agent message row style（这里只锁样式复用，不表示 Agent Space transcript 会包含 public agent authored rows）
- shared-context row = 一条 owner-authored transcript row，其 row shell 上的 avatar / displayName / timestamp 都来自 **share action 本身**

这意味着 shared-context row 的外壳字段 **不** 继承原消息作者与原消息时间；原消息作者/时间只存在于卡片内部的 preview / details 中。

#### 4.1.5 Shared-context thumbnail

panel 内的 shared-context 表达为 transcript 中的一条 merged-forward row，而不是 pinned summary 区。

该 row 内部卡片的 contract：

- title = `{Owner displayName}'s shared context`
- channel-level subtitle = `From #channel, N messages`
- thread-level subtitle = `From #channel / {thread id or title}, N messages`
- preview rows 统一渲染成 `author: snippet`
- preview row **不区分** thread item vs ordinary message item；如果 batch 中有一条 thread，则 thumbnail 中也只展示该 thread root 的普通单行 snippet
- attachment 占位为轻量 inline text，例如 `[image]`、`[file] notes.md`
- top-right 不放单独的 chevron affordance；整张卡可点即可

#### 4.1.6 Shared-context details

shared-context details 是 panel family 的展开视图，用来承接 thumbnail 中被折叠掉的结构信息。

它的 contract：

- 顶部只有 header bar / jump-to-source / close
- 不再额外重复一个 `Owner's shared context` summary block
- 普通消息在 detail 中恢复为真实消息列表
- 若 batch 中存在 thread item，则 **只在 details 中** 恢复 thread-specific affordance
- thread item 在 details 中应表现为真实 AgentTeam channel/thread preview row，即复用 `MessageRow` 的 `threadSummary` 行为，而不是 inline 展开整条 nested thread transcript
- 如果同一次 share action 还附带了 message，这条 message 作为 shared-context row 下方的独立 ordinary row 存在于 transcript 中；details panel 只展示 shared messages 本身，不把这条附加 message 混入 details

#### 4.1.7 Composer

owner 可以直接在 panel 内 compose。这条是 O1 的 owner direct authoring contract 在 O4 的 surface 映射，而不是某个实现偏好。

panel composer 复用当前 AgentTeam thread-style 的**紧凑单行 composer**：

- editor/input 与 send action 在同一条基线内联排列；
- 允许在内容变长时纵向自增高，但默认呈现应与 channel / thread 的单行 compact composer 对齐；
- 不额外重复一条独立 metadata row，也不添加 `private collaboration only` helper text。
- 移动端 mounted panel 使用与 thread 相同的 vertical layout：消息列表占据剩余高度，composer anchored / sticky 在底部；不能因为消息过少漂到上方，也不能因为消息过多被推出首屏。

#### 4.1.8 Publish action

publish 不是 panel 内的常驻独立按钮。

它属于 message hover action cluster 里的 `⋯` 菜单项，而不是 reaction/copy 旁边的 top-level icon。label 随 scope 变化：

- channel-level：`Publish to channel`
- thread-level：`Publish to thread`

#### 4.1.9 Archived state

archived Agent Space surface 必须满足：

- 顶部 archived/read-only banner
- composer disabled
- transcript 仍可 browse

### 4.2 ShareFlow

v1 的 share surface 不再建模成“先弹一个独立 modal”，而是对齐飞书式 selection flow。它不再只面向 Agent Space，而是一个通用 share flow。真实产品 surface 在任何屏幕尺寸下都应一次只显示一个 active step；`Selection mode`、`Share to`、`Confirm` 依次以 modal / drawer / sheet 的线性 flow 前进。

#### 4.2.1 Entry

入口位于单条消息 hover / long-press `⋯` 菜单中，并至少包含两类 action：

- `Forward`：单条转发快捷入口，直接以该消息作为唯一 source 进入 `Share to` step，默认 shape = `Single forward`；
- `Select message`：进入 selection mode，支持多选后再选择 `Combine forward` 或 `Single forward`。

v1 不要求：

- drag-to-panel
- composer-side `Attach context`
- 其他平行入口

channel、DM 与 thread message row 都应暴露同一套 `Forward` / `Select message` action；移动端通过长按打开，不需要额外 tap-to-select 模式。

#### 4.2.2 Selection mode

进入 selection mode 后支持：

- 单选
- 多选

单条 share 只是多选的特例。选择一条已有 reply thread 的 root message 时，share snapshot 应同时包含该 thread 当前的 replies；thread 也可以作为 batch 中的一项被选中，但在 thumbnail 中仍按普通 root snippet 进入 preview，不获得额外缩略样式。
具体的 thumbnail / detail 呈现规则以 §4.1.5 / §4.1.6 为准，不在 selection mode 中另起一套表达。

selection mode 底部提供两个直接 action buttons，而不是先展示一条提示框再二次确认：

- `Combine forward`
- `Single forward`

它们用文本按钮表达 forward mode；点击后直接进入 `Share to` step。v1 默认推荐 `Combine forward`，但单条消息的 `Forward` 快捷入口直接选择 `Single forward`。

#### 4.2.3 Share-to step

完成选择后，用户通过 `Share to` 进入 target 选择。target 在这里支持多选；完成多选后通过 `Continue` 进入 confirm step。

target selector 只列出当前 viewer 实际可 share 的目标，不通过“选了再报错”来解释权限边界。v1 中 target 支持多选，target row 以 checkbox + 选中态表达选择结果；confirm page 会持有一个 selected targets 集合，并以 target chips 回显。目标范围包括：

- 你参与的 channel scopes
- 你的 DMs
- 你订阅的 thread scopes
- 你的 Agent Spaces

其中，你订阅的 reply threads 等价于 O2 / O1 语义下 viewer 在 `scope_notification_settings` 中存在 row 的 thread set；target picker 应与这个 subscription truth 对齐，而不是另造一套 thread 可见性来源。

target picker 的默认排序采用 **按 recency** 的方式呈现，也就是把用户近期发消息过、近期访问过或近期发生过交互的 target 优先排在前面，而不是固定按 sidebar family 顺序分 section。

v1 同时支持 search：

- search 跨全部 target family 生效
- 搜索结果也按 recency 优先，而不是强制保留 family section 结构

#### 4.2.4 Forward mode and resulting shape

share 的 shape 不在 target picker 中重复暴露，而是直接由 selection mode 底部的 `Forward as` action group 决定：

- `Combine forward` → `Merged context`
- `Single forward` → `Separate messages`

它们分别对应 O3 已锁定的 richer share 形状：

- `Merged context` = 在目标里产出**一条** merged-forward style 消息
- `Separate messages` = 在目标里产出**多条**独立消息（每条源消息一条）

`Merged context` 是唯一使用 shared-context / quote card 形态的 forward mode。`Separate messages`（包括单条消息的直接 Forward）应 materialize 为转发人自己发送的 ordinary message rows；这些 row 不使用 shared-context card、owner_quote message type 或 quote wrapper。

v1 不再在 target 选择页额外放一个 shape selector。

#### 4.2.5 Confirm step and message

点击 `Continue` 后进入 confirm page。

该页允许输入一条 optional message；当 selected targets > 1 时，这条 message 会随同同一 share shape 一起应用到每个目标：

- 有输入 -> share action 额外生成 1 条 ordinary message，排在 shared rows 下方
- 无输入 -> 纯 share，不附带额外 message

message 输入框放在 confirm page 的 preview 下方，而不是 selection bar 顶部或独立轻 modal。confirm page 的 `Share to` 区域应以 wrap chips 回显已选 target，而不是重新回到搜索/下拉态。
该 message 的最终落地 row-shape 是**独立 ordinary message row**；share shape（Merged context / Separate messages）只描述 shared rows 自身，不描述这条附加 message。

### 4.3 ChannelComposeRoutingModifier

`ChannelComposeRoutingModifier` 用于在 channel main 中，发送方当场决定当前 `@agent` 消息是保持在 channel-level 路径，还是同时开一个 thread 路径。

#### 4.3.1 Label and shape

- label = `Also start a thread`
- 形态 = 轻量 checkbox

v1 不使用 pill，不藏进 `⋯` 菜单。

#### 4.3.2 Layout

composer 结构固定为两排：

- 第一排 = 输入框
- 第二排 = emoji 按钮、`+` tools 按钮、`☐ Also start a thread`，然后 send 固定在最右侧
- `Also start a thread` 跟在 emoji / `+` 右边，而不是单独占据第二排左侧

#### 4.3.3 Visibility

该 modifier 仅在以下条件同时满足时出现：

- 当前 surface 是 channel main composer
- 当前 draft 中 `@` 到至少一个可路由的 private agent

因此：

- human-only / 无 mention -> 不显示
- `@human + @private-agent` 混合 mention -> 仍显示
- 只有 public agent mention -> 不显示；public agent 不走 Agent Space thread-routing modifier
- thread composer / DM composer -> 不显示

#### 4.3.4 Defaults and persistence

- 默认 = unchecked
- 不记忆上次选择
- 不做 per-agent persistence

该控件的出现/消失应尽量平滑，避免造成 composer 高度的突跳式变化。

## 5. Agent Space entry surfaces

### 5.1 Primary entry principle

v1 将 Agent Space 视为 **挂载在 channel / thread 上的上下文工作区**，而不是独立导航目的地。

因此：

- 当前 viewer 打开**自己的** channel-level / thread-level Agent Space 的快捷入口，来自当前 surface composer 第二排、位于 emoji / `+` 控件右侧的 **Agent Space 快捷图标**
- 相关 parent 消息上的 `Open Agent Space` affordance 仍然存在；它既可以打开别人的 private Agent Space，也可以在 row-scoped 语义下打开当前 viewer 自己的那个
- 打开动作应把 Agent Space 呈现为 mounted panel / detail family，而不是跳到独立页面
- sidebar / global nav 不承担 v1 的主入口职责

原 header `⋯` 菜单中的 archive / settings / leave 等 action 保留；notification 仍是独立 header icon，但 Agent Space 快捷入口不再放在 header 右上角。

### 5.2 Which host surfaces expose the entry

v1 同时存在两类入口：

1. **composer-adjacent quick entry**：当前 viewer 只要在该 host surface 上拥有一个可写的 Agent Space，就在 composer 第二排暴露自己的 `Agent Space` 快捷入口；
2. **message-level browse/open entry**：只要某条 parent message 能解析到一个当前 viewer 可 browse 的 Agent Space，这条消息就可以暴露 `Open Agent Space`；如果它恰好就是当前 viewer 自己的可写空间，这个入口与 composer 快捷入口打开的是同一个 Agent Space。

这意味着：

1. channel main 是否显示“我的 Agent Space”快捷入口，取决于当前 viewer 是否在该 channel 上拥有一个可写的 channel-level Agent Space；
2. thread surface 是否显示“我的 Agent Space”快捷入口，取决于当前 viewer 是否在该 thread 上拥有一个可写的 thread-level Agent Space；
3. author × host-surface 的对象模型约束仍然决定“这个 Agent Space 属于谁、对应哪类 parent collaboration scope”，并继续决定某一条 parent row 是否能解析到“别人的” Agent Space；
4. owner ordinary row、owner `@private agent` mention entry row、share / publish row、private-agent-authored row 仍然可能通过 source/publication/linkage relation 与某个 Agent Space 对齐；message-level entry 是 row-scoped 上下文打开入口，而不是“我的快捷入口”的唯一替代物。

### 5.3 Visibility and access semantics

两类入口的可见性不同：

- composer-adjacent quick entry 是 **viewer-scoped**：只有当前 viewer 自己拥有可写 Agent Space 时才显示；
- message-level `Open Agent Space` 是 **row-scoped**：只要该 row 能解析到一个当前 viewer 可 browse 的 Agent Space，就可以显示。

访问语义如下：

- 当前 viewer 点击 composer-adjacent quick entry → 打开自己的可写 Agent Space panel；
- 当前 viewer 点击某条 parent row 上的 `Open Agent Space` → 打开该 row 解析出的那个 Agent Space；如果该空间属于当前 viewer，则以可写方式打开；如果不属于当前 viewer，则以 read-only browse 打开。

read-only browse panel 的 contract：

- transcript 仍可 browse
- composer disabled
- banner 文案与 archived state 明确区分；它表达的是“你正在以非 owner 身份浏览”，不是“这个 Agent Space 已归档”

这条 read-only 打开能力只适用于 **channel / thread 上挂载的 Agent Space panel**。它不自动放开一条新的 DM 能力：v1 仍不允许 non-owner 与别人拥有的 agent（private / public）建立 DM conversation；其中 public agent 的 DM owner 在 v1 默认按 creator / manager-of-record 解释。

### 5.4 Scope is determined by the current host surface

入口不单独切 scope；scope 由承载该入口的 host surface 决定：

- 从 channel main 的 composer 快捷入口或相关消息打开 → channel-level Agent Space
- 从 thread surface 的 composer 快捷入口或相关消息打开 → thread-level Agent Space

同一个 panel 实例不承担“在打开后再切到另一个 scope”的职责。
同一个 host surface 只暴露与其 **当前 scope** 匹配的入口；不会因为别的 surface 语义下也有关联，就在当前 surface 上额外挂出跨-scope shortcut。

### 5.5 Entry combines composer quick entry and per-message browse entry

v1 不再把“我的 Agent Space”放在 header 右上角；它是一个 **composer-adjacent affordance**，位于第二排 emoji / `+` 控件右侧。与此同时，`Open Agent Space` 仍保留为 message hover action cluster 里的一级 action；它既可以浏览别人的 private Agent Space，也可以从某条 row 的上下文直接打开当前 viewer 自己的那个空间。

这意味着：

- “我的 Agent Space”不进入 `⋯` 菜单，也不退化到 header 右上角；
- “相关消息上的 Agent Space”仍可在 parent timeline 中逐条暴露 `Open Agent Space`，不区分该空间最终属于自己还是别人
- 不实现额外的 inline pill / inline badge 作为主入口
- 也不能退化成“先去 sidebar / global nav 找 Agent Space，再回忆它属于哪条消息”

### 5.6 Panel placement by host surface

从不同 host surface 打开时，panel placement 规则如下：

- 从 channel main 打开 → `channel main | agent space`
- 从 thread 打开 → `thread | agent space`

thread 打开场景里的 `thread | agent space` 指：

- channel main 在 UI 上收起，为 thread + Agent Space 双栏让位
- 但逻辑上不是 navigate away；关闭 Agent Space 后，用户应能一步回到 `channel main | thread` 的既有双栏态
- channel main 被 UI 收起期间，其阅读位置、展开状态、未读标记等宿主 UI 状态应被保留；恢复时应尽量回到收起前的可见状态，而不是重建一个“新的” channel 视图

### 5.7 Explicitly not in v1

以下变体在 v1 明确不做：

- 不把“我的 Agent Space”放在 header 右上角
- 不把 `Open Agent Space` 放进 `⋯` 菜单
- 不把它做成 message inline pill / provenance badge
- 不做 owner picker / tab switcher 这种“先打开一个模糊入口，再在内部选 owner”的模型
- 不允许从 channel main 的 thread root row 直接 deep-link 到 thread-level Agent Space

### 5.8 No separate secondary resume / discovery path in v1

v1 不再单独设计第三条 secondary resume / discovery path。

原因是：

- 当前 viewer 自己的 Agent Space 已由 composer-adjacent quick entry 覆盖；
- private-agent-authored / share-materialized / owner ordinary 等相关消息，已经为“相关 row 对应的 Agent Space”提供了 browse / open 入口。

因此，v1 的完整入口方案是：**我的空间既可走 composer 快捷入口，也可走 row-scoped `Open Agent Space`；别人的空间走 message-level browse entry**；sidebar / global nav 仍然不是必需的补充入口。

## 6. Parent → Agent Space linkage

### 6.1 Primary behavior

当 parent row 与 Agent Space panel 同时可见时，v1 保留 **parent ↔ Agent Space relation lookup contract**。

这条 contract 仍服务于：

- 从 parent 某条消息显式打开别人的 Agent Space 时的首次定位；
- Agent Space panel 已打开后，hover 当前 parent row 驱动的 follow；
- shared-context / publish / auto-publish row 的 source/publication 对齐
- Agent Space 内显式 `Jump to source` 后返回 parent 的定位语义
- 任何后续明确需要“给定 parent row，解析 Agent Space 对应 row”的显式导航动作

如果某条 parent row 在 Agent Space 中没有精确对应项，允许退化到最近的合理锚点，但不能跳到明显无关的位置；v1 仍不做反向 hover 联动（Agent Space hover 反过来驱动 parent）。

### 6.2 Resolution order

给定当前 parent view 中的可见 row `P` 与已解析出的目标 Agent Space `S`，联动目标 row 的解析顺序固定为：

1. **publish relation 命中优先**：如果 `P` 是由 Agent Space row publish / auto-publish 到 parent materialize 出来的，则直接定位到该 source row；
2. **source relation 次之**：如果 `S` 中存在一条从 `P` share / merged-forward materialize 进来的 row，则定位到该 shared-context row；
3. **time-anchor fallback**：如果两张 relation 都未命中，则在 `S` 的 transcript 中查找 `created_at ≤ P.created_at` 的最近一条 row；
4. **无命中则不动**：如果 `S` 为空，或 `P` 早于 `S` 中第一条 row，则保持当前滚动位置，不强行跳转。

v1 不沿 ancestor / reply-chain 递归回溯；relation lookup 未命中后，直接进入时间锚 fallback。

### 6.3 Explicit open vs hover follow

两种触发方式的 contract 不同：

- **显式打开**（点击 parent row 上的 `Open Agent Space`）：
  - 总是执行一次 resolve + scroll + highlight；
  - 不受 hover debounce / suppress 约束；
  - 即使当前 Agent Space 处于 read-only / archived，也仍执行定位。

- **hover follow**：
  - 只在 Agent Space panel 已打开时启用；
  - 只在 hover 的 parent row 解析到**当前已打开的那个 Agent Space**时触发；
  - 用于帮助用户在 parent 与 Agent Space transcript 之间建立上下文映射；
  - 不应在 panel 未打开时暗中激活 Agent Space。

### 6.4 Debounce and suppress

hover follow 必须带最小节流与抑制规则：

- hover 停留 **300ms** 后才触发；
- 如果用户正在 Agent Space 里主动 scroll、hover、或 focus composer，则暂时 suppress follow；
- suppress 在 Agent Space 内最后一次主动交互后约 **1.5s** 恢复；
- 连续 hover 到同一个已解析目标 row 时，不重复触发 pulse。

这些规则的目标是避免 parent timeline 快速扫读时把 Agent Space 滚动抖成“跟手镜像”。

### 6.5 Highlight style and lifecycle applicability

联动高亮应：

- 复用现有 `Jump to message` 的短暂高亮样式，而不是引入新的 pulse 视觉语言；
- 在 owner writable、non-owner read-only、archived 三种 Agent Space 状态下都生效；
- 仅改变定位与短暂视觉强调，不改变 message 的 durable state。

### 6.6 Parent surfaces do not support private-agent visual filtering

channel / thread parent surface 不提供按 private-agent author 隐藏 parent rows 的开关。

最终模型里 private agent output 是 parent timeline 的 canonical message row，不再通过 Agent Space transcript publish / auto-publish materialized row 表达。parent surface 因此不维护 per-user / per-space 的 private-agent visual filter，也不保留基于 publication relation 的隐藏规则。

这个约束的目的：

- parent timeline 始终展示真实协作面上的消息事实；
- owner-private visibility / wake / cursor 由 scope context 和 delivery facts 管理，不由 parent UI filter 参与；
- linkage 只处理当前可见 parent rows 与 explicit source facts，不需要为被隐藏的 private-agent parent rows 设计额外 jump / reveal 行为。

### 6.7 Explicitly deferred

以下变体在 v1 不做：

- Agent Space → parent 的反向联动；
- 沿 ancestor / reply-chain 的递归映射；
- panel 未打开时由 hover 被动激活 Agent Space；
- 新的专用 linkage 高亮样式或独立 motion 系统；
- 针对已删除 private-agent row filter 的搜索 / jump 临时解隐藏行为。

## 7. Current closure level

O4 在 panel / share flow / routing modifier / entry surfaces / parent→Agent Space linkage 上已经达到 v1 `working-locked` 级别的收敛；parent surface 不支持 private-agent visual filtering。对象模型层面的主要决策已落位，因此后续工作主要转入实现与验证，而不是继续补 O4 的产品语义。

## 8. Global O4 constraints

后续所有 surface 都应默认继承以下约束：

- 必须兼容 light + dark mode
- 必须复用现有 AgentTeam token / component primitives
- 不能把 observer browse 能力错误表述成 unread / badge / delivery
- 不能让 projection 看起来像新的 authored object
- 不能在 surface 层重新发明 share / publish pipeline 语义

## 9. In-repo exploration cleanup policy

O4 的 v1 surface contract 已经收敛后，仓库内不再保留一次性探索 route、mock data 或 handoff 文档。后续视觉密度 / interaction affordance 的探索应沉淀回本篇正文或生产实现，而不是新增长期存在的独立演示入口。

## 10. Implementation verification checklist

### 10.1 Responsive behavior

- `AgentSpacePanel`：desktop 维持 side panel；narrow viewport 退化为 bottom sheet / bottom-anchored panel，不再并列占据 workspace 主栏。
- `ShareFlow` 的 target chips 在 confirm page 必须可 wrap；目标过多时优先换行，不允许挤压输入框与主按钮到不可点击。
- `ChannelComposeRoutingModifier`：仍保持“第一排输入框 / 第二排左 checkbox + 右 emoji/send”的两排结构；窄屏允许第二排内部重新分配间距，但不改成额外第三排。

### 10.2 Dark-mode checklist

- 所有新增 selected / hover / muted / chip / banner 状态必须只使用现有 AgentTeam token 语义（如 `bg-background` / `bg-muted` / `bg-primary/5` / `text-muted-foreground` / `border-border`），不引入裸色值。
- `ShareFlow` target row 的选中态（checkbox + `bg-primary/5` + border tint）必须在 dark mode 里仍保持可识别，不允许只剩微弱边框差异。
- confirm page 的 target chips、紧凑 preview row、message composer shell、primary button 需要和当前 AgentTeam dark theme 的 message composer / chip / button 对齐，不另造暗色 palette。
- `AgentSpacePanel` 的 archived banner、shared-context row、selection highlights 在 light/dark 两套下都要通过真实截图核对，而不是只看 token 名称推断。

## 11. Reference inputs

实现或继续扩写 O4 时，至少应并读以下输入：

- `web/src/agentteam/components/ui/index.ts`
- `web/src/agentteam/workspace/ThreadMessages.tsx`
- `web/src/agentteam/workspace/AgentSpacePanel.tsx`
- `web/src/agentteam/workspace/AgentSpaceShareFlowDialog.tsx`
- `web/src/agentteam/workspace/ChannelRoute.tsx`
- `web/src/agentteam/workspace/ReplyThreadPanel.tsx`

## 12. Out of scope for this pass

当前 working draft 仍然不解决：

- supersede statement 的最终 wording
- analytics / rollout / migration
- pixel-perfect motion / animation timing
- 未来多 owner header disambiguation
- 超出当前 O4 已锁定 scope 之外的新 surface

### 12.1 Known edges intentionally deferred

以下边界情况本轮不扩正文，只作为已知后续议题记录：

- author 之后离开 host channel / thread 后，历史 row 上的 entry icon 是否继续可见、点开后与 archived/read-only banner 如何区分；
- owner 离开某个 host channel 后，再从别处对同一 private agent 发起 mention 时的 routing / 解析时序；
- 同一 human 在多设备并发修改 notification state 时，以 server-side durable truth 为准，但具体的多设备冲突呈现与最后写入反馈留待实现 / 后续规范细化。
