Build 74 Phase 2 · Lead 裁定与 Stop-drain 诊断实施方案
Lead AI 编写;等待 Project Owner 明确批准。 本文是本批唯一实施依据,取代旧方案的准入、结果、测试与任务 B 实施条款;旧方案及其归档保留为历史提交,不回改历史读数。本文完成的是方案与静态/原始字节复核(E1,引用历史真机原始 Session),不是新包 E4 验收。实施记录须在本文按日期增量追加,不能由 Implementation AI 自判 PASS。
0. 基线、证据与不变量
| 项 | 固定边界 |
|---|---|
| 冻结产品 | Build 74 产品 commit 1ec94623f3623d37be206f82e114a6b441547db5;签名测试 ZIP SHA-256 3a557cc0c0c666f90736c34fa9b633adb646a92a55ecfdae095c41f349a5dbc1。新包通过真机 E4 前不称正式验收完成。 |
| 方案输入 | eeee607 所提交的旧方案、R2 artifacts/build74-owner-e4-followup-20260924-1232/final-audit.md 与同目录原始证据目录;S2、T1-r1/r2/r3、T2 Session 及私有只读分析归档。旧方案当前未提交的 §15 是执行方建议,不是 Lead 批准文本。 |
| 共享工作区 | 不碰 MacApp/Tests/1.trace/,不覆盖未跟踪的两份并行 devlog,不改原始 Session,不执行 reset/clean 或全量暂存。反事实副本与原始数据必须以 Session ID、Raw SHA-256、事件序列和算法版本区分。 |
| 产品边界 | 无侵入;Network __aenter__、逐源失败和全局 missing 语义另批;Phase C Hybrid Total 继续 FROZEN;不调整启动命令、role 标记、CoreProfile 过滤配置、Mode A 锚点、队列/超时或任何显示指标公式。 |
已证、未证与纠错
- 已证(源码+原始字节):四轮冻结 UI 配置相同,Total 均 missing;S2/r1/r2 交付 CoreProfile 原始字节没有目标 IFR opener;r3 有目标线程的 1 条 code=12 opener、2 条 IFR closer,处于
frame-continuation/post-stop-drain,被冻结保留谓词排除。仅在离线副本翻转 role,可令 r3 配对、S2 仍 missing;其数值是反事实,不得作为真实 Total。 - 已证(清点脚本的准确分母):私有归档
scripts/analyze_drain_admission_delta.py先过滤生命周期命名空间、_lifecycle_actions()非空,随后以_thread_pids[tid] == targetPID过滤。其newlyAdmissibleInFrameContinuationChunks的 S2/r1/r2/r3 为 0/0/0/3,实际是“目标归因 actionable 清点”,不是仅按 role/phase/namespace 的预筛,更不是最终准入。任意线程 actionable 对照 S2=9、r3=31。候选数、身份通过数、闭合链记录数必须分列,不得再共用“准入增量”。 - 已证(源码):现有
consume()在target_generation=None时不拒绝;_records无界、_reset_semantics()被_rebuild_semantics()调用;report(source_raw_sha256=…)本身不读取 Raw,真正的重放由derive_launch_trace_session()创建解码器并逐事件consume()。现有两遍_thread_pids是全局归因,不证明 TID 从未被别的 PID 复用。 只读容量 census:按raw-events.jsonl中 binary chunk 的偏移顺序重组成 RAW v2 流,四轮 trace header thread 数依次为 2828/2731/2248/2288,三类映射记录去重 tid 数依次为 563/505/573/721;把两集合简单相加作保守上估为 3391/3236/2821/3009,均低于拟设保护阈值 8192。r3 诊断候选 tid 的归因见证只有一个 PID 值且等于目标 PID。该上估只证明这四个历史样本可容纳,不是未来上界;不得直接把含非 binary 块的存储文件当作连续 kd_buf 流扫描。 - 未证:设备丢失 marker 的 arg1 含义、TID 重用在四轮之外的分布、drain 第二条 closer 的真实语义、设备 tick 与主机 stop 时刻同轴关系、T2 双时间轴 4.38 倍跨度的原因、与 Apple Instruments 同事件端点的一致性。
sourceQuality.lossFree只覆盖主机活线队列丢失;设备丢失 marker 是丢失片段/标记,不是被丢事件条数。 - 纠错:
coreProfileRestartCount=0不等于reconnectGeneration=0;sourceEpoch可合法不为 1,必须与本 Session 的 launch/source 基线比较;“drain 收到”不等于“设备事件发生在 tap 停止之后”;dataCompleteness=complete是产物封闭,不代表请求指标均有样本。 四轮原始事件外层的(targetGeneration, sourceEpoch, reconnectGeneration, sourceID)均只有一个组合,且与各自launch.requested.raw一致;这是历史样本的一致性事实,不是写死其具体数值的依据。
1. 架构决定(ADR-P2-01)
决定状态:方案已定,实施待 Owner 批准。
| 选项 | 正确性 | 成本 | 裁定 |
|---|---|---|---|
| 把所有 drain chunk 改标为 startup | 会把普通帧、其他线程与其他代际一并提升 | 实现简单但风险高 | 否决 |
直接把 r3 配对提升为 totalDurationMs / repaired |
缺同事件语义、设备/主机时钟桥与新包 E4,且 drain timeout/设备丢失仍在 | 污染产品和 UI 契约 | D1 否决 |
| 只在最终 Raw 重放生成有界、可拒绝的生命周期诊断 | 可保留原始证据与缺值语义,不改活线 | 一次既有扫描+小型有界账本 | 本批唯一允许实施的产品变化 |
D1:主报告与 UI 的硬边界
本批 totalDurationMs 不发布;totalQuality、totalSource、totalRepairReason、status、reason、phaseResults、requiredMissingPhases、phaseCoverageComplete、spanCount、unmatchedBeginCount、_open、_spans、_completed、_initial_frame_end_* 与冻结版逐字段相同。活线 UI 仍显示 partial/missing;最终报告可比活线多一个诊断块,但不能据此出现启动总时长或“阶段已覆盖”的展示。诊断块不得含 *Total*、*Repair*、diagnosticEndpointMs、launch→closer 毫秒值或任一可直接被 UI 当作 Total 的标量。未来开放 Total 是独立决策批次,至少需要同会话同事件端点身份、设备/主机桥与外部参照的可比证据、来源与质量标签、Swift 展示来源位、新包 E4 正负形态。
D2:时间与容量
不使用 launch_start+15s、max(startup chunk tick)、主机 stop 时间或 4 秒 drain 等待预算作设备域准入上/下界。唯一时间判定是同一时基下 closer.machTicks > opener.machTicks >= openSceneBegin.machTicks;其中严格 > 是本诊断新保守门,不是冻结 _pair_markers 的 < 比较的逐字复用。缺 timebase、非正差、tick 乱序无法重建或跨 epoch,均不给闭合诊断。
容量先按第 3 节定义的精确候选层清点四轮与合成高压,512 仅作为显式安全上限,不声称覆盖所有真实会话。超限选 A:整批诊断失效;保留 overflow/计数/原因,不保留前缀形成的 opener、closer 或数值。主机时间窗限制采集耗时,不证明条数上界。
D3:显示指标拆批与依赖
本批只做 B0 只读取证,不接线指标。B0 先以 T2 原始 1716 条帧复算主机接收轴与设备 presentation 轴、stale/host gap/refreshMultiple 分布,并核对 graphics.raw 中已有的 ios.foreground.fps 路径;仅能得到双轴差异,不能擅称时钟成因。B1(DisplayPerformanceProjector 是否为四项的唯一所有者)待 B0 与重复出数检查后另批裁定并实施;B2(显示指标具名 missing reason)须与 Device Network 的独立全局缺值语义批次对齐后另批;B3(请求指标覆盖摘要)在 B1/B2 契约稳定后另批。dataCompleteness 不改义;FrameTime 时钟取证可独立延伸,但未解决前不得提升四项质量等级。
2. A1 诊断实现契约(Owner 批准后由 Implementation AI 执行)
2.1 入口与写面
- 仅最终
derive_launch_trace_session()为解码器显式启用stop_drain_diagnostic=True,实时构造保持默认关闭。最终重放将RawEvent外层target_generation/source_epoch/reconnect_generation/source_id/sequence作为独立可选参数传给consume();不能仅从 payload 默认值推断或硬编码 epoch 1。校验后的 manifestrawSHA256绑定诊断来源。 - 在现有 kd_buf 单次扫描中,独立于
retain_record抽取binary ∧ role=frame-continuation ∧ phase=post-stop-drain ∧ _lifecycle_actions(record)≠[]的记录;先记actionableAnyThreadCount,后经身份门得到targetActionableCount,最后链门得acceptedEventCount。候选只存固定宽度 tuple:tick、arrival sequence、tid、debugID、必要的 args、Raw sequence、chunk/record offset;不得复制 chunk 字节或向_records、_markers注入。最小扫描和全量扫描的 action code 覆盖必须等价;尤其 code=12 要按_lifecycle_actions可接受的 func 形态检查,不能只在真机分类中写死0x2B870030。如需补扫描 ID,只在诊断 opt-in 的局部集合补齐,不改默认活线LIVE_LIFECYCLE_DEBUG_IDS。 - 主报告语义重建与诊断账本分离:
_reset_semantics()只清派生语义/可重算诊断结果,不清会话原始候选账本;target rebind、原始来源不一致或溢出使诊断账本失效。_semantic_dirty仍只由原有_records改变;诊断计算在最终report()的_ensure_semantics()之后从只读快照进行。多次 report 幂等;活线_emitted_report早退路径不新增诊断。 - 不触碰
realtime.py的 role 决策、CoreProfile 采集与 stop/drain 时序,不改变_pair_markers()、_recover_total_endpoint()、_lifecycle_anchor_ticks()。若最终重放现有路径无法取得某项外层身份,不猜值,输出identity-unknown诊断拒绝原因。不得为补诊断改变主报告的 target 归因。
2.2 四道准入门与拒绝优先级
| 门 | 可执行判据 | 失败时 |
|---|---|---|
| G1 来源 | Raw 已校验;binary chunk;role 与 phase 精确命中;同一个 CoreProfile sourceID。 |
不入候选;来源缺失/不一致记 source-unknown / source-mismatch。 |
| G2 会话身份 | chunk 外层 generation 存在且等于 launch generation;source epoch、reconnect generation 存在且等于 launch/source 基线,不要求数值为 1/0;target PID 有独立 launch 绑定。 | 缺值 identity-unknown,不一致 generation-mismatch / epoch-mismatch / reconnect-mismatch;整批不给闭合诊断。现有主解码器 fail-open 行为不变。 |
| G3 线程归属 | trace header+扫描到的线程映射形成诊断专用 tid→单一 PID/冲突 账本;目标 tid 必须有明确且无冲突的目标 PID 见证。一个 tid 曾映射到不同 PID 时,即使冻结全局 _thread_pids 的最终值为目标,也拒绝该 tid;映射缺值亦拒绝。 |
thread-binding-ambiguous / thread-binding-unknown;不得用 PID 数字偶合或未证的“最终映射”放行。此法保守,可能漏掉真实链,不制造目标身份。 |
| G4 闭合 | 冻结主语义中同 tid 仍有 UIKit Scene Creation open begin;drain 中 1 条 code=12 opener 接续该 begin,随后同 tid 1 条 INITIAL_FRAME_END_DEBUG_ID closer 严格晚于 opener;无互相冲突的中间 transition。按 (machTicks, arrivalSequence, actionOrder) 稳定排序,较早可闭合 closer 胜出。 |
无起点/多 opener/逆序/无 closer/中间冲突均拒绝。胜出后其余 closer 记 terminal-already-closed,不生成第二 span。 |
拒绝优先级:Raw/来源完整性 → 会话身份 → 容量 → 线程归属 → 链闭合。统计每层原始数与拒绝原因,避免“0”掩盖缺值。r3 的预期是目标 actionable 3、链接受事件 2、多余 closer 1;S2/r1/r2 的目标 actionable 为 0,不是承诺未来所有负向都为 0。第二条 closer 与第一条的正差为 rejectedTick − selectedTick = 296418,仅作为离线测试断言,不输出 selectedMinusRejected 反号字段。
2.3 有界内存、超限和完成性
- 诊断候选上限 512;线程归属账本唯一 tid 上限 8192。这是保护阈值而非真实数据上界证明。超任一上限立即标记
truncated=true、diagnosticUsable=false,之后只保留 O(1) 饱和/精确计数,不保留前缀链作闭合结论;不影响既有主报告。对真实四轮先做只读分层 census;若 8192 不覆盖基线,须回 Lead 重新裁定上限,Implementation AI 不得自行调大。 - 内存复杂度
O(min(C,512)+min(M,8192)),C 为 actionable drain 记录、M 为映射 tid 数;单次既有 Raw 扫描、每条 O(1) 分类,诊断末尾最多排序 512 条,O(512 log 512);无额外全 Raw 扫描、无新进程/主机轮询、无额外网络调用。原始 chunk 字节不复制。 handoffDrainStatus=timeout、设备丢失 marker 均作为完整性警示,不得推断未见记录一定不存在。若观察到完整两事件链,可标chainObservedClosed=true同时captureComplete=false;若只见 opener 或 closer,则chainObservedClosed=false。两者无论如何都不提升 Total/phase 主字段。
2.4 诊断块精确合同
最终 launch-trace-report.json 可仅增 stopDrainLifecycleDiagnostics,示意字段:algorithmVersion="stop-drain-lifecycle-diagnostic.v1"、sourceRawSHA256、actionableAnyThreadCount、targetActionableCount、acceptedEventCount、rejectedEventCount、rejectReasons、diagnosticUsable、chainObservedClosed、truncated、captureComplete、drainStatus、selectedOpenerMachTicks、selectedCloserMachTicks、对应的 selected*RawSequence/RecordOffset、sourceEpoch、reconnectGeneration、targetGeneration、deviceLostEventMarkerCount、deviceLostArgSemanticsVerified=false。缺值为 null 而非 0;拒绝或超限时所有 selected 字段必须为 null。仅保留可复核的原始 tick 与归因/来源字段,不派生任何 launch→closer ms 或 IFR duration 数值。公开站点/归档不得写真实 PID、tid、sourceID 或 Session UUID;本地诊断可保留原始标识供审计。
四轮预期主报告逐字段等于冻结版(剔除本批新增诊断块和不可比的生成时间字段),r3 诊断链可闭合、S2/r1/r2 仍无闭合链;如果实际回放不符,应记录 FAIL 与原始差异,不能改预期凑数。
3. B0 只读取证合同(可与方案收口同轮执行,非产品开发)
- 从 T2 的已验证 Raw 读取
display.frame-lifetime.raw,记录 Session 别名、Raw SHA-256、事件数、sourceID/epoch/reconnect、算法版本与首末 sequence。原始 Session 和报告只读;输出在私有分析目录,公开文档只放匿名汇总。 - 在各自时间域独立计算
hostSpanMs=(max(hostReceiveMonotonicNs)−min(...))/10^6、presentationSpanMs=(max(presentationTimestampNs)−min(...))/10^6;比值仅是观察到的跨度比,不作为时钟换算系数。逐事件/相邻帧统计 host gap、presentation gap、负/零/缺 timestamp、stale host gap(按冻结FRESHNESS_STALE_HOST_GAP_NS)、refreshMultiple。不得拿主机 Stop 时刻为设备 tick 定上下界。 - 分别追踪
DisplayPerformanceProjector的五项输入、活线 camelCase 输出、_consume_metric_frame()的 metric-ID 样本入口,以及metric_engine.py中graphics.raw → ios.foreground.fps现有路径;输出所有者冲突矩阵与五项 coverage 对账。metrics-derived.jsonl=0不等于“所有 metric_engine 路径不存在”;T2 的 1686 个 FrameTime 样本不证明其余四项已具备发布质量。 - B0 结论只允许写“观察到的两轴差异、哪些路径未接线、哪些需要同事件时钟见证”。若缺时钟桥或同事件 ID,原因标
unknown;不得把 4.38 倍归因于固定设备时钟比例,也不得扩_apply_frame_coverage.metric_map直接出数。
4. Implementation AI 文件边界与执行顺序
须先得到 Owner 对本文的明确批准。 执行时按以下顺序,不跨批:
- 先对私有副本做四轮分层 census 和 B0;固定原始 SHA、候选定义、三扫描模式;若 r3 不能维持 G1–G4 或 8192 上限已不足,停止产品实现并回 Lead。
- A1 仅可改
MacApp/Sidecar/perfowl_collector_core/launch_trace.py的最终重放参数、诊断账本、末尾只读投影,以及与之匹配的 Python 测试/fixture;需要新增独立小模块时先在 Implementation Update 说明最小原因,不可顺手改realtime.py、online_report.py、metric_engine.py、Swift/UI 或站点指标口径。拒绝把候选注入主_records。 - 公式/字段先按本文冻结,随后写
site/devlog/同文档日期化 Implementation Update,记实际文件、与本文偏差、验证命令、性能对比、E2/E4 边界与遗留项。未通过门禁写partial/blocked,不得自宣阶段 PASS。 - B1/B2/B3、Device Network、Phase C 和正式 Total 发布均不在本次可实施范围。任何“为测试方便”改变 CLI 默认 kdf2/csd、UI 录制配置、drain 时限、role 或源过滤都需另获 Lead/Owner 批准。
5. 必须交付的验证矩阵(不允许预设真机事件形态)
| Gate | 原始输入/合成边界 | 机械断言 |
|---|---|---|
| A-P | r3 原始字节、原 role,不改标;最小/全量/离线三模式 | 分层计数可复算;target actionable=3、接受=2、额外 closer 拒绝=1;两个 selected tick 指向真实记录;主报告仍 totalDurationMs=null/partial;三模式诊断等价。 |
| A-N | S2、r1、r2 原始字节,各三模式 | 无诊断闭合链;Total/phase/ignored terminal 与冻结版逐字段一致;S2 的 9 条任意线程记录不能被目标化;r1 缺 launch start 不得以 0 代替。 |
| A-I | generation 缺值/错值,epoch 非 1 但与本 Session 一致、epoch 不一致/缺值,reconnect 变化/缺值,sourceID 混入、PID 缺失、TID 复用/冲突 | 合法非 1 epoch 可通过该门;其他不可信身份均 fail-closed,仅诊断失效,不改主解码器。 |
| A-C | 两 closer 到达序与 tick 序相反、同 tick、多 opener、只有 closer、只有 opener、插入普通帧/其他进程事件、跨 chunk 半记录 | 只选最早可闭合 closer;没有 opener 不构造端点;冲突拒绝;普通帧不误入;半记录复原与原 scanner 一致。 |
| A-B | 候选 512/513、映射 tid 8192/8193,最小/全量/离线三模式 | 阈值内照常;超限整批诊断 truncated=true、selected ticks=null、accepted=0;主报告不变。测试必须 PASS,不允许“允许失败”。 |
| A-S | _reset_semantics()、重复 report、target rebind、live _emitted_report、最终新解码器 Raw 回放 |
原始候选不因语义重建消失;派生诊断可重算;rebind 不跨代;live 无新增块;final 才有;report(source_raw_sha256=…) 单独调用不冒充 Raw 重放。 |
| A-Q | 设备丢失 marker、drain timeout、Raw 不完整或 hash 错 | lossFree 不遮蔽设备丢失;timeout 可同时有观测闭合链与 captureComplete=false;Raw 校验失败不输出闭合诊断。 |
| B0 | T2 原始 1716 帧及四段滚动/静止样本(如取得) | 双轴计算、缺值、stale 与五项路径逐条可复算;无同事件桥则时钟原因保持 unknown,四项报告不提前出数。 |
真机 E4:只使用冻结 Build74 同形态 App UI 入口作为对照,核对 effectiveCoreProfileConfig 的四个生命周期过滤类别、csd=0、bm=0;CLI 默认 kdf2=[0xFFFFFFFF]/csd=128 形态一律 INVALID。新包每轮先按原始字节分类(完整链、只有 opener、只有 closer、无 lifecycle、身份缺值/冲突、溢出/timeout),再套相应判据;不得要求每轮都重现 r3 三条事件,也不得把没有正向链的轮次宣称功能已获 E4。至少一个新包真实正向闭合链、真实负向形态、原始哈希/报告一致性和活线/最终主字段对照齐备,Lead 才可考虑 A1 E4 PASS。所有会话的 Total 仍按原生契约,不因诊断提升。
6. 效率与交付门禁
- 基准采用同一批已校验 Raw,冻结版与修改版交错各至少 3 轮,报告 finalizer wall、CPU、峰值 RSS、读 I/O、首个 live snapshot 延迟、长会话最坏值;诊断开关默认关闭的 live 链路不得新增扫描/等待。A1 finalizer 相对基线目标:wall 与 CPU 增量各 ≤5% 或 ≤100 ms(取较宽者),增量 RSS ≤8 MiB;超过即回 Lead,不自行放宽。最坏合成容量边界必须稳定完成且不造成无界分配。
- 跑匹配 Python 专项、全量 Sidecar、Swift 现有报告/工作台回归、知识契约门禁与
site/npm run build(0 错误/0 死链),并独立审计 git diff 只含本批文件。对共享工作区只窄范围暂存;受保护未跟踪文件保持不变。 - 若 Owner 批准 A1 开发,完成后按
AGENTS.md的签名、公证/staple、独立安装、SHA-256、双远程、Webhook 门禁交付;任一缺口如实记partial,不得把 E2、旧 Build74 包或 HTTP 200 当新包 E4。
7. 尚未解开的事实与下一决定
当前不能证明普通帧不会在更晚设备窗口复用相同 terminal、不能证明 T2 双轴差异的物理原因、不能从另一场 Apple trace 推定 Perfowl 同场端点一致,也不能以 deviceLostEventMarkerCount 推出具体丢失条数。A1 是诚实诊断而非启动成功率修复;若 Owner 的目标是立即发布更多 Total,必须另起证据批次,不得把本方案静默扩权。B0 完成后由 Lead 再定 B1 的所有者;Network 与 Phase C 均保持独立门禁。
当前状态:方案完成,Owner 批准 PENDING;产品实现未开始;Build74 正式 E4 验收未完成。
8. Lead Execution Gate Update(2026-09-24,Project Owner 工作流程调整)
Project Owner 已明确取消逐批审批:Lead AI 完成方案 → 给 Owner 可转发的执行指令 → Implementation AI 执行并交付 → Owner 将交付内容转给 Lead AI → Lead AI 独立验收。因此本文此前所有“等待 Owner 批准”“须先得到 Owner 明确批准”“若 Owner 批准 A1 开发”的表述,自本增量段起均仅作为已被取代的历史门禁保留,不再阻止执行;技术范围、D1/D2/D3、安全及证据门禁不变。
当前实施门禁:Lead 已完成本文并发出配套执行指令;Owner 将该指令转交 Implementation AI 即可开始。先执行 §3 B0 与 §4 第 1 项的只读取证/分层 census;若 G1–G4 对 r3 不成立、8192 保护阈值已不足、主报告不变量无法保持或性能预算预判不可达,实施方停在取证阶段并交付阻塞证据,不得自行扩大范围。若前置门通过,再实施 §2 A1、§5 全矩阵、§6 性能和交付门禁。Implementation AI 只报告实现、自测与证据,不自判阶段 PASS;Owner 转交完整交付后,由 Lead 决定是否通过及下一批方向。
实施交付必须至少包含:exact commit/parent/受控文件清单和共享工作区残留状态;四轮与 T2 的匿名化 Session/Raw SHA/输入输出清单;B0 双轴与所有者冲突矩阵;A1 主报告零差异证明、分层计数、512/513 与 8192/8193、身份/线程复用/timeout 对抗测试;专项及全量测试命令与原始输出;前后性能对比;日期化 Implementation Update、站点/新增归档与构建结果;签名/公证/stapling/安装/包 SHA 的真实状态;双远程与 Webhook 结果;仍缺的 E4 真机证据及下一阶段。任一门禁缺口如实标 partial/blocked,不以旧 Build74 包或历史 r3 回放冒充新包 E4。