第 6 章:控制权交接协议
本章定义 Handover_Policy(控制权交接策略)的协议流程,包括三类策略的语义、交接的原子性保证、超时回滚和通知机制。本章对应蓝图 §2.4 的设计意图。
6.1 适用场景
控制权交接发生在多个控制方需要先后使用同一 Terminal_Resource 的场景中。本规范定义两类核心交接:
- Fay-to-Fay:一个 Fay 将其持有的 Session 控制权转移给另一个 Fay
- Fay-to-Human:Fay 将控制权归还给人类用户,或人类用户将控制权委托给 Fay
本规范以 Fay-to-Fay 为主要描述对象。Fay-to-Human 交接复用相同流程,将"人类用户"建模为通过特殊接口直接与终端 OS 交互的实体。
6.2 交接发起
6.2.1 触发条件
交接由以下场景之一触发:
- 新 Fay 主动请求资源:Fay-B 通过 AuthRequest 请求访问已被 Fay-A 占用的资源
- 现 Fay 主动让出:Fay-A 通过
SessionTransferRequest主动请求将控制权交给指定 Fay-B - 管理触发:人类用户或管理接口要求转移控制权
6.2.2 交接请求消息
SessionTransferRequest (body of ProtocolMessage) {
required source_session_id : Session_ID // 当前持有控制权的 Session
required target_fay_id : Fay_ID // 目标接管方
required target_credential : CredentialContent // 目标方的授权凭证
required handover_reason : string
optional handover_metadata : map<string, string>
}
终端收到交接请求后启动交接评估流程。
6.3 交接评估
终端按以下步骤评估交接是否允许:
6.3.1 第 1 步:源 Session 校验
- 验证
source_session_id对应的 Session 存在且处于active - 验证发起方有权请求此次交接(如来自该 Session 的 iFay_Runtime 或具备管理权限的实体)
失败 → 返回 E_HANDOVER_INVALID_SOURCE
6.3.2 第 2 步:目标授权校验
- 校验
target_credential是否合法(按第 3/4 章规则完整校验) - 校验
target_fay_id对该资源在原 Session 的access_mode下有授权
失败 → 返回 E_HANDOVER_INVALID_TARGET
6.3.3 第 3 步:策略评估
终端按 §6.4 应用 Handover_Policy 决定是否允许交接。
失败 → 返回 E_HANDOVER_REJECTED_BY_POLICY
6.3.4 第 4 步:原子性预占
终端在策略评估通过后立即将原 Session 切换到 handover_pending,进入预占状态:
- 该资源在交接完成前不接受其他控制权请求
- 原 Session 仍能维持心跳(保持 active 等价的心跳要求)但不能发起新的资源操作
6.4 交接策略类型
Handover_Policy 按 Resource_ID 粒度配置,每个资源 MAY 采用不同策略。本规范定义三种策略类型,所有终端 MUST 至少实现 §6.4.1 优先级规则脚本。
6.4.1 优先级规则脚本(Priority Rule Script)
终端按预定义规则脚本计算源 Session 与目标 Fay 的优先级分数,分数高者获得控制权。
配置结构:
PriorityPolicyConfig {
required policy_type : "priority_script"
required script_id : string // 终端预配置的脚本标识
optional parameters : map<string, string>
}
评估流程:
- 终端加载
script_id对应的规则脚本 - 输入:源 Session 信息、目标 Fay 标识、目标凭证 grants、当前时间、Resource_ID 元数据
- 输出:源优先级分数
S_source、目标优先级分数S_target - 决策:
S_target > S_source→ 允许交接;否则拒绝
规则脚本的具体语言(如 CEL、Lua 子集、JSON Logic)由实现选择,但 MUST:
- 是确定性的(相同输入产生相同输出)
- 不能访问网络或文件系统
- 执行时间限制在 100 ms 内
6.4.2 AI 模型实时判定(AI Model Real-time Decision)
终端调用预集成的 AI 模型对当前上下文进行实时判定。
配置结构:
AIPolicyConfig {
required policy_type : "ai_model"
required model_endpoint : string // 终端可访问的模型推理端点
optional context_fields : array<string>
required decision_timeout_ms : uint32 (default 500)
}
评估流程:
- 终端构造决策请求,包含 source/target 信息和
context_fields指定的上下文 - 调用 AI 模型推理端点
- 模型返回决策:
allow/reject/require_human require_human时降级到 §6.4.3 人类用户决策
终端 MUST:
- 设置硬性超时(默认 500 ms),超时按
reject处理 - 缓存最近决策结果以避免高频抖动(缓存有效期 ≤ 5 秒)
- AI 模型不可用时降级到优先级规则脚本
6.4.3 人类用户决策(Human User Decision)
终端通过用户界面请求人类用户做出决策。
配置结构:
HumanPolicyConfig {
required policy_type : "human_decision"
required ui_channel : enum["system_dialog", "companion_app", "external_panel"]
required decision_timeout_seconds : uint32 (default 30)
required default_action : enum["allow", "reject"] // 超时默认动作
}
评估流程:
- 终端通过
ui_channel向人类用户呈现交接请求详情 - 等待用户输入:允许 / 拒绝
- 超时 → 按
default_action处理
人类决策模式 MUST:
- 在 UI 中清晰展示:源 Fay 标识、目标 Fay 标识、资源标识、访问模式、交接原因
- 不在 UI 中展示敏感凭证细节(如签名、密钥 ID)
- 默认动作建议设为
reject(保守安全)
6.5 原子性保证
交接 MUST 满足原子性:在任意时刻,一个 Resource_ID 最多有一个活跃控制方。
6.5.1 原子序列
终端 MUST 按以下顺序执行交接,每一步在临界区内完成:
[T0] handover_pending 进入:源 Session 状态切换,资源进入预占
[T1] 终止源 Session:source_session_id 状态 active → terminating
触发 OS 访问控制撤销
[T2] 资源回收完成:source 状态 terminating → terminated
此时资源处于"无活跃 Session"状态
[T3] 创建目标 Session:按 §5.2 流程为目标 Fay 创建新 Session
状态进入 creating
[T4] OS 访问控制下发:为目标 Fay 启用资源访问
[T5] 目标 Session 切换 active:交接完成
外部观察者在 [T2] 与 [T3] 之间观察到的资源状态是"无活跃 Session",不会观察到两个 Session 同时活跃。
6.5.2 中间步骤失败的回滚
若 [T0]–[T2] 中任何步骤失败:
- 源 Session MUST 回滚到
active - 资源回收预占撤销
- 返回
E_HANDOVER_FAILED_AT_RELEASE
若 [T3]–[T4] 失败(源已终止但目标无法创建):
- 终端 MUST 立即清理资源(资源进入"无活跃 Session"状态)
- 通知原 iFay_Runtime(源 Session 已终止)和目标 iFay_Runtime(接管失败)
- 返回
E_HANDOVER_FAILED_AT_ACQUIRE - 资源状态:保持空闲,由后续请求竞争。MUST NOT 自动恢复源 Session
6.5.3 并发交接请求的串行化
针对同一资源的多个并发交接请求 MUST 被串行化:
- 资源处于
handover_pending期间,新交接请求被排队或拒绝 - 实现 MAY 选择拒绝(
E_HANDOVER_IN_PROGRESS)或排队(最大队列长度 8) - 排队的请求按 FIFO 处理,每个请求在前一个交接完成(成功或失败)后才进入评估
6.6 超时处理
每次交接 MUST 设置硬性超时。超时阈值由策略类型决定:
| 策略类型 | 默认超时 | 范围 |
|---|---|---|
| 优先级规则脚本 | 1 秒 | 0.5–2 秒 |
| AI 模型实时判定 | 1 秒 | 0.5–3 秒 |
| 人类用户决策 | 30 秒 | 5–120 秒 |
6.6.1 超时回滚原则
若交接在超时内未完成(即未到达 [T5]),终端 MUST:
- 中止当前正在进行的交接步骤
- 若处于 [T0]–[T2](源未完全终止):回滚到原 Session active 状态
- 若处于 [T3]–[T4](源已终止):按 §6.5.2 处理(不恢复源,资源置空闲)
- 向相关方发送
HandoverFailedNotification
6.6.2 超时通知
HandoverFailedNotification (body of ProtocolMessage) {
required handover_id : uuid
required source_session_id : Session_ID
required target_fay_id : Fay_ID
required reason : enum["timeout", "policy_rejected", "release_failed", "acquire_failed"]
optional details : map<string, string>
}
6.7 重试策略
交接失败后的重试策略由发起方决定。本规范不强制重试机制,但定义重试的边界:
- 同一交接请求的重试间隔 SHOULD ≥ 1 秒
- 同一 (source_session, target_fay) 对的重试次数 SHOULD ≤ 3 次
- 重试 MUST 使用新的 handover_id
终端 MAY 拒绝过于频繁的重试请求并返回 E_HANDOVER_RETRY_LIMIT。
6.8 Fay-to-Human 交接
将控制权归还给人类用户的交接遵循上述流程,但目标方为人类用户:
target_fay_id字段使用特殊值"human:" + terminal_id(表示当前终端的人类用户)- 目标授权校验跳过(人类用户对自己终端的资源默认有完整权限)
- 策略评估通常使用 §6.4.3 人类用户决策(确认接管意愿)
- 创建目标 Session 时,Session 不绑定到任何 Fay,而是直接由 OS 用户进程持有
人类用户主动接管的反向流程对称:将原 Fay Session 替换为人类持有的 OS 进程。
6.9 交接的可观测性
终端 MUST 向以下方提供交接事件可观测性:
| 接收方 | 接收的事件 |
|---|---|
| 源 iFay_Runtime | SessionStateChanged(active → handover_pending → terminating → terminated) |
| 目标 iFay_Runtime | AuthResult(创建新 Session 的成功响应) 或 HandoverFailedNotification |
| 终端审计日志 | 完整交接记录(含 handover_id、source、target、policy 决策、最终结果) |
6.10 交接消息序列
成功交接的完整消息序列:
[Source Runtime] [Target Runtime] [Terminal]
│ │ │
│── SessionTransferRequest ─────────────→│
│ │ │── 评估策略
│ │ │── source: active → handover_pending
│←─ SessionStateChanged(handover_pending)│
│ │ │── 终止 source
│←─ SessionStateChanged(terminating)─────│
│←─ SessionStateChanged(terminated)──────│
│ │ │── 创建 target
│ │←─ AuthResult ────│
│ │ │── target: creating → active
│ │←─ SessionStateChanged(active)
失败回滚的消息序列:
[Source Runtime] [Target Runtime] [Terminal]
│ │ │
│── SessionTransferRequest ─────────────→│
│ │ │── 评估策略
│ │ │── source: active → handover_pending
│←─ SessionStateChanged(handover_pending)│
│ │ │── 超时或失败
│ │ │── source: handover_pending → active
│←─ SessionStateChanged(active)──────────│
│←─ HandoverFailedNotification ──────────│
│ │←─ HandoverFailedNotification
