浏览 1.0.0 文档
1.0.0 文档修订 2

Binary DB v0:身份、恢复与转换

展开公开句柄的作用域、原子写入与恢复边界、转换的接纳条件、容量与排除项。

适用人群: 迁移、恢复与兼容性实现者

schema 的最后一章把物理记录同对外身份、崩溃恢复以及被接纳的转换连接 起来。它同时给出硬性容量上限、明确排除在外的领域和文件,以及布局 v0 的兼容性边界。

对外身份与紧凑句柄#

  • Task 身份以权威为作用域,由稠密的记录序号推导得出。
  • Change 用 C-01..C-64 表示序号 0..63
  • 已发布 Local Change 的 Remote 身份,是所属 Local Task 已发布的 Remote Task 索引,与所存的 Remote Change 序号配对而成; 它不是全局 Remote Change 索引。
  • Land 在所属 Change 内用 L-01..L-64 表示序号 0..63;它完整的 对外身份包含 Task 和 Change 身份。
  • Patchset 在所属 Change 内用 P-01..P-64 表示序号 0..63;它完整的 对外身份包含 Task 和 Change 身份。
  • Attestation 用 A-01..A-64 表示序号 0..63
  • Review 在所属 Patchset 内用 R-01..R-64 表示序号 0..63;它完整的 对外身份包含 Task、Change 和 Patchset 身份。
  • Policy Decision 在所属 Patchset 内用 K-01..K-64 表示序号 0..63; 它完整的对外身份包含 Task、Change 和 Patchset 身份。
  • Waiver 用 W-01..W-64 表示序号 0..63
  • Task Snapshot Link 用 S-01..S-256 表示序号 0..255
  • Stash 身份由 stash_index 推导得出,例如 STH-000001
  • AIT Tag 的对外身份就是它的名字;稳定的内部引用使用稠密的 tag_index,从不需要文本形式的 Tag ID。
  • 规范的 Snapshot 身份是 SNP- 加一段 48 位十六进制后缀。
  • Tree 和 Blob 的对外后缀是 80 位。
  • Tree Pack 和 Object Pack 的对外后缀是 48 位。
  • Git repository 指纹是 96 位后缀,导入/导出 generation 与 operation 身份是 64 位后缀,Plan 哈希是 96 位后缀, Git 映射身份是推导出的 80 位 GIM-* 后缀。

每个八位工作流句柄,在其声明的所属作用域内都使用下面这套位模型:

Code · text
bits 0..5 ordinal 0..63 within (owning identity, kind)
bit 6 tombstone/deleted
bit 7 indirect/extended

Change、Attestation 和 Waiver 保持各自声明的、以 Task 为作用域的分配方式。 Patchset 和 Land 在所属 Change 内分配。Review 和 Policy Decision 在所属 Patchset 内分配。因此同一个 Task 里不同 Change 之间, Patchset 或 Land 序号可以重复;不同 Patchset 之间,Review 或 Policy 序号也可以重复。完整的所属身份能把每一个重复的数字后缀区分开。

布局 v0 没有指定扩展句柄的 payload 格式。写入方一旦会超出声明的序号 范围,就必须在写入之前失败;它不得把 indirect 位当成自行发明一种格式的 许可。

多文件写入与恢复边界#

布局 v0 没有定义工作流层面的 wal.binjournal.bin、事务 ID 字段、 按记录的 WAL 序列,也没有 Binary DB 激活 generation 令牌。 GitGenerationRecord 标识的是导入的 Git 源状态或一份确定性的 导出计划;它不是数据库事务令牌。写入方的事务层负责单写入方/按 Task 加锁、依赖优先写入、有序的 fsync、只追加的提交点,以及可修复的 head/索引投影。

追加进去的明细记录,就是 Patchset、Review、 Policy Decision、Waiver、Attestation 和 Land 创建时的领域提交点。相关的 task、 change 或 patchset 头部记录都是可修复的投影。Land 状态变更采用 status-last 协议:先写入终态/重置数据并 fsync,再把 status_kind 作为 提交标记写入并 fsync。

tree_entry_range.bin 是唯一按序号对齐的定长依赖文件,它既不是 payload,也不是可重建索引。创建时会先写入每一条必需的区间行并 fsync, 之后才写所属的 Tree 提交记录。在稳定的激活边界上,它的条数等于 Tree 属主文件的条数;恢复时只能丢弃未提交的尾部依赖,遇到已提交依赖 缺失或中间序号不匹配则必须 fail closed。Task 关闭的变更完全发生在 task.bin 内部;Change 归档/重开的变更完全发生在 change.bin 内部。Land 创建会追加并持久提交一条完整的 land.bin 记录。每一次变更都替换或追加它那一条完整的定长 记录。若一次覆写没有抵达提交点,事务层会恢复其前像;单条记录内部 字段之间的顺序对外不可观测。

恢复过程会校验每一个头部和记录对齐,遍历已提交的明细 记录,修复 latest_*_index_plus1、计数和 next 序号,重算 最新/当前 Patchset 索引,按所属关系和存活性校验每个 Remote Change 选中的 Patchset 指针(而不是从 Patchset 元数据重建它),忽略孤立的依赖/payload 行, 并把每个声明身份作用域内的重复序号判定为损坏而拒绝。Task 层面用于 Patchset、Review、Policy Decision 和 Land 的索引只重建物理 清单顺序。它们的属主索引则重建序号链和 next 序号分配:Patchset 和 Land 的属主是 Change,Review 和 Policy Decision 的属主是 Patchset。不同属主作用域下出现相同的数字序号是合法的。

Snapshot 创建时会先追加每一条经过校验的父边并对边文件 fsync, 之后才追加带 bit 4 置位的子 Snapshot 记录。Snapshot 记录 就是提交点;写入被打断可能只留下孤立的边,恢复时会忽略它们。 恢复过程还会校验:远端 head 的历史边界没有本地父级, 且零父级的非边界 Snapshot 确实是真正的根。Tag payload 必须在 Tag 记录追加/更新之前落盘持久化。

Tree 创建时先追加归一化的 Tree entry 行和与之匹配的定长区间, 再写 Tree 提交记录。恢复过程会对照所属 Tree 校验归一化区间,并按 Tree Pack 的稀疏序号位校验每一个物理 pack 序号,然后才接纳该 pack 投影。

Git repository、generation、identity、parent、file 以及带类型的 payload 行都是 依赖。不可变的 Git commit/ref/Tag 映射记录是其映射的 提交点,会先于可重建索引候选完成 fsync。恢复过程会 忽略从已提交映射不可达的依赖行,校验全部 映射区间和数值形式的 AIT 引用,然后重建 Git 索引。Git operation checkpoint 会先写入自己的游标和时间,再写入并 fsync checkpoint_meta;重放一个已完成的 checkpoint 是空操作,可从不可变映射 重建得出。

bin 到 bin 的转换接纳条件#

转换器必须把每一个源字段归入以下几类之一:精确的定长字段/位 映射、唯一被接纳的 Patchset summary payload、schema 定义的 推导,或明确的非权威投影。落在这几类之外的字段会 fail closed; 不得把它塞进通用 payload。

离线转换器写入的是一个独立的目标 generation,可以分配新的 稠密物理目标记录索引。它保留源端的 Task 顺序,并且对其他 每一个权威文件家族,在已写出的行之间保留经过校验的源记录顺序。 在写记录之前,它会为每个被接纳的家族建立完整的源索引到目标索引的 映射。随后通过这些映射改写每一个属主 索引、*_index*_index_plus1、前一条记录的链接、selected/latest 指针、定长区间起点、按序号对齐的旁路行,以及重算后的 payload 偏移。可重建的 .idx 文件是从完成后的目标权威生成的,而不是复制过来的。

物理重编号绝不改变 change_ordinalpatch_ordinalattest_ordinalreview_ordinalpolicy_ordinalwaiver_ordinalland_ordinalsnapshot_ordinal;它们的对外句柄在各自声明的作用域内 保留与源端完全一致的序号。Patchset 序号在 Change 内保留, Review 序号在 Patchset 内保留,Policy Decision 序号在 Patchset 内保留,Land 序号在 Change 内保留。跨不同所属 Change 或 Patchset 的重复是合法的,不会被重新编号。对 Policy Decision 而言, 被接纳的遗留 .../P-##/POL-## 身份会把确切的 POL-## 后缀映射到 以 Patchset 为作用域的 K-##

同一个声明属主作用域内出现任何重复、同一种类在该属主作用域内超过 64 行、所属关系有歧义,或源 ID 与定长序列不一致,都会 fail closed。Task 层面的 Patchset、Review、Policy 和 Land 清单 链接按写出的物理记录顺序重建。Change 的 Patchset 和 Land 链接,以及 Patchset 的 Review 和 Policy 链接,按确切序号重建。任何 在目标映射中没有恰好一条对应项的源引用都会 fail closed。源 文件保持不可变,完全通过校验的目标 generation 会被原子激活。 不会额外增加任何新旧映射的 bin 或 payload。

唯一被接纳的 diff_stats 不一致情形,是显式选中的 离线遗留 stale-zero 闸门。该闸门使用一份精确配置的、由完整 Patchset 身份组成的允许列表;禁止部分匹配、只按序号匹配或通配匹配。

对于列表中的每个 Patchset,提供的值必须是完整对象,其中 files_added = 0files_changed = 0files_deleted = 0files_modified = 0,并且 paths.addedpaths.deletedpaths.modified 数组恰好为空。它规范的 base 和 revision Snapshot 引用 必须都能解析到存在且存活的 v0 Snapshot 权威,且对二者 完整 Tree 的精确比较必须成功并产生非空差异。转换器随后 只用这份重算出来的差异来校验是否可接纳; 目标端不存储任何 diff-stat 值。

没有显式开启该闸门时,任何不一致都会 fail closed。即便开启了 闸门,未列入或仅部分匹配的身份、缺失/多余/改名的 diff_stats 成员、提供的非零计数、提供的非空路径 数组、重算出的零差异、缺失/被墓碑标记/格式错误的 Snapshot、 不可读或格式错误的 Tree,以及任何其他不一致,都会 fail closed。不接纳任何 通配、只按序号匹配、兜底 Snapshot、重建出来的源值、 新字段、新位、新 bin、新索引、新 payload、记录宽度变更或 layout_id 变更。

唯一被接纳的另一种源 Task 状态写法,是显式 选中的、绑定到确切 repository 键和完整锁定源清单摘要的离线闸门。 服务端编排器会在转发该闸门之前校验这两个值。仅在该闸门下,源端的 status = "canceled" 映射到既有的 TaskRecord.task_meta bit 7, 与源端 status = "abandoned" 完全一致。遗留 payload 里没有 Task 关闭时间字段,因此转换后的终态 Task 会依据既有的"关闭时间未知"规则 保留 closed_at_s = 0

没有显式开启该闸门时,源端 status = "canceled" 会 fail closed。即便 开启了它,另一份清单、另一个 repository 键、部分或大小写折叠的 写法,以及任何其他未知的 Task 状态,都会 fail closed。该闸门不会 改变转换报告,也不会新增任何字段、位、bin、索引、payload、 记录宽度变更、重建标记、推断出的时间戳,或 layout_id 变更。

第一种引用缺失的例外,是针对某个 Patchset 的显式选中离线 遗留抢救模式——该 Patchset 规范的 revision_snapshot_id 在同一份锁定源 generation 的内容 Snapshot 权威中不存在。没有开启那个显式模式时, 引用缺失会 fail closed。开启之后,转换器 不为该 Patchset 写出任何行,也不写出任何依赖被省略 Patchset 的 Review、 Policy Decision 或 Check、Attestation、Land。如果 被省略的 Patchset 是所属 Change 权威的 current/latest 或 selected Patchset,转换器就不为该 Change 及其任何 Patchset 和依赖项写出行;它绝不会挑一个兜底的 current 或 selected Patchset。所属的 Task 仍然保留。

这一例外不接纳缺失的或哨兵值的 Patchset Snapshot 索引, 不会凭空造出或墓碑标记一个 Snapshot,也不会豁免缺失的 base Snapshot、格式错误的 Snapshot ID、已被墓碑标记或损坏的现存 Snapshot, 以及任何无关的权威缺失。目标端的 Change、Patchset、Review、Policy、 Attestation、Land 和 Actor 行在写出的行之间保留源顺序, 每一个存留下来的定长引用、链头、计数、selected/latest 指针、 按序号对齐的旁路行和可重建索引都会被稠密地重映射。 转换报告必须逐一列出被省略的 Change 和 Patchset 身份, 以及写出/省略的依赖行计数;省略绝不静默发生, 也绝不改动源字节。

第二种省略例外,是针对某个确切配置的 Change 身份、需要单独选中的 具名遗留抢救。那个源 Change 声称已 landed,但没有存留下来的成功 Land, 也没有完整的、可据以重建的已接受 Patchset/Snapshot 闭包。没有那个确切具名选项时,转换会 fail closed。开启之后, 转换器会省略该 Change、它拥有的每一个 Patchset 和依赖行,以及每一条引用它的 Land 行; 它不会凭空造出 Land、不会挑兜底 Patchset、不会推断时间戳, 也不会影响任何其他 Change。报告中必须写明所选中的 Change 及全部 依赖行计数。不允许任何通配、基于状态或隐式的省略。

被接纳的遗留 landed Change 归一化,比上面几种省略例外的范围更窄。 对于 current_patchset_number = 0 的 Change,只有当它显式的 selected 指针指向同一个 Patchset 时,才从它存留下来的最大 patch_ordinal 重建 latest/current。即便重复出现的 Change statuslanded_at 投影有出入,确切的 Land 行依然权威。每一次尝试都会被保留, 只要有一次尝试成功,Change 的生命周期就是 landed,且由最大的成功 land_ordinal 提供 landed 状态——哪怕之后还有一次未成功的尝试。当前 可变的 selected 指针不必等于任何历史 Land 所接受的 Patchset。这些规则只丢弃重复的投影,绝不丢弃 权威行,也不新增任何字段、位、bin、payload、兜底 Patchset 或 推断出的时间戳。

在转换之前,服务端编排器可以在不获取也不创建源锁的前提下,把源权威 复制到一个隔离的冻结 generation 中。冻结操作会在复制前 捕获当前每一个权威数据文件,复制这些捕获到的文件而不是信任 活跃 generation 那份可能已经过期的文件列表,然后再次捕获完整的 源清单,并要求按 relative_pathbyte_size 和完整 SHA-256 做到复制前/复制后/副本三者精确相等。它还要求源注册表清单的 确切字节在整个操作过程中保持不变。任何漂移都会 fail closed,且不会留下 已发布的目标。新生成的冻结 generation 沿用既有的清单 schema,其文件列表 和指纹恰好对应那些被复制的字节。Repository 清单副本和运行期锁文件不计入数据文件 列表。只有当每一个声明的文件都匹配、且不存在未声明的权威数据文件时, 转换才会接受那个冻结 generation。

无论在选中的源里还是在冻结副本里,都不要求也不创建源锁文件。 只有当选中的源清单明确证明某个确切文件或它整个声明家族的记录数为零, 或者该权威类别根本不包含那整个可选家族、并且没有任何存留的源记录 会引用它时,编排器才可以把缺失的遗留 .bin.idx 创建为只有头部的文件。家族只存在一部分、清单计数非零、 存在未解析的引用,或缺少证明,都会 fail closed。 绝不在选中的源根目录里做 头部合成,且转换报告会逐一列出每一个暂存的只有头部的文件。

新接纳的时间缺失置零情形仅限于 RemoteTaskRecord.updated_at_sRemoteTaskRecord.fetched_at_sRemoteChangeRecord.fetched_at_s、已归档的 RemoteChangeRecord.archived_at_s,以及 ActorRecord.created_at_s/last_seen_at_s。它们只在所选 遗留源格式确实没有对应时间字段时才适用。 先前列举的遗留 Task closed_at_s 和首次成功 Land 的 submitted_at_s 例外保持不变。除此之外,其他缺失或非法的时间都不会 变成零,且零值不授权任何合成时间或重建位。

源端的 identity_source 是注解,不是被存储的身份。只有当它缺失, 或与从选中权威根和数值形式的记录关系推导出的规范身份一致时,才可以 省略它。非默认、冲突或无法解析的值会 fail closed。源端的 published_remote_name 同样不被存储。只有当它缺失/为空, 或与本次转换显式选定的那一个远端权威完全相等时,才可以省略它; 不同的或有歧义的远端名称会 fail closed。

只有当源权威能证明某个源 Snapshot 确实没有父级时,它才会成为真正的 v0 根。因此被证明为空的权威依然为空,两个或更多被独立证明的根,在同一片 DAG 森林中依然是各自独立的连通分量。每一个存留的非边界 Snapshot 都必须 能到达这样一个根。如果源端证据反而表明它有祖先、只是那些父级没有被 导入,转换器就会设置 remote_head_history_boundary;若证据不足、 无法区分这两种情况,则 fail closed。转换器绝不会仅凭位置、记录顺序、 连通分量大小、Line 归属或当前 head 状态就推断出一个根或历史边界。

文本形式的对外 ID 只按其声明的紧凑序号或 哈希规则解析,随后再对照所属的定长记录做校验。源端的缓存 键、推导出的标签/消息、重复的名称、diff 统计和结果 投影,只有在本权威文档所列的显式推导规则之下才可以被丢弃。未知的 枚举文本、溢出、不一致、权威缺失或解析有歧义,都会在激活之前中止转换。

容量与扩展#

在做任何部分追加之前,写入方都会预检可表示的计数和窄字段:

Code · text
current_count  = (file_size - BIN_HEADER_SIZE) / record_size
projected_count = current_count + records_to_append

超长的 u8/u16 文本属于输入校验失败,不是加宽布局 v0 的 许可。除了明确列举的 Task closed_at_s 尾部、Change 生命周期尾部、Land 目标 Line 尾部,以及 Patchset summary/Worker Job 定位符/时间宽度这几项修正,加上列举出的 Git 映射 时间字段移除,以及单独划定作用域的运行期家族之外,真正的 记录/索引容量扩展都需要显式迁移到新的 layout_id,转换完整的依赖引用闭包,写入 独立的新文件,校验它们,并执行原子切换。有界的 运行期转换会迁移并收窄 Worker Job 记录,废止它的 全局身份家族,只新增两个声明的本地索引,并只追加 声明的 Patchset 定位符;更早的定长时间修正只收窄了具名的、 带时间戳的那些记录以及 ready 索引。随后的 u64 秒转换只加宽 完整列举出的普通时间字段集合。这两次转换都不允许改动其他字段或文件。 即便持久化的布局编号仍然是 1,同一个文件里混用不同记录宽度依然是禁止的。

尽管 parent_countparent_ordinalu16,Snapshot 父级数量的上限仍是 1,024。AIT Tag payload 的上限由 u16 payload_len 决定。 Git payload 和单字段长度值的上限由 u32 决定;Git SHA-1、 指纹、generation、operation 和 Plan 哈希的字节数组,都采用上面声明的确切 定长宽度。除了明确移除的 AIT 生成的映射时间戳之外,禁止收窄、截断、用哈希前缀 替代,也禁止在这些 20 字节字段里接受 SHA-256 的 Git Object ID。

剩下的那一个按序号对齐的旁路文件家族,会在写入前预检其属主计数和 所有 u32 索引。它是 layout-1 的 schema 扩展,不是 加宽既有记录或把其字段搬进 payload 的许可。

Task 尾部是一次性的 layout-1 转换,不构成通用的 加宽先例。转换必须显式选中旧的本地 40 字节或 远端 36 字节源布局,把整个文件改写成修正后的本地 44 字节或远端 40 字节布局,并且只有在完整校验之后才激活。

Change 尾部同样是一次性的 layout-1 转换。 对紧邻的前一种拆分表示做转换时,必须显式 选中 44 字节的 Change 源布局及其对齐的 8 字节生命周期 源,改写并校验完整的 52 字节 change.bin,在新 generation 中省略 change_lifecycle.bin,并且只有在每一处 base Line、归档时间、属主和 Snapshot 关系都校验通过之后才激活。

Land 尾部同样是一次性的 layout-1 转换。 对紧邻的前一种拆分表示做转换时,必须显式 选中 32 字节的 Local 或 36 字节的 Server Land 源布局及其对齐的 4 字节目标 Line 源,改写并校验完整的 36 字节 Local 或 40 字节 Server land.bin,在新 generation 中省略 land_target_line.bin, 并且只有在每一处目标 Line、属主、存在时的 Patchset、 Snapshot、序号链、状态和时间戳关系都校验通过之后才激活。

Patchset summary 定位符同样是一次性的 layout-1 转换。 转换 47 字节的源时,必须先构造并校验声明的 57 字节前缀加 patchset_summary_payload.bin。之后的 Worker Job 定位符修正再显式选中那个确切的 57 字节 前缀,追加 ci_worker_job_index_plus1,在一个独立 generation 中写入完整的 61 字节 patchset.bin,并且只有在每一处 summary 区间、同 Repository 的 Worker Job 目标以及 Patchset 关系都校验通过之后才原子激活。

Repository 内本地化的 Worker Job 身份变更也是一次性的 layout-1 转换。转换时必须在声明的 100 字节源记录存在时显式选中它,移除其中的 u64 job_id,改写并 校验完整的 92 字节 worker_job.bin,用两个声明的 Repository 本地索引 替换被取代的全局 Job 序列/索引文件,并且 只有在每一个永久本地索引、带类型 payload、Patchset 定位符、状态和时间戳都校验通过之后才激活。

之后的 Worker Job 定长记录变更是又一次一次性的 layout-1 转换。转换时必须显式选中那个确切的 92 字节源记录及其四个带类型 payload 家族,解析并校验 它们的完整闭包,在一个独立的非激活 generation 中写入声明的 88 字节 worker_job.binworker_job_input_payload.bin,并在目标中省略 worker_job_request_payload.binworker_job_result_payload.binworker_job_error_payload.binworker_job_lease_owner_payload.bin。 只有在每一个 Job kind、定长引用、归一化输入、结果、相关 Job、 错误、lease 哈希、Patchset 定位符、状态和时间戳都校验通过之后,才会激活。

取消 payload 并改用运行期 lease 的变更是又一次一次性的 layout-1 转换。转换时必须显式选中那个确切的 88 字节源记录和 worker_job_input_payload.bin,解析并校验 它们的完整闭包,在一个独立的非激活 generation 中写入声明的 60 字节 worker_job.bin,并在目标中省略 worker_job_input_payload.bin。 只有在定长引用、源 payload 契约以及"已静默、无运行中 Job"的 闸门都校验通过之后,它才丢弃源输入区间和 lease_owner_hash。 转换不会写入任何运行期 lease 副本。只有在 每一个 Job kind、定长引用、结果、相关 Job、错误、 Patchset 定位符、状态和时间戳都校验通过之后,才会激活。

之后的 Worker Job 直接引用变更是又一次一次性的 layout-1 转换。转换会显式选中那个确切的 60 字节源记录,并写入声明的 52 字节 worker_job.bin。 对 land.process 而言,旧的主体 Land 必须解析为确切的 maindirect、同 Repository 的 Server Land,其已接受的 Patchset 成为 patchset_index_plus1。对 main-seed.refresh 而言,旧的主体 Patchset 和 辅助的先前 Snapshot 成为那两个具名字段;它旧的上下文 Line 必须恰好是 main,并被丢弃。Patchset 的 CI、聚合和 Policy 主体成为 patchset_index_plus1repo.ci 主体在其旧的上下文 Line 精确校验为 main 之后成为 snapshot_index_plus1。 内容维护和 Repository 对账要求那三个旧的领域引用全部为零。 旧的相关 Job 引用在存在时会对源端的 attachedsuperseded 结果做精确校验,随后被丢弃。 只有在每一个新的具名引用、Job kind、结果、 错误、Patchset 定位符、状态和时间戳都校验通过之后,才会激活。这次历史 改写不会让原生 v0 的入队依赖于一个已存在的 Land。

定长时间变更是又一次一次性的 layout-1 转换。它选中 确切的 33 字节 Repository、52 字节 Worker Job、 12 字节 ready 索引和 61 字节 Patchset 前身,并改写出 声明的 25 字节、36 字节、8 字节和 57 字节目标。被接纳的 RFC 3339 运行期时间戳会按上面声明的方式归一化,并有意缩减到整秒。既有的 Patchset ci_completed_at_s 值必须放得进 u32;溢出会在写入任何目标之前 失败,而不是被截断。Patchset 的改写保留其前 28 字节以及逻辑上的 CI、summary 和 Job 定位符值,同时把尾部移到 修正后的偏移上。

同一次修正会选中确切的 100 字节 commit 映射、84 字节 ref 映射 和 52 字节 Tag 映射前身,并写出它们声明的 92 字节、 76 字节和 44 字节形式,其中不含 recorded_at_unix_nanos。在丢弃 这个由 AIT 生成的值之前,转换会核实物理记录顺序 能复现源端每一次"最新记录"的选择结果;不一致则 fail closed。 带签名的 Git identity 时间戳和时区仍然是逐字节保留语义的 源数据。只有在非激活 generation 中,记录整除关系、每一条 时间戳区间与排序规则、所有索引以及完整的依赖 引用闭包都校验通过之后,才会激活。

u64 秒变更是又一次一次性的 layout-1 转换。 它唯一被接纳的前身选择符是确切的 u32-time-v0;只选 layout_id = 1,或者从文件整除关系去猜,都是不够的。该选择符指的是 紧邻的前一个完整活跃 v0 表示,其普通 *_at_s 字段和宽度已在上面的修正表中 列举。缺少选择符、换成别的选择符、出现未声明的文件、某个源文件 未精确对齐到其具名前身宽度,或者出现混合宽度的 文件,都会在发布任何目标之前失败。

转换会冻结或读锁定完整的源权威,并记录其 完整文件清单和指纹。对每一条定长记录,它会按确切的声明顺序 复制声明时间字段之前、之间和之后的全部字节,并把每个小端 u32 秒值零扩展成对应的小端 u64。它不会解析、取整、重排、推断或 替换任何时间戳。它会逐字节精确复制每一个不受影响的 payload 和对象。 GitIdentityRecord.timestamp_s 不做转换。Worker 的 worker_ready.idx 会从转换后的权威 Job 记录重建; 其余所有可重建索引,要么从转换后的权威重建,要么对照未改动的身份和序号 键做精确校验。

转换器写出一个完整的非激活 generation,用活跃的 v0 编解码器校验 每一条修正后的记录,校验完整的跨文件引用和内容闭包, 并把仍处于锁定状态的源指纹与它捕获的前置条件做比较。激活要求 读写方都兼容,会重新检查那个源前置条件,并原子地只选中完整的 generation,同时保留一个可恢复的先前 generation 或直接 权威。转换失败或冻结后源发生变化,都不会动到活跃 权威。活跃文件绝不会混用前身和修正后的 记录宽度,且在转换或激活持有权威锁期间,任何运行时都不得写入其中任一表示。

排除在外的领域与文件#

布局 v0 不定义:

  • wal.binjournal.bin 或按领域划分的事务字段;声明的 Git 导入/导出内容 generation 是 v0 中唯一的 generation ID 例外;
  • Local Patchset 文件、Local Change 记录中的 selected-Patchset 游标,或 不可变 Patchset 元数据中的 selected-for-landing 权威;
  • 通用的 ci.binjob.bin;运行期作业只使用带类型的、 以 Repository 为作用域的 worker_job.bin 家族,而紧凑的 Patchset CI 证据 及其选中的本地 Job 定位符仍留在 Patchset 记录里;
  • 通用的 patchset_payload.binattest_payload.binpolicy_payload.binland_payload.bin;类型收得很窄的 patchset_summary_payload.bin 是 Patchset 唯一的例外;
  • 任何 payload 或旁路文件中的 Task 关闭时间;所属 Task 记录的 closed_at_s 尾部字段是其唯一权威;
  • 任何 payload 或旁路文件中的 Change base Line/归档状态;所属 Change 记录的定长尾部字段是它们的唯一权威;
  • 任何 payload 文件中的 Land 目标 Line 身份或归一化的 Tree entry 区间; 上面声明的所属 Land 记录尾部和定长 Tree 区间旁路记录 是它们的唯一权威;
  • 服务端的 Stash 文件;
  • 仅用于转换的 Actor 文件或通用 Actor payload;转换使用 既有的 actor.binactor_payload.bin 权威;
  • 共享字符串池;
  • object_pack_data.bin;对象字节仍留在它们的 pack 容器中;
  • line.bin 里全仓库范围的 current-Line 字段;
  • snapshot_payload.bin 里的 Snapshot 父索引扩展;
  • LocalChangeRecord 里的全局已发布 Remote Change 索引;
  • Git mirror 映射、最后一次 mirror 的 head 状态、mirror 方向/阶段、 运行期结果 JSON,或通用的 Git 映射 payload;
  • Worker Job 的结果 JSON、完整错误文本、文本形式的 lease 属主身份,或 worker_job_request_payload.binworker_job_result_payload.binworker_job_error_payload.binworker_job_lease_owner_payload.bin 的活跃定义;worker_job_input_payload.bininput_leninput_offsetlease_owner_hash 同样从活跃 v0 中 废止;
  • Worker Job 的 Land 索引、目标 Line 索引、相关 Job 索引,或第二个 Snapshot 引用字段;活跃 v0 只存储 worker_job.bin 中声明的那些具名 Patchset 和单个 Snapshot 引用;
  • identity_sourcepublished_remote_name、Git 映射中重复的 AIT Line/Tag 名称,或文本形式存储的 Line ID;
  • 作为 Binary DB 权威的通用运行期 payload、服务端调度策略/配置 payload、指标/时序存储、追踪/日志存储、通知/outbox 存储、软件包制品字节、外部提供方令牌保险库,或临时的 运行期 lease 副本;
  • 其他服务端全局运行期领域;活跃的运行期 v0 只包含 全局 Repository 注册表/名称 payload/命名空间索引,以及上面声明的 以 Repository 为作用域的 Worker Job 家族;
  • 服务端全局的 Worker Job 定长记录、payload、公开序列,或 调度/身份索引;定长的 Job 权威和两个可重建的 Job 索引都留在各个数值 Repository 权威内部;
  • 作为 Binary 权威的已废止运行期/规划会话,或 Test 清单/覆盖率数据; 以及
  • 从服务端全局指向仓库工作流/内容/Plan 权威的数值引用。那些跨根引用仍然是上面声明的、带类型的确切对外身份 字节。

遗留的 SQLite 可以由显式的一次性导入/导出工具读取,但它不是 权威的运行期兜底。已落地的 .ait/git-interop/v1 JSON 映射/checkpoint 存储同样只能被一次显式的一次性转换读取,转换成声明的 Git 定长记录和带类型 payload;它不是 并行的运行期权威。可选缓存和可重建索引,绝不能成为某个领域关系的 唯一来源。

Version authority

Checked against the exact 1.0.0 source

This page is public documentation, not a second product contract. Use the exact source and distribution contract for release authority.

Owning component Snapshots
  • ait-coreSNP-B06A48DA0245
  • ait-serverSNP-E90456E6425E
  • ait-runnerSNP-6B0A1BB3AFAD
  • ait-pythonSNP-973E3BFAF3DE
  • ait-nodeSNP-F962CC66AA62