# Agent Note: Composer 上下文堆栈顺序

Status: implemented

[English](2026-07-30-composer-context-stack-order.md) | 中文

## 问题

Goal、Todo 与 Queue 独立注册到同一个 `conversation.input.dock` 列表，但各自的注册顺序与间距规则没有编码组合矩阵。因此，渲染器将 Todo 放在 Queue 和 Goal 之前，而 Queue 与 Goal 都带有用于 composer 边界的负外边距。三者同时出现时，Queue 与 Goal 相接，Goal 与 composer 相接，颠倒了设计层级。

## 决策

composer 上下文堆栈采用唯一规范的升序排列：Goal 为 `0`，Todo 为 `10`，Queue 为 `20`，随后是位于列表外的 composer bar。顺序值之间的空档使未来条目可以声明预期位置，不必依赖插件激活顺序。

`ConversationRoot` 负责独立上下文卡片之间的 6px 间距。Goal 是一张独立的 752×36px 卡片，折叠后的 Todo 是一张独立的 752×44px 卡片。Queue 是末端 dock 条目：其 776px 包装层包含相同的 752px 面板列，并减去共享间距与具名的 5px 布局重叠量，因此后渲染的 composer 卡片只覆盖 Queue 边缘。空条目渲染为 null，不占用间距。

顺序与重叠是两项独立契约。注册顺序定义语义层级，stack 上的 CSS 变量定义共享几何。系统不能仅因 Queue 是最后一个可见条目，就推断它可以与 composer 重叠，因为没有 Queue 时，Goal 或 Todo 可能成为最后一个可见上下文卡片，而它们必须与 composer 保持间隔。

## 验证

注册测试固定了三个顺序值。浏览器截图覆盖完整的 Goal／Todo／Queue 组合矩阵、没有 Queue 的 Goal+Todo，以及仅有 Queue 的情况；这些场景共同覆盖全部相邻关系：Goal–Todo、Todo–Queue 与 Queue–Composer。

## 考虑过的替代方案

**Goal 和 Queue 分别保留独立的负外边距。** 不予采纳，因为受影响的相邻项会随 slot 顺序变化；除非语义顺序也固定，否则局部外边距无法表达允许哪一种关系。

**在 `ConversationRoot` 中分别渲染每个已知 dock id。** 不予采纳，因为这会把可扩展的列表 slot 变成硬编码的组件清单，并迫使 owner 在每新增一个注册方时随之修改。

**让最后一个 dock 条目贴卡。** 不予采纳，因为 Goal 和 Todo 是独立卡片；Goal 或 Todo 缺席时的组合不得改变剩余卡片的界面语义。

## 后果

所有存在组合下的视觉层级都保持稳定，Queue 是唯一与 composer 相接的上下文界面。新的 input-dock 插件必须相对于 Goal `0`、Todo `10` 与 Queue `20` 选择顺序；若条目位于 Queue 之后，还必须明确决定由哪个界面负责 composer 边界。
