第 6 章:控制权交接协议

本章定义 Handover_Policy(控制权交接策略)的协议流程,包括三类策略的语义、交接的原子性保证、超时回滚和通知机制。本章对应蓝图 §2.4 的设计意图。

6.1 适用场景

控制权交接发生在多个控制方需要先后使用同一 Terminal_Resource 的场景中。本规范定义两类核心交接:

  1. Fay-to-Fay:一个 Fay 将其持有的 Session 控制权转移给另一个 Fay
  2. Fay-to-Human:Fay 将控制权归还给人类用户,或人类用户将控制权委托给 Fay

本规范以 Fay-to-Fay 为主要描述对象。Fay-to-Human 交接复用相同流程,将"人类用户"建模为通过特殊接口直接与终端 OS 交互的实体。

6.2 交接发起

6.2.1 触发条件

交接由以下场景之一触发:

  1. 新 Fay 主动请求资源:Fay-B 通过 AuthRequest 请求访问已被 Fay-A 占用的资源
  2. 现 Fay 主动让出:Fay-A 通过 SessionTransferRequest 主动请求将控制权交给指定 Fay-B
  3. 管理触发:人类用户或管理接口要求转移控制权

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>
}

评估流程

  1. 终端加载 script_id 对应的规则脚本
  2. 输入:源 Session 信息、目标 Fay 标识、目标凭证 grants、当前时间、Resource_ID 元数据
  3. 输出:源优先级分数 S_source、目标优先级分数 S_target
  4. 决策: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)
}

评估流程

  1. 终端构造决策请求,包含 source/target 信息和 context_fields 指定的上下文
  2. 调用 AI 模型推理端点
  3. 模型返回决策:allow / reject / require_human
  4. 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"]    // 超时默认动作
}

评估流程

  1. 终端通过 ui_channel 向人类用户呈现交接请求详情
  2. 等待用户输入:允许 / 拒绝
  3. 超时 → 按 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:

  1. 中止当前正在进行的交接步骤
  2. 若处于 [T0]–[T2](源未完全终止):回滚到原 Session active 状态
  3. 若处于 [T3]–[T4](源已终止):按 §6.5.2 处理(不恢复源,资源置空闲)
  4. 向相关方发送 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_RuntimeSessionStateChanged(active → handover_pending → terminating → terminated)
目标 iFay_RuntimeAuthResult(创建新 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