35 KiB
部署门禁完整性设计草案
11. 归档截图保护与全仓回执增量(已批准)
- 先以独立副本和 SHA 保全四张本次运行截图,再仅恢复这四个 worktree 文件;保留全部 14 个已跟踪历史证据及其原登记摘要,不改 index。
- 两个 spec 只变更 fs 导入及截图目录定义。QA_VISUAL_OUTPUT_DIR 是输出根;使用 spec 前缀和 mkdtemp 创建独立目录,未传变量时也只写新的 ignored output 子目录。受管发现/浏览器命令传本轮报告内 visual 根,不依赖外层调用者自觉,不改业务断言/认证。
- sourceSnapshot 保留限定目录 digest,另记录 repository 的完整 porcelain-v1-z、人类可读 status、全仓 tracked 文件内容/类型/模式(symlink 不跟随)、完整 stage entries/flags 及 indexDigest。删除、内容变化、同为 dirty=true 时的二次改写和 index-only 变化均可见。忽略运行产物不是为已跟踪 output 路径豁免。
- sourceUnchanged 与 repositoryUnchanged、cleanAtStart/cleanAtEnd 分列;诊断前后及失败收尾均采样。环境有效与候选被改写不混淆;普通模式遇候选改写非零,诊断固定 PARTIAL/2。尚未启用的 R1 以后必须消费干净状态,不能用 unchanged 代替 clean。
- 治理校验显式登记归档 evidence.md 的截图表/根目录/14 条预期数量;解析表格并验证普通文件及摘要,表格丢失、缺行、重复、缺文件、路径逃逸、symlink 或摘要变化均 error。恢复演练文档记录的是历史私有候选值,不具备仓库路径到摘要的可复核表;本轮不取私有数据、不冒充 17 项全验。
- 针对性测试覆盖路径默认/覆盖/重复加载隔离,已跟踪 PNG 改写、既有 dirty 再改、index-only 变化,以及证据篡改/缺失/表格缩水。只运行这些验证和 typecheck/治理,不重跑 67 分钟诊断。
最新授权(2026-09-07):用户批准 §10 实施及一次诊断,bootstrapObservation 改为外部黑盒观测(表单可见、零 refresh、独立原生在线采样),不修改 AuthContext、不安装 spec route mock。旧 207 清单的决策资格撤销,原件保留;环境失败不能按业务断言失败继续。R1、阶段 B、31+2 迁移不自动启动。
1. 复用范围与状态含义
本文入口强制消费为获批生效后的目标,不是当前已启用事实。阶段 0 先运行原始 full-local 摸清红项;结果交用户决定强制点生效时机。机制交付、R1 启用、冻结候选重新生成回执、首次真实部署是不同步骤;后三者不属于本 task 自动完成动作。启用须全套验证已绿且明确获批,不设计可日常置位的 disable/skip 总开关。具体切换补丁边界在基线审阅后确定,当前不修改任何真实入口。
复用 run-release-gate.sh 中已经存在的 static → full-local → deploy 顺序,不照抄成另一套规则。把发布前两阶段整理为同一条可单独调用、绝不部署的验证路径,供 ci-release 与真实 bootstrap 路径共用。
| 入口/profile | 证明范围 | 可直接作为普通发布资格 |
|---|---|---|
| release-predeploy | 原 ci-release static + full-local 均真实完成,且受管结果完整、来源一致 | 是,仅发布前资格,不代表已部署 |
| local-candidate full | 保留完整基础层、witness/acceptance 判定及 LOCAL_CANDIDATE_PASS | 否,不能冒充 release-predeploy |
| local-candidate focused | 保留 FOCUSED_BROWSER_PASS,不含 full 基础层 | 否 |
| local-candidate list | 仅枚举 LIST_ONLY | 否 |
| 直接 Playwright 的筛选执行 | 仅所选用例的诊断结果 | 否 |
| project-wide 获批跳过 | 明确 PARTIAL、未覆盖阶段与批准引用 | 否 |
当前 full-local 的 Playwright 会发现配置下的全部非 manual 测试;同一次报告可供受管集合验证使用,避免重复执行完整浏览器。不能把对子集的验证称为 run-local-candidate full 已执行,也不能只抽取通过的结果后忽略全套的失败退出码。
2. 入口收敛,避免递归
拟新增 run-release-gate.sh verify-candidate 作为验证专用模式,内部复用原 stage_static / stage_full_local;此名称是新子命令,不是新门禁实现。
ci-release / all
-> 同一发布前验证阶段
-> 获得并校验 release-predeploy 回执
-> 既有 production-identity-bootstrap
-> deploy-existing -> deploy.sh
production-identity-bootstrap / deploy-existing 直接调用
-> 无回执时只调用 verify-candidate,不反调 ci-release
-> 同一回执验证
-> 保留既有身份、来源、迁移、回滚窗口及部署前后置检查
-> deploy.sh
run-release-gate deploy / 底层 deploy.sh 直接调用
-> 必须消费同一验证器确认的回执
-> 无效则在发布写入前拒绝,不以内部调用标记免检
- ci-release/all 的发布分支使用保留生产前置的入口,不回退成绕过 deploy-existing 的裸部署;直接底层调用至少不能绕过新增的候选验证。
- 高层成功验证后传递的是回执引用,不是
GATE_PASSED=1等可直接置位的信任标记。下层仍验证来源、profile、覆盖、结果和适用输入,不重复跑整套测试。 PRODUCTION_READ_ONLY_PREFLIGHT=1仍只做原有只读检查并明确退出,不生成 release-predeploy 回执,也不赋予后续写入资格;不能被当作“跳过测试但继续发布”。- 普通发布指向 existing 部署;initialize 的独立批准和数据模式约束保持。即使直接调用底层初始化路径,也不能通过缺少回执逃掉候选检查。本 task 不运行 initialize。
- 门禁不合格时允许必要的只读诊断,但远端 rsync、build/up、init/migrate/seed 等写动作必须为 0。既有
--no-deps、健康等待及禁止自愈不变。
3. 最小共享回执模块
拟增加一个共享候选回执模块及其单测,供发布 runner、local-candidate runner 和底层发布入口使用;不增加数据库表、密钥、外部服务或第三套执行器。
| 字段组 | 内容与约束 |
|---|---|
| 身份 | schemaVersion、runId、profile、候选完整 commit/tree、工作树前后状态 |
| 校验输入 | 门禁策略、manifest、Playwright 配置、相关锁文件摘要和实际 Node/Playwright 版本;绑定当前候选重新核验 |
| 时间 | startedAt、finishedAt 与各阶段实际观测时间;未结束必须是 INCOMPLETE,不能补造成功时间 |
| 选择 | 实际命令类别及安全参数:模式、grep、grep-invert、project、shard、only/手工模式、retries 等;不保存含凭据的原始命令行 |
| 清单 | expectedSpecs/observedSpecs,以及带项目身份的 expectedTestIds/observedTestIds;仓库相对路径规范化、去重并拒绝越界来源 |
| 结果 | 每阶段退出码、每用例预期/实际状态及 attempts;成功、失败、skip、错误和缺失分别表示,不仅保存汇总数 |
| 例外 | 受影响阶段、非空理由、操作人别名、明确批准引用、真实可知的批准时间与观测时间;未知批准时间留空,不用当前时间补造 |
| 资格 | PASS/FAIL/PARTIAL/LIST_ONLY/INCOMPLETE、deploymentEligible 与稳定拒绝原因;必须由验证器重新推导,不能直接信任布尔字段 |
清单采集遵循以下顺序:
- 冻结候选来源与所用工具链;开发脏树允许产出诊断记录,但 deploymentEligible 永远为 false。
- 在同一候选、同一配置与规范执行参数下枚举预期清单;枚举不是行为通过。标准发布无 grep/shard/only 等缩减范围,禁止 focused-only 声明。
- 实际执行 static/full-local;接收真实 Playwright 结构化结果,记录实际 spec 与用例,并检查报告完整性、全套命令退出码和 runner 错误。
- 受管 witness 与 acceptance 必须完整发现、实际执行并通过;集合必须从当前候选定义生成,不从待验证回执自报的 expected 字段取信任根。同一 spec 中遗漏合同用例也必须被拦。
- 继续复用既有 witness 的来源绑定、重复/未知标签等判定。full-local 全套报告不能只剩绿色子集;全套命令失败仍失败。受管子集零 failed/skipped,其他测试的状态仍完整记录,不通过删结果让报告变绿。
- 标准发布明确禁用重试至绿,使用零重试和 forbid-only;required 测试不能靠 expected-failure 获得通过资格。历史诊断若有多次 attempts,如实保留,不能改写为一次成功。
- 结束后和写入前重新验证 commit/tree、干净工作树与校验输入;不匹配、缺少结束标志或回执损坏均拒绝。
local-candidate 原验证器对其选定集合的严格行为保持;共享解析或复用辅助函数不能把它改为接受失败/跳过。本轮不削减 acceptanceSpecs、不删除旧门禁,只恢复错误用例和增补证明链。
4. 持久化和故障处理
- 每次运行有独立目录,先写 INCOMPLETE,再原子完成脱敏汇总;成功与失败都留存,写回执失败本身不具备发布资格。
- 持久汇总放既有 ignored artifacts 体系;它是本地运行证明,不提交到产品版本。发布日志记录 runId、候选短 SHA、profile、结果及相对证据引用。
- cleanup 可以回收本次独占服务和临时文件,但不能删掉唯一结果。SIGINT/阶段错误/进程被强制终止时,有效结果只能是失败或缺失/未结束,不会被默认补成 PASS。
- 多次执行、失败后再跑和其他 profile 的记录各自保留,不覆盖、拼接或给旧结果重新命名。相同候选的有效回执可由同一发布链引用,不以时间戳或“上次绿”替代内容匹配。
- 不记录完整本地路径、生产连接、原始业务响应或敏感环境;测试结果中的路径归一化,用例标识不嵌入真实人员/合同内容。
- 这是防止意外复用、范围误读和无记录绕行的本地审计合同,不是防伪完整性保证。执行端本身有写文件能力,一份内部自洽的手写回执仍可能通过;独立推导集合及重验来源不能消除这一威胁。本轮不引入签名服务或秘密,也不把可审计说成不可绕过。
- 保存足够的候选、工具链、环境前提、完整命令及逐项集合,使第三方可重跑复现。首次真实部署前由用户或独立方重跑并与回执逐项比对;原主会话的重复自检不抵扣。重跑差异如实阻断,不拼接两个报告成为 PASS。
5. project-wide skip 的拟定边界
仅处理现有两个开关,不顺带审计和重写所有业务 flag:
- PROJECT_WIDE_SKIP_BUSINESS_FLOW
- PROJECT_WIDE_SKIP_VISUAL
开关值须精确合法;缺理由、受影响阶段或批准引用时,在跳过任何阶段前失败。获批诊断必须落地包含上述信息的 PARTIAL 回执,列出未运行 spec/阶段,并以非零结束,不经过原来的完整 PASS 输出。
普通发布 profile 不接受这两个开关或诊断回执;也不新增一个更高层的万能 skip。批准引用的结构验证只证明记录齐全,不能自动证明用户真的授权;执行端仍须引用真实批准,不补造批准时间。该边界已获用户批准,阶段 0 不实施代码。
6. 合同用例恢复
- 原用例继续留在 payment-reviewer-permissions.spec.ts,维持 manifest 归属;不改名移动来绕开失败记录。
- 扩充本地合成 API fixture 到当前详情 DTO,按实际“查看详情”导航,证明目标详情和生效状态加载后再断言不可新增/编辑/续约/归档。
- 管理权限对照使用同一合成生效合同,证明相应动作确实存在,不用终止或归档状态天然隐藏动作来伪造只读权限通过;只在合成测试中操作。
- 若当前页面真实暴露不应有的动作,保留原始失败、报告最小影响范围并停止该修复分支,等待权限范围批准;不顺带改权限、不降断言、不重试至绿。等待期间 R1 强制点保持未获启用授权,机制 diff 仍可独立评审;完整候选资格不成立,不自动授权发布。获批修复后须重跑全套验证,不能用定向绿清掉启用前提。恢复该 UI 回归不等于生产真实身份权限验收。
7. 兼容性、回滚与成本
- 直接 deploy、底层脚本和无记录 skip 将新增失败情形,这是本任务预期的兼容性收紧。提供明确错误、验证专用入口和缺失证据说明,而不是自动放宽。
- 保留 existing 数据生命周期及全套生产前后置合同;首次真实使用新工具仍需单独批准和人工观察,不自动发版验证。
- 其他全套测试失败会真正阻断发布。本轮不得缩减范围以便发布,也不能把修改后的机制先绕过一次再称已上线。
- 回滚应用版本不等于回滚部署工具。没有新的明确批准,不使用旧裸部署命令、删除回执验证或调低判定自救。
- 本轮不优化完整测试耗时;优先复用原 ci-release 阶段与一次 full-local 结构化报告。今后若要合并其他门禁或减少覆盖,必须另证等价并审批,不能在这次顺便做。
8. 阶段 0 补充方案:PWA 输入归属(已批准,验证见 implement)
8.1 已批准采用 (a),full-local 负责准备输入
- 选择 (a),不选“排除后由另一个入口兜底”。当前需要先让完整分母可测,不宜同时引入排除清单、第二执行义务及多份报告合并;这些额外关系会再制造本任务正在消除的漏跑风险。
- 复用现有 run-pwa-cross-version-upgrade.sh 的 A/B 构建逻辑,提取一个小型共享准备/清理 helper;专用 runner 与 full-local 都使用它,不复制两套构建规则,也不把专用 runner 的一张 PASS 冒充 full-local 已执行该用例。
- 使用本次源码生成两份临时生产构建与不同的 12 位合成构建标记,四项 PWA_BUILD_* 输入只在本次测试进程中传递;它们是测试版本标签,不是候选提交身份。真实候选 SHA 另行记录,不能混淆。
- 两份 outDir 与 client/dist 分离;不搬用历史产物,不用假路径、同一构建冒充 A/B,不写共享 env、用户 shell 配置或生产配置。已有专用入口继续可用,PWA spec 顶层缺输入仍明确失败,不改成 skip 或静默 fallback。
- 在 full-local 的发现阶段之前准备输入;先完整 --list 留下当前候选的发现集合,再沿用原服务端/前端/真实 DB 回归及全套浏览器执行顺序。列出集合只证明分母可枚举,绝不等于这些用例已经执行。
- 全套仍无 spec/grep/shard 筛选,不改 playwright.config 的忽略集合、不改 route-manifest 的 witness/acceptance 归属。传入 PWA 输入后,同一套全量执行结果必须实际包含 PWA 用例,不能将它拆出去然后漏算。
8.2 覆盖归属与运行代价
- 按当前候选的 testDir/testMatch 和 manual 目录边界独立推导所有非 manual spec;选择 (a) 时它们全部归 full-local,本轮排除集合为空。不能用当前 route-manifest 作为完整套件的全集,也不照搬 local-candidate 的文件名含 live 过滤来缩减 full-local。
- 对照全量发现结果核对文件归属,再保存用例集合;PWA 是“full-local 内需要额外输入”的成员,不是例外。未来要拆出其他专用 spec,必须先明确登记原因、必跑入口、责任归属及如何兑现结果,不能默默过滤。
- 用户已修正并批准:保留默认文件间并发,不加全局 --workers=1。PWA spec 内部已声明 serial,并使用独占随机 loopback 端口和本测试的 BrowserContext;构建只读,无证据要求与其他文件互斥,当前不新增 project。若实测出现隔离问题,先报告证据,不自行全局串行。
- --retries=0 作为 R2 独立要求显式传给发现/执行,覆盖 CI 默认一次重试,不随 PWA 方案改变而删除。成本为额外两次 Vite 生产构建,浏览器及服务端默认并发不变;不承诺固定增量分钟数。
- 输入准备失败或收集失败立即非零,保存具体错误、阶段和未运行范围;清理仅处理本轮自有构建/服务/数据库,不删除唯一结果。后续业务阶段若再 fail-fast,仍如实记录未到达浏览器,不能宣称完整红项已齐。
8.3 拟验证的最小行为
- 共享 helper 的隔离命令捕获:A/B 各构建一次、输入不同、输出目录独立、任一构建失败即非零、四项输入仅传给测试进程、清理不碰其他目录。fake 工具只放测试临时目录,不写共享 PATH。
- 全量发现必须包含 PWA,且与当前非 manual 文件归属相符;遗漏输入、误把 PWA 排除、只保留 manifest 子集都不能得到“分母完整”。不能只 grep 命令中出现 --list 或 PWA_BUILD_* 就认为已验证输入与归属。
- 原 PWA spec 内容与断言不变;A/B 不收敛或其他浏览器失败只留原始结果,不 reload、不清缓存、不重试至绿、不修 PWA 产品代码。
- 结构化输出区分发现集合与实际执行、failed/skipped/not-run,绑定当前源码及真实参数;这只是阶段 0 诊断资产,不提前实现或启用 R1 发布准入。
8.4 负金额原断言冲突与分层纠正依据
只读源码与现有规约确认:
- reimbursements.js:3931 起先检查每条明细;任何 amount <= 0 立即返回 400 VALID_001,details.items=positive_amount_required,并附受影响明细 ID。
- 通过以上检查后才到 :4021 的明细求和和 :4026 的总额非负守卫。对同一组稳定、有限、全为正的明细,不可能求出负总额。
- reimbursement-invoice-ocr.md:936 明确规定上述明细诊断;reimbursements.expense-standards.test.js:325 已有非正明细前置守卫单测,fixture 是零金额。上轮 1680 单测通过不能因此冒称“真实 DB 负金额总额守卫已经覆盖”。
- 原 regression-workflow-actions.sh:999 强制断言 details.total_amount=negative_not_allowed。仅改成负明细会在更早处被合法拒绝,不能同时保持该原诊断断言为绿;这不是产品漏拦,也不应为了测试绕过正明细检查、引入竞态或伪造聚合结果来冒充真实 DB 覆盖。
因此上一轮“改明细、不改断言”要求不能在这条稳定真实 DB 路径上同时满足,当时保留了原失败并报告。用户现已批准分层纠正:真实 DB 场景正式改名为 items_positive_amount_required,构造负明细并核验入库值/合计,仍要求 HTTP 400、VALID_001、无 workflow instance,精确诊断为现有规约规定的 items=positive_amount_required,并核对目标明细 ID;不是把 400 改为 200,也不是删诊断或放宽为任意 400。
总额函数沿用既有 __testables 入口直接单测,不修改函数逻辑、不伪造数据库聚合。负数和非有限值的两个拒绝分支由直接单测证明;在当前稳定正明细提交链上,负总额拒绝分支不可达,不再挂成待补同一路径 E2E。函数本身仍被正常调用,不能把“拒绝分支不可达”误写成整个函数没有执行。负金额场景之外复用表头 setter 的其他场景不顺手修改;后续新红项照原范围留痕。
8.5 审定与实施边界
用户已审定 PWA (a) 及修正、金额分层方案,当前执行范围不再重复索取批准。三项前置处理的目的只是让分母可测,不是全套变绿。合同用例、其他新红项、任何产品/权限修复、阶段 A 和 R1 强制点仍不在本轮动手范围,提交/push/部署也未获授权。
2026-09-06 最新批准覆盖本节此前待审状态:PWA 按 (a) 实施、零重试独立于 PWA、禁止默认全局串行;负金额不沿用旧场景名改诊断,而是改名为 items_positive_amount_required 的真实 DB 黑盒场景,验证负明细、精确诊断与 itemIds、无 workflow。另通过已有 __testables 导出原 ensureNonNegativeAmount,直接单测负数/非有限值/有效值,不改函数逻辑或提交路径。规约记录稳定正明细提交路径使总额负数分支不可达,纵深防御由函数单测证明,不长期挂成同一路径的欠验收项。其他新红项仍只留痕。
9. full-local 诊断分支增量设计(方向采纳,实施待审)
目标是让相互独立的测试阶段不因先前断言失败而全部失去执行机会,不是替换普通发布门禁,也不承诺一次获得每个有内部依赖的子用例结果。复用当前 run-web-gates.sh 的输入、集合、构建及本地环境 helper;拟新增显式模式 full-local-diagnostic,不复制第三套发布执行链。
9.1 两种入口的不可混淆合同
- full-local 保持原 fail-fast:任一阶段失败即非零,后续不运行。本轮不把普通入口自动切到诊断、不改部署调用链、不启用 R1。
- full-local-diagnostic 只用于获批本地合成环境;记录理由、操作者别名和明确批准引用,缺项拒绝,不自动补造。即使所有已执行测试为绿,聚合状态也固定 PARTIAL、退出 2,不生成发布 PASS 或发布回执。输入/运行错误及中断同样非零,保留具体阶段状态。
- 诊断报告类型、执行模式及实际命令与正式验收不同;未来候选验证器必须按真实 profile/阶段结果拒收诊断,不信任可置位的 qualified/GATE_PASSED 等布尔字段。R1 未实现前不宣称现有发布入口已经具备这项验证能力。
- 继续固定零重试、保留并发、不增加排除,不使用 grep/spec/shard 子集或 test.fail/only。完整发现继续先行;65/275 是当前快照,不硬编码成以后候选的预期集合。
9.2 继续的是测试阶段,不是失败的前置条件
- 服务端单测、类型检查、独立真实 DB 回归套件的断言失败可记 FAIL 后继续尝试其他具备前置条件的阶段。逐阶段记录命令、起止、耗时、退出码、结果及失败/未覆盖范围。
- PWA 输入、集合发现、数据库创建/迁移、必要构建、服务启动/readiness、隔离确认属于依赖前提;失败则只阻断其依赖分支并标 NOT_RUN/BLOCKED 及原因。不能在没有可用构建或数据库时盲跑并把环境错误计作产品失败。
- 各写库套件之间及浏览器前建立新的本轮独占临时库与服务,重用同一候选的构建与种子过程,不修改种子。不能仅凭失败套件的 cleanup exit 0 就认定数据已恢复;原库和新库都登记所有权、生命周期及清理结果,禁止接入生产或清理非本轮资源。
- 阶段命令在独立严格 shell 进程中执行,由外层捕获退出码,不全局 set +e、不把 shell 函数放入条件上下文导致内部 errexit 失效、不用 || true 吞掉失败。
- server regression-all 保持原内部 fail-fast,不传 --json-report:首次诊断证实该选项会在失败后复用同库继续,不满足本节的隔离硬约束。后续内层套件如实 NOT_RUN,只有外层独立新库分支继续;保留日志中的启用/跳过事实,不能因名称含 all 就声称全部模块运行。它内部再次包含 workflow-actions,重复执行须单独列为阶段来源,不冒充两个不同红项。首轮原始聚合回执保留,资产/IM 后续失败附同库污染风险,不倒写净库结论。
- 不改 workflow-actions 内部状态相关的 23 组来强行继续。第 8 组仍失败时,该套件第 9–23 组仍 NOT_RUN;诊断模式使后续独立套件和浏览器可以运行,不使所有服务端分母自动完整。Playwright serial 失败连带未执行的用例亦保留框架原始状态及依赖原因。
9.3 证据、成本与最小验收
- 诊断浏览器阶段显式 --trace=on,不能继承与 retries=0 组合后永不产物的 on-first-retry。共享浏览器 helper 只转发内部调用参数,普通 full-local 不新增 trace/worker/筛选参数;本次不改 client/playwright.config.ts。用真实命令捕获验证该参数到达 Playwright,删掉诊断调用处参数的隔离源码变异必须被捕获。trace 只留在本轮本地证据目录,不自动公开或提交。
- 保留候选 SHA、dirty/tree/diff 与包含新增文件的运行前后摘要、工具配置、完整发现、实际用例结果、阶段与清理状态。未到达浏览器或报告中断时,缺失用例保持未运行/未知,不能计为通过;本地诊断文件不提供防伪或签名保证。
- 用命令捕获 fixture 分别证明:普通模式失败后没有后续阶段调用;诊断模式遇测试失败仍到达具备前提的浏览器阶段;准备或清理失败不会假绿;独占库隔离;全部命令返回 0 时聚合仍 PARTIAL/2;缺批准记录拒绝;集合、并发及零重试不退化。移除真实的模式/退出保护须让相应反例变红。
- 实施获批后只运行一次隔离诊断,不修新红项、不重试至绿;交执行失败、未覆盖、环境阻断三类清单及逐阶段耗时,不能承诺必然取得全部子用例结果。
- R1 启用需要另外一轮普通 full-local 全绿的完整总耗时与逐阶段耗时;诊断增加隔离重建且容忍阶段间继续,其耗时不能冒充普通发布绿路径成本。红项清空、全绿实测与启用批准仍各自留痕。
本节拟改动仅为 run-web-gates.sh、必要的共享阶段/结果 helper、对应 QA 测试和现有部署规约;不改审批解析、规则/种子、场景 8/9、合同/R102/PWA 产品或用例断言、发布入口。方向采纳不替代本增量设计审阅,其他阶段 A 内容仍未开工。
2026-09-06 后续授权覆盖本节待审状态:用户已明确批准 §9,允许只实施诊断子项并立即进行首次诊断,不等待场景 8。阶段内部继续边界、独占新库、PARTIAL/2 和非发布资格均不变;其他阶段 A 和 R1 仍未获启用授权。经理解析只读盘点可作为既有盘点延伸,不能据“没有经理”直接推断实际选中规则必含经理节点或合法兜底一定不可用。
10. 环境启动合同(R2/R6,2026-09-07 已批准实施及一次诊断)
10.1 Scope / Trigger
环境是完整候选验收的组成部分,与来源和覆盖同级,不能交给仓库外包装临时决定。本节纳入 full-local 普通与诊断浏览器链的受管环境创建、测量、失败处理和回执消费;不开展 31 文件认证迁移、不修合同或其他业务红项、不启用 R1、不授权生产或全套重跑。
旧包装有本地留痕,具体见 diagnostic-run-20260906-01/run-isolated.sh:43 和 online-20260907-01 的对照证据;缺口是它没有作为受管环境合同被共同审查。207 撤销的是结果清单的决策资格,不是删除原件或宣称 207 条全部同根因。新清单及正常绿路径耗时仍未知。
10.2 Signatures / 受管入口与字段
- 由 run-web-gates.sh 的公共入口调用受管环境 helper,普通与 full-local-diagnostic 共用;子阶段只能在该 runner 建立并核验的上下文内工作。无临时 artifacts 执行依赖,无调用者可置位的 ENVIRONMENT_PASSED=1 放行合同。
- 首版建议明确限定现有本地 Linux 通道的 isolated-online-v1:runner 创建独占网络命名空间及内部 up 链路,服务/浏览器同处核验过的环境,无外连默认路由;本地独占库、socket、PWA 服务的归属及清理由 runner 管理。平台/能力不支持就报告 ENVIRONMENT_INVALID,不自动降级到宿主或开放外网。其他平台 profile 要另审,不能靠空字段冒充兼容。
- 回执增加 environment.schemaVersion、profile、policyDigest、runnerDigest、probeDigest、platform、namespace、nativeOnlineProbe、bootstrapObservation、status、cleanupStatus;摘要绑定当前候选及包含新增文件的策略输入,不由回执自报 expected 字段定义合格环境。
- namespace 至少记录 inheritedRunner、ownedChild、browser 所处 namespace 的脱敏指纹及来源、runnerCreated、browserMatchesOwnedChild、topologyPolicyMatched。Linux 进程本来就处于某个网络 namespace;不得用单个“是否 namespace=true”混淆继承环境与本轮创建的隔离。
- bootstrapObservation 明确 scope=environment-probe、observationPoint=guest-entry-black-box、freshContext、initialSessionHint、loginFormVisible、refreshRequestCount、listenerBeforeNavigation、nativeOnlineSamples、窗口及 observed/unknown 状态。它是当前候选登录页的实际黑盒行为,不宣称读取 AuthContext 分支瞬间 online,也不代表全部业务用例。
10.3 Contracts / 执行与观测
- 入口冻结候选及环境策略,记录继承环境,然后由 runner 创建受管子环境。先验证 namespace 关系、内部链路/无外连路由及空白页原生 online=true;失败立即退出,不进行昂贵业务验收。不得改写 navigator.onLine 或把浏览器强制在线的配置当成内核环境事实。
- 复用既有构建和独占库准备,在同一受管环境启动真实候选服务。运行一次专门环境探针,只打开登录页,不登录、不提交业务、不读真实数据;必须取得第 3 条黑盒事实及独立原生在线采样,再启动业务 spec 集合。不声称取得 AuthContext 分支瞬间的内部值。此探针独立登记为必需环境阶段,不混入原业务用例数或假称完整覆盖。
- 不改 AuthContext。用全新 context(无 cookie/localStorage)及 serviceWorkers=block,导航前安装请求监听,直接访问真实候选 /login,不安装 mockSyntheticApis 或任何 route mock。必须表单可见且整个观察窗口内 refresh 请求数为 0;401/失败/重试请求也计数。独立读取原生 online,记录采样点,不冒充 bootstrap 当时的内部值。表单可见但发生 refresh 的反例必须被拒绝。
- bootstrap 探针和浏览器进程 namespace 事实两者都要核对;不能仅信回执某个布尔值。运行期间及结束时重新核验 runner 所拥有的 namespace/拓扑关系;关系变化、观测缺失、权限不足一律 unknown/invalid,不当作“无隔离”或 PASS。 父 runner 的 namespace 由父进程通过本轮独占 Unix socket 即时采样返回,响应绑定本轮 ID、PID 与当前策略;不是旧文件自报值。子 user namespace 无权跨层 readlink 父 namespace 时,不放宽为成功:改为由具有权限的被观测父进程直接测量,IPC 不可达或事实不符仍拒绝。子进程自身及浏览器 namespace 仍直接读取,祖先关系仍独立核对。
- 无法从进程自身可靠证明全部祖先包装都不存在。本合同保证的是 runner 重建并实测了获准的内部环境,不是“证明没有人从外层调用 unshare”。不同机器 namespace 指纹可不同;复现比较受管 profile、策略和关系事实,而不是硬比 inode 字面值。
- 一旦全局前提不合格,立即停止后续分支。普通 full-local 返回非零 ENVIRONMENT_INVALID;诊断内部记录环境失败并结束为 PARTIAL/2,不像业务断言红项那样继续展开浏览器。此前完成的原始阶段保留,但整轮不得给完整候选背书;未运行项如实 NOT_RUN,不制造几十个 skipped/failed 结果。
- 环境在线只约束全局启动及受管拓扑;mobile-approvals-offline、r89、r108 等在独立 context 内主动 setOffline 的行为合法保留。不得增加全程“所有 context 必须在线”的断言,更不能禁止/跳过离线场景。全局 kernel 环境不因某一个 context 的离线仿真而被判坏。
- 环境事实与候选、策略、实际集合一起由 R2 验证器消费;R1 强制消费启用时一并成为必需项,普通发布不设环境豁免。在 R1 仍未启用期间,诊断自身仍须执行环境前置,否则无法产出新清单。
- 回执不是防伪证明,外层有文件写权限的执行者仍可伪造。第三方按当前候选和受管命令独立重跑;原始/派生记录和脚本摘要并存,保留原失败,不能用新成功覆盖旧错误环境运行。
10.4 Validation / Error Matrix
| 输入或异常 | 必需结果 |
|---|---|
| namespace 创建失败、权限/工具缺失、原生 online=false | 环境失败;后续业务浏览器启动数为 0,无降级或豁免 |
| 空白页在线,但实际候选 bootstrap 缺失/false | 停止业务集合;观测缺失与离线分别标码,不假填 true |
| 调用者只置 ONLINE=1 / ENVIRONMENT_PASSED=1 | 不改变测量或验证结果,不能获得资格 |
| 回执缺环境、unknown、策略摘要过期、browser 不在 runner 拥有的 namespace | 非零拒绝;资格消费阶段的远端发布写动作数为 0 |
| 候选/探针/拓扑规则在运行后改变 | 旧回执不能给新候选背书 |
| 一个 context 离线,其他新 context 在线 | 合法场景,不污染全局环境结果、不跳过离线用例 |
| 环境有效,但合同仍卡“更多” | 真实业务用例红项保留,不能因环境已修就判整套通过 |
| 诊断所有已运行测试绿 | 仍 PARTIAL/2;诊断耗时不充当普通 full-local 全绿耗时 |
10.5 Good / Base / Bad
- Good:受管入口在继承的 loopback-only 条件内重建并核验 isolated-online-v1,真实候选 bootstrap 在线,原 spec 不改,回执记录当前环境策略与观测作用域。
- Base:环境有意保持无公网,但原生浏览器在线;业务使用本地服务,显式 context 离线由各自场景负责。在线标记不授予 live/公网访问权。
- Bad:在 artifacts 包一层 unshare,运行后才解释 207 个超时;或强改 navigator 为 true、把 document-start 写成 bootstrap、把 namespace unknown 写成未隔离,再用 exit 0 当完整验收。
10.6 Tests Required / 范围与实施顺序
- 拟涉及受管面:run-web-gates.sh、full-local-diagnostic.mjs、full-local-diagnostic-stage.sh;新增 scripts/qa 中的环境创建/探针/回执辅助模块及对应 tests;R2 共享回执模块在其实现时消费同一合同,不复制策略。独立探针不通过重写 31 个 spec 的 import 实现。
- 产品源码写入面为零,业务 spec 写入面为零。新增受管环境与黑盒探针及测试;不使用修改源码后的实验副本作为候选。具体文件清单按 implement.md 冻结,新增产品语义或业务测试迁移需另批。
- 先用 fake 工具/命令捕获验证:先创建及探针后业务调用、失败启动数 0、无 fallback、PARTIAL/2、环境回执拒绝矩阵、按归属清理。变异删除在线/归属/消费任一保护必须使对应回归失败。
- 在获准本地通道运行独立原生探针和无 mock 候选黑盒探针;保留原断言,不重试至绿。不修改产品、online 值或认证控制流;显式 context 离线与全局拓扑分离。此前 context 隔离实验只作其已观测范围的证据。
- 环境实现独立复核通过后,按明确运行授权仅重跑一次完整诊断,绑定最终交审源码,不修清单中新红项;服务端场景 8 后续 NOT_RUN 的边界仍存在,不能声称一次诊断必定覆盖服务端全部分母。阶段 B 随后只处理原合同详情及续约/归档验收,产品权限缺口仍停下报告。
- 最新用户明确批准本节实施和落地后一次完整诊断;主会话针对性验证不冒充独立复核,交审中须单列待独立复核状态。R1 仍等新的真实清单、普通 full-local 全绿实测耗时及单独批准。
10.7 Wrong / Correct
Wrong:caller 声明 online=true → 未核验的包装启动浏览器 → 无 bootstrap 证据也汇总 207 为待修清单。
Correct:当前候选策略定义环境 → 受管 runner 创建并实测 → 真实 bootstrap 在线才启动业务集合 → 环境、覆盖与来源由验证器共同判定 → 错误环境回执留存但撤销决策资格。