☰
Vortex 集合安装日志审计:§F 模式的九大不变量、完全安装判定与中断恢复核查
2026/10/14 17:22:14 网站建设 项目流程
  • 桌面应用

【免费下载链接】Vortex

Vortex Development

项目地址:https://gitcode.com/gh_mirrors/vor/Vortex
点击查看免费下载

本文基于 Vortex 仓库watch-log技能包中的 §F 模式文档 collection-install.md,讲解如何对一个“集合(collection)安装”做完整日志审计:从识别安装信封(envelope)、逐成员生命周期追踪,到“是否完全安装”的可计算判定,以及九大安装完成不变量各自的破坏签名。读完本文,你可以照着 Steps 六步流程,把一次 Vortex 集合安装从日志中审计成一份“每个问题都有名字”的结论报告,并对应的源码锚点都能定位到具体文件。

1. 定位:§F 是什么,和 §E 有何不同

§F 是 watch-log 技能 的六种分析模式之一。它的前置知识来自三份文档:reference.md(核心)、shared/lifecycle.md(生命周期标记)与 shared/sessions.md(会话边界与终止分类)。

§E(trace 模式)沿一个实体追踪它在哪里卡住;§F 则对整个集合安装做审计:对照安装完成不变量(install-completion invariants),找出具体破坏了哪一条。审计范围默认限定在一个会话内(默认最新会话,按 §B 规则界定),且必须在报告中明确说明用的是哪个会话。

文档还给出一个关键提醒:日志文本会随代码演进漂移(log text drifts),在依赖“某条消息缺失”作为结论前,必须先 grep 各表中列出的源码文件,确认消息字符串仍然存在。

这些不变量是 LAZ-483 建立的契约,因此对 dev 集合安装运行同一套审计,同时就是一份483 回归检查。

2. 识别目标集合

审计的第一步是确定“审哪个集合”(Identify the collection):

  • 从用户参数($ARGUMENTS)中取得集合名/ID,或“the collection install”这类泛指;
  • 若都没有,就在限定范围内的日志中 grepstarting install of collection,列出候选项(带上collationId与totalMods)供用户选择;
  • 成员(member)线程靠modId/referenceTag/collationId,以及安装日志上携带的sourceModId(即 collection id)来串联。

starting install of collection锚点的真实出处是集合安装驱动器 InstallDriver.ts#L1023-L1026:

log("info", "starting install of collection", { totalMods: required.length, missing: this.requiredMods.length, });

注意这里的totalMods取的是必需成员总数(required.length),而missing是本次运行开始前仍需安装的成员数——这两个数字正是第 5 节“完全安装判定”公式的输入。

3. 信封:集合级生命周期锚点

集合级信封(envelope)由以下日志锚点构成,它们把一次集合安装框成一段可验证的时间线(Envelope):

日志消息出处含义
starting install of collection {totalMods, missing}InstallDriver(InstallDriver.ts#L1023)安装起点锚
did install dependencies {modId}InstallDriver(InstallDriver.ts#L674)依赖阶段完成
add collection rulepostprocessCollection(postprocessCollection.ts#L57)集合排序规则已应用
postprocess collectionpostprocessCollection(postprocessCollection.ts#L83)成功终态锚
pause collection/resume collection/failed to pause collection/User logged out during collection install, pausingcollections/index.ts(如 L364、L1604)暂停/恢复/登出暂停
already installing a collectionInstallDriver(InstallDriver.ts#L402)第二次安装请求被拒绝

从源码结构看,postprocessCollection之所以是“成功终态锚”,是因为它做完了集合安装收尾的全部事情:先log("info", "postprocess collection"),再应用modRules排序规则(每条新规则打出add collection rule),然后触发deploy-mods部署并调用各扩展的parse钩子(postprocessCollection.ts#L76-L104)。因此“到达postprocess collection”在日志上等价于“集合安装走到了终态”。

4. 逐成员生命周期与 SSOT 状态

每个成员(依赖)的通用安装标记沿用 shared/lifecycle.md 中 §E 使用的序列:

start mod install → installing to {modId, destinationPath} → extracting mod archive → invoking installer → finish mod install {outcome} → Installation completed successfully {installId, modId, duration}

它们分别落在 InstallContext.ts#L174(start mod install)、InstallManager.ts#L1707(installing to)、InstallManager.ts#L3977(extracting mod archive)、InstallManager.ts#L4112(invoking installer)与 InstallManager.ts#L1221(Installation completed successfully)。

集合侧的“下载-安装交接”由 InstallManager 打出:Found collection for download(InstallManager.ts#L703)与Found collection for failed download(InstallManager.ts#L794)。

这里有一条审计上的重要边界:SSOT 状态写入本身不打日志。{type:"status", status:"downloaded"|"failed"|...}这类状态写入(通过writeCollectionSession,实现见 collectionSessionWrite)直接落到会话 hive(state.session.collections),不是日志字符串。所以要“观察”这些状态,只能通过上述安装生命周期日志间接推断,必要时借助persist:diff {hive:"session"}的到达记录(§C 的标记,持久化通道见 persistenceIPC.ts#L29)。

5. 完全安装判定(每份报告必须回答)

每份集合审计报告必须显式回答一个判词:该集合是否“完全安装”(fully installed)——不能只说“本次运行结束了”。计算方式(Fully-installed verdict):

  1. 从信封数字入手:starting install of collection {totalMods, missing}给出成员总数与开始时仍需安装的数量,因此totalMods - missing在本次运行前已经安装;
  2. 统计限定窗口内打出Installation completed successfully的成员数;
  3. 得installed = (totalMods - missing) + completed-this-run。

三类结论:

  • Fully installed—— 到达postprocess collection,且installed == totalMods,没有失败/卡住的成员;
  • Completed, not fully installed—— 到达 postprocess 但有缺口,须点名(X 个失败、Y 个 skipped-or-unaccounted)。注意totalMods包含可选(recommends)成员,而可选成员默认跳过(InstallDriver.ts#L1004-L1012 中对未显式决策的 optional 调用markCollectionMemberSkipped);跳过(用户跳过、可选默认)只写会话状态,成功路径没有日志行——所以“没有安装线程、也没有失败”的成员应归类为 “skipped or unaccounted”,本身不是错误。唯一的跳过日志出现在失败路径:could not find collection rule for skipped download(collectionSkip.ts#L138);
  • Not completed—— 从未到达postprocess collection:卡住/被打断/被搁置(按不变量 9 分类),同样给出上述计数。

6. 九大不变量与破坏签名

下面是完整不变量表——健康安装必须成立的事实,以及每条被破坏时在日志里出现的签名(Invariants to assert):

#不变量(健康安装成立的事实)日志中的破坏签名源码位置
1每个成员都到达终态(installed 或 failed)Called callback for stuck installation(某成员卡在 "installing");或 stall-rescue 流程触发:Collection install stalled, attempting rescue之后出现Collection install stalled after rescue attempt, resolving(安装器强制解析了停滞阶段,成员可能被留在非终态)InstallManager
2失败的下载会把成员结算为 failed(并让阶段继续推进)Found collection for failed download之后没有跟随的成员 failed 结算;或Collection is not currently installing - ignoring download failure在集合确实在安装时触发InstallManagerhandleDownloadFailed(InstallManager.ts#L775-L847)
3没有重排循环(requeue loop)同一modId的start mod install运行次数超过MAX_DEPENDENCY_RETRIES(值为 3,定义于 InstallManager.ts#L567)InstallManager
4磁盘满会让成员终结性地失败解压遇到磁盘满,但成员既没完成也没打出 "Not enough disk space" 终态失败(失败模式:requeue → skip → stuck)InstallManager(InsufficientDiskSpace,抛出点 InstallManager.ts#L4014)
5孤儿归档(磁盘上有文件、无下载记录)在重新下载前被对齐(reconcile)磁盘上存在孤儿归档,但依赖下载停滞时没有出现reconciling orphaned archive before download {fileName, gameId}(reconcileOrphanedArchive.ts#L39)reconcileOrphanedArchive.ts
6集合到达 postprocess有starting install of collection但会话结束前没有postprocess collection/did install dependencies(阶段卡死);或Error during scheduled phase deployment(某阶段部署失败,可能阻塞推进)InstallManager / InstallDriver / postprocessCollection
7暂停/恢复与登出是干净的pause collection/ 登出暂停没有配对的resume collection,或出现failed to pause collectioncollections/index.ts
8进度值保持合理下载/安装进度值超过 100(免费用户路径上 101/100 的freeUserDownloadPosition失败,见 collectionInstallSession.ts#L55)InstallManager 免费用户路径
9被打断的安装不丢进度;用户主动的 resume 保留已完成成员重启前打出过Installation completed successfully的成员在重启后被重装(进度丢失);或resume collection重跑已完成成员/无法继续。注意:resume 是用户主动的,因此没有resume collection的搁置(parked)安装不是失败会话 SSOT(state.session.collections)

不变量 2 值得对照源码理解:handleDownloadFailed在确认集合正在安装后,会打聚合通知,然后必须调用writeCollectionSession(..., { type: "status", status: "failed" })结算成员并maybeAdvancePhase(InstallManager.ts#L836-L846)——代码注释明确说明:终结性的下载失败不会被重排,若不结算,成员会一直停在 "downloading" 并被 Failed 过滤器漏掉。这正是破坏签名“failed download 之后没有成员 failed 结算”的含义。

同理,不变量 3/4 对应依赖错误恢复的决策树planDependencyErrorRecovery:InsufficientDiskSpace与安装自身产生的ProcessCanceled被判为不可重试(重试注定重蹈覆辙),直接结算为 failed;普通瞬时错误则在MAX_DEPENDENCY_RETRIES(3)内 requeue(InstallManager.ts#L2675-L2708)。

6.1 停滞、救援与关键错误信号

安装器内置了 stall 检测安全网,以下信号一旦出现必须上报(Stall, rescue, and critical-error signals):

  • Collection install stalled, attempting rescue {sourceModId}([WARN],InstallManager.ts#L2833)——某阶段停滞(首次超时),救援进行中。还不是失败,但是预警信号。对应实现是pollAllPhasesComplete的 5 分钟无进展超时(STALL_TIMEOUT_MS = 5 * 60 * 1000,InstallManager.ts#L2795-L2858),首次超时会forceCleanupStuckInstalls并视需要重排已下载成员;
  • Collection install stalled after rescue attempt, resolving {sourceModId}([WARN],InstallManager.ts#L2861)——救援未能解除阻塞(第二次超时),安装器强制解析该阶段。该阶段的成员可能停留在非终态:须结合逐成员汇总找出是哪些,并按停滞(关联不变量 1/6)上报;
  • Critical error in dependency installation {downloadId, sourceModId}([ERRO],InstallManager.ts#L2756)——依赖安装抛出了未捕获异常;要确认成员是结算为failed而不是卡死;
  • Error during scheduled phase deployment {sourceModId}([WARN],InstallManager.ts#L3443)——某阶段部署失败(关联不变量 6);
  • Download not found when trying to resume {intendedId}([WARN],InstallManager.ts#L6388)——resume 时某个预期成员的下载缺失;关联不变量 9(resume 完整性)。

6.2 不变量 9 — 中断与恢复(数据丢失观测)

这是会话 SSOT 的核心承诺(LAZ-483 建立的保证):被重启/崩溃打断的安装,恢复时应从会话状态继续,不重做也不丢失已完成成员。每次中断都必须上报(它是真实信号),严重度框架如下(Invariant 9):

检测中断:一次starting install of collection,其会话在集合到达postprocess collection之前结束(下一个Vortex Version启动锚,或无postprocess collection的 EOF)。会话边界标记见 Application.ts#L213-L217(Vortex closing→clean application end)与 Application.ts#L465(Vortex Version)。

边界分类(沿用 shared/sessions.md / §B 的四态终止分类,不要塌缩成 clean-vs-crash):

  • clean(Vortex closing→clean application end)
  • killed-during-exit(有Vortex closing,无 clean end;典型于 dev 停止/重启/调试器杀进程)
  • hard-crash(完全没有Vortex closing,会话直接结束——真正的崩溃信号)
  • in-progress(最新会话,应用仍在运行)

严重度:

  • prod(日志目录$APPDATA/Vortex/):每次中断都是发现(finding)。安装中途硬崩溃是崩溃 bug;clean/killed 退出则是 resume 正确性与数据丢失隐患,需持续跟踪;
  • dev(日志目录$APPDATA/@vortex/main/):中断某种程度是预期的(开发者重启测试机),要报告但标注为预期——除非开发者明确表示这次重启不是故意的(此时按 prod 对待,硬崩溃尤其如此)。

Resume + 进度丢失检查:在边界之后的会话里找resume collection(collections/index.ts#L1604)或同一集合的新starting install of collection,看它是否到达postprocess collection。然后比较边界之前打出Installation completed successfully的成员modId与边界之后重跑start mod install/ 完成安装的成员:

  • 重启前已完成的成员被重装 =进度丢失/数据丢失(SSOT 未保住它们)——无论 dev/prod 一律上报;
  • 已完成成员在 resume 时被正确跳过 = SSOT 保住了进度(通过);
  • 没有任何resume collection= parked,等待用户恢复——不是失败(resume 是用户主动行为)。报告为 parked/incomplete,而非 stuck。

prod 监控视角:对 prod 日志,这条不变量就是集合安装可靠性的现场信号。对每个被打断的安装,报告:边界类别、恢复后是否保留了“N 中已完成 M”式的进度(无重做)、resume 本身是否成功。硬崩溃边界、或任何“已完成成员被重装”(数据丢失)都是要升级处理的真实发现;无恢复尝试的 clean 退出则是良性的。

此外要上报“下载事件找不到归属”的诊断性忽略日志——某成员附近成批出现时,是不变量 1 或 2 即将被破坏的强提示:

  • No collection mod found for sourceModId(InstallManager.ts#L352)
  • No active collection installation found(InstallManager.ts#L374)
  • No matching rule found in collection for download(InstallManager.ts#L382)
  • Collection mod not found in state(InstallManager.ts#L390)
  • Skipping download failure - download not found(InstallManager.ts#L780)

7. 审计步骤(Steps)

按 Steps 执行:

  1. 解析日志集并按 §B 限定到会话;找到集合信封;
  2. 构建逐成员汇总:对每个成员线程(modId),记录到达的阶段、结果(completed / failed /stuck)、完成时的duration(若有)以及重试次数(该modId的start mod install出现次数);
  3. 逐条走不变量表;每个破坏点引用成员、匹配行与时间戳。“没有终态”视为 stuck(不变量 1/6),不是成功;
  4. 计算完全安装判定:信封是否到达 postprocess?installed = (totalMods - missing) + completed-this-run对totalMods,缺口按 failed / stuck / skipped-or-unaccounted 分类;
  5. 报告信封结果(是否到达postprocess collection)以及任何暂停/恢复/登出转移是否配对。若未到达 postprocess,则执行不变量 9:找出结束它的会话边界、分类(clean / killed-during-exit / hard-crash / in-progress)、检查后续会话的 resume 与进度丢失,并套用 dev/prod 严重度框架;
  6. 列出窗口内[ERRO]/[WARN]中 payload 引用到成员的那些。

8. 输出格式(Output shape)

一份合规的 §F 审计输出包含以下要素(Output shape):

  • 一行判词回答“该集合是否完全安装?”:fully installed / completed-not-fully-installed / not completed(stuck/ interrupted / parked),并附成员计数(installed / failed / skipped-or-unaccounted / stuck,共totalMods);
  • 逐成员表:modId· 到达阶段 · 结果 · 时长 · 重试次数;
  • 不变量结果:1–9 每条 pass /FAIL(附违规行),本会话未走到的路径标 n/a;
  • 信封时间线(start → did install dependencies → add rule → postprocess)带 Δ 时间,外加暂停/恢复/登出事件;
  • 中断(若有):边界分类(clean / killed / hard-crash / in-progress)、是否 resume 并到达 postprocess、进度丢失结论(重做 vs 保留);按严重度框架写明 dev-expected 还是真实发现;prod 一律视为发现;
  • 异常清单:requeue 循环、stuck 成员、孤儿归档停滞、进度 >100、忽略下载成批出现、resume 时的数据丢失。

9. 小结

§F 把“这次集合安装到底成不成功”从一个模糊印象变成了可验证的判定:信封锚点给出骨架,逐成员汇总给出明细,九大不变量(对应 InstallManager.ts、InstallDriver.ts、postprocessCollection.ts、collections/index.ts、reconcileOrphanedArchive.ts 等实现)给出可 grep 的破坏签名,而不变量 9 则把重启/崩溃边界与数据丢失连成一条可审计的链。对 dev 安装,同一套审计顺带就是 LAZ-483 契约的回归检查。使用时注意两个前提:审计窗口按 shared/sessions.md 限定到单个会话,且依赖“消息缺失”的结论前必须先确认对应日志字符串仍在源码中存在。

  • 桌面应用

【免费下载链接】Vortex

Vortex Development

项目地址:https://gitcode.com/gh_mirrors/vor/Vortex
点击查看免费下载

相关推荐

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询