# Task Attention、Wake 与 Inbox UX

> Canonical path: `specs/task/task-notifications-and-related-task-ux.md`
> Status: target-spec
> Scope: Task 原生 assignee、Watch / Unwatch、Activity / Message attention、Human Inbox unread、Agent delivery / wake、Tasks 分类，以及 related-task surfaces。
>
> 本文只定义 Task 原生语义。Workflow 如何切换 assignee、发起 review 或驱动 status 属于后续 Workflow phase。
>
> 相关规格：
>
> - [`specs/task/task-scope.md`](./task-scope.md)
> - [`specs/task/task-timeline-messageization.md`](./task-timeline-messageization.md)
> - [`specs/task/board.md`](./board.md)
> - [`specs/message/scope-model.md`](../message/scope-model.md)
> - [`specs/message/delivery-runtime.md`](../message/delivery-runtime.md)
> - [`specs/message/unread-runtime-memory.md`](../message/unread-runtime-memory.md)

## 1. 产品问题

Task 同时服务 Human 和 Agent。旧模型把“谁创建”“谁 claim”“当前 Agent”“建议给谁”“谁 review”混在 Task 行上，并把 Agent wake 隐式写进这些字段的 mutation path。结果是：

1. 同一个 Task 可以出现多个互相冲突的“当前负责人”；
2. membership、Watch、Human unread 与 Agent wake 被错误地当成同一状态；
3. typed Activity 明明已经记录了事实，却必须再造一条 Message 才能提醒；
4. claim / assign / start 各自携带不同副作用，调用者习惯会改变执行结果；
5. Human 无法在统一 Inbox 中稳定看到自己 Watch 的 Task 更新。

目标是把责任与 attention 收敛为一套对 Human / Agent 对称的模型，同时继续复用 Scope、Outbox、UnreadRuntime 和统一 conversation index。

## 2. Canonical Task 身份

### 2.1 三种独立事实

Task 保留三种互不替代的身份事实：

| 字段                              | 含义                                    | 是否决定 attention |
| --------------------------------- | --------------------------------------- | ------------------ |
| `createdBy` / `createdByProfile`  | 谁创建了 Task                           | 否                 |
| `executionOwner`                  | 哪个基础设施执行域拥有相关执行副作用    | 否                 |
| `assigneeRef` / `assigneeProfile` | 当前下一步由谁负责；可空；Human / Agent | 是                 |

`createdBy` 与 `executionOwner` 有各自的审计和运行时意义，不能因为 assignee 为空就作为 UI fallback，也不能在迁移后重新写入 assignee。

### 2.2 删除旧的 Task 行责任字段

Task 公开 store / API / client / UI contract 不再暴露：

- `currentAgent` / `currentAgentProfile`；
- `claimedBy*` / `claimedByProfile`；
- `suggestedAssignee` / `suggestedAssigneeProfile`；
- Task 行上的 `reviewer` / `reviewerProfile`。

Review Request 中的 `reviewerRef` 是独立 review fact，不是 Task assignee alias；本文不新增或实现 Review Request action。

Canonical wire shape：

- mutation input：`assigneeRef`；
- read output：`assigneeProfile`；
- storage：`tasks.assignee_member_id`，引用 workspace member；
- UI label：`当前负责人`。

公共 contract 与 presenter 不保留旧字段 alias 或 fallback。唯一例外是第 9 节定义的、可删除且有明确截止条件的 store persistence rollout adapter；它只保证滚动升级期间新旧节点的物理列互通，不能泄漏为 API / CLI / Web 产品语义。

## 3. 原生 mutation 语义

### 3.1 Create

创建 Task 只有一个 operation：

```text
create(task fields, assigneeRef?)
```

删除 Create / Create and assign / Create and start 三种 mode 以及 `createMode` / `create_mode`。是否创建即进入某个 status 不再由 create mode 隐式决定；本 phase 不改变现有 status lifecycle。

### 3.2 Assign、claim 与 unassign

- assign：显式把 `assigneeRef` 更新为指定 Human / Agent；
- claim：当前调用 principal 把自己设为 assignee；
- claim 仅允许 Task 当前未指派，或已经指派给自己；不得静默抢走其他 assignee；
- reassign：有权限的调用者显式把 assignee 从 A 改成 B；
- unassign：清空 assignee；当前 assignee或有管理权限的调用者可以执行；
- assign / claim / reassign / unassign 都写 canonical Task fact 与 typed Activity；
- status 与 assignee 独立，本 phase 不自动把 claim 映射成 `in_progress`，也不自动把 unassign 映射成 `todo`。

### 3.3 Assignee 不是持久 Watch

assignee 对后续事件的 attention 是从 Task fact 派生的责任，不在 `scope_notification_settings` 中写一份隐藏 Watch。

因此：

- assignee 可以显式 Unwatch，但这只清除其额外 Watch；
- 只要仍是 assignee，仍会因 assignee 责任收到后续 Task 事件；
- 要停止责任 attention，必须 reassign 或 unassign；
- assignee 变更后，旧 assignee 仍可作为 participant 读取历史，但不再因旧责任收到未来事件，除非其显式 Watch 或被 direct mention。

## 4. Membership 与 Watch

### 4.1 Membership 只表达参与和可见上下文

以下动作可以确保 member 成为 Task scope participant：

- 创建 Task；
- assign / claim；
- author Task message；
- 在 Task message 中被 direct mention；
- 加入 collaborator；
- 产生 Task typed Activity；
- 其他明确授予 Task 可见性的动作。

加入 membership 不等于 Watch，也不自动产生 Human unread 或 Agent wake。

### 4.2 Watch 复用 Scope notification

Task 不新增 watchers 表。显式 Watch / Unwatch 复用
`scope_notification_settings`，membership 仍只复用
`scope_memberships`。逻辑状态为：

| Principal | Watch       | Unwatch / 默认 |
| --------- | ----------- | -------------- |
| Human     | `active`    | `mute`         |
| Agent     | `auto-wake` | `no-wake`      |

正常 contract 中这些状态仍属于 Scope notification，而不是 Task 行。为支持第
9 节的不停机滚动升级，expand binary 暂时使用同一张表内 nullable
`task_watch_state` 作为 Task-only 权威列，并把新选择 mirror 到旧 `state`；
这不是第二套 Watch store，也不能扩张到非 Task scope。新节点的 Task UI、
Inbox 与 attention planner 不得回退读取 legacy `state`。旧节点的 claim /
current-agent 逻辑即使再次把 legacy `state` 写成 `auto-wake`，也不能覆盖
v2 `no-wake`；migration 只 expand/backfill `task_watch_state`，不批量改写
legacy `state`。

自动创建的 participant 在没有已有 setting 时使用 Unwatch 默认值。系统不得因为 creator、commenter、activity actor、source-thread participant 或 collaborator 身份把 setting 自动升级为 Watch。

Watch 状态独立于 assignee：

- Watch 表达“我订阅这个 Task 的普通更新”；
- assignee 表达“当前下一步由我负责”；
- 同一 member 同时满足两者时 recipient 去重；
- Unwatch 不修改 assignee，reassign 也不擅自修改显式 Watch。
- Watch / Unwatch 只影响后续事件的普通订阅资格，不追溯重算已经固化的 recipient snapshot，也不清除已有 Inbox unread；已有未读只能由 mark read / 打开 Task 的统一读游标清除。

## 5. Activity、Message 与 attention 是三回事

### 5.1 Activity 是事实

Task mutation 通过 `TaskTimelinePlan.TypedActivityIntents` 写入 `scope_activity_events`。Activity 保存 status、assignee、checkpoint、blocker、artifact 等结构化事实与 timeline 展示信息。

Activity 不是 Message，不保存协作正文，也不能为了通知而合成 hidden message。

### 5.2 Message 是协作内容

Task discussion 使用普通 task-scope `scope_messages`。Message 保存 human / agent authored content、attachments、mentions、reactions、search 和 provenance。

Message 可以同时声明 direct mentions。Mention 是本条事件的 attention reason，不是持久 Watch。

### 5.3 Attention 是事件投影

每条 committed Task event 计算一次稳定 recipient snapshot：

```text
recipients =
    explicit watchers
  ∪ current assignee
  ∪ current message direct mentions
  − actor
```

约束：

- typed Activity 没有 message mention，不从自由文本或 payload 猜 recipient；
- direct mention 与 assignee responsibility 穿透 recipient 的 Unwatch / `mute` / `no-wake`，但不改变其持久 setting；
- actor 永远不因自己产生的事件获得自通知 / self-wake；
- 普通 membership、历史 assignee、creator、commenter、activity actor 与 source scope visibility 不扩张 recipient；
- recipient snapshot 在 owning transaction / durable outbox boundary 固化，worker replay 不读取最新 Watch / assignee 重新解释旧事件；
- 同一个 member 因多种 reason 命中时只投递一次，但 diagnostics 可以保留 reason 集。

### 5.4 一条事实只有一个投递源

- pure typed Activity 写 `event_ref_type=activity_event` 的 `scope_fanout_outbox`；
- Task Message 使用 message-owned outbox；
- Message 同事务产生的 `discussion_added` Activity 仅进入 timeline，不再创建第二个 Activity outbox；
- Human unread、Agent delivery / wake 与 realtime invalidation 都消费同一 recipient snapshot；
- replay 必须幂等，不能因 retry 重复增加 unread 或重复 wake。

## 6. Human Inbox

### 6.1 一个 Task 一个聚合 Inbox row

每个 Task scope 在统一 Inbox 中最多对应一个 conversation row：

```text
conversation id = task:{taskScopeId}
kind            = task
surface type    = task
```

Message 与 typed Activity 都只更新这个 member-local row。不得创建专用的 Task
通知主体，也不得把每条 Activity 变成一个独立 Inbox item。

Human 作为以下任一 recipient 时，该 row 获得 unread：

- 显式 Watch；
- 当前 assignee；
- 本条 Task Message 的 direct mention。

actor 自己的事件不产生 unread。普通可见 participant 可以打开 Task 看到完整 timeline，但没有 recipient relation 时不会收到 unread。

对 Human member-local Inbox serving，显式 `task_watch_state=mute` 是该
member 的 Task row visibility predicate：Unwatch 只从当前 member 的 Inbox
list 与 realtime cache 移除精确的 `task:<scopeId>` row，不写
`conversation_member_states.hidden_*`，不归档或删除 `im_conversation_index`，也不
推进或清除 Task timeline、message/activity read cursor、unread 或 manual-unread
事实。该 predicate 只匹配同一 `scope_id + member_id` 的 Task，不影响其他 Task、
channel、DM 或 thread。再次 Watch (`task_watch_state=active`) 沿用仍存在的
member-local index row；如果 row 尚不存在，则复用既有 Task materializer 创建它。
因此 Unwatch/Watch 不应调用通用 hide/archive action。

### 6.2 Durable truth 与 serving

实现复用：

- `scope_memberships` 的 message / activity read cursor；
- `scope_notification_settings.task_watch_state` 的显式 Watch；
- `scope_activity_events` 与 `scope_messages`；
- member-local `im_conversation_index` / `im_stream_events`；
- owner-local UnreadRuntime；
- 现有 conversation action API。

不得恢复：

- `internal/store/taskattention`；
- `task_message_unread_count`；
- `task_activity_unread_count`；
- `task_inbox_active`；
- `task_inbox_sort_at`；
- Task 专用 notification / reminder 表。

### 6.3 Unread 与 mark read

Task row unread 是 targeted message unread、targeted typed-Activity unread 与 manual unread 的聚合。

Mark read：

1. 推进当前 member 的 Task message cursor；
2. 推进 Task activity cursor；
3. 清除同一 conversation 的 manual-unread marker；
4. 更新 UnreadRuntime 与 member-local conversation index；
5. 清除 Inbox、Task detail、related-task surface 上同一份 unread。

Mark read 不删除 Activity / Message，也不修改 Watch。

### 6.4 Tasks 分类

Inbox 增加 `Tasks` 分类。它筛选统一 conversation model 中 `kind=task` 的 rows；
不是新的 Inbox、独立 Task 通知主体或第二套 unread store。

Task row 至少展示：

- `#tN {title}`；
- Task icon，不在 title 中再加 `[任务]` / `Task` pill；
- assignee profile；
- 最新 recipient-visible preview；
- unread / manual unread；
- 通过 Inbox-owned route projection 打开 canonical Task detail，保持左侧
  Inbox list 与选中 row；窄屏详情头可直接重新打开 Inbox drawer，且不离开
  当前 Task route；projection 不得复制 Task detail、数据或 mutation。

Row actions 复用 pin、hide、mark read / unread、Watch / Unwatch。Task detail 与 Inbox row 必须显示同一 Watch 状态。对已有 Inbox row 的显式 Unwatch 立即按 member + Task scope 精确移除该 row；Watch 重新使用已有 materialization/index row。该动作与 hide/archive 独立，不能清除 unread 或 timeline 事实。

### 6.5 Hide / resurface 的 expand 阶段

本 phase 给 `conversation_member_states` 在线增加
`hidden_through_activity_seq`，并让所有新 hide writer 同时记录 message /
Activity 两个 frontier；但在 mixed-version backend 窗口，Task row 的
hide / resurface reader **仍只消费 message frontier**。原因是旧节点在
expand migration 之后仍可能执行 hide，却只更新
`hidden_through_seq`；新 reader 若立刻消费一次性 backfill 得到的旧
Activity frontier，会把该 Task 错判成已发生 hide 之后的 Activity 而提前
重新显示。

因此 expand release 中：

- Task 可见时，targeted typed Activity 仍正常产生 Human unread、更新聚合
  Inbox row，并按同一 recipient snapshot 触发 Agent delivery / wake；
- hide 会清掉当下 message / Activity unread；
- hidden Task 只由 hide frontier 之后的新 Task Message 恢复显示；单独的
  typed Activity 不恢复该 row，也不在入口产生一个“有 badge 但无 row”的
  状态；
- `hidden_through_activity_seq` 在本 release 是 unconditional dual-write
  expansion column，不是已激活的 read contract。

全部旧 backend writer 退出后，contract release 必须先对**所有当前 hidden
Task rows**再次执行幂等
`GREATEST(hidden_through_activity_seq, scopes.latest_activity_seq)` backfill，
再在同一 release 同时切换 Inbox visibility readers 与 UnreadRuntime
suppression/resurface 语义。不能用时间戳推断写入先后，也不能只切 SQL
reader 或只切 runtime。

## 7. Agent delivery 与 wake

Agent 使用与 Human 相同的 recipient 集合：

- Agent Watch -> 普通 Task 更新 auto-wake；
- Agent assignee -> 责任事件 wake，即使其显式 Unwatch；
- direct `@agent` -> 本条 Message wake，即使 `no-wake`；
- 普通 Agent participant且非上述关系 -> 不 wake；
- actor agent -> 不 self-wake。

Agent 的 runtime packet 可以携带 Task profile、Activity / Message source 与 reason，但 execution truth 仍由 `scope_fanout_outbox` 与 delivery runtime 管理。Task 不提供 offline history replay 作为 wake；Agent 恢复上线不会因为“过去可读”而批量重放旧 Task 事件。

## 8. Related-task surfaces

Thread related tasks、Agent DM Tasks、Channel Tasks Tab、Inbox 与消息中的 Task
ref 都打开同一个 Task detail，并共享 assignee / unread presenter。在至少 1024
CSS pixels 的桌面 viewport 上，除 workspace 一级 Tasks hub 外的上下文入口都使用
`/tasks/:channelId/:taskNumber` 的 route-backed dialog，并保持来源 surface
mounted；只有从一级 Tasks hub 进入时默认使用
`/channels/:channelId/tasks/:taskNumber` 的 focused page。同一 tab reload 必须恢复
dialog；缺少有效 background state 的 cold/direct dialog path、新标签页、窄屏与
显式 Expand 使用 focused page。`/inbox/tasks/:channelId/:taskNumber` 只作为
Inbox-owned focused fallback 投影同一 Task detail component，不得成为第二套
query/cache/mutation 或 UI。

### 8.1 Thread related tasks

Thread related-task list 可以展示所有当前 viewer 可见的 related tasks，但只有 viewer 是 attention recipient 时显示 unread。Source thread 的所有 participant 不会因为 Task 来源于该 thread 自动 Watch。

### 8.2 Agent DM Tasks

Agent DM 的执行列表只以 canonical assignee 查询：

```text
task.assigneeProfile.agentId == current DM agent id
```

它不再 union current agent、claimer、suggested assignee、Task reviewer 或 comment history。

## 9. 迁移与兼容

Task / Scope 采用不停机的 expand → rolling cutover → contract：

1. expand release 的 fresh bootstrap 同时包含 canonical assignee 与 legacy physical columns，使同一个 rolling-compatible binary 可运行在新装库和升级库；最终 contract release 才从 bootstrap 删除旧列；
2. expand migration 在旧集群在线增加 canonical assignee columns，并从 legacy responsibility projection 初次回填：

```text
claimedBy
  > currentAgent
  > suggestedAssignee
  > Task-row reviewer
```

3. ref 必须解析为同 workspace canonical member；无法解析的数据使 migration / verification 明确失败，不能静默丢失；
4. expand migration 在 `scope_notification_settings` 增加 nullable
   `task_watch_state`，但**不改写**旧 `state`：旧节点在 rolling window
   仍须按原 contract 读写它。migration 只给现有 Task rows 初始化新权威列：
   Human 的旧 `active` 保留为 `active`、其余初始化为 `mute`；Agent
   responsibility 路径为 claimed/current Agent 强制产生的旧 `auto-wake`
   初始化为 `no-wake`，与责任无关的旧 `auto-wake` 保留为显式 Watch，
   其余初始化为 `no-wake`。rolling 期间新节点只以
   `task_watch_state` 判断 Task Watch；`NULL` 也按 Unwatch；
5. 新节点的 Task Watch setter 同时写 `task_watch_state` 与旧 `state`。旧
   节点后续 claim/current 路径即使再次覆盖 `state`，也不能改变新权威列，
   因而不会把 assignee 的派生 attention 污染成永久显式 Watch；
6. expand migration **保留**旧 Task responsibility 列、notification
   `state`、相关索引与 FK；滚动升级期间，未升级节点仍可读写旧 schema；
7. 新 runtime 的 API / CLI / Web 只接受并返回 `assignee`，不暴露旧
   responsibility wire alias。旧浏览器 / 旧 Web 刷新后切换，不属于本次
   compatibility boundary；必要兼容只封装在 Task store persistence
   adapter、Task Watch bridge 与旧异步 payload receiver。mixed-version
   窗口内，legacy responsibility projection 仍是 effective assignee
   source，优先级为
   `claimed_by_ref > claimed_by_member_id > current_agent_ref > suggested_assignee_ref > reviewer_ref`，
   canonical columns 是同步 mirror 与未来 contract source；
8. 新节点 assign / reassign 同步 canonical columns 与 legacy claim pair，
   并清空低优先级 legacy responsibility fields；unassign 同时清空
   canonical 与所有 legacy responsibility fields。这样旧节点的
   post-backfill claim / reassign / unclaim 会立即反映到新节点；
9. mixed-version 测试必须覆盖“初次 backfill 后旧节点再次 assign /
   reassign / unassign”，以及“旧节点再次把 notification `state` 写成
   `auto-wake`，但新节点的 `task_watch_state` 与 recipient 选择不变”。
   不能用只在 canonical 为空时才 fallback 的实现掩盖 stale canonical；
10. 全部旧节点退出后运行最终 reconciliation。后续 contract binary
    先滚动切到 canonical assignee read/write，并把 Task Watch 的 v2
    权威值收敛回通用 `state`；此时旧 physical columns 与
    `task_watch_state` 暂留。确认全 fleet 已退出 bridge binary 后，再在线
    drop 旧 responsibility 列、索引、FK 与临时 `task_watch_state`；
11. 旧节点可能已经写入的 `task_dispatch` payload / outbox 在 rolling
    window 继续可接收、重试与重放；新 canonical write path 不再创建它。
    只有在旧 writer 全部退出且队列 drain 后，contract release 才删除
    receive / replay compatibility；
12. schema bootstrap、expand migration、rolling read/write 与最终
    contract 各自有明确 schema verification；
13. recipient-targeted Task Message / Activity 使用 payload v2，并在
    `scope_fanout_outbox` 中保持独立的 `pending_v2 ↔ leased_v2`
    lifecycle。旧 worker 编译进二进制的精确 `pending` / `leased`
    predicates 因而不能领取、过期接管或标记这些 rows；新 worker
    retry 也不得把 `leased_v2` 降回 legacy `pending`。普通 v1
    channel / DM / thread delivery 继续使用 legacy lifecycle，直到旧
    backend 全部退出。对应 migration Down **不是**可无条件在线执行的
    rollback：必须先停止 v2 writer，保留至少一个 v2-capable consumer，
    并 drain 或 suppress 全部 `pending_v2` / `leased_v2` row 后才能降级
    schema；否则把 live v2 row 改名为 legacy status 会让旧 worker 领取
    它无法解码的 payload。`00293_task_unread_snapshot_shadow` 同属这个
    mixed-backend adapter：同一 snapshot row 上的 versioned Task shadow
    保护已经 delivered 的 v2 Human unread completion，旧 binary 后到的
    regular-column upsert 不能擦除它；普通 V1 old-writer Task event 在
    rolling / crash window 继续是既有 best-effort，不能靠 opaque count
    merge 声称无损恢复。普通 periodic flush 不推进 shadow aggregate，
    只有专用 v2 completion barrier 可以推进；partial read/effective-from
    overlap 必须 suppress/defer。停止 v2 writer、drain/suppress 全部 v2
    row、确认不再需要 mixed-backend restart fence 后，还必须在任何旧 reader
    启动前把受保护 shadow reconciliation/repair 回 regular columns；仅 dual-write
    不能保证 rollback，因为 barrier 后到的 old-writer regular upsert 可能已使
    regular columns 陈旧。完成 repair gate 后 contract release 才能删除 shadow
    reader/writer 和这两个 additive columns；其 migration Down 不能在新 binary
    仍运行时执行，也不能把“先回滚应用”当成安全流程；
14. 不为历史 Activity / Message 回灌 unread；新 recipient-targeted
    事件才进入新 attention projection。
15. `hidden_through_activity_seq` 先 additive dual-write、后 contract
    activate：mixed-version 阶段 readers 保持 message-only；旧 backend
    全退后必须二次 backfill 当前 hidden Task rows，再原子切换 SQL /
    UnreadRuntime 的 Activity-driven resurface 语义。

这是有期限的部署兼容，不是永久产品语义：旧集群继续使用旧二进制与旧 schema；升级集群在滚动窗口允许新旧节点共用数据库；公共 Task contract 从第一台新节点开始就只有 canonical assignee。

## 10. Guardrails

实现必须保护：

- Task 公共 contract 只出现 `assigneeRef` / `assigneeProfile`；
- Task 行不出现 current agent、claim owner、suggested assignee 或 reviewer alias；
- Review Request reviewer 不被误删或映射成新的 Task 字段；
- membership ensure 不自动写 Watch；
- Task Watch rolling bridge 只存在于 `scope_notification_settings`，不得新增
  Task watcher table，也不得让旧 `state` 覆盖 v2 权威值；
- assignee responsibility 不写成 notification setting；
- Task attention recipient 只由 Watch、当前 assignee、当前 Message direct mention组成；
- actor 排除与 recipient dedupe 在统一 planner 完成；
- Task Message 与 `discussion_added` Activity 不双重投递；
- typed Activity 不合成 hidden message；
- Task unread / Inbox 不恢复 legacy taskattention 或旧 durable counters；
- Inbox `Tasks` 是统一 conversation filter；
- status semantics 与 Workflow orchestration 不在本 phase 改写。

## 11. 验收标准

1. Task read contract 只有 `assigneeProfile`，mutation 只有 `assigneeRef`。
2. Human / Agent 都可以成为 assignee；assignee 可空且全局唯一。
3. Create 只有一个 operation，可选 assignee；旧 create modes 被删除。
4. Claim 只把未指派 / 已指派给自己的 Task 设给自己，不能静默 takeover。
5. Participant 默认 Unwatch；显式 Watch / Unwatch 复用 Scope notification settings。
6. Watcher、assignee、direct mention 分别按公式收到当前事件，actor 被排除，多原因命中只投递一次。
7. Human Watch Task 后，下一条他人 typed Activity 让该 Task 的聚合 Inbox row 变 unread。
8. Human assignee 即使 Unwatch，仍收到责任期内下一条他人 Task event；reassign 后不再因旧责任收到未来事件。
9. Agent Watch、assignee 与 direct mention 使用同一 recipient formula 转成 wake；普通 participant 不 wake。
10. Task Message 不因 `discussion_added` Activity double unread / double wake。
11. Mark read 同时清除 targeted message、typed Activity 与 manual unread。
12. Inbox 有 `Tasks` 分类，并且一个 Task 只有一个 row。
13. 不恢复旧 task unread columns、Task Inbox projection 或 `internal/store/taskattention`。
14. 旧集群升级按优先级完整回填 assignee，fresh schema 与 migrated schema 一致。

## 12. 测试要求

Backend：

- fresh schema / historical schema migration / schema verify；
- migration priority、Human / Agent ref resolution、invalid legacy ref fail-closed；
- create / assign / claim / reassign / unassign authorization与 typed Activity；
- Watch / Unwatch 对 Human / Agent setting 的映射；
- recipient union、actor exclusion、dedupe、assignee-over-Unwatch、mention-over-no-wake；
- Activity outbox 与 Message outbox recipient snapshot；
- discussion Activity no-double-delivery；
- Human Task conversation index / unread / mark-read；
- Agent delivery / wake与 replay idempotency；
- conversation list / actions 对 `kind=task` 的支持；显式 Unwatch 只过滤目标 member-local Task row，Watch 恢复同一 index row，且保留 unread / timeline 事实。

Frontend：

- assignee-only create / detail / board UI；
- Current Assignee picker、assign / unassign / claim；
- Watch / Unwatch；显式 Unwatch 的精确 Inbox row removal、刷新过滤、Watch 恢复与非目标 row 保留；
- Inbox Task row 与 `Tasks` filter；
- unread、mark read、route 和 realtime refresh；
- 不存在旧 create mode、current agent、claimer、suggested assignee、Task-row reviewer UI。

E2E：

- Human Watch -> typed Activity -> Tasks Inbox unread -> open / mark read；
- Agent claim / assign -> subsequent Task update wake；
- direct mention穿透 Unwatch且不改变 Watch；
- Task Message 不产生双份 attention。
