news 2026/9/14 1:59:39

Claudian Collab 私有云 Bootstrap:八阶段绑定状态机、持久化 Host 围栏与失败即恢复的设计解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Claudian Collab 私有云 Bootstrap:八阶段绑定状态机、持久化 Host 围栏与失败即恢复的设计解析

Claudian Collab 私有云 Bootstrap:八阶段绑定状态机、持久化 Host 围栏与失败即恢复的设计解析

【免费下载链接】claudianAn Obsidian plugin that embeds Claude Code/Codex as an AI collaborator in your vault项目地址: https://gitcode.com/GitHub_Trending/cl/claudian

本文以 Claudian(一个把 Claude Code/Codex 嵌入 Obsidian 知识库的插件)Collab 协作子系统中的私有云 Bootstrap 模块为核心,完整解析 bootstrap 模块规约 定义的职责边界、八阶段绑定生命周期、持久化转换记录的存储与单调性保证、former-Host 停止围栏、双成员就绪报告以及激活后“只前进不回头”的恢复语义。读完后你可以理解该模块如何把一个局域网(LAN)权威项目安全切换到云权威:哪些状态必须落盘、哪些操作失败即封禁项目、恢复路径为什么保证不会回滚 LAN 权威。

模块定位:私有云 Bootstrap 只做什么、绝不做什么

bootstrap 模块的第一条规约划清了职责边界:该作用域拥有以下能力——

  • 保留的私有双客户端 readiness/report 固定夹具(fixture);
  • former-Host(源主机)停止围栏(stop fence);
  • 开发环境的激活请求与重放(development activation request/replay);
  • 客户端本地的绑定转换(client-local binding transition)。

生产权威转移、语义检查点捕获/导入、转移声明(claims)、源端放弃(source relinquishment)、目标代际(target generation)与终态响应器,全部属于 authority-transfer 模块,并且“绝不允许调用或包装本模块”。这是一个严格的单向依赖约束:生产路径永远不依赖 bootstrap 的私有能力,bootstrap 也不会反过来侵入生产权威转移。

从源码结构看,这个边界体现在模块内只有“development bootstrap”命名空间的实现:CloudBootstrapCoordinator.ts 面向的DevelopmentBootstrapCloudPort接口方法(activate/begin/cancel/get/report/upload)全部对应@claudian-collab/protocol协议包中的DevelopmentBootstrap*请求类型,每个响应都经过对应 operation 的 codec 解码(decodeStatus),防止服务端返回结构污染本地状态机。

转换记录:唯一的阶段权威

规约指出“一条转换记录是唯一的阶段权威”。在 CloudBootstrapTransitionRecord.ts 中,这个“唯一权威”被实现为一张严格解码的 JSON 记录,当前 schema 版本为CLOUD_BOOTSTRAP_TRANSITION_SCHEMA_VERSION = 2(第 31 行)。

八阶段生命周期

阶段集合是冻结常量(第 33–42 行),与规约逐字一致:

export const CLOUD_BOOTSTRAP_TRANSITION_PHASES = Object.freeze([ 'intent', 'readiness-confirmed', 'origin-rotated', 'cloud-verified', 'membership-replaced', 'index-repaired', 'lan-authority-retired', 'fence-terminal', ] as const);

推进阶段只有一个入口advanceCloudBootstrapTransitionPhase(第 582–612 行),它强制三条规则:

  1. attempt 必须已激活current.attemptState !== 'activated'时直接抛错,即本地绑定阶段只属于“云端已激活”之后;
  2. 严格单步前进nextIndex !== currentIndex + 1即拒绝,不存在跳阶段或回退;
  3. 终态围栏前置条件:进入fence-terminal要求 fence 处于host-stoppednot-applicable,否则抛错。

CloudBootstrapBindingFinalizer中的NEXT_PHASE映射表(CloudBootstrapBindingFinalizer.ts 第 32–40 行)与上述阶段序列一一对应,finalize主循环在每一轮先verifyActivation复核激活结果,再执行当前阶段对应的本地副作用,最后才推进阶段并持久化——这是规约中“激活后的恢复只把绑定阶段向前驱动”的具体实现。

记录的字段与不变量

CloudBootstrapTransitionRecord接口(第 70–105 行)携带:

  • attemptId/attemptStatepending|activated|cancelled)与activationResult(含activationOperationIdplacementGenerationactivatedAt);
  • manifestmanifestSha256(对 manifest 的规范化 JSON 做 SHA-256,见第 221–227 行);
  • oldAuthority(旧 LAN 端点、Git URL、CA 指纹、源 Host 成员 ID)与newAuthority(云端serverUrlgitRemoteUrl、绑定/线协议版本);
  • repositoryIdentitymainOidpersonalRefOidobjectFormatsha1/sha256);
  • fence(Host 围栏,见下节)、terminalCleanupCompletedownerInstallationKey(v2 新增,标记恢复所有权)。

解码函数decodeCloudBootstrapTransitionRecord(第 291 行起)执行一组“不可能状态”校验,其中值得注意的有:

  • developmentActorId必须等于memberId——这是规约“actor-bound report”(报告必须绑定发起成员)在记录层的强制;
  • manifestSha256必须与重新计算值一致,且oldAuthority的 CA 指纹、repositoryIdentity的各 OID 必须与 manifest 完全吻合;
  • cancelled状态只允许 fence 为released-before-activationnot-applicablefence-terminal阶段与fence.state === 'active'互斥;
  • terminalCleanupCompleted为真时 attempt 不能仍处于pending

持久化存储:目录 fsync、单调性检查与损坏即封禁

CloudBootstrapTransitionStore.ts 实现了规约中“转换目录及其父目录条目持久同步后才算返回”的全部细节:

  • 路径与限额:活动记录位于.claudian/collab/cloud-bootstrap-transitions/{projectId}.json,已取消的历史归档在.claudian/collab/cloud-bootstrap-transition-history/{projectId}/{attemptId}.json;单条记录序列化后不得超过MAX_TRANSITION_BYTES = 128 * 1024(第 25–27 行)。
  • 独占创建 + 原子写create使用createCollabFileExclusively(文件模式0o600,目录0o700),save使用writeCollabFileAtomically,写后调用syncTransitionStorage()——它连续对转换目录与.claudian/collab父目录做syncCollabVaultDirectoryDurably(第 303–306 行)。任何一层目录 fsync 失败都会以operation-failed错误向上抛,即规约所说的“directory-sync failure fails closed”。
  • 单调性守卫assertMonotonic(第 91–118 行)在每次save前校验:不可变身份字段(immutableIdentity,含 manifest、双端 authority、仓库身份等)不得变化;阶段索引不得倒退;attempt 状态只允许pending → activated/cancelled;fence 状态只允许active → host-stopped/released-before-activationhost-stopped → released-before-activation/terminalupdatedAt不得回退。
  • 损坏即封禁list()(启动目录枚举)对超大或损坏的记录不抛错,而是把项目 ID 收进blockedProjectIds并置retryRequired;读失败同样封禁并触发重试。被blockedLifecycleProjectIds封禁的项目,inspectLifecycleOwner会返回nonterminal——即它作为“非终态生命周期所有者”阻止普通项目工作继续。这正是规约“不可读、超大或损坏的记录既挂起普通项目工作,也让 Host 启动以失败关闭”的落点。
  • 取消归档:只有cancelledterminalCleanupCompleted的记录才能被archiveCancelled移入 history 目录,之后才允许用新的 pending 记录替换路径上的活动记录——对应规约“只有带该检查点的取消记录才可归档替换”。

Former-Host 停止围栏:失败关闭的双重挂起

规约要求“在源 Host 开始 bootstrap 之前,持久化 Host 围栏以及 token 挂起的项目准入和工作会话”。实现分布在两个文件:

CloudBootstrapLocalFence.ts 的closeAndDrain(第 61–76 行)按固定顺序执行:先suspendProjectAdmission挂起项目准入,再suspendProject挂起工作会话(挂起失败则回滚准入挂起),然后drainAdmittedOperations排空已准入操作,最后把项目标记为 quiesced。恢复路径resumeSuspendedProject(第 86–101 行)体现了规约中最微妙的一条补偿规则:先恢复工作会话,若随后准入恢复失败,则立即用一对新的挂起替换并保留,再抛出durable-progress-recovery-requiredCLOUD_BOOTSTRAP_ADMISSION_RESUME_FAILED_REASON)——“重试永远不会使用陈旧 token”。

CloudBootstrapCoordinator.ts 的stopFormerHost(第 329–354 行)在closeAndDrain之后调用formerHost.stopAndDrain,并把返回证据逐项断言为autoStartDisabled === true && resourcesDrained === true && routeUnregistered === true,任何一项缺失都以cloud-bootstrap-host-stop-incomplete失败关闭;成功后markCloudBootstrapHostStopped把 fence 推进到host-stopped并持久化。

围栏对启动路径的约束是全局的。在组合根 ClaudianCollabService.ts(第 377 行附近)中,LanHostCoordinatorrunWithProjectStartGuard被包进cloudBootstrapTransitions.runWithLanHostStartGuard。该守卫(Store 第 195–217 行)的语义是:只要存在 fence 为active/host-stopped/terminal且本安装是恢复所有者的记录,任何启动尝试(显式启动、恢复、项目创建、host-transfer 恢复)都会抛cloud-bootstrap-host-fence-active;而遗留的无主记录(ownerInstallationKey === undefined)则以cloud-bootstrap-legacy-owner-missing要求恢复。这就是规约“单一LanHostCoordinator.startProject权威把持久化转换守卫应用到每一个调用方”的实现证据。

另外两点与规约一致:工作会话挂起“自行完成 close 和 drain”,bootstrap 不得终态 drain 被挂起的项目;只有“持久化观察到的激活前取消”才允许恢复那对精确的挂起 token,且不会自动启动 LAN(见cancelsettleLocalTerminalresumeAfterCancellation的调用链)。

双成员就绪报告:各自的 actor-bound 证据

规约规定“两个成员提交独立的 actor-bound 报告”,并给出上传黑名单:任何路径都不得上传 SQLite、凭据、CA 材料、项目目录归档、未发布文件、本地-only 提交或私有草稿。

Coordinator 侧的实现印证了这条黑名单的“正向白名单”设计:

  • collectReport(第 356–396 行)构造的DevelopmentBootstrapReport只包含clientReadiness(由CloudBootstrapReadinessCollector采集)、manifest 的comparison段、报告者成员 ID、观察到的个人 ref OID;源 Host 额外附加hostStopAttestation(fence ID、stoppedAt、manifestSha256 等停止证据),且只有 fence 为host-stopped时才允许签发——“源 Host 不能替另一个成员背书”。
  • 报告先经decodeDevelopmentBootstrapReport解码,再以submitDevelopmentBootstrapReport提交;assertActorMatchesMember强制developmentActorId === memberId
  • 规约强调“quiesced 准入只证明停止了新的项目工作”,就绪检查仍必须巡检所有持久化生命周期所有者:publication操作非空、Manager-responsibility 回执处于offered/acknowledged都视为非终态。Store 的inspectLifecycleOwner(第 180–193 行)正是这类巡检端口之一,把本地转换记录自身也归入“absent/nonterminal/terminal”三类判定。

源 Host 激活主流程:捕获、上传、激活与恢复

CloudBootstrapCoordinator.startFormerHost(第 171–200 行)串起完整链路:

  1. 捕获 manifestsource.captureManifest(projectId),随后校验 manifest 的projectId/sourceHostMemberId与输入一致;
  2. 创建转换记录createTransitionlocalIdentity.load加载本地 LAN 权威身份,交叉校验 CA 指纹、成员 ID、以及“fenceId 是否存在 ⇔ 是否拥有权威”的等价关系,再落盘记录。若创建失败,discardBundle(manifest)立即丢弃 bundle——对应规约“捕获中、无主、已取消或已激活的产物经唯一 intent 所有者丢弃”;
  3. 停止 former Host(上节围栏);
  4. 驱动激活driveFormerHost(第 398–451 行)按序执行begin→ 若服务端状态未含本成员则report→ 若bundleState === 'missing'则以application/x-git-bundle流式upload(携带byteCountsha256)→ 仅当state === 'ready'时调用activate。服务端返回recovery-required/rejected时抛出durable-progress-recovery-required

参与方(非源 Host)走submitParticipant:先断言自己不是源 Host,创建记录,closeAndDrain后采集并直接提交报告。

recoverProject(第 222–263 行)是幂等的恢复入口:cancelled/activated状态走本地终态结算;fence 仍active先补做停止;随后拉取远端 attempt 状态,源 Host 在远端不存在记录时重新驱动begin,否则补交未含的参与者报告。规约中“步骤 5 可能在云端已激活、双端仍持有本地转换意图时完成;终态绑定等待步骤 6 的快照与 upload-pack”描述的正是这种“远端先行、本地收尾”的窗口,由settleLocalTerminal统一收口:丢弃 bundle、取消则恢复挂起 / 激活则执行binding.finalizecompleteAfterActivation,最后markCloudBootstrapTerminalCleanupCompleted打上检查点。

绑定收尾:membership-replaced 与 lan-authority-retired 的原子性

CloudBootstrapBindingFinalizer.ts 的finalize主循环(第 49–81 行)把每一阶段的“效果执行 + 阶段推进 + 持久化”绑成一个不可分割的序列,并且:

  • 每一轮先verifyActivation复核;进入index-repairedlan-authority-retired阶段前额外执行revalidateCloudBindingverifyCloudreplaceMembershiprepairIndex)——对应规约“在安静之后、第一个云操作之前重新验证完整捕获的权威与 Git-ref 快照”;
  • membership-replaced阶段执行replaceMembership(从每个权威有效成员重建并安装严格带标签的云端成员身份文件),index-repaired执行repairIndex——对应规约“该阶段原子安装成员身份并是适配器选择边界;独立的项目索引随后重建,两个文件互不复制阶段、互不隐藏无关项目”;
  • lan-authority-retired只移动 former Host 的精确无权威目录(效果由组合层注入的effects.retireLanAuthority完成),另一客户端记录为 no-op;保留数据是惰性诊断态,永不打开、永不自动启动、也绝不作为回滚权威。

fence-terminal时围栏状态被advanceCloudBootstrapTransitionPhase原子置为terminal,随后markCloudBootstrapTerminalCleanupCompleted要求“已激活且阶段为fence-terminal”才允许落检查点(CloudBootstrapTransitionRecord.ts 第 563–580 行),与规约“激活恢复把绑定阶段向前驱动、仅在云成员身份权威后重开被挂起项目、再检查点化终态清理”的次序完全一致。

启动目录、后台恢复与重试策略

CloudBootstrapService.ts 是模块的编排层:

  • 本地恢复屏障prepareLocalRecoverytransitions.list()枚举全部有效转换记录,把所有“不确定”项目(blockedProjectIds+ 本安装拥有的非终态记录)逐一fenceUncertainProject;任何围栏失败整体以cloud-bootstrap-local-recovery-fence-failed失败关闭,并调度目录重试。规约的“启动在组合根发布 feature 服务之前,目录化每个有效的项目键转换文件并围栏所有损坏或终态不完整的项目”即此屏障;已终态完成的激活/取消记录不重复围栏(terminalCleanupCompleted直接跳过)。
  • 后台工件恢复:屏障之后才调用recoverLocalArtifacts(规约中“工件与远端转换恢复保持为该屏障之后的后台工作”)。
  • 指数退避重试:目录级与项目级重试共用delayMs = min(1000 * 2^(n-1), 30000)(第 238、311 行),任何pending结果或异常都会#requestRetryclose()时中断全部 AbortController 并取消挂起重试,保证插件退出干净。
  • 恢复只前进recoverRecord中每条记录都先assertRecoveryOwner+#assertActorBinding;规约要求恢复时“重读精确的云 attempt,并在每个激活后阶段之前匹配其激活操作、放置代际、激活时间戳、项目、manifest 与 attempt 身份”,这些匹配由observeCloudBootstrapAttemptStatus(CloudBootstrapTransitionRecord.ts 第 635–682 行)的attemptId/projectId/manifestSha256一致性断言,以及activationPhase === 'completed'、fence 必须已host-stopped/not-applicable的激活完整性校验共同保证。激活后恢复“只向前或保持可见的 pending”,cancel对已激活记录直接抛cloud-bootstrap-already-activated,不存在恢复 LAN 权威或清除终态围栏的路径。

云端成员身份的字段白名单

规约最后一条对云端成员身份给出了精确的字段白名单,可从newAuthority的强制解码中逐条对照:

  • serverUrl:必须是https协议的规范 origin(canonicalCloudOrigin);
  • gitRemoteUrl:必须严格等于cloudProjectGitRemoteUrl(serverUrl, projectId)推导出的地址(第 376 行),即“派生 Git URL”;
  • bindingVersion/wireVersion:必须等于协议包的COLLAB_CLOUD_BINDING_VERSION/COLLAB_PROTOCOL_VERSION
  • 记录中的developmentActorId即开发 actor ID。

oldAuthority(LAN 端点、CA 指纹等)只留在本地转换记录里,不进入云端成员身份——“不含活动 LAN 凭据、CA、Host 所有权或恢复阶段”由此在解码层被结构性保证。同时整个流程通过保留本地 bundle 与“只上传 bundle 流”的设计,全程保住了未发布文件、本地提交与私有草稿的可重建性。

小结

bootstrap 模块的工程质量集中体现为三件事:单一事实源(一条转换记录 + 八阶段冻结序列)、失败即关闭(目录 fsync、围栏守卫、损坏封禁、单调性断言全部 fail-closed)、恢复即前进(激活后无回滚、取消只补偿、重试带指数退避直至终态检查点)。如果你要继续深入,建议按以下顺序阅读:

  • 规约与实现对照:AGENTS.md → CloudBootstrapTransitionRecord.ts → CloudBootstrapTransitionStore.ts;
  • 协调与编排:CloudBootstrapCoordinator.ts → CloudBootstrapService.ts → CloudBootstrapBindingFinalizer.ts;
  • 围栏与组合装配:CloudBootstrapLocalFence.ts、ClaudianCollabService.ts(runWithLanHostStartGuard装配处)、集成测试 FormerHostFence.test.ts。

【免费下载链接】claudianAn Obsidian plugin that embeds Claude Code/Codex as an AI collaborator in your vault项目地址: https://gitcode.com/GitHub_Trending/cl/claudian

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 1:58:10

滑动窗口算法解析与字符串最小子串实战

1. 题目背景与核心需求解析2026年携程暑期实习开发岗笔试第三题"字符串min-27"是一道典型的字符串处理算法题,这类题目在技术面试中出现的频率高达78%(根据2025年LeetCode企业题库统计)。题目要求开发者在一个字符串中找出满足特定…

作者头像 李华
网站建设 2026/9/14 1:57:49

Codex 配 TaoToken:自然语言生成自动化脚本的接入路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 1:57:04

SVM与Iris数据集:从sklearn源码到实验报告全解析

简介:一份面向机器学习初学者的SVM分类实战作业包,基于经典Iris鸢尾花数据集完成支持向量机建模与实验分析,适合Python机器学习课程作业、期末复习或入门实践。资源内含完整Python源码与实验报告,使用Python 3.9及sklearn、numpy实…

作者头像 李华
网站建设 2026/9/14 1:54:39

基于Django与TensorFlow的口罩检测系统开发实践

1. 项目概述与核心价值这个毕业设计项目结合了当前最热门的两大技术方向:Web应用开发和计算机视觉。使用Django作为后端框架搭建Web服务,配合TensorFlow实现的卷积神经网络(CNN)模型,构建了一个能实时检测口罩佩戴情况的完整系统。这种技术组…

作者头像 李华
网站建设 2026/9/14 1:53:34

从汽车电子到AI:电源管理器件选型实战与底层基石

干硬件这行时间长了,你会发现一个很有意思的现象:每次项目复盘,最终定位到的问题往往不在SoC,不在MCU,而是在那些最初选型时只花了五分钟的元器件上。电源管理链路更是重灾区。这几年从汽车电子项目做到AI相关的主板与…

作者头像 李华