# 群组方法公共约定

[群组托管协议](../README.md)

## 写请求规则

除方法明确说明外，`device_signature` 是本次调用设备对排除该字段后的完整对象所作网络绑定 Ed25519 签名。中继必须通过设备会话确认签名设备就是本次调用设备，并确认该设备属于调用账户。

成员公钥由其所属对象的设备签名保护。验证方必须验证设备证书的双重签名、账户 ID 派生关系、预期账户绑定及业务请求签名。

群组写方法的完整请求参数对象，其 [Canonical JSON](../../../general.md#canonical-json) UTF-8 编码不得超过 1 MiB（1,048,576 bytes）。批量方法不另设固定项目数，但仍受该限制、群容量和对应列表约束。

## 校验与错误处理规则

### 必需校验

当前方法的必需校验包括以下适用项目：

- 传输大小、JSON 结构、固定值和字段表示；
- 设备会话和时钟容错；
- 证书及业务签名、账户绑定、群归属、成员访问、角色和封禁状态；
- 适用的 `prev_hash`；
- 当前成员、邀请、申请、成员密钥重置、访问区间、密钥版本和容量等业务状态；
- 密钥盒账户覆盖、编码结构以及签名承诺与当前状态的一致性。

只有全部必需校验通过，才能按[原子提交与持久化规则](#原子提交与持久化规则)要求使业务结果生效。读取结果也必须满足相应访问条件。

### 错误选择与映射

同一请求存在多项校验失败时，除具体方法或[管理链](../core-objects.md#中继提交与并发控制)明确规定错误优先级外，可以返回任一适用错误。错误优先级约束响应选择，不限定检查先后。错误响应不得向未满足相应访问条件的调用方披露受保护的群信息，错误码、`message` 和 `data` 均须遵守该边界。

所有群组方法使用[公共错误码及 HTTP/JSON-RPC 映射](../../methods/conventions.md#错误码)：

- 参数结构、字段表示、取值或分页位置非法返回 `bad_request`；
- 方法要求的客户端创建时间未通过中继时钟容错检查时返回 `clock_skew`；字段类型或表示非法仍返回 `bad_request`，邀请、待处理记录和密钥材料到期按相应方法处理；
- 已成功解析的完整请求或方法限定的完整业务对象超过字节上限时返回 `request_too_large`；单个字段的格式、编码长度或取值不合法仍返回 `bad_request`。原始 WebSocket message 超限按传输规则关闭连接；
- 会话未建立、已过期或已撤销，或 HTTP 请求的会话令牌缺失或格式无效时返回 `unauthorized`；
- 请求声明的调用账户与设备会话或验签证书账户不一致，有效会话的模式、成员资格、角色、邀请授权或访问区间不满足要求，或者调用账户被封禁时返回 `forbidden`；
- 请求、业务对象或设备证书的密码学签名无效返回 `invalid_signature`；签名有效但设备当前不再获授权时，按公共会话及设备状态规则处理，不将其判为签名错误；
- 目标群、记录或游标依赖的状态不存在或已不可取得时返回 `not_found`；
- 请求依据的业务状态已变化、使用旧密钥版本写入，或者群已关闭而不能继续写入时返回 `state_conflict`。

## 原子提交与持久化规则

写方法产生事件或业务状态变化时，该方法要求的请求证据、群状态或待处理列表、密钥、访问区间和事件必须作为完整一致的结果原子生效。操作生效时，所依据的权限、版本、引用记录、有效期及其他前置条件必须仍然成立。操作失败不得留下部分业务效果，包括 sequence、`epoch`、邀请使用次数或部分批次结果的变化。

写操作引用的列表记录已经变化时，按相应方法返回 `state_conflict` 或 `not_found`，客户端再按需重新读取列表。

中继返回成功或发送通知前，必须完成该操作所需的持久化；重启或故障恢复后，已生效的结果仍须完整一致。通知失败不回滚已经生效的协议状态。

除创建请求外，参与[管理链](../core-objects.md#中继提交与并发控制)的请求还必须遵循统一的 `prev_hash` 校验、并发冲突及原子提交规则。格式错误返回 `bad_request`，旧链头返回 `state_conflict`。

## 列表分页规则

列表方法的 `limit` 和实际页大小统一遵循[分页约定](../../methods/conventions.md#分页)；页面缩小不改变下述游标语义。

### 游标格式与绑定

`cursor` 和 `next` 出现时必须是非空、大小写敏感的字符串，并匹配 `^[A-Za-z0-9._~-]+$`。游标的内部格式由中继决定。

游标至少绑定群、列表类型、调用账户可见范围和遍历位置；客户端不得解析、修改、跨方法复用，也不得从游标或记录顺序推断时间先后、优先级或处理顺序。`limit`、游标编码或位置非法返回 `bad_request`；游标依赖的状态已不可取得时返回 `not_found`，客户端可以省略 `cursor` 重新读取。

### 遍历与刷新

首次读取省略 `cursor`，后续依次使用 `next`。列表的返回顺序不承载业务语义；列表及调用账户可见范围未变化、游标仍可使用时，同一次遍历顺序必须保持稳定，完整遍历必须取得该范围内的全部记录，不得重复或遗漏。

`next` 出现时，本页记录数组必须至少包含一项；省略该字段表示本次遍历已经结束。

分页期间列表发生变化时，客户端可以省略 `cursor` 重新读取以刷新结果。列表结果不能代替提交时的当前状态检查。

中继每次返回页面前都必须按群的当前状态检查调用账户的访问权限。当前权限不再覆盖游标绑定的可见范围时，返回 `forbidden`。调用方可以省略 `cursor`，按当前权限重新读取；权限仍覆盖原可见范围时，可以继续使用原游标。
