发布与打包机制的独立复核¶
日期:2026-10-18。范围是发布机制与当前本地资产的只读检查;没有执行发布、Nginx reload、浏览器访问或重跑正文实验。不修改作者/交叉正文指纹,本报告不作为最终线上验收收据。
读取范围¶
完整读取 scripts/prepare_course.py、assemble_course.py、review_artifacts.py、verify_review_fingerprints.py、browser_check.py、deployment/pi.baoer.me.conf。为确认依赖与相邻责任,另读 course_config.py、mkdocs.yml、mkdocs_hooks.py、review_sources.py、verify_download_packages.py。这些读取只说明下述具体机制核对,不扩张为所有发布脚本审计。
当前确认的机制¶
固定版本与压缩包¶
course_config.py固定 source=pi-1.3.0、commit=71023aec1546d6d677a65669c5665c0927ce0dd0、edition=20261018-pi130,research 来源仅为本次research/v1.3.0。- prepare 从实际 examples 输入构建实验 ZIP;
Path.rglob('*')包含.gitignore,当前该文件已纳入。package-lock 包含在 ZIP,但不整篇复制进实验源码附录,二者职责不同。 - assemble 的显式章节顺序包含 21/22 和全部当前正文;Markdown ZIP 包含分章、完整单页、研究附件、源码阅读器、内嵌实验 ZIP,以及重建所需 mkdocs.yml、requirements.lock、mkdocs hook。它排除对自身 ZIP 的递归打包。
- delivery-final.json 被 prepare 明确跳过:最终公网收据需在 ZIP 固定之后单独生成,不把最终 ZIP 哈希回填进同一 ZIP 导致循环。
- review_artifacts 对实验 ZIP 文件集合及每项字节做比较,对 site 源码阅读器提取 code 行逐行比较,并检查 raw Markdown 下载与合并正文一致。它不单独完成整个 Markdown ZIP 内容完整性验收;后者还依赖 assemble 后的临时解压 strict build、下载重建及公开资产比对。
只读检查时,实验 ZIP 33 项、0 重名,与当前打包/审查文件集合一致,全部字节相同,包含 .gitignore。Markdown ZIP 当时 336 项、0 重名,含 21/22 与重建配置,证据目录只有 v1.3.0;没有 node_modules、.agent、.sessions、.checkpoints、.env 或旧版 v1.0.1 目录。80 个源码阅读器与选定列表恰好匹配,没有多余旧阅读器。
该时点 Markdown ZIP 仅 docs/labs/15-production.md 落后于刚修正的取消图,已告知 root 在最终冻结后重新 assemble。这是正在生成中的资产状态,不将其当作最终已发布结果。最终完整源码报告的附件尚在归档中,也不按内容缺陷判定。
至少三份独立审查¶
verify_review_fingerprints.py 重新枚举全部 primary Markdown 与 examples,比较当前 SHA256,不仅检查报告文件存在。core/product/labs/source 四个 reviewer 槽位逐个计数;同一个 reviewer 不会因为列两次文件获得两个票。
作者排除表覆盖 core 的六章、product 的六章、labs 的三章。labs 自己的 examples 不计独立,只有由 root 编写的 env/chord 两个 fixture 被明确豁免作者排除。作者范围出现在自己的独立清单会产生错误,不会静默算作一票。任一文件少于三名独立 reviewer 会失败;source 全文审还必须覆盖全部当前输入。提供 canonicalFilesSha256 时也会重新核对。
只读模拟当前枚举得到 56 个主输入,现有作者交叉清单没有作者范围误计。第四完整清单当时尚未归档,所以最低计数仍为 2;这是预期未完结状态,正式发布应等该清单与受影响文件复验归档,再通过实际 gate。机制验证不了人是否真的独立读过源代码,也不解析自然语言 PASS 的真实性;独立分工、报告内容及最终结论仍由审查过程负责。
Nginx 归档与隐藏路径¶
HTTP 将常规请求重定向 HTTPS,ACME challenge 是明确例外。HTTPS 的 /archive/v1.0.1/ 使用单独 alias 指向 /var/www/pi-course-archive/1.0.1/,不受当前站点 rsync 删除目录影响;无尾斜线入口有重定向。
归档 location 没有 ^~,因此 location ~ /\. 的隐藏路径拒绝仍能覆盖归档下 .git 等路径。/archive/v1.0.1/ 的版本点号位于 v1 后,既不是 slash-dot,也不是隐藏路径。/assets/...zip|md 使用 no-store,归档资产不被根 /assets/ 正则误路由。本次只核对配置文本,不证明线上已加载该配置或证书仍有效。
浏览器路由与交付证据¶
browser_check 从实际 site/index.html 派生路由,使用 .as_posix().strip('/'),不会把 v1.3.0 的点号当扩展名删除。只读列出的路由确实含 /appendix/v1.3.0/product-review-final/ 等路径,没有 v1/3/0 式误拆。expected_diagrams 同样按 route 字符串定位原始 Markdown。
机制逐页检查 HTTP 状态、diagram-ready、Mermaid 数量与 SVG 数量、错误图、最小文字大小和横向溢出;另测搜索、移动导航、深色图、源码行跳转和浏览器下载实际字节。COURSE_QA_SKIP_DOWNLOADS=1 会明确记录 downloadsSkipped,不能将这种运行称为下载验收。浏览器可执行文件路径固定在本机,换环境须配置/安装对应 Chromium;本报告不声称完成一次浏览器实跑。
已报机制问题与修法¶
- 排除规则不同步。 指纹 gate 排除
.dsh、*.pyc、*.record.json,初读的 prepare/review_artifacts 文件枚举却不排除这些项,可能出现打包文件无需三份审查的覆盖缺口。当前目录没有这样的额外输入,所以当前实验 ZIP 集合比对仍全过。建议提取一个共享输入过滤函数供打包、artifact 检查和审查 gate 使用。 - HEAD 不等于干净源码。 初读的 prepare 只 assert HEAD==COMMIT,随后读取工作树;review_artifacts 也对比同一工作树。固定 checkout 若有未提交修改,两者可能一致通过却不是 commit 原文。当前
git -C pi-1.3.0 status --porcelain为空,当前没有此偏差。建议 prepare 拒绝 tracked 修改,或直接从 Git blob 生成原文。 - 生成目录不会自动清旧条目。 prepare 覆写本次选中的阅读器与证据,没有清理失去来源的旧文件;assemble 又会遍历全部 assets。当前独立核对 selected/actual 差集为空,证据仅 v1.3.0,因此没有发现当前混版。以后换版或删除某份生成附件时,需显式清理或增加多余文件集合检查。
上述问题已交 root 修正;以下为修正后独立复验。没有在本轮执行额外 npm 安装、全文测试或线上发布。
修正后复验与限定结论¶
- 打包、artifact 比较和指纹 gate 现在均调用
course_config.example_inputs(),共享 runtime 目录、.pyc和.record.json排除规则。重新只读枚举仍为33个examples、56个主输入;原正文/实验SHA清单没有因机制修正改变。 - prepare 在任何正文生成前拒绝 tracked dirty checkout,并拒绝SELECTED中未被固定release追踪的reader。review_artifacts 直接以
git show <固定COMMIT>:<path>获取比较对象,不再以同一工作树自证正确。 - prepare 删除不在SELECTED中的旧reader HTML,并从原始证据重建当前edition的两份生成目录,避免已移除的本轮报告残留。其他edition目录仍需要换版时显式迁移/清理;当前已核对没有旧版目录,不将这一维护限制当作当前混版。
- 对修正后的6个Python文件执行只读
compile语法检查,通过;独立从Git固定对象读取80个原文,与当前site阅读器逐行比较,0不匹配。没有运行prepare去改变正文,也没有运行浏览器或发布命令。
限定结论:上述机制问题已修复并复验,当前可继续最终生成与交付验收。 这不是最终发布PASS:第15章修正后仍须统一重打包、第四报告归档、通过三独立审查gate、严格构建/下载重建与实际线上/browser检查。历史归档服务及最终公网字节也需最终交付收据证明。
本次复验对应的机制文件SHA256如下;仅绑定本报告机制输入,不修改正文独立清单:
| 文件 | SHA256 |
|---|---|
scripts/prepare_course.py |
69c465428d7426c40f8ae78306954793814a9d3fe5035c2f1cb7faf4ccba8b74 |
scripts/assemble_course.py |
73fd9b718a2f46c3d7cf8825e1da12bce2cee7722a67ec4ac346106d96c7e5c5 |
scripts/review_artifacts.py |
48521155da62110651c8a5457b7770a8331a9a8e3b09f78ff070da486bfe9f6c |
scripts/verify_review_fingerprints.py |
e9da5591c38e12a0ac127b2ff9552edb04c704ffc331740784b0851f579f7e68 |
scripts/browser_check.py |
768b24ed0f3bcf530644cc2d2fab0dd3c6617a67c194928b3bfead8a31be6ead |
scripts/course_config.py |
acbbf10ea5b7c8213e7103f2f4f1f6833b1ee0292af7c73050d427459d4dd196 |
deployment/pi.baoer.me.conf |
cc72b49c261990a5e922d8352e768c572da28abf052780aae2cd87803f0b5edd |