Skip to content

CI/CD 与质量保障落地参考

整理日期:2026-10-03。

本文将 CI/CD 讨论整理为工程初始化和后续实施的参考。功能范围、协议版本、运行模式和交付阶段以 设计文档 为准;模块实现与测试方法另见 实现参考库,协议资料见 本地规范镜像。

首版接口与行为从 实施文档导航 查阅;行为验收为测试提供稳定案例 ID 和预期结果,兼容与分发契约明确公共边界与版本语义。功能进展仍在 GitHub Issues 和执行报告记录,不在文档维护另一份任务台账。

工程初始化已建立 pyproject.toml、uv.lock、Nox、Ruff/mypy、pytest/Hypothesis、Zensical/mkdocstrings 和 GitHub Actions 配置。实际入口见 AGENTS.md;测试、环境与制品报告写入忽略的 reports/ 并由 CI 归档。工作流存在不代表对应环境已经运行;模块行为、Linux x86_64 矩阵和最终制品分别需要实际验收;其余平台按用户确认交付本机命令并保留当前候选未验证状态,进度与运行证据见 Issue #5。本文未明确落地的补充工具和发布步骤继续属于方案,不表示已经验证通过。

其中,Python 3.11 基线、核心双异步后端、可选依赖隔离、两种数据库后端、API 文档与实现同步交付及各项行为约束来自已确认设计。平台目标及执行范围见兼容契约。按用户最新确认,仓库迁回组织 bgpglobal/rpkiparrot,全部 Actions 作业使用 self-hosted Linux x86_64 runner;其余平台提供命令,当前候选未验证不阻塞本次交付。PyPI 是包的发布目标,GitHub Actions 已用于主分支与显式矩阵检查;新增开发工具和性能门槛仍需验证。保存本文不自动增加运行依赖、启用发布或扩展产品范围。

当前由一名开发者维护,库代码由 Codex 或 Claude Code 实现和修改,直接在 main 上开发。日常流程围绕本地检查和主分支提交组织,不要求创建功能分支、独立 worktree 或 PR;需要其他流程时按用户明确指示执行。两种工具遵循相同的设计、测试与文档要求,开发约定统一维护在 AGENTS.md。

自托管运行器

ci.yml、dependencies.yml 和 platforms.yml 的所有作业都使用 [self-hosted, linux, x64]。仓库通过组织 bgpglobal-kvm runner group 的 selected repositories 获得运行权限;保留该组对其他仓库的既有授权,不扩大为所有仓库。标签必须同时匹配;没有在线且有权运行本仓库的 runner 时,作业排队,不回退到 GitHub 托管运行器。调度规则见 GitHub 自托管标签说明。

运行器要求原生 Linux x86_64、可用的 Bash、Git 2.18+、系统 CA,以及 Actions 所需的归档工具和受支持的 runner 版本。服务账号须能写入工作目录、临时目录和工具缓存,并能访问 GitHub、Python 下载源及依赖索引。固定版本的 setup-uv 安装 uv,随后安装所需 CPython;候选解析作业也使用 uv 管理的 Python 3.11,不依赖系统 Python。质量、测试、依赖和候选验收任务继续记录实际 OS、架构和解释器,发行版标签不能代替环境证据。

每个 runner 使用独立的专用工作目录,不能指向开发者的工作区。checkout 显式开启 clean: true,会清理前次运行的未跟踪及忽略文件,使虚拟环境、测试报告和候选制品不会跨作业混用。setup-uv 关闭 GitHub 远端缓存上传下载,使用本机下载缓存。工作流保留只读权限、固定 Action 提交、原有 push/schedule/manual 触发范围;不新增外部 PR 代码执行入口。

所有 Linux 作业把 TMPDIR 指向各 runner 独立的 ${{ runner.temp }},让 pytest 和子进程的临时文件随作业清理,避免累积在共享 /tmp。作业开头记录临时目录与工作区的磁盘容量及 inode;runner 服务账号必须拥有这些文件的删除权限。目录生命周期见 GitHub runner context。pytest 设置 tmp_path_retention_policy = "failed",成功用例结束即清理临时数据库;本地仅保留最近一次运行的失败用例临时目录,CI 中该目录随作业结束清理,JUnit、环境和覆盖率报告仍单独归档。临时目录策略见 pytest 官方说明。

质量目标

CI 持续验证以下四类结果:

  1. 正确性:协议与验证算法符合固定规范,更新、失效、恢复和事件行为符合设计。
  2. 通用性:第三方可以独立安装与调用,按需选择 extras、异步后端、传输和持久化实现。
  3. 兼容性:已声明支持的平台、Python 和依赖范围有实际运行证据,公共接口变化可识别和迁移。
  4. 可交付性:用户安装的制品经过验收,版本、提交、测试结果和制品哈希可以对应。

每个功能里程碑同时交付相应检查。尚未实现的功能不建立虚假的通过项;进入该功能交付阶段时,再将其测试加入必需检查。SQLite、DuckDB 和 HTTP 服务均属于首版,不能因分阶段接入 CI 而从首版验收范围中遗漏。

工具选择

用途 工具 状态与使用方式
CI 执行与发布编排 GitHub Actions 已配置 self-hosted Linux x86_64 主分支 CI、每周依赖范围任务和手动同批候选复验;普通推送不上传 PyPI,运行结果以对应提交为准
环境与依赖管理 uv 已采用;固定开发依赖并创建真实解释器隔离环境,锁文件不是第三方安装约束
本地与 CI 任务入口 Nox 已采用;组织真实解释器矩阵及 lint、类型、测试、打包与文档门禁
风格与静态检查 Ruff、mypy 已采用;格式与lint检查,源码和可执行示例以 Python 3.11 作严格类型检查
最低 Python 版本扫描 Vermin 可选补充;按语法和标准库规则推断最低版本,先评估误报与漏报,不代替运行测试
行为测试 pytest、pytest-xdist、AnyIO pytest 插件 Nox 使用最多 4 个 worker 按文件并行;同一组核心异步测试参数化 asyncio 和 Trio
覆盖率与生成测试 pytest-cov、Hypothesis 设计已选定;记录分支覆盖率,生成输入和状态操作序列
架构检查 import-linter 建议;约束模块依赖方向,防止核心依赖 CLI、服务或具体数据库适配器
公共接口检查 Griffe、外部调用示例 已检查全部公开导出、docstring、生成锚点及页面的源码摘要,拒绝缺失或过期内容;版本间API差异比较另行评估
API 文档生成 Zensical、mkdocstrings 的 Python handler 已采用;静态读取源码、保留中文锚点,严格构建并验证错误链接确实失败
构建与元数据检查 Hatchling、build、twine 已采用;先建sdist,再从该sdist建wheel,并执行twine严格检查
发布包内容检查 check-wheel-contents、项目制品清单检查 已采用;核对库模块、类型标记、许可、依赖与extras,禁止混入开发数据
依赖审计 pip-audit 建议;检查核心和各 extras 实际解析环境中的已知漏洞
工作流检查 actionlint、zizmor 建议;检查 GitHub Actions 配置及安全问题
深入缺陷探索 mutmut、Atheris 核心模块成形后评估;分别用于变异测试和解析器模糊测试

公共模块的 __all__ 使用单一字面量列表,文档门禁独立核对静态生成器读到的完整导出集合;后续 append、extend 或重新赋值会被拒绝,避免运行时接口逃过文档检查。

公开类的字段、枚举值和继承属性必须具有非空说明:可以使用字段自身的 docstring,或类 docstring 的 Args / Attributes 条目。仅有类总述、类型注解或生成页面中的字段 anchor 不算字段说明。门禁解析私有实现的公开别名及继承来源,并要求生成 HTML 包含这些公开路径;语义是否准确仍需人工审查,不能用占位文字代替说明。

API 参考回归测试直接运行 scripts/check_api_docs.py,因此 test 和 docs 依赖组都显式声明提供 griffe 模块的 griffelib;独立测试环境不依赖文档生成器偶然带入该包。

这些工具属于开发或发布环境,不进入核心运行依赖。工具版本在初始化时检查维护状态、安装要求及实际运行情况,再写入开发锁文件;不得因工具升级而无意提高库的最低 Python 版本。确需较新 Python 的开发工具可使用独立解释器,库本身仍须在 3.11 上验证。

Nox 的会话适合统一本地与 CI 入口。工作流主要负责矩阵、缓存、权限和制品传递,具体检查逻辑尽量放在仓库内可复现的会话中。开发命令只有在实际运行通过后,才补入 AGENTS.md 的开发命令章节。

AnyIO 自带 pytest 插件,使用显式后端参数化检查核心行为,共享核心夹具将实际后端与具体参数组合写入 JUnit 属性,门禁要求每个组合在 asyncio 与 Trio 的成功执行次数一致;固定后端的服务测试或测试名称中的字符串不能充当核心覆盖证据。避免多个异步 pytest 插件的自动模式相互干扰。

import-linter 可约束依赖方向;Griffe 可比较两个版本的 API。二者分别补充架构与接口检查,不能替代安装隔离和行为契约测试。

支持矩阵与依赖策略

平台与运行模式

支持目标保留 CPython 3.11、3.12、3.13、3.14。按用户最新确认,自动 CI 和候选验收仅执行 3.11、3.14;3.12、3.13 提供手动命令,未执行不计为通过。各 Python 系列的确切补丁版本记录在实际环境报告中。

维度 主分支 CI 检查 定期与发布验收
Python Linux x86_64 自动覆盖 CPython 3.11、3.14 3.12、3.13 保留手动入口;其他平台命令可检查全部四个版本,记录实际执行范围
操作系统 仅 Linux(组织自托管运行器,实际系统由环境报告记录) Windows 11、macOS 交付本机命令,当前候选未执行时标为未验证
CPU 架构 仅原生 x86_64/AMD64,各运行任务验证实际架构 Linux ARM64、macOS x86_64/ARM64 提供命令;仿真不替代原生证据,不含 Windows ARM64 和 32 位 x86
核心异步后端 asyncio、Trio 运行同一套核心异步契约 两者覆盖取消、TLS、恢复、事件与长时间运行
安装组合 核心包、每个已实现 extra、重点组合 完成文档中正式支持组合的验收
依赖版本 锁定环境;最低依赖检查按相关范围加入必需项 最新允许依赖定期重解析;发布提交重新验证兼容性
前瞻环境 不作为正式支持依据 新 Python 预发布版、其他解释器及自由线程构建按需试验

不要求所有维度无差别做笛卡尔积。优先覆盖有相互作用的组合,并列出各正式支持承诺对应的任务。实验任务可以不阻塞常规变更验收,但失败必须可见;实验通过也不自动变成支持承诺。

平台初始环境和依赖制品证据见兼容契约。当前自动验收范围为 Linux x86_64 × CPython 3.11、3.14 × 两种异步后端的四个基础组合;同步核心在这两个解释器运行,extras 按实际后端限制分组验收。3.12、3.13 交付手动命令,未执行不阻塞此次交付,也不声明该提交已验证这两个版本。其余四种平台按用户要求提供相同验收入口,并逐项标注当前候选是否实际运行。本次不要求全部五平台通过,不能把 Linux 结果标为全平台通过。这里不要求所有 extras 子集及三条依赖测试线无差别相乘。

截至 2026-10-02,GitHub 托管运行器表提供 Linux ARM64 及 macOS Intel/ARM64 环境;私有仓库也可使用标准 ARM64 运行器。Windows ARM64 已排除,不因可用运行器或依赖 wheel 存在而增加其必需任务。当前工作流不使用这些 ARM64/macOS 运行器,也不安排定期全平台矩阵。常见 Windows x64 托管镜像是 Windows Server,不能仅凭该任务宣称 Windows 11 已验证;需补充原生 Windows 11 x64 机器或同架构 VM。本次用户明确允许这些平台以验收命令交付,实际运行之前仍是未验证项。

HTTP 服务使用设计指定的 Uvicorn asyncio 环境,内置 SSH 适配器限 asyncio。它们应测试后端限制的启动诊断,不伪装成完整 Trio 支持。核心 TCP/TLS 的双后端能力保持独立。

Python 版本兼容性检查

采用“静态检查、真实解释器测试、依赖安装和制品验收”共同验证兼容性。requires-python = ">=3.11" 表达安装元数据中的最低版本,不证明代码在所有后续版本、解释器实现或平台上都正确。首批矩阵针对常规 CPython 构建;其他解释器、预发布版及自由线程构建按前瞻环境单独评估,不因版本号相同而自动计入正式支持。

层次 计划配置与职责 证据边界
Ruff target-version = "py311",与 requires-python 保持一致 按目标版本应用已启用规则和自动修复;不是完整语法或标准库兼容性证明
mypy 常规检查设置 python_version = "3.11";版本分支及版本相关接口按 3.11–3.14 分别检查 依赖可用的类型信息,不能证明动态行为或原生扩展正确
Nox + pytest 为 3.11、3.12、3.13、3.14 创建独立会话,在对应真实解释器中安装并执行同一套适用测试 覆盖到的行为提供实际证据;安装成功、导入成功或零用例运行不等于验收完成
uv 安装或发现目标解释器,管理隔离环境及依赖解析 不替代测试;解析或安装失败作为对应组合的失败记录
Vermin 按需扫描最低版本需求,确认所用规则及解析器覆盖目标语法 基于规则推断;动态导入、条件分支和 backport 等结果需要复核

配置依据见 Ruff target-version、mypy Python 版本选项、Nox 解释器与会话配置、uv Python 管理和 Vermin。工具版本在初始化时验证并锁定。类型检查涉及第三方库时,应读取对应目标环境的类型信息,不能仅切换目标版本标志就认为依赖组合已经验证。

tox 和 Pyright 分别是环境编排和类型检查的同类备选。当前优先落地 Nox 与 mypy,保持单一主要流程;Vermin 是否成为必需检查,在实际代码上评估后确定,不因本节记录就增加运行依赖。

运行矩阵应满足以下要求:

  1. Linux x86_64 自动在 3.11、3.14 分别运行 asyncio 和 Trio,形成四个基础组合;同步核心同样在两个版本执行。3.12、3.13 及其余平台提供本机命令,未执行时不计入通过。适配器有后端限制时按其声明范围单独测试。
  2. 每个会话记录实际解释器版本、路径、平台、依赖清单和用例统计。Nox 启用 error_on_missing_interpreters = True 或等效策略;缺少解释器、安装失败或缺失必需用例必须让对应检查失败,不能当作兼容性通过。
  3. 版本不兼容问题优先修复代码、声明合理依赖范围或提供有测试依据的适配;不通过静默跳过某个正式支持版本来维持成功状态。本地只运行部分会话时,报告明确列出未验证组合。
  4. 对核心包、每个已实现 extra 及正式支持的组合执行安装、导入与实际行为检查。DuckDB 等含原生代码的依赖需核对目标平台的可安装制品及运行结果;构建工具已安装不能掩盖用户安装条件。
  5. 核对各版本的 CLI 入口、异步取消与资源清理、SQLite / DuckDB 事务和恢复等已实现行为;补丁升级或依赖升级后运行相关回归。测试范围随里程碑增长,未实现功能不计入已通过项。
  6. 源码测试之外,从仓库目录外安装最终 wheel,执行公共 API 示例和适用的 CLI、后端检查。依赖矩阵继续遵循下节的锁定、最低和最新允许依赖三条测试线,不要求所有维度无差别相乘。

noxfile.py 保留四个真实解释器会话,默认只选 3.11、3.14,并设置所选解释器缺失时失败。scripts/environment.py 保存实际 Python/OS/架构/依赖,Windows 11 门禁检查 NT build 与产品类型,拒绝将 Windows Server 计入目标。scripts/check_test_report.py 拒绝零用例、失败和跳过,并可要求实际出现 asyncio/Trio 用例。初始工程测试不能替代后续模块的完整兼容性证据;最新运行结果见 Issue 与 CI 制品。

测试会话逐项记录用例名;单个用例超过 60 秒时,pytest 的 faulthandler 输出各线程栈,帮助定位生命周期和清理挂起。该诊断不取消用例、不放宽断言,也不把超时视为通过;CI 作业仍受独立的总时间上限约束。

Nox 的 tests-* 和 dependencies 使用 pytest-xdist:-n auto --maxprocesses=4 --dist=loadfile --max-worker-restart=0。自动选择不超过 4 个 worker,按文件分配,保证同一文件的 asyncio/Trio 参数组合在同一进程记录配对身份;worker 崩溃不自动重启。pytest-cov 汇总各 worker 覆盖率,JUnit 仍由原门禁检查全部已执行用例与双后端配对,不跳过失败或放宽断言。并行调度见 pytest-xdist 官方说明。

串行诊断使用 uv run --locked nox -s tests-3.11 -- -n 0。手动补验 3.12、3.13 的完整命令见兼容契约;这些版本不会因保留 Nox 会话而自动运行,也不能把 3.11、3.14 的结果计为其通过证据。

三条依赖测试线

测试线 目的 约束
锁定环境 复现开发与常规 CI 锁定工具与依赖,受审查地更新;记录解释器和平台
最低支持依赖 验证依赖下界真实可用 按环境标记解析库的运行依赖下界,不能只验证安装成功
最新允许依赖 尽早发现上游变化 在声明范围内重新解析,不复用旧锁文件冒充最新版测试

uv 支持最低版本解析。落地时先明确 lowest 与 lowest-direct 的测试范围;后者不能证明所有间接依赖的下界都已测试。最低运行依赖与测试工具约束分开管理,避免无差别降低全部开发工具,或安装测试工具时悄悄升级了待验证依赖。保存最终安装清单并检查目标版本确实生效。

发布元数据使用经过验证的依赖范围。开发锁文件不作为第三方用户必须采用的环境。依赖更新作为可审查的变更在 main 上完成,运行相关本地检查和主分支 CI;功能库依赖选择继续遵循设计和实现参考中的复核要求。

安装隔离与公共调用

核心安装检查应在只安装目标 wheel 及其声明依赖的干净环境中执行,验证导入、离线解析和验证功能。运行检查所需的测试驱动可以从外部调用该环境,避免完整开发依赖掩盖可选依赖缺失问题。

每个已实现 extra 单独检查;重点组合包括 cli,sqlite、http,trio 和 cli,service,duckdb。SSH 单独安装及 cli,ssh,trio 组合验证认证连接、CLI 和 Trio 限制。完整安装仅作为组合检查之一,不能替代最小安装。

验收覆盖以下行为:

  • 未安装 CLI、HTTP、DuckDB 或服务依赖时,核心导入和无关模块仍可使用;执行缺少依赖的功能时给出明确安装提示。
  • 核心导入不启动事件循环、不创建数据库、不修改根日志处理器;CLI 帮助、版本和补全没有网络或数据库副作用。
  • 从仓库目录之外安装和调用 wheel,不依靠 editable 安装、源码路径或 PYTHONPATH 才能通过。
  • wheel 包含 py.typed 和实际需要的包资源,公共调用示例在安装后的包上通过运行与类型检查。
  • 示例覆盖离线使用、宿主拥有任务组、自定义传输、公共持久化契约和远程 SDK;只使用公共 API,不依赖特定消费应用。

scripts/package_validation.py 对同一批候选制品创建十二种独立安装环境。每个环境先检查所有公共模块延迟导入,以及未装 HTTP、数据库、SSH 或服务依赖时的明确失败;随后从仓库外执行适用的JSON、ROV/ASPA、RTR、订阅、诊断、直接数据库提交与重开、受管理的数据库恢复、SDK和真实服务示例。只有安装 trio 的组合才执行对应Trio示例,未装组件的负向检查单独记录,不伪称其功能已运行。最后安装类型检查器,对实际复制的公开示例作严格检查。报告保存各环境的依赖、已执行例子、类型检查和原始sdist/wheel SHA-256;制品在验收中发生变化时拒绝结果。

隔离安装的冷导入探针覆盖全部 20 个核心公共模块,记录并拒绝应用文件读取、文件修改、SQLite 连接、socket/DNS 操作、子进程、线程或事件循环启动,同时保留可选依赖与根日志检查。正常 Python 模块加载允许读取模块文件,探针期间关闭字节码写入;即使被导入代码捕获了探针异常,已记录的副作用仍使检查失败。独立故障用例验证各类操作确实被捕获,安装报告中的 public_import_side_effects 保存实际执行结果。

测试体系与设计条款追踪

确定性测试与独立依据

同步解析、索引和验证保持可单独测试。常规 CI 中的行为测试使用本地向量、可控时钟、模拟字节流和本机服务;安装步骤可下载依赖,但测试执行不依赖公网 RTR 缓存或实时数据集。

范围 重点验证 建议方法
PDU 与 RTR 状态机 任意分包、连续 PDU、长度和字段错误、非法顺序、重复与不存在的撤销、session、serial 回绕、协商和定时器 独立字节向量、固定录制、可控字节流与故障注入
ROV 全部覆盖 VRP、ASN 与长度条件、AS0、IPv4/IPv6、简要与详细结果一致 规范向量,以及不复用索引实现的简单全量扫描模型
ASPA 与 BMP 固定草案、路径和邻居上下文、provider 查询、标准结果与上下文受限结果的区分 规范算法分支向量、独立模型、输入契约测试
JSON 与能力 真实生产者格式、缺失字段与明确空数组、无效记录、完整解析后提交 有版本记录的样例、畸形输入与整批回滚测试
快照与多源 载荷和元数据原子发布、来源独立撤销、去重、切换和回切 状态操作序列、并发观察和独立来源模型
时效与恢复 旧文件、HTTP 304、重启和导出重载不能延长有效期;固定快照仍在线检查时效 显式时钟、边界时间、时钟回拨及恢复失败测试
事件 初始观察无空窗、发布后通知、顺序、溢出、epoch、跨代读取与受影响范围 控制交错时机;比较全量重验结果与事件标记范围
持久化 完整原子提交、回滚、完整性、身份和时效、内存与持久化版本分离 SQLite、DuckDB 共用契约,加后端特有故障测试
共享模式 SQLite 多读取者、第二写入者拒绝、写入者退出后的本地失效;DuckDB 模式限制 独立进程、拥有者锁、版本传播和异常退出测试
传输与生命周期 TLS 身份检查、超时、取消、重连、注入连接的关闭归属、线程任务清理 两异步后端、本地测试证书与可控故障点
CLI 与服务 同快照同参考时间下结果一致、stdout/stderr、无 ANSI、退出码、中断、远程分页和游标 公共 API 对照、Typer 公共测试接口及独立子进程
资源与诊断 输入和暂存上限、有限队列、截断标记、离线回放、凭据不泄露 超限输入、慢消费者、日志检查与录制回放测试

对事件受影响范围,可生成一组测试路由,分别在变化前后进行全量验证,要求实际结果发生变化的路由全部包含在事件建议的重验范围内。测试集合仅作为测试依据,不给库增加维护 BGP RIB 的职责。

对取消和故障,不仅检查抛出异常,还检查快照、来源状态、事务、连接、等待者和受管理工作线程的最终状态。数据库进程中断测试应区分提交前、提交中和提交后,并验证恢复结果属于完整状态。

属性、状态机与故障探索

Hypothesis 状态机测试用于生成 announce、withdraw、reset、End of Data、断线、时间推进和恢复序列。独立模型保持简单,不复制被测实现的索引和状态转换代码。

主分支 CI 使用时间有界的生成测试配置;定期任务增加输入和操作序列规模。失败时保存缩减后的输入、操作序列、依赖版本和复现方式,并把有效反例转为固定回归用例。不可通过删除反例、无理由降低样本规模或自动重试至通过来掩盖缺陷。

模块稳定后,评估在 Linux 专用任务中加入 mutmut 和 Atheris。前者检查测试能否发现关键判断被改错,后者探索 PDU、JSON 等解析边界。运行时长、内存和输入规模均设上限,失败样例进入回归集。采用前验证工具与项目环境的兼容性。

规范、生产者与互操作

协议基线直接引用设计中的固定版本。测试向量记录规范章节、预期行为和适用版本;真实生产者样例及录制记录来源、软件版本、协议或草案版本、哈希、许可和必要的脱敏说明。自有编码器的往返测试只是补充,不能作为解码正确性的唯一依据。

定期或发布前使用可控的第三方实现执行互操作,记录实际服务端版本及配置。实验性 RTR v2、ASPA 必须核对确切草案语义;没有匹配实现时,在报告中明确未验证范围,不据此宣称完全互通,也不临时替换本项目的协议基线。

规范原文与注册表保持固定镜像,本地与主分支 CI 可离线检查清单和哈希。镜像更新、规范升级和实现变更分别审查,普通构建与测试不自动刷新镜像。已知规范冲突按镜像索引记录并核对,不把测试预期建立在未说明的猜测上。

质量门槛

实施时为重要设计条款建立到规范与测试的对应关系。可以维护验收表或测试元数据,至少包含条款标识、设计出处、规范版本与章节、测试入口、适用环境,以及已实现、待实现或缺少互操作条件等状态。

建议把以下条件作为相关变更与里程碑的验收及发布门槛:

  • 必需的行为、安装、类型和架构检查通过,正式支持组合没有无理由跳过;矩阵任务未运行不能算作通过。
  • 协议判定、原子发布、过期、回滚、能力降级和事件恢复等关键分支逐项有验收依据。
  • 分支覆盖率按模块建立基线,新增未覆盖逻辑与下降需解释;具体百分比在有真实测试后确定,不能用总体高覆盖率替代关键行为验收。
  • API 文档与实现同项交付是已确认准则:公共入口的 docstring、参考文档和相关示例完整,行为变化包含兼容性说明及必要的迁移示例;文档缺失时该 API 不算完成。对应自动检查在初始化时落地。
  • 不稳定测试保留故障证据并修复;临时隔离项记录原因、责任和复查期限。涉及关键正确性的缺口未解决时,不宣称该范围通过发布验收。

工作流分层与报告

日常顺序为:尽可能建立或关联 GitHub Issue,在 main 实现代码并同步文档,检查实际差异并运行相关本地检查,提交和推送后由主分支 CI 验证。Issue 中记录任务范围、验收依据和进展,docs/ 维护长期设计与使用说明。代码由工具生成不替代实际运行证据,提交已经进入 main 也不等于通过验收。

整个代码生成阶段已获用户授权,Codex 或 Claude Code 可按任务进展自行执行 git commit 和 git push 到本仓库的 main,无需逐次确认。暂存和提交只包含当前任务的明确变更;交付时报告提交标识、推送结果及实际可获取的 CI 状态,未运行或尚未完成的 CI 不计为通过。

触发 工作内容 结果用途
本地提交前 检查差异与 Issue 范围;执行改动相关的静态、类型、行为、文档及制品检查 及时修复问题,保留实际执行与未执行的检查记录
推送到 main 静态与类型检查、架构约束、核心矩阵、规范向量、短状态机测试、安装隔离、发布包验收、集成测试、公共示例、文档及工作流检查和报告归档 必需任务通过后,该提交才具备相应验收依据;失败时优先修复,不自动发布
每日或每周 Linux x86_64 最新依赖;长时间运行、互操作、模糊、变异和性能任务按已落地入口显式执行 提前发现回退,保留可复现证据
发布候选 选择 main 历史中的确切提交执行完整验收,检查最终制品与版本材料 正式支持范围通过后发布

主分支 CI 的常规反馈可先以约 10–15 分钟为工程目标,实际测量后调整。缓存依赖下载以降低耗时,缓存键包含相关平台、解释器与锁定信息;隔离安装任务不复用可能残留额外依赖的环境。

当前仓库策略允许直接更新 main,不设置必须经 PR 或第二名维护者审批的日常开发前提。推送后的 CI 不能追溯阻止已经完成的提交,因此本地检查、失败后的及时修复和发布前完整验收分别承担对应职责。版本 tag 或手动发布入口仍须绑定通过验收的明确提交;普通主分支推送不触发正式 PyPI 发布。初始化建立检查工作流,没有修改 GitHub 分支规则或启用 PyPI 上传。

纯说明性文档变更运行格式、本地链接、内容一致性及已建立的文档构建检查,无需新增运行时测试。API 的可执行示例变更运行对应示例检查;源码 docstring、公开导出和类型注解变化也触发 API 文档检查。测试代码、工作流、依赖或构建配置变更不能被误判成纯文档变更。若使用路径过滤,保留一个能准确汇总必需任务结果的稳定检查入口。

建议归档 JUnit 结果、分支覆盖率、环境与依赖清单、Hypothesis 反例、互操作记录和性能数据。发布任务另归档制品哈希及版本材料。报告明确区分通过、失败、跳过和未执行;网络审计服务不可用或工具执行失败不能显示为检查通过。

本地会话和 CI 采用相同检查逻辑。失败报告应提供复现所需的 Python、平台、安装组合、后端和依赖约束。敏感配置和私钥不进入日志或归档制品。

公共 API 与版本管理

公开入口、导出符号、类型信息和调用示例应明确。Griffe 比较当前代码与选定的已发布基线;尚无发布版本时使用明确的审查基线,不假定存在最新 tag。

API 文档生成与同步验收

实现和文档必须在同一项变更中完成,适用范围与内容要求见 设计文档 的“API 文档与实现同步”。初始化已选择 Zensical 与 mkdocstrings,具体版本固定于 uv.lock。docs/api.md 组织已实现公共导出,scripts/check_api_docs.py 检查公开对象和方法的源码说明,语义、字段与生命周期说明仍须审查;仅含版本常量的空 API 参考不能通过。下表保留方案选择依据。

方案 建议与适用条件
Zensical + mkdocstrings[python] 优先评估;继续使用 Markdown 编写指南,由 Python handler 生成 API 参考,适合当前以 Python 和 Markdown 为主的仓库
Sphinx + autodoc + Napoleon + MyST 备选;需要 Sphinx 的 Python 文档交叉引用与扩展体系时采用,MyST 用于保留 Markdown 编写方式
MkDocs + mkdocstrings 可作为兼容性备选;若选择 Material 主题,须单独考虑其维护阶段,不将主题与生成器混为同一项目

mkdocstrings 的 Python handler 可提取源码中的接口信息,支持不同 docstring 风格;建议采用 Google 风格,类型以源码注解为准,docstring 解释语义。纯 Python 模块优先静态解析,考虑设置 allow_inspection: false,避免生成参考时隐式导入可选模块;无法解析时应明确失败并处理。文档环境与仅安装核心包的隔离检查保持独立。

Zensical 已列出 mkdocstrings 支持,但不能据此假定所有 MkDocs 插件或配置都兼容。首个构建只使用必要功能并显式组织公共 API 导航。Material for MkDocs 已处于维护阶段,官方当前公告将关键修复与安全更新延长至 2027-05-05,新功能开发集中于 Zensical;这是新站点优先评估 Zensical 的原因之一。维护公告

备选方案中,Sphinx autodoc 会导入被记录模块,必须控制可选依赖及导入副作用;Napoleon 可处理 Google / NumPy 风格 docstring,MyST 提供 Markdown 支持。无论选择哪一套,领域语义和使用指南均需手写,生成器不能替代同步编写要求。

从首个 API 里程碑建立以下检查:

  1. 公开接口覆盖:使用明确的公共模块、导出和成员清单,对照实际生成的参考与说明;缺少 docstring 的对象不能因生成器过滤而绕过检查。公开字段、枚举值和扩展协议也在覆盖范围内,普通内部辅助函数不自动变成公共承诺。
  2. 说明与签名检查:通过既定 Ruff 的 docstring 规则检查基本格式和缺失说明,结合 Griffe 或小型检查脚本核对实际公开对象;Google 风格可评估 D417 参数说明检查。自动检查不证明异常、时效、取消及结果语义正确,这些仍需审查和契约测试。
  3. 严格文档构建:校验页面、锚点、对象引用及配置;Zensical 提供 build --strict,需配合 链接与引用校验配置。用缺失对象或错误链接的小样例确认检查确实失败,不以空站点构建成功作为 API 文档验收。外部链接检查独立运行,避免公网波动掩盖本地文档问题。
  4. 示例可运行:展示的示例尽量从同一份文件提取,使用 pytest 和公共调用检查执行相关示例;异步核心示例按适用范围覆盖 asyncio / Trio,使用固定数据与本地替身。简单确定性片段可用 doctest,网络、计时和并发行为使用正常测试。
  5. CLI 与 HTTP 同步:CLI 参考从 Typer 公共命令与帮助入口生成或核对;HTTP API 从实际路由与模型生成 OpenAPI,另补完整语义。生成帮助或 schema 不启动网络、数据库或来源同步。
  6. 版本对应:主分支 CI 构建文档预览制品,尚未发布的内容标明未发布;发布时从同一发布提交构建文档并标明包与协议版本。生成 HTML 作为制品保存,站点工具属于开发依赖,不进入用户安装 extras。

scripts/build_docs.py 在暂存的 API 参考中写入库 Python 源码摘要,严格生成后由 scripts/check_api_docs.py --html site/docs/api/index.html 重算核对。摘要包含定义公开别名、 继承签名和数据类字段的内部模块,并使用相对路径,移动相同源码不会使页面失效。 同名接口新增参数、改变默认值或返回注解后,旧页面即使仍有全部锚点也会被拒绝;缺少或重复 源码标记同样失败。标记不替代实际 API 内容、docstring、锚点及手写行为语义检查,也不是对 任意修改后的 HTML 内容的密码学证明。重建完整参考后才重新验收。

Cloudflare 文档部署

deploy/cloudflare/ 保存文档的 Workers Static Assets 部署配置和独立的 npm 锁文件, 不增加 Python 包依赖。发布目标为 rpkiparrot.bgp.global:/ 展示项目概览, /docs/ 是文档导航,/docs/api/ 是完整生成的 Python API 参考。 zensical.toml 中的 site_url 用于生成规范链接和站点地图;当前内容继续标记为 unreleased,不因文档部署而宣称候选包已经上传。

API 参考按模块的显式 __all__ 筛选公开入口,保留类的公开方法、字段和继承说明, 不把实现时导入的辅助对象重复列为该模块的接口。右侧目录的子级默认折叠,箭头支持 鼠标与键盘展开;目录顶部可全部展开或收起。带锚点的链接会展开对应目录路径, API 正文仍完整呈现;没有 JavaScript 时保留可用的普通目录。 目录按功能分组、模块、类与成员分层;成员标题保持清晰字号,长签名允许在内容列中换行。

部署使用构建后的 site/,保留文档、示例与规范引用的相对目录。配置本身不证明 线上发布成功;必须完成下述本地检查及发布后的 HTTPS 验证。现有主分支 CI 仍只 构建和归档站点,发布为显式手动操作。

从仓库根目录运行,需要 Python 开发环境和 Node.js 22 或更新版本:

uv run --locked nox -s docs -- --check-failure
npm --prefix deploy/cloudflare ci --ignore-scripts
npm --prefix deploy/cloudflare run check
npm --prefix deploy/cloudflare run preview
# 另开终端检查 http://127.0.0.1:8787/docs/ 和 /docs/api/,完成后停止预览。
# 通过环境注入 CLOUDFLARE_API_TOKEN;不要将令牌写入配置或提交。
npm --prefix deploy/cloudflare run deploy

只查看本地构建、不使用 Workers 预览时,也可运行 uv run --locked python -m http.server 8000 --bind 127.0.0.1 --directory site, 然后打开 http://127.0.0.1:8000/docs/api/,完成后按 Ctrl+C 停止。 成功 CI 的 quality-and-package 制品也包含完整 site/。

check 执行 Wrangler dry run;preview 运行本机 Workers 静态资源服务;deploy 上传已构建的文件,并配置声明的自定义域名。上传前重新核对源码生成 API 门禁, 发布后检查文档导航、API 锚点、搜索索引、样式资源和不存在路径的 404 响应。 包上传和其他产品站点有各自的发布流程,不由此命令触发。

Cloudflare 身份限定在当前部署账户。新版角色下,首次创建 Worker 需要 Workers 产品级 Admin,后续部署已有 Worker 需要 Editor;自定义域名还需要针对 bgp.global 的 Workers Routes Write 和用于查找 zone 的读取权限。 旧版 token 界面的 Account → Workers Scripts → Edit 与 Zone → Workers Routes → Edit 仍可用。凭据由操作者或 CI 注入,不写入仓库。 权限和绑定依据见 Workers 权限 与 Custom Domains。

兼容与弃用

兼容性检查同时覆盖签名之外的契约:异常类型、稳定错误码、结果语义、JSON 字段和格式版本、CLI 退出码、配置含义、快照与游标行为、导出及持久化 schema。工具无法自动证明这些语义保持兼容,仍需回归测试和审查。

建议从 0.x 开始保持补丁版本兼容;确需破坏兼容时,在相应版本中明确变化及迁移方式。1.0 前确定正式的兼容承诺和弃用周期。协议草案升级单独记录行为差异,并同步向量、能力报告和使用说明。

对于持久化格式变化,按明确的 schema 兼容策略验证旧数据的读取或拒绝行为,不能以重置时间绕过恢复检查。首版跨后端迁移仍按设计重新同步,不因版本管理流程自动增加迁移功能。

构建、发布与供应链

代码生成前可以完成的账户注册、邮箱与 2FA、GitHub 发布环境和 pending publisher 表单,单独列在 PyPI 发布前的手工准备。该文档提供本仓库的建议填写值;手工配置完成后,工作流须使用一致的仓库、文件名和环境名。

PyPI 接收要求与项目质量门槛

PyPI 是计划发布渠道。平台接收上传不代表功能、协议或兼容性已经获得认证;项目仍须通过前述行为测试和本节的发布包验收。以下平台规则按 2026-10-01 的官方资料整理,正式接入和发布时复核;名称、账户权限和配额等服务端状态不能由离线检查完全证明。

项目 PyPI 或打包规范要求 可以提前完成的检查
名称与所有权 项目名符合格式与规范化规则,并且可创建或由发布身份拥有上传权限;没有项目页面不保证名称可用 校验元数据名称与文件名;首次接入核对名称和权限,不能把查询结果当作名称预留
必需元数据 核心元数据必须包含合法的 Metadata-Version、Name、Version;其余声明字段符合各自格式 检查实际 sdist / wheel 元数据及支持的元数据版本,核对两种制品的名称和版本
版本与文件名 已使用的分发文件名不能再次使用,即使文件已删除;同一发布可以有不同的制品文件 发布前核对已有文件,比较 tag 与规范化后的包版本;不以覆盖旧文件实现修复
运行依赖 PyPI 不接受发布元数据中以直接 URL 声明的依赖,例如 Git 仓库或外部 wheel 地址 检查 Requires-Dist 的语法、版本范围和环境标记,拒绝直接 URL 与本机路径依赖
文件与项目大小 当时默认单文件上限为 100 MB、项目总量为 10 GB;项目实际配额可能不同 计算候选文件大小;设置适合本库的更低内部门槛;发布前核对项目剩余配额
账户与认证 PyPI 账户需要验证邮箱并启用双因素认证;上传必须使用被授权的发布身份 首次接入配置账户、项目权限和 Trusted Publisher;CI 仅在发布任务使用对应身份

规则来源:名称规范、核心元数据规范、PyPI 名称、账户与文件名帮助、直接 URL 依赖限制、存储限制。依赖限制适用于发布制品,不因本项目使用 Hatchling 构建而改变。

Requires-Python >=3.11、完整 README、明确许可证、py.typed、测试与类型检查通过等,是本项目的发布质量要求,不应全部描述成 PyPI 对所有包的统一必填条件。许可证使用符合项目实际许可的 SPDX 表达式,配置 license-files 并检查相应文件进入制品;本文不代替项目选择许可证。许可证字段与文件的格式依据见 许可证元数据。

按当前纯 Python 实现设计,计划发布通用 wheel 与 sdist;可选依赖 DuckDB 自身包含原生组件,不意味着 rpkiparrot 必须自行构建各平台二进制 wheel。若后续引入自有原生扩展,重新评估 wheel 标签、平台构建和验收矩阵。通用 wheel 标签本身不证明所有操作系统上的功能都可用。

发布包验收任务

发布包验收由 nox -s package 调用 scripts/package_validation.py,同时纳入当前 CI 的 quality 作业。它检查实际分发文件,补充源码测试;最终候选仍须绑定明确提交与同一批制品完成验收,不能仅凭任务已配置声称通过。纯说明性文档变更仍遵循前述工作流分层规则。

检查 本项目验收内容 时机
标准构建 隔离构建 sdist,再从 sdist 构建 wheel;不依赖缺失的 Git 工作区文件或仅本机存在的资料 相关主分支提交、发布前
元数据 名称、版本、Requires-Python、依赖、extras 和入口正确;发布时与 tag 及声明能力对应 相关主分支提交、发布前
README 内容类型正确,严格渲染检查通过;包描述中的链接与图片地址适合 PyPI 展示 相关主分支提交、发布前
wheel 内容 实际包模块、py.typed、许可和必要资源齐全;没有误带字节码、缓存、数据库、录制或规范镜像 相关主分支提交、发布前
核心依赖 无 extra 时直接运行依赖仅为 AnyIO,允许其声明的间接依赖;开发工具和可选组件没有混入 相关主分支提交、发布前
extras 与依赖一致性 核心包、每个已实现 extra 和重点组合独立安装;执行 pip check 和实际调用,保留最终依赖清单 相关主分支提交、发布前;最新依赖另定期检查
安装后行为 从仓库外使用目标 wheel,执行核心契约、公共 API 示例和适用的 CLI 入口;不依赖 editable 安装或源码路径 相关主分支提交、发布前
第三方类型检查 在安装后的包上检查公共调用示例,确认 py.typed 和公开类型信息实际可用 相关主分支提交、发布前
包体积与许可 大小在项目门槛和平台配额内;声明的许可文件实际存在,第三方资料保留适用许可 相关主分支提交、发布前
制品身份 提交、版本、文件清单和哈希对应;上传的是已验收文件,上传前不重新构建 发布前、上传时

nox -s package 已执行以下基础构建和元数据检查,并继续执行本节规定的内容、隔离安装、示例与类型门禁。单独运行下面三个命令仍不代表完整制品验收;具体提交和候选身份以生成的报告为准:

python -m build
python -m twine check --strict dist/*
check-wheel-contents dist/*.whl

build 默认先构建 sdist,再从中构建 wheel。dist/ 仅包含本次候选制品,不混入历史版本或后来生成的其他报告。sdist 和 wheel 均进入元数据与内容检查;sdist 解包后的独立构建用于发现漏文件和不必要的工作区依赖。

twine check --strict 主要检查长描述能否在 PyPI 渲染,并将警告视为失败;它不能证明所有链接可访问、包能正确安装或程序能运行。check-wheel-contents 补充字节码、重复文件和布局检查,必要资源、类型标记与许可清单仍需显式核对。

在每个只安装目标包及所选 extras 的隔离环境中运行 python -m pip check。pip check 检查已安装依赖是否满足声明,不能发现所有漏声明的导入依赖;实际功能与缺少 extras 的行为测试继续执行。检查工具不要通过自身依赖给目标环境补齐缺失的运行依赖。

仓库 README 中的 docs/... 相对链接适合源码浏览,发布包描述须采用文档站或仓库的绝对链接,或在构建时转换并检查最终描述。站点和仓库地址确定后再配置,不写入猜测的地址;如生成发布用 README,确认 sdist 也包含独立构建所需输入。PyPI README 指南

制品验收与发布顺序

CD 的主要交付对象是 Python 包、版本说明和文档。可选 HTTP 服务仍作为库的安装能力交付;本方案不自动增加生产服务部署或容器分发承诺。

  1. 准备发布提交:核对版本、变更说明、支持矩阵、协议基线、兼容性及已知限制。从 main 历史中选择确切提交,以指向该提交的受保护 tag 或手动入口触发发布。
  2. 完整验证该提交:执行正式支持范围的验收。之前主分支或其他提交的成功结果不能替代本次发布验证;慢速检查的结果同样绑定确切提交和环境。
  3. 构建候选制品:使用 Hatchling 与 build 生成 sdist,再从 sdist 构建最终 wheel,确认源码包可在没有 Git 工作区辅助文件的环境中独立构建。构建隔离不等同于自动锁定构建依赖,需另行固定并记录构建工具环境。
  4. 验收实际制品:按上节发布包验收任务检查元数据、内容、依赖和说明文档,并在干净环境安装最终 wheel 执行核心契约、CLI、公共示例和支持矩阵中约定的制品测试。
  5. 发布同一批制品:确认源码包和 wheel 的哈希,把已验收文件交给发布任务,不在上传前重新构建。必要时先执行下节的 TestPyPI 演练,通过后使用 PyPI Trusted Publishing 发布并生成发布证明。
  6. 发布后验证:从 PyPI 安装该确切版本,检查基本调用、CLI 入口及元数据;发布与该版本对应的文档和变更说明。发现严重问题时按撤回版本和补丁发布流程处理,不尝试覆盖已有制品。

wheel 只包含运行和分发所需内容,不夹带规范镜像、临时数据库、录制或凭据。sdist 的文件选择应同时满足独立构建和许可证要求;如包含测试样例或第三方资料,保留相应来源与许可。

PyPA build 提供标准构建入口。PyPI Trusted Publishing 使用 OIDC 短期身份,避免维护长期发布令牌;发布证明用于关联发布身份和制品,不能代替功能验收。

TestPyPI 演练与发布后检查

首次接入、修改构建或发布流程时,使用 TestPyPI 验证上传、页面展示、下载和安装过程;不要求每次主分支推送都上传。TestPyPI 与正式 PyPI 的账户、项目、权限及包数据相互独立,发布身份分别配置;自动发布可使用 Trusted Publisher,显式手动发布也可使用对应站点的 API token。TestPyPI 成功不能证明正式 PyPI 上的名称、权限和配额已经满足要求。TestPyPI 说明、官方 CI/CD 发布指南

手动上传复用成功主分支 CI 的 quality-and-package 制品,并将该 run ID 传给 platforms.yml 的 candidate_run_id,在 CPython 3.11、3.14 上验收同一批文件。 核对报告中的提交与两个分发文件的 SHA-256 后,以 TWINE_USERNAME=__token__ 和 TWINE_PASSWORD 环境变量注入 TestPyPI token,运行 python -m twine upload --repository testpypi --non-interactive <已验收的wheel> <已验收的sdist>。 token 保存在仓库外,不写入命令参数、日志、Issue 或仓库配置;上传前不重新构建文件。 平台接收结果和安装验证保存在对应发布 Issue,普通 main 推送仍只运行 CI。

演练使用明确版本和候选文件,下载后核对哈希,避免安装到了正式 PyPI 上的同名旧包。依赖不一定存在于 TestPyPI:可先从正式 PyPI 安装明确解析的运行依赖,再从 TestPyPI 以 --no-deps 安装确切候选版本,随后运行 pip check 和基本功能检查。记录制品和依赖的实际来源,不把两个索引混合解析的偶然成功当成包验收。

如果演练后改变代码、元数据或版本,应重新构建并重新验收;最终上传正式 PyPI 的文件仍须与通过验收的候选文件一致。正式发布后从 PyPI 安装确切版本,核对版本与下载文件哈希,执行核心导入、离线调用和适用 CLI 入口检查,并确认公开说明与链接。演练或发布后检查失败时保留报告,修复流程或发布新的修复版本。

工作流与依赖安全

  • 普通主分支 CI 使用最小权限;发布身份仅提供给受信任的发布任务。不让带发布权限的任务执行不可信代码或接收来源不明的制品;如后续按需接收外部 PR,同样保持这种权限隔离。
  • 第三方 Actions 固定到完整提交 SHA,并受审查地更新;构建和上传分离,制品传递校验提交、运行标识及哈希。
  • 通过 actionlint 和 zizmor 检查工作流,按 GitHub 安全建议 管理权限、输入和不可信代码。
  • 使用 pip-audit 检查核心与 extras 的实际解析环境。它检查已知依赖漏洞,不能替代代码审查,也不能证明没有未知漏洞。
  • 已确认影响所用功能的漏洞应修复;确需临时例外时记录适用范围、理由及复查期限。审计结果与发布依赖清单关联。

具体仓库保护、发布环境及 PyPI Trusted Publisher 配置在接入平台时实施并验证。文档中的步骤不是已经生效的账户或工作流配置。

性能与长期稳定性

从离线模块阶段开始保存可重复基准,覆盖全量加载、增量更新、快照构建、峰值内存、简要与详细验证吞吐、持久化、恢复及 SQLite 共享传播延迟。数据集注明来源、规模、地址族和分布;环境记录硬件、操作系统、解释器及依赖版本。

真实输入、三来源工作负载、受限/参考环境与预算初值以规模与资源基线为准;同时加入运行中来源增删和配置替换的提交、退休任务及全局暂存峰值。上游资源建议只用于选取测量档位,不能当成本项目通过指标。

基准分开记录查询成本、更新成本和对宿主的影响,至少包括以下工作负载:

工作负载 要检查的放大或退化
递增规模下的简要 ROV 与 ASPA 单条/批量查询 前缀覆盖和 customer 查找的增长趋势;解释构造另计,不能默认每次扫描全部 VRP/customers
百万级固定表上的小增量、相同载荷仅刷新期限 候选索引重建、来源支持复制、全状态摘要与落盘的 CPU/分配/写入成本;按整次事务测量,识别逐条复制全表
逐条支持具有大量不同到期时刻,多来源高度重合 到期调度、重复合并和事件生成的次数;不能靠拖延有效期或漏掉受影响范围降低成本
多来源同时全量同步,同时保留允许数量的旧快照 原始输入、解析对象、候选索引、事件及持久化 pending 的共同 RSS 峰值;测试超限后的旧状态与清理
同步期间并发解析、构建、批量验证、导出和数据库提交 asyncio/Trio 的事件循环调度延迟,查询尾延迟,取消到任务退出和实际资源释放的时间;报告 p50/p95/p99 和最大值

查询应使用适合覆盖前缀与 customer 的索引;这不固定第三方 trie 或具体内存布局。全表扫描可用于独立正确性模型,不能未经规模基准就成为在线查询的默认实现。受管理线程主要隔离阻塞工作,不自动证明 CPU 工作可并行或事件循环响应达标;同步纯函数与 Client/服务调度分别验收。不可中断的后端调用须如实报告清理延迟,不能把结束等待误报为工作线程已退出。

先记录趋势,在稳定环境和真实规模数据上形成基线后,再确定回退门槛与资源默认值。共享 CI 运行器的单次耗时波动不直接作为严格性能结论;涉及性能的变更使用可比环境复测。基准过程同时核对结果正确性,避免把遗漏工作误当成加速。

定期长时间运行检查反复同步、重连、订阅建立与取消、慢消费者、后端故障及恢复,关注内存、任务、线程、连接和句柄是否持续增长。所有任务设置运行预算和清理流程,失败保留定位材料。

分阶段落地

阶段 CI/CD 交付 可验收结果
工程初始化 pyproject.toml、开发环境、Nox、Ruff、mypy、CPython 3.11–3.14 会话、最小工作流、构建和 API 文档生成检查 本地与 CI 可执行相同检查;缺少解释器明确失败,最小包在目标版本可构建与独立安装,文档生成及失败诊断可验证
离线模型与验证 JSON 生产者样例、ROV/ASPA 向量、独立模型、属性测试、公共类型、API 文档与示例及 CLI 离线检查 核心安装隔离通过,公开接口文档完整,规范与设计条款可追踪
RTR 与多源 双后端网络、测试时钟、故障注入、状态机、事件及固定录制 原子发布、来源隔离、时效及订阅恢复有边界证据
持久化与共享 SQLite、DuckDB 公共契约、进程中断、恢复和多进程测试 两后端及各自运行限制通过验收,内存与持久化版本可区分
服务与首版发布 远程一致性、录制回放、Linux x86_64 矩阵及其他平台命令、性能基线、互操作和发布演练 首版范围完成验收;发布材料列明实际通过项与互操作缺口
扩展与 1.0 准备 SLURM、Router Key 公共 API、SSH 对应测试,兼容与弃用策略 扩展能力按设计交付,公开接口承诺与迁移资料明确

初始化时先确定具体平台与 Python 列表、开发工具版本、依赖锁定方式、Nox 会话、必需状态检查和报告保留策略。各里程碑再补充生产者版本、互操作实现、故障点与基准数据;尚未测量的性能阈值保持待定。

落地后持续更新本文中的状态说明,使建议、已启用检查和正式支持范围清楚对应。README.md 保持用户入口,详细产品语义留在设计文档,开发命令与必读入口留在 AGENTS.md,避免多处复制完整方案。

同一批候选制品的原生矩阵验收

主分支 CI 的 package 步骤使用 --require-clean,仅从干净、已提交的来源验收完整十种安装组合。platforms.yml 现为 Linux x64 candidate acceptance,只支持手动触发,在 Linux x86_64 上使用 Python 3.11、3.14,不配置其他 OS/架构或每周全平台运行。

gh workflow run platforms.yml --repo bgpglobal/rpkiparrot --ref main -f candidate_run_id=CI_RUN_ID

candidate_run_id 指向本仓库 main 上已成功完成的 CI 运行。解析任务检查工作流、提交身份和未过期的 quality-and-package 制品,固定其 artifact ID;每个解释器任务检出该运行的确切提交,不跟随继续变化的 main。

提供 candidate_run_id 时,源码行为测试复用该确切提交的原 CI 的 3.11、3.14 结果,候选工作流不重复执行同一套源码测试。这两个真实解释器分别执行同批制品的完整十种隔离安装、公共示例与类型检查;交付证据同时引用原 CI 的源码结果和本次制品结果,不把复用写成新执行。

每个矩阵单元下载相同 artifact ID,先用 scripts/candidate_artifacts.py verify 核对原始报告的提交、干净状态、完整十种安装组合以及 sdist/wheel SHA-256,再以 package_validation.py --reuse --require-clean --dist .local-data/candidate-ci/dist 安装验收。复用模式另在临时目录从原 sdist 独立重建并比较 wheel 内容;临时重建文件不替代候选。每格 reports/candidate-artifacts.json 保留原 CI run ID、artifact ID、提交和两项哈希,安装报告记录本机实际结果。最终交付文件仍取自该原始 CI 制品,不重新构建。

不提供 candidate_run_id 的手动运行仍在 Linux x86_64 的 Python 3.11、3.14 环境执行完整源码测试并分别构建开发制品,其结果不能称为同一批发布候选验收。跨运行下载使用只读 Actions 权限和固定版本的 download-artifact,不增加上传包仓库或发布权限。

在其他原生平台复验相同候选

先在原生机器执行兼容契约中的本机检查。需要验证相同发布候选时,在该机器克隆仓库,检出候选的完整提交 SHA,保持工作区干净。从成功 CI 运行下载 quality-and-package(包含 dist/ 与原始 reports/),不要覆盖或重新构建其中的文件。以下是 macOS/Linux shell 命令,填写实际运行 ID、制品 ID 和提交;GitHub CLI 须已登录且可读取私有仓库。

(
set -eu
candidate_run_id=CI_RUN_ID
candidate_artifact_id=ARTIFACT_ID
candidate_commit=FULL_COMMIT_SHA
: "${target_os:?Select the native OS from the compatibility commands}"
: "${target_arch:?Select the native architecture from the compatibility commands}"
# 在干净的专用验收 checkout 执行,检出确切候选。
git checkout --detach "$candidate_commit"
gh run download "$candidate_run_id" --repo bgpglobal/rpkiparrot --name quality-and-package --dir .local-data/candidate-ci
uv python install 3.11 3.12 3.13 3.14
for python_version in 3.11 3.12 3.13 3.14; do
    uv run --locked --python "$python_version" python scripts/environment.py --expect-os "$target_os" --expect-arch "$target_arch" --output "reports/candidate-host-$python_version.json"
    uv run --locked --python "$python_version" python scripts/candidate_artifacts.py verify .local-data/candidate-ci --commit "$candidate_commit" --run-id "$candidate_run_id" --artifact-id "$candidate_artifact_id" --output "reports/candidate-$python_version.json"
    uv run --locked --python "$python_version" python scripts/package_validation.py --reuse --require-clean --dist .local-data/candidate-ci/dist
    cp reports/package/artifacts.json "reports/package-$python_version.json"
done
)

Windows 11 x64 在 PowerShell 中使用对应命令:

$candidateRunId = 'CI_RUN_ID'
$candidateArtifactId = 'ARTIFACT_ID'
$candidateCommit = 'FULL_COMMIT_SHA'
git checkout --detach $candidateCommit
if ($LASTEXITCODE -ne 0) { throw 'Candidate checkout failed' }
gh run download $candidateRunId --repo bgpglobal/rpkiparrot --name quality-and-package --dir .local-data/candidate-ci
if ($LASTEXITCODE -ne 0) { throw 'Candidate download failed' }
uv python install 3.11 3.12 3.13 3.14
if ($LASTEXITCODE -ne 0) { throw 'Required interpreter installation failed' }
foreach ($pythonVersion in @('3.11', '3.12', '3.13', '3.14')) {
    uv run --locked --python $pythonVersion python scripts/environment.py --expect-os Windows11 --expect-arch x86_64 --output "reports/candidate-host-$pythonVersion.json"
    if ($LASTEXITCODE -ne 0) { throw 'Required native platform check failed' }
    uv run --locked --python $pythonVersion python scripts/candidate_artifacts.py verify .local-data/candidate-ci --commit $candidateCommit --run-id $candidateRunId --artifact-id $candidateArtifactId --output "reports/candidate-$pythonVersion.json"
    if ($LASTEXITCODE -ne 0) { throw 'Candidate identity verification failed' }
    uv run --locked --python $pythonVersion python scripts/package_validation.py --reuse --require-clean --dist .local-data/candidate-ci/dist
    if ($LASTEXITCODE -ne 0) { throw 'Candidate acceptance failed' }
    Copy-Item reports/package/artifacts.json "reports/package-$pythonVersion.json" -ErrorAction Stop
}

实际 CI 的 run ID 与 artifact ID 可从 Actions 页面或 gh api repos/bgpglobal/rpkiparrot/actions/runs/CI_RUN_ID/artifacts 获取。当前工作流不替用户执行这些非 Linux x86_64 命令;未运行的目标保留为未验证,历史其他提交的记录不替代当前候选证据。