Claudian 项目权威转移(Authority Transfer)机制:LAN 与 Cloud 之间所有权迁移的相位策略、凭据托管与重启恢复
【免费下载链接】claudianAn Obsidian plugin that embeds Claude Code/Codex as an AI collaborator in your vault项目地址: https://gitcode.com/GitHub_Trending/cl/claudian
Claude Code 作为 Obsidian 插件嵌入 Vault 的 Claudian 提供了一套多人协作(Collab)子系统,其中“项目权威转移”(Project Authority Transfer)负责把整个协作项目的权威控制权在生产环境内于 LAN(局域网 Host)与 Cloud(云端权威)两个方向之间安全迁移。本文以模块规范文档 AGENTS.md 为主体(CLAUDE.md 仅以@AGENTS.md引用指向它),完整覆盖其模块职责边界、权威与身份规则、生命周期与恢复策略、验证要求四大部分,并结合 AuthorityTransferModule.ts、AuthorityTransferRecord.ts 等源码实现加以佐证,帮助读者理解一个具备持久化状态、可重启恢复、且保证“无双重写入者”的分布式所有权交接系统是如何被设计出来的。
一、模块职责边界:权威转移拥有什么、不拥有什么
规范文档的第一节(Ownership)明确了该作用域的“拥有物”与“复用物”,这是理解整个模块的前提:
该作用域拥有(owns)的能力:
- 生产环境 LAN-to-Cloud 与 Cloud-to-LAN 两个方向的相位(phase)策略;
- 源端/目标端编排(source/target orchestration);
- 语义化检查点(checkpoint)的捕获与导入;
- 转移凭据(transfer-claim)的托管(custody)与赎回(redemption)收敛;
- 权威代际(authority-generation)的迁移、取消(cancellation)、终局结算(terminal settlement)与重启恢复(restart recovery)。
该作用域必须复用、不得自建的能力:
- 项目本地的转移记录与“操作所有的工件”(operation-owned artifacts)必须通过 CollabLocalProjectRepository 持久化;启动枚举与恢复必须注册到 CollabProjectLifecycleSubsystem。文档明确禁止“创建第二个 Vault 目录、生命周期子系统、Project 索引或物理状态属主”——即整个协作子系统只有一个持久化目录与生命周期仲裁者;
- 项目准入令牌(Project admission tokens)、工作会话 drain/reset、Host 启动守卫、origin 与成员替换、索引重建、退役处理、本地 Keep/Delete 清理等能力,必须通过其原有属主的接缝(seam)复用,不得修改这些属主的文件,也不得“绕过它们推断完成状态”。
两个易混淆的邻近机制被明确排除在生产权威转移之外:
- bootstrap/ 是“私有的双客户端开发夹具”(private two-client development fixture);
- HostTransferPackage 属于物理的 LAN-to-LAN Host 交接。
二者都不是生产转移传输、检查点、凭据或恢复机制。
生命周期仲裁规则(规范文档中最长的一条):在 Host 接受改变项目准入之前,必须先获取CollabProjectLifecycleSubsystem的按项目生命周期仲裁器,并且在每次恢复尝试中重新进入它。任何非终局物理 Host 转移、Leave/清理、Retire/确认、私有 bootstrap、Manager 责任交接或另一次权威转移,都必须经由其自己的属主结算或被阻塞——协调器本地的检视(coordinator-local inspection)永远不能取消或绕过它。ProjectOperationAdmission只是提供后续普通工作的 drain/挂起令牌,不是生命周期仲裁器。
从源码结构看,这条规则在实现中得到直接体现:AuthorityTransferModule.ts 中sourceActiveService返回的acceptLanToCloudTransferTarget与cancelProjectAuthorityTransfer操作,都通过this.options.lifecycle.runExclusive(projectId, 'authority-transfer', 'continuation', ...)包装执行,即所有接受/取消操作都被纳入生命周期子系统的互斥域;而AuthorityTransferRecovery与AuthorityTransferClaimantRecovery在构造函数中通过.register(options.lifecycle)注册到同一子系统(见该文件 L217-L227)。
二、权威与身份:谁可以提议、谁可以接受、谁在何时被绑定
规范文档第二节(Authority and identity)定义了转移中每个角色的权限边界与凭据语义:
提议与接受:
- 任意“已认证的活跃 LAN 成员”(authenticated active LAN Member)可以提议一个确切的规范 Cloud URL与稳定意图;
- 只有当前 LAN Host可以接受该确切提议、结算待定准入、静默(quiesce)、捕获、上传、保留凭据托管并提交源端让渡(source relinquishment);
- 关键安全假设被显式声明:“在线(presence)从来不是同意或身份证明,全员在线参与也从来不是必需的”——即缺席成员不会被要求参与,也不能仅凭在线状态推导授权。
初始绑定范围:
- LAN-to-Cloud 初始仅通过“被接受的源证明”绑定源 Host;
- Cloud-to-LAN 初始仅通过目标 Host 的临时权威(provisional authority)与其本地生成的凭据绑定被选中的目标 Host;
- 所有其他被导入的活跃成员在确切凭据赎回之前保持未绑定(unbound)状态。
凭据托管与赎回(claim custody and redemption):
- 切换(cutover)之前,源端持久保留完整的原始凭据批次(raw claim batch),目标端持久确认其确切摘要(digest);批次确认只证明“托管”(custody),不证明成员身份已迁移;
- 源端持有的凭据只有在“同一前成员转发确切的目标签名的赎回回执”(target-signed redemption receipt)或“有界过期”(bounded expiry)之后才会被擦除(scrubbed)。
凭据申领(claimant)的自持性:LAN 申领者自己生成并持久保存自己的凭据,只提交其哈希。凭据绝不用于:认证 Cloud 入站、签发凭据、创建成员身份、选择角色、移动 refs、或绑定另一个成员。
从源码结构看,这套语义在模块的组合层被严格编码。AuthorityTransferModule.ts 提供四组绑定入口,分别对应两个方向 × 两种角色:
bindLanToCloudSource(L230-L270):创建LanToCloudSourceCoordinator,注册到AuthorityTransferRuntimeRegistry,并可选地通过activateLanToCloudSourceRoute激活源端活动路由(对应第四节“原子钉住源端点”的规则);bindCloudToLanTarget(L272-L314):创建CloudToLanTargetCoordinator,要求expectedTargetUrl必填,并强制目标提供prepareTarget能力;bindLanToCloudClaimant/bindCloudToLanClaimant(L316-L429):创建申领者协调器,其中源端端口暴露getClaim与acknowledgeRedemption(幂等键为${operationIntentId}-source-ack),目标端端口暴露claimTransferredMembership。值得注意的细节是方向性的凭据哈希校验:LAN-to-Cloud 方向若请求携带credentialHash会抛出authority-transfer-cloud-claim-credential-unexpected,而 Cloud-to-LAN 方向缺少credentialHash则抛出authority-transfer-lan-claim-credential-missing(L359-L361、L421-L424)——这正是“Cloud 侧申领不得提交凭据哈希、LAN 侧申领必须提交”的规范约束在运行时的强制点。
另外,bindLanToCloudSource与bindCloudToLanTarget在绑定前都会检查该项目的源/目标绑定互斥(authority-transfer-direction-runtime-conflict),保证同一项目同一时刻不存在双重方向运行时,从结构上对应了验证要求中的“no dual writer”。
三、申领者恢复:full / target-only / local-only 三档运输可用性
规范文档第二节最后一段定义了申领者恢复(claimant recovery)的重建规则,其核心是:重建只解析对持久相位仍然具有权威的运输(transports),分三档:
- 赎回前需要完整源端与目标端(full mode);
- 源端确认不再需要后只需目标端(target-only mode);
- 目标成员身份已提交后只需本地(local-only mode)。
过期时的行为也被精确规定:赎回前的记录在无远端重放(remote replay)的情况下被擦除;而已完成的目标赎回则通过本地收敛向前恢复(local convergence),不去重试已过期的源端确认。而“成员身份已收敛”的记录属于终局清理,永远不解析任何运输。
从源码结构看,这三档被直接建模为一个可辨识联合类型RecoveredAuthorityTransferClaimantBinding(AuthorityTransferModule.ts L136-L164),其mode字段取值恰为'full' | 'target-only' | 'local-only'。运行时解析函数resolveClaimantRuntime(L566-L616)按direction × mode分派到六个私有绑定函数:
local-only→bindLocalOnlyClaimant:收敛器改为convergence.recoverConvertedClaimant(current),源/目标端口全部抛错不可用;- lan-to-cloud 的 full/target-only、cloud-to-lan 的 full/target-only 各自对应独立的绑定路径;
- 若恢复出的方向与记录中的
status.direction不一致,则抛出authority-transfer-claimant-direction-mismatch并释放 Cloud 会话——保证恢复永远与持久记录对齐。
对于 Cloud-to-LAN 记录,文档还要求“记录只保留钉住的公开 LAN 目标端点与所需的 CA 信任”(BindCloudToLanClaimantInput['targetHost']的endpoint/caCertificatePem/caFingerprint结构,L129-L133 与之吻合),且任何申领者操作都不得依赖先前绑定的活动运行时——这也是 target-only 分支(bindCloudToLanTargetOnlyClaimant,L465-L505)完全不需要lanClient的原因。
四、生命周期与恢复:代际、栅栏、检查点与不可变端点
规范文档第三节(Lifecycle and recovery)给出了恢复语义的完整约束:
代际(generation)规则:
- 现有权威从代际
1开始;目标端恰好激活在source + 1; - 源端让渡之前,取消操作必须证明目标未接受栅栏(fence);
- 让渡发生之后,所有属主向前恢复,任何 Host 启动或本地恢复路径都不得重新打开源端。
从源码结构看,代际不可变性与“取消禁止”都固化在 AuthorityTransferRecord.ts 的assertAuthorityTransferTransition(L410-L522)中:
status.sourceAuthority.generation、status.targetAuthority.generation在前后记录之间必须逐字段相等,否则抛出Authority transfer identity changed(L436-L440);- 一旦
relinquishmentProof非空,任何进入取消相位序列的转移都抛出Authority transfer cancellation is forbidden(L456-L460、L517-L521)——这正是“让渡后不得再取消/重开源端”的可执行断言。
重启栅栏(restart fence):同一文件中AuthorityTransferRestartFence取值'open' | 'permanent' | 'temporary',由expectedRestartFence(L105-L132)按角色与相位推导:
| 条件 | 栅栏取值 |
|---|---|
lifecycleOwnership === 'proposal'(提议未接受) | open |
相位为collecting-readiness | temporary |
源端且relinquishmentProof非空(已让渡) | permanent |
源端且相位为source-reopened或cancelled | open |
目标端且相位为target-staged/claims-retained/cloud-relinquished/cancel-intent/target-invalidated | temporary |
| 其他源端中间相位 | temporary |
解码时若记录的restartFence与推导值不一致即抛TypeError(L251-L254),意味着栅栏状态不可能被手工篡改——它是状态的纯函数。
Host 接受时的准入收口:Host 接受会关闭邀请与 Join 准入、吊销活跃邀请,并通过其属主结算可恢复的待定 Join;分歧或模糊的待定状态会阻塞转移,绝不被序列化(serialize)。
逻辑检查点的内容排除:检查点生产排除 SQLite 字节、凭据、邀请机密、CA 私钥、工作树(working trees)、未发布文件、缓存,以及本地草稿/本地未推送提交。捕获把“一个已静默的权威快照”绑定到“确切的允许 ref/OID 清单”与“包所有的清单(manifest)”。这一批工件由 checkpoint/ 子目录下的AuthorityTransferCheckpointGit、AuthorityTransferCheckpointManifest、AuthorityTransferCheckpointRepository等实现承载;摘要钉死则由assertAuthorityTransferTransition中的checkpointSha256不可变检查(L461-L466)与batchRevision/batchSha256不可变检查(L467-L475)在记录层再次强制。
工件权限与日志卫生:原始凭据批次、检查点工件与目标暂存区是“权限受限的、操作所有的状态”,创建前具有持久意图,在允许的取消/完成/过期时精确清理;绝不在转移记录或日志中持久化绝对路径、记录内容、凭据、端点或 Git 输出。实现侧可见 DurablePrivateFile.ts 与 AuthorityTransferArtifactBodies.ts 承担了私有文件工件职责;且持久层要求“源密钥、证明、清单与目标私有状态使用权限受限的临时文件、文件同步、原子提升(atomic promotion)、最终文件校验,以及在平台允许时尽力同步父目录;重启只移除或替换确切的操作部分(partial),绝不把部分写入的最终工件当作持久成功”。
源端端点的不可变性:LAN Host 接受时原子地钉住(pin)活动源端路由,并在转移工作开始前持久记录该确切端点;该端点在所有权有 LAN-to-Cloud 相位中保持不可变,是源端活动或源端终局恢复唯一可绑定的端点;模糊的保存后结果保留运行时钉住,而证明发生在栅栏之前的取消则释放它。从源码结构看,AuthorityTransferRecord.sourceLanEndpoint的解码函数decodeSourceLanEndpoint(AuthorityTransferRecord.ts L87-L103)强制端点必须为带显式端口、无凭据的 https origin,且转移前后不可变(assertAuthorityTransferTransitionL421-L429 仅允许从null在proposal所有权下转为非空),与规范完全对应。
双向恢复的终局行为:
- 完成的 LAN-to-Cloud 源端恢复:在其持久源端端点上恢复终局应答器(terminal responder),并在结算前收敛任何幸存的 LAN Host 成员身份;其持久过期已过的应答器直接恢复到本地清理,永远不要求原 Cloud 目标可达。记录中的
terminalResponder状态机(active | pending | expired)与expireAuthorityTransferTerminalResponder、isAuthorityTransferTerminalResponderExpired等函数(L355-L379)正是该规则的载体; - Cloud-to-LAN 恢复:直接对着持久的目标 URL准备监听器,绝不先打开未钉住的后备监听器;完成的目标恢复只从操作所有的本地状态校验确切的签名目标证明,并重建激活、成员收敛、目标活动路由与 Host 启动——永远不要求已让渡的 Cloud 源可达。重放同一持久目标活动转移是幂等的,包括“成员身份已提交但索引重建或 Host 启动失败”之后的恢复。
五、持久记录的结构与不可变不变量
AuthorityTransferRecord.ts 是上述规则的可执行核心,其AuthorityTransferRecord接口(L31-L47)定义了本地记录的全部字段:
schemaVersion(当前为2,常量AUTHORITY_TRANSFER_RECORD_SCHEMA_VERSION);localRole: 'source' | 'target'与lifecycleOwnership: 'owned' | 'proposal';operationIntentId(幂等操作意图)、transferId、projectId;restartFence、receiptVerifier、sourceLanEndpoint、stagingDirectoryName;terminalResponder与terminalCleanupCompleted(终局应答器及其清理完成标记)。
解码函数decodeAuthorityTransferRecord(L178-L288)实现了严格的全键匹配(exactKeys),并强制一组交叉一致性不变量,例如:
stagingDirectoryName必须严格等于`.claudian-authority-transfer-${status.transferId}`(L226)——暂存目录与转移 ID 一一绑定,保证清理“只删操作所有的暂存”;localRole === 'source'当且仅当status.direction === 'lan-to-cloud'(L227);receiptVerifier只允许出现在源端 LAN-to-Cloud 记录且项目/转移 ID 一致(L229-L234);sourceLanEndpoint只允许出现在源端、LAN-to-Cloud、owned所有权的记录中(L235-L239);- 让渡证明的
committedAt必须落在[createdAt, updatedAt]内且早于expiresAt(L243-L250)。
assertAuthorityTransferTransition(L410-L522)进一步规定了状态迁移的唯一合法形状:相位只能沿@claudian-collab/protocol包提供的有序相位序列(COLLAB_LAN_TO_CLOUD_TRANSFER_PHASES/COLLAB_CLOUD_TO_LAN_TRANSFER_PHASES)前进一步(L496-L501),或沿取消相位序列(COLLAB_AUTHORITY_TRANSFER_CANCELLATION_PHASES)在未让渡时前进一步;同相位重复提交只允许proposal → owned且停留在collecting-readiness的一次所有权升级(L483-L494)。这使得“精确重放”(exact replay)在记录层面成为可验证性质。
六、目录组织与验证要求
模块目录本身按职责分片,与规范文档的能力清单一一对应:
- lan-to-cloud/:
LanToCloudSourceCoordinator与生产源端效果(ProductionLanToCloudSourceEffects); - cloud-to-lan/:
CloudToLanTargetCoordinator与生产目标端效果; - claim/:申领者协调器、记录、绑定解析、恢复与运行时注册表;
- checkpoint/:检查点 Git 捕获、清单、仓库与准入结算;
- persistence/:持久化存储与批次承诺/托管记录;
- recovery/:
AuthorityTransferRecovery重启恢复入口; - 顶层文件:
AuthorityTransferModule(生产构造边界)、AuthorityTransferRecord(持久记录与不变量)、AuthorityTransferLocalFence(本地栅栏)、AuthorityTransferLocalConvergence(本地收敛)、AuthorityTransferReceiptVerifier(回执验证)、AuthorityTransferObservedStatus(观察状态)、AuthorityTransferArtifactBodies(工件体)与DurablePrivateFile(持久私有文件)。
规范文档第四节(Verification)规定了验证纪律:
- 在协调器与其所属持久化接缝处使用 TDD;
- 在每个持久相位之后执行 kill 恢复,并证明:精确重放、让渡后源端不重启、目标代际、无双重写入者、离线成员保留下的收敛、单凭据回执擦除(one-claim receipt scrubbing),以及只清理确切操作所有的暂存。
测试侧与之一致:tests/unit/app/collab/authority-transfer/ 下包含AuthorityTransferModule.test.ts、AuthorityTransferRecovery.test.ts(恢复子目录)、AuthorityTransferClaimantCoordinator.test.ts、AuthorityTransferLocalConvergence.test.ts、AuthorityTransferLocalFence.test.ts、AuthorityTransferReceiptVerifier.test.ts、AuthorityTransferRuntimeRegistry.test.ts与ProductionAuthorityTransferCoordinators.test.ts,覆盖了上述大部分可验证性质。
最后一条纪律约束了该模块当前的产品化状态:在“Step 13”的能力门控入口工作完成之前,普通用户 UI 保持缺失;内部组合与测试驱动只能调用完整的、已协商的操作——即该机制目前通过组合层与测试驱动入口访问,不向终端用户暴露半成品界面。
小结
Claudian 的权威转移模块用一份规范文档(AGENTS.md)与一组高约束的源码实现(AuthorityTransferModule.ts、AuthorityTransferRecord.ts 及各方向协调器)共同刻画了一个可恢复的所有权交接系统:其设计要点可归纳为——单一持久化目录与生命周期仲裁者、方向互斥的运行时绑定、凭据“自持 + 哈希提交 + 回执赎回”的托管模型、记录字段全键匹配与相位单步前进的不可变不变量、源端点原子钉住与端点不可变、以及“每个持久相位后 kill 恢复”的验证纪律。这些规则相互配合,使得迁移在任意一次进程中断后都能从持久记录精确重放,而不会重新打开已让渡的源端或产生双重写入者。
【免费下载链接】claudianAn Obsidian plugin that embeds Claude Code/Codex as an AI collaborator in your vault项目地址: https://gitcode.com/GitHub_Trending/cl/claudian
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考