planP4E2 completed / E4 pendingapproved2026-09-18

R8-Fix-5.1:端到端关闭绝对截止期(End-to-End Closeout Absolute Deadline)修复方案

P0:8 秒预算不是端到端预算

R8-Fix-5 的 COLLECTOR_CLOSEOUT_SOFT_BUDGET_SECONDS = 8.0 实际只裁剪了 CoreProfile drain、source stop、consumer drain 与 ingress writer drain。其后的 raw_ingress.stop_worker()(内部硬编码 5s)、writer_executor.shutdown(wait=True)、recorder.finalize()、metric_recorder.finalize()、session_writer.seal()、online_report.close()、CLI 最终交付、WireOutput.close(timeout=5.0) 与解释器退出都各自持有私有超时,因此 Stop → Process EXIT 最坏情况远超 8 秒,而 Swift 宿主的 10 秒 watchdog 以 Process.isRunning 为准。

独立验收复现

SessionWriter.append_batch()   阻塞 2 秒
drain_writer(timeout=50ms)   ->  ~50ms    partial-writer-drain-timeout
stop_worker()                ->  ~2015ms  <- 那 50ms 什么也没限制住

根因

修复主线

目标

Stop -> Python Process EXIT worst case < 9s
正常路径 P95 < 3s
宿主机 10s watchdog 至少留 1s 余量

禁止项

不得修改 FPS / FrameTime / P95 FrameTime / Jitter / Refresh Rate 公式、FrameLifetime 语义、ActivityTrace 与 CoreProfile Source Owner、CapturePlan、MetricRegistry、Swift 10s gracefulTimeout、R8-Fix-5 的 pump 32events/1ms 与 filter 64messages/1ms 公平门禁;不得放宽 stale-source、不得用 1000/FPS 补 FrameTime、不得补 0/60/16.67、不得扩容 queue、不得删除 undrained/drop 诊断、不得把 partial 改写成 completed、不得恢复历史回放进入 live Stop;不得 reset/stash/clean/checkout 共享脏工作区。

测试 A–G

编号场景必须断言
Aappend_batch 阻塞 2s + 50ms drain 预算整个 writer closeout < 300~400ms;worker 状态 abandoned/timed-out;accepted ≠ persisted;Session = partial
B真实 subprocess,writer job sleep(30s)Python 进程退出 < 1s
C正常 writeraccepted == persisted;closeoutStatus = clean;executor 正常 join
Drecorder.finalize() 慢有界;partial;失败阶段 = raw-finalize
Eseal 慢有界;partial;失败阶段 = report-seal;report 未被 close
Fwire writer 阻塞terminal flush 有界;closeout_exit 仍发出;进程可退出
G宿主契约worst-case closeout + wire close 仍留 ≥1s watchdog 余量

E2 门禁 G1–G17

G1  stop -> 进程退出 <9s (worst) / 正常 P95 <3s
G2  所有阶段共享同一 CloseoutDeadline
G3  remaining_seconds() 过期返回精确 0.0,无兜底 floor
G4  重阶段不得花费 TERMINAL_EXIT_RESERVE_SECONDS
G5  OrderedRawIngress.stop_worker() 无私有超时,且被 deadline 裁剪
G6  worker 无法 join 时被遗弃而非 join(daemon)
G7  writer 异常 -> 禁止全量 seal,Session 封 partial
G8  minimal partial manifest 不含可用 rawSHA256
G9  WireOutput.close 不再硬编码 5s
G10 terminal wire flush 有 fence,超时记 timed-out
G11 stopped != closeout 完成,三者分开记录
G12 heartbeat 提供 P50/P95/Max 且样本 bounded
G13 stopDiagnostics 字段完整,null 不写成 0
G14 closeoutStatus 在全部阶段结束后最后计算
G15 测试 A-G 全部存在且通过
G16 公平性测试全绿,公式 / Source Owner / CapturePlan 未被修改
G17 Python 全量、Swift 全量、站点构建、git diff --check 全部通过

不可接受的假修复

只把 stop_worker 的 5s 降到 2s,而 executor.shutdown(wait=True) 依然阻塞;
只在 asyncio.wait_for 超时后就宣称"同步线程已取消";
writer 超时后仍然继续执行完整 seal;
用扩大 queue / 延长 Swift 超时来掩盖关闭问题。

E2 实现与验证结论(2026-09-18)

新增 test_closeout_deadline.py(25 项:Test A/C/D/E + deadline 算术、ledger、daemon executor、bounded stage)与 test_closeout_process_exit.py(4 项:Test B 真实 subprocess、Test F 阻塞 wire、Test G 宿主契约),全部通过。Python 全量 643/643 OK。状态:implemented · gate-open / E2 completed / E4 pending。完整实现细节、字段清单与实现回填见站点 devlog Canonical 文档。