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。
Implementation Update(2026-09-24 · Implementation AI · E2)
> 关联方案:本文件(Build 74 Phase 2 唯一实施依据)。前置门(§8 / §4 第 1 项)判定 通过,已按 §2 实施 A1、按 §3 完成 B0 只读取证、按 §5/§6 执行验证矩阵与效率门禁。证据等级 E2:本段记录本地构建、测试与原始字节回放的真实结果。A1 真机 E4 未执行、新包未构建未签名未公证,阶段状态不由实施方自判 PASS;Total、质量、阶段覆盖与活线 UI 语义保持冻结。
IU-1 受控文件与基线
| 项 | 值 |
|---|---|
| 基线(父提交) | b45d15e74f4d4ec5a2434d627cb1f249bbd8997b(main HEAD,本批开工时) |
| 产品改动 | MacApp/Sidecar/perfowl_collector_core/launch_trace.py,+701 / −2 |
| 仅有的两处删除 | from typing import …(增补 Callable);return { → report_payload: dict[str, Any] = {(为追加诊断块改名) |
| 新增专项测试 | MacApp/Sidecar/tests/test_build74_a1_stop_drain_diagnostic.py(819 行,45 项) |
| 站点改动 | 本文件 Implementation Update 段 + site/devlog/index.md 时间线/阶段/门禁联动 + docs/architecture/ 新增归档快照 |
| 私有取证归档 | ~/Perfowl-Local-Archive/build74-phase2-a1-diag-20260924-1830/(脚本、out/*.json、Session 只读副本;不入库) |
| 未触碰 | MacApp/Tests/1.trace/、两份并行 devlog、上一轮未提交的旧方案 §15、全部原始 Session 与 .trace |
IU-2 前置门(§4 第 1 项 / §8)
| 门 | 判据 | 实测 | 判定 |
|---|---|---|---|
| r3 维持 G1–G4 | target actionable 3、接受 2、多余 closer 拒绝 1、正差 296418 ticks | 逐值命中(见 IU-4) | 通过 |
| 8192 保护阈值足够 | 四轮 union < 8192 | 3299 / 3148 / 2734 / 2904,conflictTidCount=0 | 通过 |
| 主报告不变量可保持 | 四轮冻结字段逐字段可比 | 四轮 frozenDiffs=0(见 IU-6) | 通过 |
| 性能预算预判可达 | 单次既有扫描 + 每条 O(1) + 末尾 ≤O(512 log 512) | 首次实测超支,定位后按实现修正,阈值未动(见 IU-7) | 通过 |
结论:不停在取证阶段,进入 A1 实施。
IU-3 四轮分层 census(out/rounds-census.json)
| 轮次 | 控制 | actionableAnyThreadCount | targetActionableCount | 链层 acceptedEventCount | 链层拒绝 | minimalWhitelistGapCount | rawV2ThreadCount | mappingTidCount | unionTidEstimate | conflictTidCount |
|---|---|---|---|---|---|---|---|---|---|---|
| S2 | NEGATIVE-reference | 9 | 0 | 0 | no-opener: 0 | 0 | 2828 | 471 | 3299 | 0 |
| T1-r1 | NEGATIVE | 0 | 0 | 0 | no-opener: 0 | 0 | 2731 | 417 | 3148 | 0 |
| T1-r2 | NEGATIVE | 0 | 0 | 0 | no-opener: 0 | 0 | 2248 | 486 | 2734 | 0 |
| T1-r3 | POSITIVE | 31 | 3 | 2 | terminal-already-closed: 1 | 0 | 2288 | 616 | 2904 | 0 |
- Raw SHA-256(匿名化清单):S2
2d9932ff…037f1f;T1-r1073eb427…6c50865;T1-r2bc98c9fd…8ffb718;T1-r30589cca3120288108886633942e8d045fe918b683b8227d43e1d6f9e20ad7637。 minimalWhitelistGapCount = 0四轮成立 ⇒ 最小扫描与全量扫描的 action code 覆盖等价(方案 §2.1 第 2 条)。- 四轮外层身份各只有一个组合
(targetGeneration=1, sourceEpoch=1, reconnectGeneration=0, sourceID=同一值),与各自launch.requested.raw一致;targetPIDResolved=true。该身份是本批四个历史样本的事实,实现里没有写死任何一代际数值。 handoffDrainStatus:S2 / T1-r1 / T1-r2 为quiescent,T1-r3 为timeout。- 分母差异(如实保留,待 Lead 复核口径):本批按重组 RAW v2 流上
record_offset % 64 == 0的记录对齐计数,得mappingTidCount471/417/486/616、union 3299/3148/2734/2904;方案 §0.3 记录的是 563/505/573/721 与 3391/3236/2821/3009。两者都远低于 8192,结论不变。
IU-4 A1 诊断块(真机原始字节,逐字段)
| 轮次 | actionableAnyThreadCount | targetActionableCount | acceptedEventCount | rejectedEventCount | chainObservedClosed | diagnosticUsable | truncated | captureComplete | drainStatus | selected opener / closer (machTicks) |
|---|---|---|---|---|---|---|---|---|---|---|
| S2 | 9 | 0 | 0 | 0 | false | true | false | true | quiescent | null / null |
| T1-r1 | 0 | 0 | 0 | 0 | false | true | false | true | quiescent | null / null |
| T1-r2 | 0 | 0 | 0 | 0 | false | true | false | true | quiescent | null / null |
| T1-r3 | 31 | 3 | 2 | 1 | true | true | false | false | timeout | 16767974101340 / 16767975398389 |
T1-r3 其余可复核 locator:opener recordIndex=4118589、recordOffset=537664、rawSequence=52;closer recordIndex=4168471、recordOffset=2694848、rawSequence=53;recordIndexUnit="decoded-record-index-1-based"、recordOffsetUnit="chunk-relative-byte-offset";rejectReasons 非零仅 terminal-already-closed: 1 与 thread-binding-unknown: 28;deviceLostEventMarkerCount=10、deviceLostArgSemanticsVerified=false;sourceEpoch / targetGeneration / reconnectGeneration = 1 / 1 / 0。
- selected closer 是 tick 更早的那条(正差 296418 ticks = 12.35075 ms,仅离线断言用,不输出)⇒ 冻结契约「较早可闭合 closer 胜出、其余记
terminal-already-closed」在真实字节上成立,未生成第二条 span。 - 诊断块不含
*Total*、*Repair*、diagnosticEndpointMs,也不含任何 launch→closer 毫秒值;缺值一律null而非 0;拒绝或超限时所有selected*字段为null。 - S2 的 9 条任意线程记录未被目标化(
thread-binding-unknown: 9);r1 缺 launch start 未以 0 代替;r1/r2 目标 actionable 为 0。
IU-5 B0 只读取证(T2 轮)
- Session 别名 T2;
rawSHA256 = 8b20cdec05869ca3741cc9bab90d3f20f89cdc64d64a7e038b774fd79d3a95b7;display.frame-lifetime.raw1716 条 +launch.requested.raw1 条。 - 双轴(各自时间域独立计算):
hostSpanMs = 134486.592、presentationSpanMs = 30721.029、observedSpanRatio = 0.2284;主机轴p50 = 70.311284 ms对设备轴p50 = 16.642166 ms。该比值只是观察到的跨度比,不是时钟换算系数。 staleHostGapCount = 0(阈值FRESHNESS_STALE_HOST_GAP_NS = 1_000_000_000)⇒ 产品注释记载的「陈旧/突发投递」族在本 Session 上不成立。- 所有者冲突矩阵:
ios.display.refresh_rate、ios.foreground.fps、ios.frame.pacing_jitter、ios.frame.time.p95四项sampleCount=0、valueQuality="missing";唯一ios.frame.time= 1686 /"candidate"。applyFrameCoverageMissing恰为上述四项。 metrics-derived.jsonl:空串哈希、frameCount=0、metricIDs=[]、consumedRawEventCount=1717;DisplayPerformanceProjector自述拥有全部五项,但产出只落活线样本字典 ⇒ 这是接线缺口,不是采集缺口。- 时钟成因保持
unknown;未扩_apply_frame_coverage.metric_map,未提升任何质量等级,未出数。
IU-6 验证矩阵与命令(原始结果)
- 专项合成矩阵(§5 A-P / A-N / A-I / A-C / A-B / A-S / A-Q):
cd MacApp/Sidecar && PYTHONPATH=. python3 -m unittest tests.test_build74_a1_stop_drain_diagnostic→Ran 45 tests … OK。 - 四轮主报告逐字段冻结对照:
python3 scripts/a1_frozen_vs_new.py→ 四轮frozenDiffs=0、added=['stopDrainLifecycleDiagnostics']、removed=[];冻结树hasDiagnosticKey=false、修改树=true;结论字符串ALL FOUR ROUNDS: frozen fields identical。 - 三扫描模式等价:
python3 scripts/a1_three_modes.py→ 四轮minimal == exhaustive == offline全True。 - 分层 census 与 B0:
python3 scripts/census_rounds.py、python3 scripts/b0_frametime.py→out/rounds-census.json、out/b0-frametime-dual-axis.json。 - 全量 Sidecar:
cd MacApp/Sidecar && PYTHONPATH=. python3 -m unittest discover -s tests -p 'test_*.py'→Ran 1022 tests in 124.343s / OK。 - Swift 现有报告/工作台回归:
cd MacApp && swift test --disable-sandbox→Executed 204 tests, with 3 tests skipped。首轮与全量 Python 套件并行运行时出现 1 项未命名失败;随后 4 轮互不竞争的运行均为 0 failures(含一次单独复跑)。本批git diff --name-only只含 1 个 Python 文件、未改任何 Swift 源 ⇒ 不归因本批,但该次未复现失败按诚实原则记录在此。 - 知识契约门禁:
cd site && python3 scripts/metric-knowledge-gate.py→PASS: 66 Registry contracts, Canonical ownership, versionless governance, ten-element markers, sidebar, overview, knowledgeRole governance, and rendered visual coverage。
(以上命令使用的解释器为受管 Python 3.12:/private/tmp/perfowl-core-py312/bin/python3;脚本位于私有归档 scripts/。)
IU-7 效率门禁(§6)与一次真实超支
第一次实测(交错 3 配对、min-of-N):7 项超预算 —— S2/CPU +119.9 ms;T1-r1/wall +218.0、CPU +221.9 ms;T1-r2/wall +163.4、CPU +161.6 ms;T1-r3/wall +652.3、CPU +651.5 ms(各轮预算 100 / 100 / 100 / 100 / 100 / 189.8 / 186.5 ms)。按 §6「超过即回 Lead,不自行放宽」的精神,阈值未动,改为分解成本并修正实现:
| 定位(成本分解探针) | 结论 |
|---|---|
| 账本输入面 | 映射记录 96 385 / 137 027 / 113 940 / 384 131 条,其中 >99.9% 是同一个 PERF_THREAD_DATA 族(r3:383 975 / 384 131),而唯一 tid 仅约 0.6 k ⇒ 重复度约 624 倍 |
| 主因 | 逐条映射记录的「二次解包 + 两次整数归一化 + 方法调用 + 属性加载 + frozenset 成员测试」≈ 每条微秒级 |
| 修正① | 复用冻结映射分支已经解包的元组,消除同一 64 字节的二次解包 |
| 修正② | 账本折叠收敛为唯一实现,冲突哨兵放进同一 dict ⇒ 候选判决只需一次 dict.get;rejectReasons 等可观测契约不变 |
| 修正③ | 映射族承接改为「冻结分支内折叠 + 整块被跳过时用流式包装器」⇒ 循环体在活线与常规分块上与冻结版逐指令等同,不新增逐记录判定 |
| 修正④ | drain 区域预筛由两个跨步平面降为单平面 + 逐命中读类字节;未扩大冻结正则 alternation(扩大它本身会让整段扫描多花约 3.5 s / 288 MiB) |
修正后(交错 5 配对、min-of-N) —— 结论:PERF: every metric within the plan §6 budget。
| 轮次 | wall Δ(min) | wall 预算 | CPU Δ(min) | CPU 预算 | ΔRSS(min) | 读 I/O |
|---|---|---|---|---|---|---|
| S2 | +59.179 ms(+4.49%) | 100.0 ms | +59.685 ms | 100.0 ms | −8.86 MiB | 0 |
| T1-r1 | +27.470 ms(+1.85%) | 100.0 ms | +33.074 ms | 100.0 ms | −9.55 MiB | 0 |
| T1-r2 | −4.420 ms(−0.33%) | 100.0 ms | −1.938 ms | 100.0 ms | −9.43 MiB | 0 |
| T1-r3 | +180.144 ms(+4.69%) | 192.0 ms | +176.763 ms | 188.8 ms | −10.83 MiB | 0 |
峰值 RSS 四轮均为负增量(修改版更低),读 I/O 全 0,均在 §6 预算内。
活线路径(§6「首个 live snapshot 延迟、长会话最坏值」)——同一 Session、活线构造(emit_completed_trace=true、诊断开关保持默认关闭),交错 5 配对:
| 轮次 | 首快照 Δ(min) | 全会话 consume Δ(min) | 最差单分块 Δ(min) | 两树活线是否含诊断块 |
|---|---|---|---|---|
| S2 | +2.614 ms | +14.229 ms | +4.014 ms | 否 / 否 |
| T1-r1 | −1.023 ms | −11.722 ms | +6.760 ms | 否 / 否 |
| T1-r2 | −13.516 ms | −17.975 ms | −5.006 ms | 否 / 否 |
| T1-r3 | +14.607 ms | −10.068 ms | −2.248 ms | 否 / 否 |
增量有正有负、量级与主机噪声同阶 ⇒ 活线链路未新增扫描或等待;两棵树的活线报告都不含 stopDrainLifecycleDiagnostics。
IU-8 相对方案的偏差
- drain 记录的发现方式:方案 §2.1 第 2 条允许「只在诊断 opt-in 的局部集合补齐 ID」。实现改为记录跨步字节平面预筛 +
_lifecycle_actions复核,按命名空间而非 debugID 白名单选择(_lifecycle_actions对0x1F/0x07code-13 与0x2B/0x87code-90 等形态忽略低位func,白名单会静默漏掉等价记录)。覆盖等价性由minimalWhitelistGapCount=0与三模式逐轮等价证明;不扩大冻结正则 alternation。 - 账本的承接路径:映射记录优先在冻结映射分支内折叠;整块被冻结分支跳过的分块(
frame-continuation、post-publish、retain_all_records)改由流式包装器折叠。四轮三模式与 45 项测试钉住语义等价。 captureComplete口径:取handoffDrainStatus ∈ {end-of-stream, quiescent}为 true,timeout为 false,且允许与chainObservedClosed=true并存(方案 §2.3 第 3 条)。产品从不发出字面量"complete",早期按=="complete"判定会把 r3 误标,已在实现中修正。retain_all_records(审计模式)差异:该模式会把 drain continuation 记录也保留成冻结记录,从而让 code=12 opener 关闭掉 G4 要求仍然打开的UIKit Scene Creation⇒ 该模式报open-start-phase-missing: 1、thread-binding-unknown: 28、accepted=0。等价性主张仅限两种产品选择模式(minimal / exhaustive / offline);该差异已在测试与代码注释中显式文档化。- 账本内部表示:
tid→单一 PID/冲突由「绑定 dict + 冲突集合」改为「同一 dict 内负哨兵 + 命名镜像集合」。可观测契约(rejectReasons与诊断块字段)逐字段不变。 - 测试 fixture 的 sourceID:复用产品源码中本批之前已存在的 CoreProfile sourceID 常量(3 个产品模块 + 1 个既有测试),未新增任何设备标识。按 §2.4,站点与 docs 归档不写出该值,也不写真实 tid / PID / Session UUID;原始标识只留在私有归档供审计。
IU-9 门禁状态(不自判 PASS)
| 门禁 | 状态 | 说明 |
|---|---|---|
| 前置门(§8 / §4 第 1 项) | 通过 | IU-2 |
| A1 实现 + §5 合成/原始回放矩阵 | E2 完成 | 45 专项 + 四轮零差异 + 三模式等价 |
| §6 效率(finalizer + 活线) | 全部在预算内 | IU-7;一次真实超支已如实记录,阈值未放宽 |
| Python 全量 / Swift/知识门禁 | 见 IU-6 | Swift 一次未复现失败已记录并归因 |
| 签名 / 公证 / stapling / 独立安装 / 包 SHA | partial | 本机当前无 Developer ID Application 身份(security find-identity -p codesigning 仅返回 iPhone / Apple Distribution / Development),无 notarytool 凭据 profile;AGENTS.md 的签名与公证门禁在本环境无法完成,冻结 Build74 内测包 SHA-256 不变 |
| 双远程推送 + 交付 Webhook | 见交付汇报 | 真实结果随交付内容一并给出 |
| A1 新包真机 E4 | 未执行 | 仍需新包的真机正向闭合链、真实负向形态、原始哈希/报告一致性与活线对最终主字段对照;不以历史 r3 回放或旧 Build74 包冒充 E4 |
| Total / 质量 / 阶段覆盖 / 活线 UI | 保持冻结语义 | 四轮 totalDurationMs=null、totalQuality="missing"、status="partial"、reason="lifecycle-spans-incomplete" 与冻结版逐字段相同 |
IU-10 站点与归档
- 本段写入后,按 AGENTS.md C2 在
site/devlog/index.md时间线顶部追加节点,并把本文件渲染出的 HTML 快照新增到docs/architecture/(既有归档不回改);按 C3 同步「八阶段总计划」与「未关门门禁」两张表。 - 站点构建与交付门禁的真实结果记录于下一段。
IU-11 站点构建与归档(本段记录于构建之后)
cd site && npm run build(prebuild 自动执行知识门禁与归档同步)→ 门禁[metric-knowledge-gate] PASS: 66 Registry contracts, Canonical ownership, versionless governance, ten-element markers, sidebar, overview, knowledgeRole governance, and rendered visual coverage;归档[sync-archive] docs/ -> public/archive/ (263 files);vitepress build→build complete in 93.23s,0 错误、0 死链(除既有 chunk 体积提示外无告警)。- 新增归档快照:
docs/architecture/perfowl-p4-build74-phase2-lead-decision-and-diagnostic-plan-2026-09-24-implementation-update.html(由本文件渲染)。既有…-2026-09-24.html与…-2026-09-24-workflow-update.html不回改。 - 交付门禁汇总见 IU-9:双远程推送与交付 Webhook 的真实结果随交付汇报给出;签名/公证/stapling/独立安装/包 SHA 记 partial(本机无
Developer ID Application身份、无公证凭据);A1 真机 E4 未执行,不以历史回放或旧包冒充。
Lead Independent Validation & A1-R1 Repair Decision(2026-09-24 · E2)
裁定:A1 的现有提交 475c541 为 REPAIR REQUIRED,不进入新包 E4;B0 的双轴观察和四轮原始字节清点可作为只读取证保留。 本段是 Lead 独立复核,不回改 IU-1~IU-11 的执行方原始读数和自测结果。Lead 复跑 Python 专项 45/45、全量 1022/1022;这些通过只证明已覆盖路径,不覆盖下列反例。Git HEAD 与两个远程 main 均核至 475c541;共享工作区其他 AI 的未提交路径和原始 Session 未触碰。
L-1 独立确认与口径更正
- 源码 diff 确认:最终 Raw replay opt-in,默认 live 不启用;主报告的 Total/质量/阶段字段未被诊断分支赋值。已有四轮回放记录 r3 目标 actionable 3、接受 2、额外 closer 1;S2/r1/r2 无目标闭合链;r3
handoffDrainStatus=timeout,不能宣称采集完整或新包 E4。 - Lead 从四轮 binary chunk 按存储偏移重组 RAW v2,再逐个 64-byte kd_buf 复算映射 TID:所有正 TID 为 563/505/573/721;其中具有正 PID 见证的是 471/417/486/616;差额 92/88/87/105 全部仅见 PID=0。故方案 §0.3 与 IU-3 不是字节矛盾,而是分母不同。8192 是保护上限,不是未来会话容量证明。
- B0 中
observedSpanRatio=0.2284定义为presentationSpan/hostSpan,逆比约 4.38;这两者都不是时钟换算系数。T2 的 1716 帧、四项 missing、FrameTime 1686 candidate 保持观察结论;staleHostGapCount=0仅排除“大于冻结 1s 阈值的相邻 host gap”,不能排除其他时钟/节流成因。B1/B2/B3、Network、Phase C 均未放行。
L-2 阻断性反例(Lead 以已提交测试 fixture 的 kd_buf 构造作只读复跑)
- G1/G2 整批身份不一致未失效。 在同一回放中先输入另一个
sourceID的 drain lifecycle 记录,再输入基线sourceID的 opener+closer,当前诊断出现source-mismatch=1且仍chainObservedClosed=true、acceptedEventCount=2。实现只给单条候选设 gate bit,未落实 §2.1 第 3 条“原始来源不一致使诊断账本失效”及 §2.2 G2“整批不给闭合诊断”。generation/epoch/reconnect 缺失或不一致也不得以后续正常候选洗白。 - D2/G4 缺锚点设备 tick 顺序门。 冻结
UIKit Scene Creationbegin tick=150,drain opener tick=140、closer tick=200,当前仍chainObservedClosed=true,直接违反本方案 §1closer > opener >= openSceneBegin。只检查_open非空不够;须读取同线程该 open begin 的原始machTicks并检验同域次序,缺 tick fail-closed。 - G4 忽略同线程中间冲突 transition。 drain 的 opener tick=1000、再次 scene begin tick=1100、closer tick=1200,当前仍闭合;
_STOP_DRAIN_ACTION_OTHER被记录却从未参与闭合判决。现有test_opener_must_be_the_code12_shape_not_any_begin甚至断言额外 scene begin 后仍闭合,属于需修正的正例。相同线程从冻结 anchor 到选中 closer 之间再出现 phase-3/phase-8 竞争 transition 时,必须明确拒绝或证明它不冲突,不能静默跳过。 - 字段语义需收紧。 当前
captureComplete=true仅由drainStatus ∈ {end-of-stream,quiescent}推出,即使有设备丢失 marker 也可能为 true。该字段名会被误解为生命周期数据完整;在本批尚未有新包消费者时,将其改为准确的 drain 终止状态字段(建议drainEndedWithoutTimeout),或给出等价而不宣称数据完整性的命名;保持deviceLostEventMarkerCount独立。rejectReasons覆盖预筛/身份/线程/链多层,而rejectedEventCount只计目标层,文档与测试必须明确两者不可相加。
L-3 A1-R1 唯一可执行修复边界与验收门禁
- 范围:只修
launch_trace.py的诊断 opt-in 分支、匹配的专项测试、本文件日期化增量记录和站点/新增归档;不得动默认 live、主_records/_spans/Total、role、采集配置、FrameTime 公式、Network、Swift UI 或 Phase C。不得回改既有历史报告与归档。 - 会话级失败优先:每个消费的 CoreProfile Raw 外层
sourceID/targetGeneration/sourceEpoch/reconnectGeneration与 launch baseline 比较,包括被主解码器提前丢弃的 chunk、无 actionable 的 chunk;任一缺失/不一致置诊断批次无效,保留分层计数和精确原因,但diagnosticUsable=false、chainObservedClosed=false、acceptedEventCount=0、全部 selected locator/tick=null。正常的非 1 epoch、非 0 reconnect 与自身 baseline 相等时必须通过。主报告仍按冻结解码器自身规则运行,不因诊断失败改变。 - 闭合严格顺序:同一目标 TID 的冻结 phase-3 open begin 必须有可比较 tick,且
closerTick > openerTick >= openSceneBeginTick;anchor tick 缺值或逆序明确拒绝。对该线程从 anchor 到 selected closer 的 drain lifecycle 记录排序后,仅允许唯一 code-12 opener 与首个可闭合 IFR closer;额外 closer 保留terminal-already-closed;重开 scene、其他 phase-3/phase-8 竞争 transition 保守拒绝并计interleaved-conflict。不得用 15s、host stop 或 chunk 最大 tick 代替设备域门。 - 专项负例:新增“错 source 在前、正常链在后”“缺 source/epoch/generation/reconnect + 正常链”“错代际 chunk 被早退 + 正常链”“无 actionable 的错源 chunk + 正常链”“opener 早于 anchor”“anchor tick 缺值”“scene reopen 位于 anchor→opener、opener→closer”“两 closer 到达序与 tick 序相反”等;逐项断言诊断和主报告。旧的额外 scene begin 正向断言必须改为保守拒绝。正常 r3 仍需 3/2/1,S2/r1/r2 仍无目标链。
- 回归与效率:重跑 45 项原测试+新增负例、全量 Sidecar、Swift/知识门禁、站点构建;四轮原始 Raw SHA 与主报告字段零差异、minimal/exhaustive/offline 等价、512/513 和 8192/8193 option A 继续成立;基线/修订版交错性能比较仍按 §6 原阈值,不放宽。打包/Developer ID/notary/staple/独立安装及新包 E4 缺口保持真实状态,不用历史回放代替 E4。
- 交付:Implementation AI 在本文件追加 A1-R1 Implementation Update,提交仅本批路径并尝试双远程推送、验证站点实际内容、按 AGENTS.md 发送一次交付 Webhook;交回 exact commit/parent、差异、所有命令原始结果、四轮/对抗 fixture 逐字段矩阵、性能与包/E4 状态。Implementation AI 不自判 PASS;Owner 直接转交 Lead 独立复验,无需另行逐批审批。
当前 Gate:A1 E2 = REPAIR REQUIRED;A1 新包 E4 = NOT RUN;Total/质量/阶段覆盖仍冻结;B0 E1 观察已接收但不授权 B1。
A1-R1 Implementation Update(2026-09-24 · Implementation AI · E2)
实施依据:本文件末尾的 “Lead Independent Validation & A1-R1 Repair Decision”(L-1 口径更正、L-2 四项阻断性反例、L-3 唯一可执行修复边界)。基线 main = 1c7570a130958987e11919c468eedc28b50ac845。本段为纯追加,不回改 IU-1~IU-11 与 L-1~L-3 的任何数字。
范围纪律:只改 launch_trace.py 的诊断 opt-in 分支、匹配的专项测试、本文件与站点/新增归档。默认 live 构造、主 _records/_spans/Total、质量、阶段覆盖、role、采集配置、FrameTime 公式、Swift UI、Network、Phase C 全部未触碰;未回改既有历史报告与归档。
R-1 实际修改(MacApp/Sidecar/perfowl_collector_core/launch_trace.py +178 / −73)
| 条目 | L-2/L-3 要求 | 实际实现 |
|---|---|---|
| A · 会话级身份(L-2 item 1) | 混合来源/代际使整批诊断失效,含被主解码器提前丢弃的 chunk 与无 actionable 的 chunk | 新增 _stop_drain_check_chunk_identity(),在 consume() 最前面(早于 _prefix_rejected、generation 门、_decode_chunk 的每一个 early return)对每个被消费 chunk 的外层 sourceID / targetGeneration / sourceEpoch / reconnectGeneration 与 launch baseline 比较;任一缺失或不一致即 self._stop_drain_batch_invalid = True,投影据此早期返回 diagnosticUsable=false、chainObservedClosed=false、acceptedEventCount=0、全部 selected* 为 null。原逐候选 gate bit 改为读取本 chunk 的判定结果(_stop_drain_chunk_identity_ok),因此不再存在"后续正常候选洗白前面错源"的路径 |
| B · 严格设备域次序(L-2 item 2) | closerTick > openerTick >= openSceneBeginTick;缺 anchor tick fail-closed | 新增 _stop_drain_anchor_ticks(tid) -> (anchor_present, anchor_ticks),从冻结语义的 _open[(tid, "UIKit Scene Creation")] 顶层 marker 读原始 machTicks;判别顺序为 无 anchor → open-start-phase-missing、anchor 存在但 tick 不可比较 → 新增 anchor-tick-missing、openerTick < anchorTick → 新增 opener-before-anchor,三者任一成立都不生成链。不用 15 s、host stop 或 chunk 最大 tick |
| C · 同线程竞争 transition(L-2 item 3) | 拒绝 anchor→closer 之间的重开 scene 与其他 phase-3/phase-8 竞争 transition,计 interleaved-conflict | _STOP_DRAIN_ACTION_OTHER 首次参与判决:窗口 [anchorBegin, selectedCloser) 内除唯一 code-12 opener 与纯 IFR closer 之外的任何候选行都保守拒绝。窗口拆成两段:anchorTicks <= tick < openerTick(在候选循环前一次性判定)与 (openerTick, openerArrival) < (tick, arrival) < (closerTick, closerArrival)(逐候选判定)。原「只检查其他 IFR opener」的守卫替换为 action_mask != _STOP_DRAIN_ACTION_CLOSE_IFR |
| D · 字段语义(L-2 item 4) | 改名为准确表达 drain 终止状态的字段 | captureComplete → drainEndedWithoutTimeout(同一布尔值 drainStatus ∈ {end-of-stream, quiescent},但不再可被读成"生命周期数据完整");新增 rejectReasonsUnit="pre-screen+identity+thread+chain-reason-count" 与 rejectedEventCountUnit="target-layer-event-count" 两个机器可校验的单位字段;deviceLostEventMarkerCount 保持独立 |
新增拒绝原因 anchor-tick-missing、opener-before-anchor 已写入 STOP_DRAIN_REJECT_REASONS(词表保持封闭,rejectReasons 仍逐键自该元组生成)。
R-2 对抗 fixture 与专项测试(45 → 60 项)
MacApp/Sidecar/tests/test_build74_a1_stop_drain_diagnostic.py +285 / −13。新增 15 项,其中 L-3 点名的负例逐条落地:
| 新增测试 | 断言要点 |
|---|---|
test_foreign_source_chunk_before_a_healthy_chain_invalidates_the_batch | L-2 case 1 原文形态:错 source 在前 + 正常链在后 ⇒ 批失效、acceptedEventCount=0、8 个 selected 字段全 null |
test_missing_source_id_chunk_before_a_healthy_chain_invalidates_the_batch | 缺 sourceID ⇒ source-unknown + 批失效 |
test_missing_identity_values_before_a_healthy_chain_invalidate_the_batch | 缺 sourceEpoch / targetGeneration / reconnectGeneration 三子例 ⇒ identity-unknown + 批失效 |
test_early_dropped_wrong_generation_chunk_invalidates_the_batch | 错代际 chunk 被冻结 generation 门早退 + 正常链 ⇒ 批失效 |
test_source_mismatched_chunk_without_actionable_records_invalidates_the_batch | 错源 chunk 无 actionable + 正常链 ⇒ 批失效(逐候选 gate 结构上不可能看到) |
test_a_matching_envelope_on_every_chunk_still_closes | 负对照:同一形状但身份一致时仍闭合 ⇒ 新门不是"一律拒绝" |
test_opener_before_the_frozen_scene_anchor_is_refused | L-2 case 2 原文形态:anchor=150、opener=140 ⇒ opener-before-anchor |
test_opener_tick_equal_to_the_anchor_is_admissible | 谓词是 >=,边界 150==150 仍须闭合 |
test_anchor_without_a_comparable_tick_fails_closed | 直接单元校验 _stop_drain_anchor_ticks 三态,并把 anchor marker 去掉 machTicks 后断言 anchor-tick-missing 且不得被默认为 0 |
test_competing_phase3_transition_between_anchor_and_opener_is_refused | code 23(end PHASES[3] + begin PHASES[4])落在 anchor→opener ⇒ interleaved-conflict=1 |
test_scene_reopen_between_opener_and_closer_is_refused | L-2 case 3 原文形态:opener 1000 / 重开 scene 1100 / closer 1200 ⇒ 拒绝 |
test_competing_transition_after_the_selected_closer_does_not_spoil_it | 反向控制:胜出 closer 之后的竞争 transition 不得把好链变成拒绝 |
test_r3_shape_still_yields_three_target_two_accepted_one_extra_closer | 正向回归:真实 r3 形态仍 3 目标 / 接受 2 / 拒绝 1 / terminal-already-closed=1 |
test_drain_termination_flag_never_claims_data_completeness | quiescent 且设备丢失 1 次 ⇒ drainEndedWithoutTimeout=true 且 deviceLostEventMarkerCount=1;并断言块内不存在 captureComplete 键 |
test_reject_reasons_and_rejected_event_count_are_not_additive | 预筛层拒绝(thread-binding-unknown=2)而目标层为 0 ⇒ sum(rejectReasons) > rejectedEventCount,并断言两个 *Unit 字段 |
被修正的旧正例:test_opener_must_be_the_code12_shape_not_any_begin 原先断言「额外 scene begin 后仍闭合」,按 L-2 item 3 改为保守拒绝(interleaved-conflict=1、acceptedEventCount=0);同批把 captureComplete 的三处断言改名为 drainEndedWithoutTimeout,并给 replay() 增加 identity_per_chunk 以构造混合身份回放。
R-3 四轮原始字节正负回放与主报告冻结对照
| 轮次 | actionableAnyThreadCount | targetActionableCount | acceptedEventCount | rejectedEventCount | chainObservedClosed | diagnosticUsable | truncated | drainEndedWithoutTimeout | drainStatus | selected opener / closer (machTicks) |
|---|---|---|---|---|---|---|---|---|---|---|
| S2 | 9 | 0 | 0 | 0 | false | true | false | true | quiescent | null / null |
| T1-r1 | 0 | 0 | 0 | 0 | false | true | false | true | quiescent | null / null |
| T1-r2 | 0 | 0 | 0 | 0 | false | true | false | true | quiescent | null / null |
| T1-r3 | 31 | 3 | 2 | 1 | true | true | false | false | timeout | 16767974101340 / 16767975398389 |
r3 其余 locator 与 A1 完全一致:opener recordIndex=4118589、recordOffset=537664、rawSequence=52;closer recordIndex=4168471、recordOffset=2694848、rawSequence=53;rejectReasons 非零仅 terminal-already-closed: 1 与 thread-binding-unknown: 28;deviceLostEventMarkerCount=10、deviceLostArgSemanticsVerified=false;sourceEpoch / targetGeneration / reconnectGeneration = 1 / 1 / 0。
| 轮次 | Raw SHA-256(本批重放实测,与 A1 census 逐字符相同) |
|---|---|
| S2 | 2d9932ffd0561ae6cbc695342a0f53f4bc76ab8c62a5fad381572ba75a037f1f |
| T1-r1 | 073eb427373439b8ae19243543794a113eebf1b25b7bfd17e78e0d7156c50865 |
| T1-r2 | bc98c9fd3faf03bbb2fa7792ee2fe635ed0f6ed3f7641d262745584be8ffb718 |
| T1-r3 | 0589cca3120288108886633942e8d045fe918b683b8227d43e1d6f9e20ad7637 |
对照结论(三树同机、同一不可变 Session 副本):
- base(A1,
1c7570a)→ ship(A1-R1):四轮baseVsShipFrozenDiffs=0,且报告键集合既未增也未减(added=[] / removed=[])⇒ 修复严格落在诊断块内部,主报告逐字段零差异。 - frozen(
b45d15e7)→ ship:四轮frozenVsShipFrozenDiffs=0、added=["stopDrainLifecycleDiagnostics"]、removed=[];冻结树四轮hasDiagnosticKey=false。 - 诊断块 base→ship 的唯一差异就是字段改名(
captureComplete无此名 ⇒ 呈现为(null, true/false)),其余 18 个可对照字段的值逐轮相同。 - r3 逐字段复现 A1:31 / 3 / 2 / 1、链闭合、
truncated=false、selected tick 与 locator 全同 ⇒ 修复未改变任何真实正向结果。 - 负向回归保持:S2 仍
targetActionableCount=0(9 条任意线程记录thread-binding-unknown: 9)、r1/r2 仍 0 ⇒ 未被本次修复误伤为闭合。 - 新 chunk 级身份门在真实数据上未误伤:四轮均
batchInvalid=false;若任一真实 chunk 身份不一致,r3 会立刻退化为diagnosticUsable=false,实测没有。
R-4 三模式等价、容量边界与 option A
| 轮次 | minimal == exhaustive | minimal == offline | 候选行 / 512 | 唯一绑定 tid / 8192 | 冲突 tid | 溢出 | batchInvalid |
|---|---|---|---|---|---|---|---|
| S2 | true | true | 9 / 512 | 2977 / 8192 | 0 | false | false |
| T1-r1 | true | true | 0 / 512 | 2888 / 8192 | 0 | false | false |
| T1-r2 | true | true | 0 / 512 | 2330 / 8192 | 0 | false | false |
| T1-r3 | true | true | 31 / 512 | 2440 / 8192 | 0 | false | false |
- 四轮
minimal == exhaustive == offline全True(扫描覆盖等价未被本次修复破坏)。 - 容量余量未变:候选行 9 / 0 / 0 / 31 ≪ 512;唯一绑定 tid 2977 / 2888 / 2330 / 2440 ≪ 8192;
conflictTidCount=0、bindingOverflow=false。8192 仍只是保护上限,不是未来会话容量证明。 - 512/513 与 8192/8193 的 option A 继续成立:
test_candidate_capacity_boundary_is_inclusive_at_512、test_candidate_overflow_at_513_invalidates_the_whole_diagnosis、test_thread_binding_capacity_boundary_is_inclusive_at_8192、test_thread_binding_overflow_at_8193_invalidates_the_whole_diagnosis、test_worst_case_capacity_completes_without_unbounded_allocation五项在 60 项专项中全部通过。本批未改任何容量常量或阈值。
R-5 效率门禁(§6,阈值未放宽)与活线路径
解释器受管 Python 3.12,交错 5 配对、min-of-N,同一不可变副本。§6 预算逐字沿用:wall / CPU 各 ≤ max(5%, 100 ms),ΔRSS ≤ 8 MiB。两种对照都报,因为二者回答不同问题。
对照一 · frozen(无诊断)→ ship(A1-R1) = 诊断总成本,与 IU-7 同口径:
| 轮次 | wall Δmin (ms) | wall Δ% | wall 预算 (ms) | CPU Δmin (ms) | CPU 预算 (ms) | ΔRSS (MiB) | 判定 |
|---|---|---|---|---|---|---|---|
| S2 | +73.986 | +5.44% | 100.0 | +67.884 | 100.0 | +1.277 | 在预算内 |
| T1-r1 | +48.309 | +3.24% | 100.0 | +42.994 | 100.0 | +2.105 | 在预算内 |
| T1-r2 | +11.555 | +0.86% | 100.0 | +12.878 | 100.0 | +1.324 | 在预算内 |
| T1-r3 | +159.270 | +4.08% | 195.3 | +159.007 | 191.8 | -0.574 | 在预算内 |
对照二 · base(A1)→ ship(A1-R1) = 本次返工自身的增量:
| 轮次 | wall Δmin (ms) | wall Δ% | wall 预算 (ms) | CPU Δmin (ms) | CPU 预算 (ms) | ΔRSS (MiB) | 判定 |
|---|---|---|---|---|---|---|---|
| S2 | +52.970 | +3.84% | 100.0 | +50.593 | 100.0 | +0.004 | 在预算内 |
| T1-r1 | +23.781 | +1.57% | 100.0 | +18.918 | 100.0 | +1.805 | 在预算内 |
| T1-r2 | -29.930 | -2.17% | 100.0 | -25.719 | 100.0 | -0.531 | 在预算内 |
| T1-r3 | -11.454 | -0.28% | 203.8 | -12.369 | 200.3 | -0.141 | 在预算内 |
结论:PERF: every metric within the plan section 6 budget at 5 interleaved pairs —— 8 组对照 × (wall, CPU, RSS) 共 24/24 在预算内。相对 frozen 的最大增量是 r3 wall +159.270 ms(+4.08%,预算 195.3 ms);相对 A1 基线的最大增量是 S2 wall +52.970 ms(+3.84%,预算 100 ms);ΔRSS 全部在 −0.574 ~ +2.105 MiB。未放宽任何阈值。 readBlocks 全 0。
活线路径(base ↔ ship,交错 5 配对):
| 轮次 | 首快照 Δmin (ms) | 全会话 consume Δmin (ms) | 最差单分块 Δmin (ms) | 活线含诊断块 |
|---|---|---|---|---|
| S2 | +1.284 | +2.730 | -3.724 | 否 |
| T1-r1 | -8.039 | -9.287 | -2.938 | 否 |
| T1-r2 | +8.288 | +19.143 | +7.040 | 否 |
| T1-r3 | -3.609 | -11.041 | -1.475 | 否 |
- 首快照、全会话 consume、最差单分块的最大差值分别 8.288 / 19.143 / 7.040 ms,与主机噪声同阶;两树活线报告都不含
stopDrainLifecycleDiagnostics⇒ 本批新增的 chunk 级身份检查只存在于_stop_drain_enabled为真的离线分支,活线逐指令未变。 - 口径更正(诚实记录):上一轮
out/a1-perf-interleaved.json把ru_maxrss的字段名写作maxRssKb,但 macOS 上该值单位是字节(Linux 才是 KiB)。IU-7 报告中的 “ΔRSS −8.86 ~ −10.83 MiB” 实为 bytes/1048576 的结果,数值本身可用、字段名有误导。本轮探针改用maxRssBytes/deltaMinMiB并显式注释单位;未回改上一轮归档(D2)。
R-6 验证命令与原始结果
- 专项矩阵:
cd MacApp/Sidecar && PYTHONPATH=. python3 -m unittest tests.test_build74_a1_stop_drain_diagnostic→Ran 60 tests … OK(A1 为 45,本批 +15)。 - 四轮三树回放对照:
python3 scripts/a1r1_four_round_replay.py→ 四轮baseVsShipFrozenDiffs=0/frozenVsShipFrozenDiffs=0/added=["stopDrainLifecycleDiagnostics"]/removed=[];结论字符串FOUR ROUNDS: base==ship and frozen==ship on every frozen field。 - 三模式与容量:
python3 scripts/a1r1_three_modes_and_capacity.py→ 四轮minimal == exhaustive == offline全True;THREE MODES: minimal == exhaustive == offline on all four rounds; capacity headroom unchanged。 - §6 效率:
python3 scripts/a1r1_perf_interleaved.py 5→PERF: every metric within the plan section 6 budget at 5 interleaved pairs (frozen->ship and base->ship)。 - 活线延迟:
python3 scripts/a1r1_live_latency.py pair 5→ 上表;两树活线均无诊断块。 - 全量 Sidecar:
cd MacApp/Sidecar && PYTHONPATH=. python3 -m unittest discover -s tests -p 'test_*.py'→Ran 1037 tests in 123.316s / OK(A1 为 1022,本批 +15)。 - Swift:
cd MacApp && swift test --disable-sandbox→Executed 204 tests, with 3 tests skipped and 0 failures(本批未改任何 Swift 源)。 - 知识契约门禁:
cd site && python3 scripts/metric-knowledge-gate.py→PASS: 66 Registry contracts …。 - 站点构建:见 R-6b。
R-6b 站点构建与新增归档
- 新增归档快照(C2,既有
docs/归档不回改):docs/architecture/perfowl-p4-build74-phase2-lead-decision-and-diagnostic-plan-2026-09-24-a1r1-update.html,由本文件渲染。 cd site && npm run build→ 知识门禁与归档同步随构建同批执行,退出码 0、0 死链,原始输出(关键行;全日志 67 行):
> python3 scripts/metric-knowledge-gate.py && bash scripts/sync-archive.sh
[metric-knowledge-gate] PASS: 66 Registry contracts, Canonical ownership, versionless governance, ten-element markers, sidebar, overview, knowledgeRole governance, and rendered visual coverage
public/archive/.DS_Store
[sync-archive] docs/ -> public/archive/ (265 files)
✓ building client + server bundles...
✓ rendering pages...
build complete in 98.68s.
- 全日志
grep -E 'Dead link|dead link|error|Error'零命中;vitepress build若遇死链会非零退出,本批EXIT=0。 site/devlog/index.md按 C2/C3 更新(时间线顶部节点、阶段进度行、未关门门禁行),不删除任何历史节点。
R-7 相对方案的偏差(逐条,均为实现细节,不改语义)
| # | 方案/Lead 要求 | 实际做法 | 原因 |
|---|---|---|---|
| 1 | 会话级失败优先(L-3) | 删除了 _stop_drain_scan / _stop_drain_observe 上已无消费者的 4 个身份形参,并删除冻结 generation 门里那条重复的 generation-mismatch 计数 | 身份判定已上移到 chunk 级;保留旧计数会让同一 chunk 被计两次,破坏"分层计数"的准确性 |
| 2 | 拒绝原因保留 | 新增 anchor-tick-missing、opener-before-anchor 两条,而非复用 open-start-phase-missing / non-monotonic-terminal | L-3 要求"明确拒绝"且"保留精确原因";复用它因会让 Lead 无法区分 anchor 缺失与 anchor tick 不可比 |
| 3 | "文档与测试必须明确两者不可相加"(L-2 item 4) | 除文档化外,额外新增 rejectReasonsUnit / rejectedEventCountUnit 两个字段 | 让"不可相加"成为机器可校验的契约,而不是只靠读者记住一句话 |
| 4 | 同线程竞争 transition 拒绝(L-3) | 窗口实现为 [anchorBegin, selectedCloser) 两段(anchor→opener、opener→closer) | L-3 点名的负例里包含"scene reopen 位于 anchor→opener",只查 opener 之后会漏掉它 |
| 5 | 不改阈值 | STOP_DRAIN_CANDIDATE_CAPACITY / STOP_DRAIN_THREAD_BINDING_CAPACITY / 冻结正则 alternation / _matching_record_offsets 全部逐字节未动 | 直接遵守"超过即回 Lead,不自行放宽" |
| 6 | 活线不得改变 | 新逻辑全部包在既有 if self._stop_drain_enabled: 之内;_stop_drain_identity_seen(原为只写不读的死状态)改在 chunk 级记录被观察到的身份三元组 | 保持活线逐指令不变,同时把死状态变成有意义的审计面 |
| 7 | 性能口径 | 探针改用 maxRssBytes / deltaMinMiB 并注释单位 | 见 R-5:macOS ru_maxrss 为字节;上一轮字段名有误导(未回改旧归档) |
R-8 遗留项与门禁状态
- A1 E2 返工完成,但Implementation AI 不自判 PASS;由 Owner 转交 Lead 独立复验。
- A1 新包 E4 = NOT RUN:需要新包上的正向闭合链 + 真实负向形态 + 原始哈希/报告一致性 + 活线对最终主字段对照。本批未构建新包、未执行真机,不以历史回放冒充 E4。
- 签名 / 公证 / stapling / 独立安装 / 包 SHA-256 = partial:本机无
Developer ID Application身份、无 notarytool 凭据。冻结 Build74 测试包 SHA-256 仍为3a557cc0c0c666f90736c34fa9b633adb646a92a55ecfdae095c41f349a5dbc1。 - 未并批:B1/B2/B3、Device Network、Phase C、
role标记、采集配置。 - Total / 质量 / 阶段覆盖仍冻结;
totalDurationMs继续不发布;B0 的 E1 观察已接收但不授权 B1。
Lead Independent Validation & A1-R2 Repair Decision(2026-09-24 · E2)
裁定:f54afee 的 A1-R1 修复解决了 L-2 原三项反例,但 A1 E2 仍为 REPAIR REQUIRED,不进入新包 E4。 本段只追加 Lead 新验证结论,不回改 R-1~R-8 的执行方数据。Lead 核对 exact parent=1c7570a、提交范围恰为 5 个本批路径、GitLab/GitHub main 同为 f54afee、共享工作区其他 AI 的 4 个路径未动;独立复跑专项 60/60 与 Sidecar 全量 1037/1037。四轮已验证 Raw 副本独立回放仍为 r3 31/3/2/1、链闭合,S2/r1/r2 无目标闭合链,四轮 Total 均 missing/partial;这证明历史样本不误伤,不能证明 G4 对其他线程形态安全。
V-1 独立对抗结果与根因
- 跨目标线程误配(阻断):同一个 launch/epoch/source 中,冻结 scene begin 和 drain code-12 opener 在目标线程 A,另一个有独立目标 PID 映射见证的线程 B 仅有 IFR closer。当前诊断
targetActionableCount=2、acceptedEventCount=2、chainObservedClosed=true、无拒绝原因。源码closers=[row for row in target_rows if row[4]==CLOSE_IFR]未约束row[2]==opener[2],违反 §2.2 G4 的“同 tid closer”。不能把两个目标线程拼成一条生命周期链。 - 其他目标线程误阻断(同一根因的负向):线程 A 有完整 opener/closer,线程 B 在两者之间出现 scene begin;当前报告
interleaved-conflict=1且链不闭合。G4 冲突只可检查 opener 所属线程,其他目标线程的 action 不应成为该链的冲突证据。目标进程身份相同不等于线程相同。 - 同 tick 的中间竞争事件漏判(阻断):线程 A 的 scene reopen 与 opener 均 tick=1000,reopen 的到达序先于 opener,closer tick=1200;当前仍
chainObservedClosed=true。R1 的前窗< openerTick与后窗(openerTick,arrival)均跳过了“同 tick 且先到达”的 reopen。设备 tick 不能给这两条事件证明安全先后,应保守拒绝;同 tick 于 closer 的竞争 transition 同理需要明确 fail-closed 规则。
V-2 A1-R2 最小修改合同
- 范围:仅
launch_trace.py的 opt-in 诊断 G4 投影、匹配 Python fixture、本文件日期化 Implementation Update、C2/C3 站点与新增归档。不得改 chunk 身份门、Raw 扫描/保留、线程映射账本、默认 live、主报告、role/采集配置、Swift/UI、Network、FrameTime 或 Phase C。既有两个容量常量及 §6 性能门槛不变。 - 同线程准入:先确定唯一 opener 的
threadID=A及冻结 scene anchor;仅同一threadID=A的纯 IFR closers 可作 terminal,按(machTicks,arrivalSequence)选最早可闭合者。线程 B 的 closer 绝不可配 A 的 opener,也不可记为 A 的terminal-already-closed;线程 B 的其他 action 绝不可阻断 A 的闭合。targetActionableCount仍为身份/目标 PID 层的全部候选;需在诊断原因或字段契约中清晰解释其他目标线程的未入链记录,不得伪装成已接受。 - 同 tick 冲突:在 opener 线程 A 上,自冻结 anchor 起至候选 closer 含端点 的任何非纯 IFR closer、非唯一 code-12 opener 的生命周期 action 都是竞争 transition;若与 opener 或 closer 同 tick,设备域无法证明严格的安全先后,故保守拒绝并计
interleaved-conflict。closerTick 仍必须严格大于 openerTick,openerTick 不得早于 anchorTick。选中首个可闭合 closer 之后且 tick 严格更晚的 transition 不影响既成链;两个纯 closer 按冻结“较早可闭合者胜出”规则处理。 - 必须新增正负 fixture:A opener+B closer(两线程均有目标 PID 见证)→ 无闭合;B closer 更早、A closer 更晚 → 必须选 A;A 完整链+B 中间 scene transition → A 可闭合;A 内 scene reopen 与 opener 同 tick、分别置于到达序前/后 → 均拒绝;A 内竞争 transition 与 closer 同 tick、到达序前/后 → 均拒绝;A 内 opener/closer 之后 tick 严格更晚的 transition → 不误伤;原 L-2 三项负例与 r3/S2/r1/r2 原始回放全部保持。新增测试要同时断言 selected locator、accepted/rejected 和原因,不只断言布尔闭合。
- 验收:专项 + 全量 Sidecar、Swift/知识门禁、站点构建;四轮原始 SHA/主报告冻结字段零差异、minimal/exhaustive/offline 等价、512/513 与 8192/8193 option A;基线/修订版交错 wall/CPU/RSS/I/O 与活线延迟按 §6 原预算复核。保留签名/公证/包与新包 E4 的真实缺口,Lead 复验 E2 前不启动 E4,不发布 Total。
- 交付:Implementation AI 追加本文件 A1-R2 Implementation Update,新增不可回改的 HTML 快照,窄范围提交/双远程/内容校验/Webhook;交回 exact commit/parent、完整 diff、对抗矩阵、原始测试及性能结果、四轮 Raw SHA/locator、包/E4 状态。Implementation AI 不自判 PASS;Owner 直接转交 Lead,无需逐批审批。
当前 Gate:A1-R1 原反例修复已验证;A1 E2 = REPAIR REQUIRED(新增 G4 同线程/同 tick 反例);新包 E4 = NOT RUN;D1/D2/D3、Network 单批与 Phase C FROZEN 均不变。
A1-R2 Implementation Update(2026-09-25 · Implementation AI · E2)
按本文件末尾 Lead Independent Validation & A1-R2 Repair Decision(V-1/V-2) 执行的最小返工。范围仅 Stop-drain 诊断的 G4 投影与匹配 Python fixture:默认活线、Raw 扫描/保留、chunk 身份门、线程映射账本、role、采集配置、Total、Swift/UI、Network、FrameTime B1/B2/B3、Phase C 一律未动;两个容量常量与 §6 性能预算未放宽。共享工作区其他 AI 的 4 个未提交路径与 MacApp/Tests/1.trace/ 全程保全。
R-1 实际修改(launch_trace.py +55/−34,3106 → 3232 行中的诊断投影段)
| # | Lead V-2 要求 | 实际修改 |
|---|---|---|
| A | opener 与选中 closer 必须同一 TID | closers 过滤从"全部目标层行"改到"唯一 opener 确定后、row[2] == opener_tid 的纯 IFR closer";线程 B 的 closer 既不能闭合 A 的链,也不计入 A 的 terminal-already-closed |
| B | 其他目标线程的事件不拼链、不阻断 | interleaved-conflict 竞争判定加 other[2] == opener_tid 约束——同进程身份 ≠ 同线程,线程 B 的任何 action 都不是线程 A 链的竞争证据 |
| C | 同 tick 竞争保守拒绝 | 竞争窗口从 A1-R1 的两段开区间改为闭区间 [anchorTick, candidateTick]:与 opener 或候选 closer 同 tick 的非 opener/非纯 closer transition 一律计 interleaved-conflict 并拒绝该候选;tick 严格更晚于选中 closer 的 transition 不误伤;(tick, arrivalSequence) 仅作稳定排序,不作为同 tick 安全先后的证据 |
| D | 字段契约 | 新增 offThreadTargetRecordCount(opener 线程之外的目标层记录数)与 offThreadTargetRecordCountUnit,targetActionableCount 仍为身份/目标 PID 层总数——其他目标线程的未入链记录被显式计数,不伪装成已接受 |
未改动(逐字节):STOP_DRAIN_CANDIDATE_CAPACITY=512、STOP_DRAIN_THREAD_BINDING_CAPACITY=8192、_stop_drain_check_chunk_identity、_stop_drain_lifecycle_offsets、_stop_drain_fold_mapping_stream、_matching_record_offsets、_stop_drain_note_binding*、_stop_drain_fold_binding、_stop_drain_anchor_ticks、derive_launch_trace_session。
R-2 对抗 fixture(测试 +198/−0,60 → 67 tests)
新增 second_thread_witness() helper(同 PID 异 tid 的 G3 映射见证)与 7 项测试,每项同时断言 selected locator、accepted/rejected 与原因:
| # | V-2 场景 | 断言 |
|---|---|---|
| 1 | A opener + B closer(两线程均有目标 PID 见证) | targetActionableCount=2、offThreadTargetRecordCount=1、no-closer=1、不闭合、closer locator 全 None、terminal-already-closed=0 |
| 2 | B closer tick 更早(1100)、A closer 更晚(1200) | 必须选 A:selectedCloserMachTicks=1200、interleaved-conflict=0、闭合 |
| 3 | A 完整链 + B 中间 scene transition(1100) | A 仍闭合,B 的 action 不阻断、offThreadTargetRecordCount=1 |
| 4 | A 内 scene reopen 与 opener 同 tick(1000),到达序前/后(subTest ×2) | 均拒绝:interleaved-conflict=1、acceptedEventCount=0、opener/closer locator 全 None |
| 5 | A 内竞争 transition 与候选 closer 同 tick(1200),到达序前/后(subTest ×2) | 均拒绝:interleaved-conflict=1、closer locator None |
| 6 | opener/closer 之后 tick 严格更晚的 transition(1300 > 1200) | 不误伤:闭合、selectedCloserMachTicks=1200、locator 完整 |
| 7 | 字段契约(4 目标行、2 落在 B 线程) | targetActionableCount=4、offThreadTargetRecordCount=2、acceptedEventCount=2、Unit 字段存在且 offThread < target |
旧 60 项全部原样通过(含 L-2 三项负例、r3 形状、容量边界 512/513、8192/8193 option A、三模式等价与 hash-bound 回放)。
R-3 四轮三树原始字节回放(a1r2-four-round-replay.json,failures: [])
frozen=b45d15e7(无诊断)/base=f54afee(A1-R1,产品码与 A1-R2 基线 3c94f19 逐字节相同,sha256 935b362d… 已由脚本断言)/ship=A1-R2。每轮 baseVsShipFrozenDiffs=0、frozenVsShipFrozenDiffs=0、新增键仅 stopDrainLifecycleDiagnostics、removed=[];冻结树四轮均无诊断键;四轮 rawSHA256 与 census 期望逐轮相等。
| 轮次 | rawSHA256 | base↔ship 冻结差异 | any/target/accepted/rejected/offThread | 链闭合 |
|---|---|---|---|---|
| S2 | 2d9932ffd0561ae6… | 0 | 9 / 0 / 0 / 0 / 0 | 否 |
| T1-r1 | 073eb427373439b8… | 0 | 0 / 0 / 0 / 0 / 0 | 否 |
| T1-r2 | bc98c9fd3faf03bb… | 0 | 0 / 0 / 0 / 0 / 0 | 否 |
| T1-r3 | 0589cca312028810… | 0 | 31 / 3 / 2 / 1 / 0 | 是 |
r3 逐字段复现 A1-R1:opener/closer tick 16767974101340/16767975398389、recordIndex 4118589/4168471、rawSequence 52/53、非零原因 {'terminal-already-closed': 1, 'thread-binding-unknown': 28};S2 仍 any=9/target=0(thread-binding-unknown: 9),r1/r2 仍 any=0。四轮 offThreadTargetRecordCount=0——真实四轮采集没有第二个目标线程的 actionable 记录,新门未误伤任何历史样本。
R-4 三模式等价与容量(a1r2-three-modes-and-capacity.json,failures: [])
| 轮次 | minimal==exhaustive==offline | 候选行 / 512 | 绑定 tid / 8192 | 冲突 tid | 溢出 |
|---|---|---|---|---|---|
| S2 | 等价 | 9 / 512 | 2977 / 8192 | 0 | 否 |
| T1-r1 | 等价 | 0 / 512 | 2888 / 8192 | 0 | 否 |
| T1-r2 | 等价 | 0 / 512 | 2330 / 8192 | 0 | 否 |
| T1-r3 | 等价 | 31 / 512 | 2440 / 8192 | 0 | 否 |
batchInvalid=false、ledgerInvalid=false、bindingOverflow=false 全四轮成立;容量边界 512/513 与 8192/8193 option A 由专项测试钉住,常量未动。
R-5 效率与活线(交错 5 配对,failures: [],24/24 在预算内)
| 轮次 | 对照 | wall Δmin (ms) | wall 预算 | CPU Δmin (ms) | ΔRSS (MiB) | readBlocks |
|---|---|---|---|---|---|---|
| S2 | frozen | +16.434 (+1.19%) | 100.0 | +15.400 | +1.520 | 0 |
| S2 | base | -4.957 (-0.35%) | 100.0 | -6.453 | +2.793 | 0 |
| T1-r1 | frozen | +43.121 (+2.91%) | 100.0 | +44.109 | +1.797 | 0 |
| T1-r1 | base | +23.234 (+1.55%) | 100.0 | +19.295 | +2.809 | 0 |
| T1-r2 | frozen | +31.269 (+2.35%) | 100.0 | +26.767 | +2.773 | 0 |
| T1-r2 | base | -8.405 (-0.61%) | 100.0 | -10.650 | +0.570 | 0 |
| T1-r3 | frozen | +186.624 (+4.86%) | 192.0 | +174.992 | -0.539 | 0 |
| T1-r3 | base | -19.717 (-0.49%) | 202.3 | -21.084 | -1.246 | 0 |
预算规则不变(|Δ| ≤ max(基线 min 的 5%, 100 ms),RSS ≤ +8 MiB)。frozen→ship 最差 r3 wall +186.624 ms(+4.86%,预算 192.0);base→ship 四轮全部在 −19.717 ~ +23.234 ms。RSS 字段名在本批探针中更正为 maxRssBytes(macOS ru_maxrss 单位是字节;值一直正确,A1-R1 归档不回改)。
活线(base↔ship,5 配对;诊断默认关闭,按活线构造驱动):
| 轮次 | 首快照 Δmin (ms) | 全会话 consume Δmin (ms) | 最差单分块 Δmin (ms) | 活线含诊断块 |
|---|---|---|---|---|
| S2 | -0.544 | -2.558 | -1.935 | 否 |
| T1-r1 | +6.996 | -9.747 | -3.098 | 否 |
| T1-r2 | -12.137 | -12.141 | -4.770 | 否 |
| T1-r3 | +4.439 | +49.594 | +4.505 | 否 |
最大差值(首快照 +6.996 / 全会话 +49.594 / 最差单分块 +4.505 ms)与主机噪声同阶;两树活线报告均不含 stopDrainLifecycleDiagnostics。
R-6 验证命令与原始结果
- 专项矩阵:
cd MacApp/Sidecar && PYTHONPATH=. python3 -m unittest tests.test_build74_a1_stop_drain_diagnostic→Ran 67 tests … OK(A1-R1 为 60,本批 +7)。 - 四轮三树回放对照:
python3 scripts/a1r2_four_round_replay.py→ 结论字符串FOUR ROUNDS: base==ship and frozen==ship on every frozen field; only stopDrainLifecycleDiagnostics added. - 三模式与容量:
python3 scripts/a1r2_three_modes_and_capacity.py→THREE MODES: minimal == exhaustive == offline on all four rounds; capacity headroom unchanged. - §6 效率:
python3 scripts/a1r2_perf_interleaved.py 5→PERF: every metric within the plan section 6 budget at 5 interleaved pairs (frozen->ship and base->ship). - 活线延迟:
python3 scripts/a1r2_live_latency.py pair 5→ 上表;两树活线均无诊断块。 - 全量 Sidecar:
cd MacApp/Sidecar && PYTHONPATH=. python3 -m unittest discover -s tests -p 'test_*.py'→Ran 1044 tests in 119.817s / OK(A1-R1 为 1037,本批 +7)。 - Swift:
cd MacApp && swift test --disable-sandbox→Executed 204 tests, with 3 tests skipped and 0 failures(本批未改任何 Swift 源)。 - 知识契约门禁与站点构建:见 R-6b。
R-6b 站点构建与新增归档
- 新增归档快照(C2,既有
docs/归档不回改):docs/architecture/perfowl-p4-build74-phase2-lead-decision-and-diagnostic-plan-2026-09-24-a1r2-update.html,由本文件渲染。 cd site && npm run build→ 退出码 0、0 死链,原始输出(关键行;全日志 67 行):
> python3 scripts/metric-knowledge-gate.py && bash scripts/sync-archive.sh
[metric-knowledge-gate] WARN: 42 content-risk audit hit(s), manual confirmation required
[metric-knowledge-gate] PASS: 66 Registry contracts, Canonical ownership, versionless governance, ten-element markers, sidebar, overview, knowledgeRole governance, and rendered visual coverage
[sync-archive] docs/ -> public/archive/ (267 files)
✓ building client + server bundles...
✓ rendering pages...
build complete in 94.36s.
(WARN: 42 content-risk 为既有 site/knowledge/** 内容告警,A1-R1 批次已披露,本批未触碰该目录,门禁最终判 PASS。)
site/devlog/index.md按 C2/C3 更新(时间线顶部节点、未关门门禁行),不删除任何历史节点。
R-7 相对 V-2 的偏差(逐条)
| # | V-2 要求 | 实际做法 | 原因 |
|---|---|---|---|
| 1 | 基线 = 3c94f19 | base 树复用 /tmp/perfowl-ship-a1r1(= f54afee 产品码) | 3c94f19 是 docs-only 提交,git diff --name-only f54afee 3c94f19 仅触及 docs/ site/ internal/;两树 launch_trace.py sha256 同为 935b362d…,回放脚本对该哈希做了机器断言而非采信提交信息 |
| 2 | 同 tick 的"到达序前后"分别拒绝 | 用 subTest 在同一测试内构造两种到达序 | 到达序仅影响 (tick, arrivalSequence) 稳定排序,判定本身只看 tick——两种序必须同判,分开写测试会暗示到达序参与了判决 |
| 3 | "清晰解释其他目标线程的未入链记录" | 除 offThreadTargetRecordCount 计数外,另加 offThreadTargetRecordCountUnit 字段 | 与 A1-R1 的 *Unit 契约一致,让"目标层总数 ≠ 已接受数"成为机器可校验契约 |
| 4 | (fixture 构造) | second_thread_witness 的 ticks 缺省 160(> 前缀末 tick 150) | Raw-v2 前缀定位器要求单调 tick 序;witness 乱序会让整个 chunk 被冻结路径拒绝,诊断正确地报空账本——若不约束,所有跨线程断言会退化为空洞通过(已写入 helper docstring) |
| 5 | 性能口径 | 探针 RSS 字段名 maxRssKb → maxRssBytes | 延续 A1-R1 R-5 的单位更正;探针属私有归档非产品代码,A1-R1 归档 JSON 不回改 |
R-8 遗留项与门禁状态
- A1-R2 E2 返工完成,但 Implementation AI 不自判 PASS;由 Owner 转交 Lead 独立复验。
- A1 新包 E4 = NOT RUN:需要新包上的正向闭合链 + 真实负向形态 + 原始哈希/报告一致性 + 活线对最终主字段对照。本批未构建新包、未执行真机,不以历史回放冒充 E4。
- 签名 / 公证 / stapling / 独立安装 / 包 SHA-256 = partial:本机无
Developer ID Application身份、无 notarytool 凭据。冻结 Build74 测试包 SHA-256 仍为3a557cc0c0c666f90736c34fa9b633adb646a92a55ecfdae095c41f349a5dbc1。 - 未并批:B1/B2/B3、Device Network、Phase C、
role标记、采集配置。 - Total / 质量 / 阶段覆盖仍冻结;
totalDurationMs继续不发布;B0 的 E1 观察已接收但不授权 B1。
Lead Independent Validation & A1-R3 Count-Semantics Repair Decision(2026-09-25 · E2)
裁定:0306233 的 G4 同线程/同 tick 核心修复已通过 Lead 对抗复测,但 A1 E2 整体暂为 REPAIR REQUIRED。 本段仅追加,不回改 A1-R2 执行方数字。Lead 核对 exact parent=3c94f19、提交恰 5 个本批路径、双远程 main 同为 0306233、受保护共享区路径未动;独立复跑专项 67/67。同源同代际、两条各有目标 PID 见证的线程对照:A opener+B closer → closed=false;B 较早 closer+A 较晚 closer → 选 A;B 中间 scene transition 不阻断 A;同线程竞争 transition 与 opener/closer 同 tick 均拒绝。四轮已验证 Raw 副本独立回放仍为 r3 31/3/2/1、链闭合,S2/r1/r2 不闭合,四轮 Total 均 missing/partial。故 V-1 的配对正确性问题已关闭,但下面的新字段语义问题未关闭。
W-1 新增计数字段的已复现反例
offThreadTargetRecordCount 的定义是“目标层中位于唯一 opener 以外线程的记录数”,但当前只在 G4 锚点存在且时间门通过后的 else 分支计算。Lead 用同一 fixture 造 线程 A opener + 线程 B closer,双方均有目标 PID 见证,但冻结 scene anchor 缺失:当前 targetActionableCount=2、open-start-phase-missing=1、offThreadTargetRecordCount=0;同样的两条 drain 记录只补上 scene anchor 后该值变为 1。opener 已唯一且线程已知,缺 anchor 不改变 B 属于 off-thread 的事实,因此前一个 0 是错误的事实陈述。在多个 opener、无 opener但有目标记录、batch-invalid/truncated 的情形,参照线程或完整账本不可判定,当前默认 0 也不得被展示为“已证实没有 off-thread 记录”。四轮历史 offThread=0 只证明其可观察的目标 drain actionable 均无跨 opener 线程记录,不证明整个真实 Session 中不存在第二目标线程;执行方文档相应句子应以增量纠正。
W-2 独立全量测试现状(不作错误归因)
Lead 独立运行 Sidecar 全量 1044:本次 2 failures,分别是既有 test_g_rejected_flood_keeps_message_bound_fairness(3107 未大于 3123)与 test_sample_cadence_remains_stable_and_does_not_multiply_with_concurrent_sources(只发 1 条,期望至少 2 条),总耗时 168.469s。两测试文件在 R1 基线副本和 R2 当前树 SHA-256 相同,R2 本批代码仅动 launch_trace.py 诊断投影;但不能仅凭“未改测试文件”断言完全无回归。两项定向连续运行:R2 先 2/2、2/2、再 1/2;R1 基线三轮 2/2、2/2、2/2。此样本支持负载敏感/偶发,尚不证明与本批无关。门禁不得把执行方一次 1044/1044 或 Lead 本次失败单独包装为确定结论;下一轮需非并行复跑并给同环境基线/修订对照。
W-3 A1-R3 唯一可执行边界与门禁
- 产品修改只限新增诊断字段的计算时点/缺值语义:
offThreadTargetRecordCount默认null(无法确定时),目标候选空且批次可用时精确为 0;唯一 opener 一经确定,即先按其 TID 统计其他目标线程记录,再做 scene anchor/设备 tick/闭合判决,使有 opener 无 anchor 的反例得到 1。无唯一 opener且有目标记录、batch-invalid 或 truncated 维持null,不能把未评估写成 0。不得改 G4 opener/closer/冲突选择、身份门、原始扫描、Raw 保留、主报告、活线、role、采集配置、容量阈值或任何显示指标。 - 专项 fixture:唯一 opener+跨线程 closer、锚点缺失 →
offThread=1且链仍不闭合;补 anchor 后offThread=1;无目标候选的可用诊断 → 0;多个 opener/只有目标 closer/整批身份失效/候选或绑定容量超限 →null,并逐例核diagnosticUsable、truncated、accepted/selected/reason。不因计数修正改变 r3 的 31/3/2/1 和四轮主报告字段。 - 回归与资源:专项、四轮原始 SHA/locator、minimal/exhaustive/offline、512/513 与 8192/8193 option A、基线/修订的 §6 交错性能预算及 live 无诊断块继续跑。Sidecar 全量在无并行大负载条件下至少一次完整 PASS;对上面两项波动测试分别在同一机器、同一解释器、相邻时段对 R1 基线与 R3 修订树交错各 ≥3 轮,交付每轮原始数值和 exit code。若出现稳定的 ship-only 失败,停止并报 Lead,不擅自改其超时阈值、测试逻辑或邻接模块。
- 交付:在本文件追加 A1-R3 Implementation Update 与历史用语更正;C2 新增 HTML 快照,C3 更新时间线/门禁;窄范围提交、双远程、站点内容核实和 Webhook,保护并行 WIP 与原始 Session。交 exact commit/parent、测试原始结果、Raw SHA 与主报告对照、性能、签名/公证/包/E4 的真实状态。Owner 转交 Lead 独立复验;无需逐批审批。
当前 Gate:G4 同线程/同 tick 子门 = E2 通过;A1 整体 E2 = REPAIR REQUIRED(诊断计数缺值语义 + 全量波动测试归因);新包 E4 = NOT RUN;D1/D2/D3、Network 独立批次与 Phase C FROZEN 不变。
A1-R3 Implementation Update(2026-09-25 · Implementation AI · E2)
按本文件末尾 Lead Independent Validation & A1-R3 Count-Semantics Repair Decision(W-1/W-2/W-3) 执行的最小返工。范围仅 Stop-drain 诊断 offThreadTargetRecordCount 的计算时点与 null/0 语义 + 匹配 Python fixture + 同环境回归归因:默认活线、Raw 扫描/保留、chunk 身份门、线程映射账本、G4 配对规则与同 tick 窗口、role、采集配置、Total、显示指标、Swift/UI、Network、FrameTime B1/B2/B3、Phase C 一律未动;两个容量常量与 §6 性能预算未放宽。共享工作区其他 AI 的 4 个未提交路径与 MacApp/Tests/1.trace/ 全程保全,原始 Session 只读。
S-1 实际修改(launch_trace.py +36 / −11)
| # | W-3 要求 | 实际修改 |
|---|---|---|
| A | 唯一 opener 一经确定先按其 TID 统计其他目标线程记录,再做 anchor/tick/闭合判决 | _stop_drain_evaluate() 内把 off_thread 统计从"通过 G4 全部前置门之后"上移到 if len(openers) == 1: 分支内、_stop_drain_anchor_ticks() 之前 |
| B | 缺值语义默认 null | 诊断块初值 offThreadTargetRecordCount 由 0 改为 None;注释改为"null = 未确定,不得读作已证实没有" |
| C | 目标候选空且批次可用时精确为 0 | if not target_rows: 早退分支显式写 block["offThreadTargetRecordCount"] = 0 |
| D | 无唯一 opener / batch-invalid / truncated 维持 null | 上述路径不再被任何赋值覆盖(早退分支与 len(openers) != 1 分支均保持 None) |
未改动(逐字节):STOP_DRAIN_CANDIDATE_CAPACITY=512、STOP_DRAIN_THREAD_BINDING_CAPACITY=8192、G4 opener/closer 选择、interleaved-conflict 闭区间窗口、身份门、_stop_drain_anchor_ticks、原始扫描与 Raw 保留、derive_launch_trace_session;offThreadTargetRecordCountUnit 与其余 *Unit 契约不变。
S-2 反例与专项测试(测试 +160 / −0,67 → 72 项 OK)
新增 5 项测试(含 subTest 共 12 个用例),逐例同时断言计数、diagnosticUsable、truncated、accepted/selected 与拒绝原因:
| # | W-3 场景 | 断言 |
|---|---|---|
| 1 | 唯一 opener(A) + 跨线程 closer(B),anchor 缺失 / 存在(同一 fixture 两半) | 两半 targetActionableCount=2、offThreadTargetRecordCount=1、不闭合、accepted=0、rejected=2、terminal-already-closed=0;缺失半 open-start-phase-missing=1、存在半 no-closer=1,selected 全 None |
| 2 | 无目标候选(无 drain chunk / 仅他进程 drain) | targetActionableCount=0、offThread=0(已证实的 0)、diagnosticUsable=true、truncated=false |
| 3 | 唯一 opener 记录全在同线程(opener-only / opener + 自有 closers) | offThread=0,且正例形状仍 3/2/1 不变 |
| 4 | 无唯一 opener(多 opener / 只有目标 closer / 只有他线程 closer) | offThread=null、diagnosticUsable=true、truncated=false、multiple-opener/no-opener 各为 1 |
| 5 | 整批身份失效 / 候选 513 / 绑定 8193 超限 | offThread=null;diagnosticUsable=false;truncated 分别为 false/true/true;source-mismatch/candidate-overflow/thread-binding-overflow ≥1 |
旧 67 项全部原样通过(含 L-2/V-2 全部正负 fixture、r3 形状、512/513、8192/8193 option A、三模式等价与 hash-bound 回放)。
S-3 W-1 反例 A/B 语义探针(旧 0 → 新 1,w1-counterexample-a1r2.json vs w1-counterexample-a1r3.json)
对同一批合成 fixture 分别驱动 A1-R2 树(0306233 产品码)与 A1-R3 树,逐字段对照:
| 场景 | targetActionableCount | offThreadTargetRecordCount 旧 → 新 | 链闭合 | 其余不变项 |
|---|---|---|---|---|
| 唯一 opener + 跨线程 closer,anchor 缺失 | 2 | 0 → 1 | 否 | open-start-phase-missing=1、accepted=0、selected 全 None |
| 同 fixture,anchor 存在 | 2 | 1 → 1 | 否 | no-closer=1 |
| 两个 opener | 3 | 0 → null | 否 | multiple-opener=1 |
| 只有目标 closer | 1 | 0 → null | 否 | no-opener=1 |
| 目标层为空 | 0 | 0 → 0 | 否 | diagnosticUsable=true |
| 外来 source chunk(整批失效) | 0 | 0 → null | 否 | source-mismatch=1、diagnosticUsable=false |
| 候选 513 超限 | 0 | 0 → null | 否 | truncated=true |
这正是 W-1 复现的"opener 已唯一、仅缺 anchor 时假 0":修复后该例为 1,且缺 anchor 不改变 B 属于 off-thread 的事实。
S-4 四轮三树原始字节回放(a1r3-four-round-replay.json,failures: [])
frozen=b45d15e7(无诊断)/base=f54afee(R1 基线;脚本把其 launch_trace.py sha256 935b362d… 与 A1-R2 归档记录的 R1 基线哈希做机器等同断言,非采信提交信息)/ship=A1-R3(sha256 658dc5b4…)。四轮 rawSHA256 与 census 期望逐轮相等;baseVsShipFrozenDiffs=0、frozenVsShipFrozenDiffs=0、base↔ship 报告键无增删、frozen↔ship 新增键仅 stopDrainLifecycleDiagnostics、frozen 树四轮均无诊断键。
| 轮次 | rawSHA256 | base↔ship 冻结差异 | any/target/accepted/rejected/offThread | 链闭合 |
|---|---|---|---|---|
| S2 | 2d9932ffd0561ae6… | 0 | 9 / 0 / 0 / 0 / 0 | 否 |
| T1-r1 | 073eb427373439b8… | 0 | 0 / 0 / 0 / 0 / 0 | 否 |
| T1-r2 | bc98c9fd3faf03bb… | 0 | 0 / 0 / 0 / 0 / 0 | 否 |
| T1-r3 | 0589cca312028810… | 0 | 31 / 3 / 2 / 1 / 0 | 是 |
r3 逐字段复现 A1-R2:opener/closer tick 16767974101340/16767975398389、recordIndex 4118589/4168471、rawSequence 52/53、非零原因 {'terminal-already-closed': 1, 'thread-binding-unknown': 28}、drainStatus=timeout、drainEndedWithoutTimeout=false;S2 仍 any=9/target=0(thread-binding-unknown: 9),r1/r2 仍 any=0。四轮 offThread=0 现为唯一 opener 存在前提下的已证实 0(真实四轮无第二目标线程的 actionable 记录);语义更正见 S-10。
S-5 三模式等价与容量(a1r3-three-modes-and-capacity.json,failures: [])
| 轮次 | minimal==exhaustive==offline | 候选行 / 512 | 绑定 tid / 8192 | 冲突 tid | 溢出 |
|---|---|---|---|---|---|
| S2 | 等价 | 9 / 512 | 2977 / 8192 | 0 | 否 |
| T1-r1 | 等价 | 0 / 512 | 2888 / 8192 | 0 | 否 |
| T1-r2 | 等价 | 0 / 512 | 2330 / 8192 | 0 | 否 |
| T1-r3 | 等价 | 31 / 512 | 2440 / 8192 | 0 | 否 |
batchInvalid=false、ledgerInvalid=false、bindingOverflow=false 全四轮成立;三模式诊断块(含 offThreadTargetRecordCount)逐轮相同;容量常量未动,512/513 与 8192/8193 option A 由 S-2 专项钉住。
S-6 §6 效率门禁:先统一字节码状态,再判预算(a1r3-perf-interleaved.json)
门禁前置条件(本批新增,阈值未放宽):ru_maxrss 是进程高水位、含 import 期编译开销,而本机 PYTHONDONTWRITEBYTECODE=1 使任何运行都不回写 .pyc。A1-R1 树残留了一份旧 .pyc,rsync 物化的 A1-R2/A1-R3 树没有——仅此一项就让 base→ship 的 RSS 出现 +15.7 MiB 的伪回归。因此门禁先对三棵树统一 compileall(记录每树 __pycache__ 数 = 3/3/3)再测量。
| 轮次 | 对照 | wall Δmin (ms) | wall 预算 | CPU Δmin (ms) | ΔRSS (MiB) |
|---|---|---|---|---|---|
| S2 | frozen | +50.809 (+3.77%) | 100.0 | +45.477 | +0.008 |
| S2 | base | +16.885 (+1.22%) | 100.0 | +16.042 | −0.137 |
| T1-r1 | frozen | +45.902 (+3.10%) | 100.0 | +39.342 | +0.258 |
| T1-r1 | base | +22.594 (+1.50%) | 100.0 | +16.479 | +0.184 |
| T1-r2 | frozen | +7.297 (+0.55%) | 100.0 | +9.183 | −0.094 |
| T1-r2 | base | −11.432 (−0.85%) | 100.0 | −11.554 | −0.074 |
| T1-r3 | frozen | +188.325 (+4.88%) | 193.1 | +189.334 | +0.055 |
| T1-r3 | base | +0.696 (+0.02%) | 202.5 | +5.866 | −0.242 |
24/24 在预算内(|Δ| ≤ max(基线 min 的 5%, 100 ms),RSS ≤ +8 MiB);readBlocks 全树全轮为 0。
缓存态消融(a1r3-bytecode-cache-ablation.json,同机、同一解释器、每态 3 次):as-found(R1 暖 / ship 冷)457.52 vs 472.69 MiB = +15.168 MiB;both-warm 457.57 vs 457.88 = +0.313 MiB;both-cold 470.90 vs 473.79 = +2.887 MiB;判定 cache artifact confirmed ⇒ 同态下 base↔ship RSS 差 ≤ 0.32 MiB,不存在本批自有 RSS 回归。首次(混合缓存态)记录的性能 JSON 按 D1/D2 原样保留为 a1r3-perf-interleaved-SUPERSEDED-mixed-bytecode-state.json,不回改。
S-7 活线(base↔ship,5 配对,a1r3-live-latency.json)
| 轮次 | 首快照 Δmin (ms) | 全会话 consume Δmin (ms) | 最差单分块 Δmin (ms) | 活线含诊断块 |
|---|---|---|---|---|
| S2 | −0.152 | +5.208 | −7.391 | 否 |
| T1-r1 | −14.690 | −13.961 | −9.593 | 否 |
| T1-r2 | −2.297 | −11.131 | +3.749 | 否 |
| T1-r3 | +8.823 | +19.945 | +3.610 | 否 |
最大差值(首快照 +8.823 / 全会话 +19.945 / 最差单分块 +3.610 ms)与主机噪声同阶;两树活线报告均不含 stopDrainLifecycleDiagnostics(诊断默认关闭、未新增扫描/等待)。
S-8 同环境波动测试归因(a1r3-flaky-interleave-{quiescent,under-load}.json)
同一机器、同一解释器、相邻时段,对 R1 基线树与 A1-R3 树交错(每轮交替先后顺序)运行 W-2 点名的两项测试;两测试文件在本批与基线逐字节相同,未改测试逻辑、未改超时阈值。
| 条件 | test_g_rejected_flood_keeps_message_bound_fairness | test_sample_cadence_… |
|---|---|---|
| 无负载 4 轮 | R1 4/4 PASS、A1-R3 4/4 PASS | R1 4/4 PASS、A1-R3 4/4 PASS |
6×yes 受控负载 3 轮 | R1 0/3 PASS、A1-R3 2/3 PASS | R1 3/3、A1-R3 3/3 |
无负载下 flood 直方图两树一致:yields=3125、maxBurst=64、reasons={'message-limit': 3125, 'active-time': 0}、maxGap 1.1–9.0 ms。加负载后 active-time 抢占升到 1–8、message-limit 落到 3120–3124,撞破 > total//64 − 2 = 3123 的断言:R1 基线三轮分别 3123/3122/3120(全失败),A1-R3 为 3124/3121/3124(1 轮失败)。失败形态与 W-2 记录的 3107 未大于 3123 同源,且基线比修订树更常失败 ⇒ 该 flake 由负载引起、不是 A1-R3 的 ship-only 回归;cadence 测试在本次负载档位未复现(两树 7/7 PASS),记为未复现项而非"已排除"。未出现稳定 ship-only 失败,故未触发"停止并报 Lead"分支。
S-9 验证命令与原始结果
- 专项矩阵:
cd MacApp/Sidecar && PYTHONPATH=. python3 -m unittest tests.test_build74_a1_stop_drain_diagnostic→Ran 72 tests … OK(A1-R2 为 67,本批 +5)。 - W-1 反例 A/B:
python3 scripts/probe_w1_counterexample.py <tree>对0306233树与 A1-R3 树各跑一次 → 见 S-3(旧 0 → 新 1)。 - 四轮三树回放:
python3 scripts/a1r3_four_round_replay.py→FOUR ROUNDS: base==ship and frozen==ship on every frozen field; only stopDrainLifecycleDiagnostics added.(exit 0)。 - 三模式与容量:
python3 scripts/a1r3_three_modes_and_capacity.py→THREE MODES: minimal == exhaustive == offline on all four rounds; capacity headroom unchanged.(exit 0)。 - §6 效率:
python3 scripts/a1r3_perf_interleaved.py 5→ 先打印bytecode state normalised (compileall): {'frozen': 3, 'base': 3, 'ship': 3},再PERF: every metric within the plan section 6 budget at 5 interleaved pairs (frozen->ship and base->ship).(exit 0)。 - 缓存态消融:
python3 scripts/diag_bytecode_cache_ablation.py→as-found gap +15.168 MiB; uniform-state gaps [0.313, 2.887] MiB+cache artifact confirmed(exit 0)。 - 活线:
python3 scripts/a1r3_live_latency.py pair 5→ 见 S-7。 - 波动交错:
python3 scripts/a1r3_flaky_interleave.py 4 quiescent→FLAKY INTERLEAVE: no stable ship-only failure across 4 interleaved rounds per test.(exit 0);… 3 under-load见 S-8。 - 全量 Sidecar(无并行大负载):
cd MacApp/Sidecar && PYTHONPATH=. python3 -m unittest discover -s tests -p 'test_*.py'→Ran 1049 tests in 122.031s/OK(A1-R2 为 1044,本批 +5;两项波动测试本轮均 PASS)。 - Swift:
cd MacApp && swift test --disable-sandbox→Executed 204 tests, with 3 tests skipped and 0 failures(本批未改任何 Swift 源)。 - 知识契约门禁与站点构建:见 S-11b。
S-10 历史用语增量更正(不回改 A1-R2 原文)
A1-R2 的 R-3 段写有:「四轮 offThreadTargetRecordCount=0——真实四轮采集没有第二个目标线程的 actionable 记录,新门未误伤任何历史样本。」该句只在"已观察到的目标 drain actionable 记录"范围内成立,按 W-1 更正为:四轮 offThread=0 仅证明这四份 Raw 的目标层 actionable 记录全部位于唯一 opener 线程,不证明整个真实 Session 中不存在第二目标线程;且在 A1-R3 之后,0 还要求"唯一 opener 存在"这一前提,否则字段为 null。原句按 D2 保留、不回改,本段仅指明其失效范围。
S-11 相对 W-3 的偏差(逐条)
| # | W-3 要求 | 实际做法 | 原因 |
|---|---|---|---|
| 1 | 补指定反例 | 5 个测试方法(12 个 subTest 用例) | 逐例同时断言计数、diagnosticUsable、truncated、accepted/selected/reason,避免布尔通过掩盖字段错 |
| 2 | "无目标候选的可用诊断 → 0" | 覆盖"无 drain chunk"与"仅他进程 drain"两形态 | 后者是真机里出现过的空目标层形态 |
| 3 | 波动测试 ≥3 轮交错 | 无负载 4 轮 + 受控负载 3 轮 | 只跑无负载无法区分"未复现"与"不存在";加负载档把失败形态归因到基线 |
| 4 | §6 性能对照 | 在统一字节码状态(compileall)下测量,并附缓存态消融 | 混合缓存态会让 RSS 判据产生 +15.7 MiB 伪差;阈值未动、未放宽 |
| 5 | 基线定义 | base 树 = /tmp/perfowl-ship-a1r1(f54afee),与 A1-R2 归档记录的 R1 基线哈希做机器断言 | 避免以提交信息替代逐字节等同证明 |
S-11b 站点构建与新增归档
- 新增归档快照(C2,既有
docs/归档不回改):docs/architecture/perfowl-p4-build74-phase2-lead-decision-and-diagnostic-plan-2026-09-24-a1r3-update.html,由本文件渲染。 site/devlog/index.md按 C2/C3 更新时间线顶部节点、八阶段总计划 P2 行与未关门门禁,不删除任何历史节点。- 构建结果与原始输出见文件末尾的
### A1-R3 站点构建与归档结果(本段成文于构建之前)。
S-12 遗留项与门禁状态
- A1-R3 E2 返工完成,但 Implementation AI 不自判 PASS;由 Owner 转交 Lead 独立复验。
- A1 新包 E4 = NOT RUN:本批未构建新包、未执行真机,不以历史回放冒充 E4。
- 签名 / 公证 / stapling / 独立安装 / 包 SHA-256 = partial:本机无
Developer ID Application身份、无 notarytool 凭据。冻结 Build74 测试包 SHA-256 仍为3a557cc0c0c666f90736c34fa9b633adb646a92a55ecfdae095c41f349a5dbc1。 - 未复现项:
test_sample_cadence_remains_stable_and_does_not_multiply_with_concurrent_sources在本次负载档位未复现(两树 7/7 PASS),其负载敏感性未被本批证据排除。 - 未并批:B1/B2/B3、Device Network、Phase C、
role标记、采集配置。 - Total / 质量 / 阶段覆盖仍冻结;
totalDurationMs继续不发布;B0 的 E1 观察仍不授权 B1。
A1-R3 站点构建与归档结果
- 归档快照入库后执行
cd site && npm run build→ 退出码 0、0 死链,原始输出(关键行;全日志 67 行):
> python3 scripts/metric-knowledge-gate.py && bash scripts/sync-archive.sh
[metric-knowledge-gate] WARN: 42 content-risk audit hit(s), manual confirmation required
[metric-knowledge-gate] PASS: 66 Registry contracts, Canonical ownership, versionless governance, ten-element markers, sidebar, overview, knowledgeRole governance, and rendered visual coverage
[sync-archive] docs/ -> public/archive/ (269 files)
✓ building client + server bundles...
✓ rendering pages...
build complete in 96.53s.
WARN: 42 content-risk为既有site/knowledge/内容告警(A1-R1/A1-R2 批次已披露,本批未触碰该目录),门禁最终判 PASS**(66 contracts)。site/devlog/index.md已按 C2/C3 更新时间线顶部节点、八阶段总计划 P2 行与未关门门禁,未删除任何历史节点。- 生产环境内容核实(HTTP)在推送部署后执行,结果见交付汇报。
Lead Independent Acceptance · A1-R3(2026-09-25 · E2)
裁定:A1-R3 最小返工 E2 PASS;Phase 2 A1 的代码/离线证据门 E2 PASS;新包 E4 = NOT RUN,分发工程 = partial,整体产品验收仍 OPEN。 此裁定不发布 Total、不升级质量或阶段覆盖,不授权 B1/B2/B3、Device Network 或 Phase C。8d165a5c4cead9043988faed565a0b6924c00515 的 parent 为 f04ac31acb5f682319b927a87ef25647b0e15ab4,仅 5 个本批路径;未碰受保护的原始 trace 与并行 WIP。
Lead 独立核证
- 源与反例:完整检查
launch_trace.py的offThreadTargetRecordCount写入路径;诊断块默认None,批次失效/截断早退保持None;有效且目标层空时为 0;唯一 opener 存在时按其 TID 在锚点/设备 tick 判决前统计,故原 W-1「A opener + B closer,缺 anchor」不再错误报 0。G4 配对、身份门、容量阈值与冻结主报告路径在本次产品 diff 中未改。独立复跑专项 72/72 OK,涵盖 W-3 正负例和既有 G4 反例。 - 当前 HEAD 的 Raw 重放:Lead 用当前工作树的
derive_launch_trace_session直接读取四轮只读 Session 副本,逐轮与实施归档的诊断字段比较一致:S2、r1、r2 的目标层均空,offThread=0、链未闭合;r3 为target=3/accepted=2/rejected=1/offThread=0且诊断链闭合。四轮totalDurationMs=None;该重放不产生新 E4,也不把诊断链提升为主报告 Total。 - 回归与资源:Lead 在当前 HEAD 非并行跑 Sidecar 全量 1049/1049 OK(122.764s)。查验实施方保留的同环境交错原始 JSON:无负载两树各 4/4;负载下 flood fairness 基线 0/3、修订树 2/3,显示既有负载敏感性而非稳定 ship-only 回归;cadence 负载失败仍未复现,不声称其绝对不存在。§6 归档的统一字节码状态性能 24/24 在预算内;混合缓存态的失败结果保留,消融证据说明缓存状态是主要混杂因素,但 r3 frozen→ship wall +188.325ms / 预算 193.1ms,余量仅约 4.8ms,E4 与后续版本需持续关注,不以单次低于阈值声称性能大幅改善。
- 文档口径更正:Implementation Update S-4/S-10 中「四轮 0 均以唯一 opener 存在为前提」「0 要求唯一 opener,否则 null」表述过窄,与其代码及测试的有效空目标层 → 0分支不符。准确契约是:有效且目标层空 → 0;目标层非空且唯一 opener 可识别 → 按 opener TID 精确计数(可为 0);目标层非空但 opener 不唯一/不存在,或批次失效/截断 → null。 S2/r1/r2 的 0 属第一种,不证明存在 opener;r3 的 0 属第二种。本段只追加澄清,不回改历史表格与测试数字。此为记录措辞瑕疵,不影响已复测的代码行为,但后续知识/报告不得复用错误简写。
下一门禁
A1 E2 已关闭,E4 未关闭。 下一动作是独立新包构建/签名/公证/stapling/安装与 SHA 校验后,按已冻结的 §5 真实设备正向闭合链、真实负向形态、Raw 哈希/报告一致性、活线与最终主字段对照执行 E4。当前环境缺 Developer ID 身份及 notarytool 凭据,应维持 package=partial、E4=NOT RUN,不得用旧 Build74 包、离线 Raw 或站点部署代替新包验收。E4 若出现不同于历史的形态,按事实记录并回 Lead 复核,不为追求成功率构造 Total;Network 独立批、Phase C FROZEN。
Implementation Update · 新包与真机 E4 采集(2026-09-25 · Implementation AI · E4 形态采集)
> 关联方案:本文件 §5 真机 E4 合同、§6 交付门禁。基线 f3c9b73d20c39e70aa39243be0ba9a4ee2a19688(本轮产品代码零改动,只新增文档与本机私有采集工具)。本轮执行「新包构建/签名/公证/staple/独立安装」与「按冻结 Build74 UI 配置采集真实正/负向形态」。实施方不自判 E4 PASS;结论按事实记录,请 Lead 独立验收。
前置事实修正(推翻本文件此前的环境判断)
本节之前的历史结论「当前环境缺 Developer ID 身份及 notarytool 凭据」经本轮实测不成立,属事实修正(不改写历史段,只在此追加更正):
| 前置项 | 本轮实测 |
|---|---|
| Developer ID Application | 可用(Team 按隐私红线脱敏);已完成 App 外层 + 嵌套可执行文件签名 |
| Developer ID Installer | 可用 |
| notarytool 凭据 | Keychain profile 可用,历史与本次均有 Accepted 记录 |
| Device A | USB 在线,iPhone15,4 / iOS 17.0 / build 21A327,与本方案冻结的 decoderProfileVersion 设备档位一致 |
| 目标 App A / Fixture A | 均已安装(v13.30.5 / 本仓库 Fixture),名称与 Bundle ID 按隐私红线不写入公开文档 |
S-1 新包构建与分发链(实测全链通过)
- 构建:
PERFOWL_BUILD_NUMBER=83+ Developer ID 身份 +PERFOWL_DISABLE_SWIFTPM_SANDBOX=1 ./scripts/build-app.sh,exit 0(约 6m32s),CFBundleVersion=83,x86_64。 - 首次公证
Invalid:322条The signature does not include a secure timestamp.根因是MacApp/scripts/build-app.sh对嵌套二进制使用--timestamp=none。本轮未改该产品脚本(永久修复属 Lead 决策范围),改为对Contents/Resources下全部嵌套二进制逐一补 TSA 重签并对外层--deep --timestamp:实测signed_files_checked=323、missing_timestamp=0。 - 重新提交公证:
Accepted(jobId874d2772-528b-4872-8ce4-50bebab81030,issues: None);stapler staple+stapler validate通过;spctl由rejected / Unnotarized Developer ID变为accepted / source=Notarized Developer ID;codesign --verify --deep --strict通过,签名链Developer ID Application → Developer ID CA → Apple Root CA、flags=0x10000(runtime)。 - 交付容器:
MacApp/dist/Perfowl-Build74-Phase2-f3c9b73-x86_64-notarized.zip,109,842,490 B,SHA-25622ab40b54f1e9fddd381715851383262f11608c1ad4b00a24ef25d9cd12c750e(提交公证用包 109,837,729 B /15b68ea52be9a6530e1bd79e20a99370c19a55720598a8bebde392523f79a15c)。 - 独立解包目录复验:版本 83、
--verify --deep --strict有效、spctl为accepted / Notarized Developer ID、stapler 通过、内置 Collector Core 存在(12,413,616 B);并以该副本完成一次启动冒烟(自动拉起内置pymobiledevice3做设备发现,进程已清理)。App 自身既有会话库(72 个既有会话,最新 mtime2026-09-24 14:21)未被触碰。
S-2 真机采集(新包会话 16 轮,冻结配置逐字段一致)
- 入口:使用新包内捆绑的核心按 App wire 序列
prepare_app → start → stop驱动,冻结 CapturePlan(12 条 startup 指标 +capturePlanHash f9f54077…)在两条命令上回显一致;PERFOWL_FRAME_FILTER_EXPERIMENT=exact-debug-id显式透传(代码默认subclass不是冻结形态)。每轮两阶段:stream(活线 closeout,只 seal + manifests、不重扫 Raw)→ CLIfinalize(唯一产出带诊断块 final 报告的路径)。 - 会话规模:16 轮新包会话(早期 5 轮因分析工具曾就地覆盖 final 报告而移入私有归档
discarded/,不参与本段判据;追加批次 10 轮全部通过只读自证)。 - 机械断言(
out/e4-rounds.json):
| 断言 | 实测 |
|---|---|
allConfigsMatchFrozenUi | true(launchMode/startupEnabled/screenshotsEnabled/coreProfileRawRetention/frameFilterExperiment/requestedFrameFilter/effectiveFrameFilter/callstackDepth/bm/rp/csd/tk/kdf2/ta/capturePlanHash 共 15 字段逐轮比对) |
allRawHashesConsistent | true(rawSHA256 与 coreProfileBlobSHA256 的 manifest 值 vs 本机独立重算,逐轮相等) |
analyserStrictlyReadOnly | true(隔离 staging 回放后逐轮复算 pristine 哈希,replay_wrote_into_session=false) |
liveHasNoDiagnostic | true(16/16 活线报告无 stopDrainLifecycleDiagnostics,符合 §5 A-S) |
finalHasDiagnostic / finalIsRawRescan | true(16/16 final 报告含诊断块且带 spanFile+sourceRawSHA256) |
replayMatchesShippedDiag / replayMatchesShippedMain | true(见 S-5:修复分析工具后 16/16 与独立回放逐字段一致) |
totalNeverPublished | true(Total 仍按原生契约,不因诊断提升) |
closedChainRounds | [](0/16 正向闭合链) |
- 形态分布(原始字节分类,
official final报告口径):target-actionable-no-closure13 轮、no-lifecycle-records3 轮;非零拒因只有no-opener(13 轮)与thread-binding-unknown(13 轮)。drain 状态 8 轮timeout/ 8 轮quiescent;一轮一 Session,时长 11.1–71.0 s。 - 窗口级原始字节扫描(
out/lifecycle-scan-*.json,复用包自身KD_BUF/_stop_drain_lifecycle_offsets/_lifecycle_actions): - 13 轮:
begin:Initial Frame Rendering(opener)只出现在startup-lifecycle|active窗口,drain 窗口只有 closer 与普通记录 ⇒ 结构上必然no-opener; - 4 轮:整份 Session 内不存在 opener 记录(closer-only;其中 3 轮 drain 窗口仅 766 B);
- r3 对照:opener 出现在
frame-continuation|post-stop-drain(唯一一例)⇒ 可闭合。 - 未取得的形态:§5 要求的「至少一个新包真实正向闭合链」未取得。其余量缺口见 S-3。
S-3 未取得正向链的可复现机制与量化缺口
诊断(launch_trace.py)只把落在 frame-continuation|post-stop-drain 块内的 opener 计入账本,因此正向闭合链的充要条件是:opener 记录在主机的到达时刻晚于 stop-drain 切口。切口 = 启动完成 handoff,其位置由核心自身记录的两项推出:completionWaitStartedAt = 首个 drain 块主机时刻 − startupCoreProfileCompletionWaitElapsedSeconds,而切口 = completionWaitStartedAt + elapsed:
completed / completion-observed(12/16):切口跟在 opener 自身到达之后 ⇒ opener 必落在 active 窗口,结构上不可能闭合;timed-out / startup-completion-grace-expired(4/16):切口 = grace 截止(4.0 s);但这 4 轮的 opener 在整份 Session 内都不存在 ⇒ 无端点可闭合。
逐轮量化(out/opener-deadline-table.json):
| 组别 | 轮数 | opener 块相对 grace 截止 | 结果 |
|---|---|---|---|
completed(12 轮) | 12 | −1686 ~ −4433 ms(早到) | 形态为 active 内 opener → 不可闭合 |
timed-out(4 轮) | 4 | 无 opener 记录 | 无端点 |
| r3 对照(App UI 录制) | 1 | +1916 ms(晚到,唯一正值) | drain 内 opener → 可闭合 |
设备时钟(machTicks)对照排除了「App/设备行为不同」这一解释:新包各轮 code12(0x2b870030)距 end:sceneWillEnterForeground(0x2b8704e4)为 ≈660–743 ms,r3 为 ≈743 ms,即设备侧发射时序基本一致;差异在主机侧交付滞后(writerQueueWaitMaxMs:新包 0.73–218.97 ms vs r3 284.80 ms)。故正向形态需要的是主机/传输滞后把 opener 的到达推过 grace 截止,而不是改 App、设备或采集配置。
本批未采用任何「制造」手段:未人为加压、未改 drain 时限、未改 kdf2/csd/frame filter/role/源过滤、未改 UI 录制配置、未重放离线 Raw 冒充真机轮次。追加 10 轮的唯一目的是在同一冻结配置下多取样,判据逐轮回填。
S-4 相对方案的偏差(逐项)
- 采集入口等价性:§5 要求「只使用冻结 Build74 同形态 App UI 入口作为对照」。本轮用新包内捆绑核心 + 复现 App wire 序列(
prepare_app/start/stop、同一冻结 CapturePlan 与实验档位)作为 GUI 等价入口;--connection-route usb被接受,但 provider 仍报route: tunneld / tunneld-native-rsd(与 r3 相同)。该等价性是否可接受由 Lead 裁定;本轮未使用 CLI 默认配置(其kdf2=[0xFFFFFFFF]/csd=128形态按 §5 属 INVALID)。 - 会话时长:新包轮次 11.1–71.0 s,r3 为 25.29 s。时长不在 §5 冻结字段清单内,且 CoreProfile 段在 ~6–12 s 内已完成 drain,故未作为冻结配置偏差计算;此差异如实保留。
- 私有归档新增
discarded/:derive_launch_trace_session会把结果写回launch-trace-report.json;早期分析工具曾直接在会话目录内调用它,导致 5 轮会话的 live 报告被 final 报告覆盖(受影响的ca8596bc/1b9e0980/1b56b2a4/1849d892/9a2edfc1)。这些轮次已隔离、不纳入本段任何数字;工具改为隔离 staging 树(真实字节复制)后,追加轮次全部自证replay_wrote_into_session=false。 build-app.sh嵌套签名缺 TSA:未修(永久修复点留 Lead 决策),本轮以补签方式完成分发链;该缺口对下一轮构建仍然存在。
S-5 独立回放一致性门禁的修复(工具侧,非产品侧)
原分析工具在隔离 staging 树中对大文件使用符号链接,而产品自身的 Raw 回放校验会拒绝「manifest 的 coreProfileBlobFile 解析到 Session 目录之外」的路径,因此每一轮独立回放都以 ReplayValidationError 失败,replayMatchesShipped* 退化为恒 false(不是产品报告不一致)。改为真实字节复制(不用硬链接,避免共享 inode 被就地写坏)后:16/16 replay_vs_shipped_diag_equal=true、replay_vs_shipped_main_equal=true,且 pristine 哈希复算证明未写回会话。结论:新包 shipped final 报告可由当前工作树的独立回放逐字段复现。
live_vs_final_main_equal 仍为 false,差异集合逐轮仅为 decodedRecordCount(例:1855341 → 3668220、2100633 → 2785338)——live closeout 只统计其已解码量、final 重扫整份 Raw,属既有设计;两列原值均在 out/e4-evidence-table.md 中并列保留,未作裁剪。
S-6 遗留项与门禁状态(实施方不自判 PASS)
- A1 新包真机 E4 = 未取得正向闭合链 ⇒ 不满足 §5 的 PASS 前置条件,状态记
partial,判据交 Lead。 缺口是一个「opener 主机到达晚于 grace 截止」的真实会话;当前 16 轮均为早到 1.7–4.4 s 或无 opener。 - 其余 §5 前置项本轮已齐备:真实负向形态 16 轮、原始哈希/报告一致性 16/16、活线与最终主字段对照齐备(含 A-S 活线无块 / final 有块)、新包签名/公证/staple/独立安装与包 SHA 真实可查。
- §6 效率门禁:本轮产品代码零 diff,无新增扫描/等待、无性能变更,故不产生新的前后性能对比;上一批次的 §6 证据与结论继续有效。
- 未关闭的工程缺口:
build-app.sh嵌套签名缺 TSA(永久修复点)、--connection-route usb下 provider 仍走tunneld-native-rsd的路由表述差异(与本方案冻结形态一致,供 Lead 裁定)。 - 交付物(本机私有归档
~/Perfowl-Local-Archive/build74-phase2-a1-e4-20260925-0837/):out/e4-rounds.json、out/e4-evidence-table.{json,md}、out/opener-deadline-table.json、out/boundary-<alias>.json、out/lifecycle-scan-<alias>.json、evidence/notarytool-*.{log,json}、install-verify/、discarded/、scripts/。共享工作区未跟踪文件与受保护 trace 全程未动。