planP4E2implemented · gate-open2026-09-22

P4 Startup Phase C · Hybrid Total 正式方案

> 当前状态:Project Owner 已于 2026-09-22 明确批准 Phase C,授权 Implementation AI 按本方案执行 C0/C1;C2 仍禁止进入。 > > 2026-09-22 增量:C0 仪表化已完成(implemented · gate-open,E2 完成 / E4 待执行)。本批只做 C0, > C1 未开始、C2 未进入、C0 Gate 未自判。Project Owner 裁定 C0 真机证据由 Test AI 采集、由 Lead AI 判定, > Implementation AI 交付「仪表化 + E2 + 取证工具」后停止。详见文末 Implementation Update。 > > 基线:c77e363b9e900f09baa326ff01748b3c38f715a2。Phase A = PASS;Phase B 架构 = PASS / CLOSED;Phase B 性能 = B-PARTIAL。Phase C 不反向修改 A/B 的 owner、prewarm、SOURCE_ACTIVE barrier 或 reconnect 语义。

1. Phase C 要解决什么

现有 Startup Total 的直接端点来自 Dedicated CoreProfile lifecycle:

System Interface BEGIN
        ↓
Initial Frame END

现有公式是同一条 CoreProfile RAW v2 中的 device mach ticks 差:

legacyTotalMs =
    ticksToNs(initialFrameEndMachTicks - systemInterfaceBeginMachTicks)
    / 1_000_000

优点是同源、同钟、语义清楚;缺点是 lifecycle BEGIN / END 任一丢失时 Total 会缺失,现有 Mode A / C 虽可在严格条件下修复一部分端点,但不能保证每轮都得到 Total。

Phase C 的目标不是“无论如何给一个数”,而是:

  1. 研究并产品化更稳定的 Hybrid Total:
  1. lifecycle 九阶段继续保留为诊断明细,不因 Hybrid Total 而弱化;
  2. 在无法证明时钟、进程归因或首帧归因时保持 missing;
  3. 先 shadow 旁路计算,E4 通过后才讨论替换主 Total。

2. 明确非目标

Phase C 不做以下事情:

3. 当前已有数据源事实

3.1 Legacy lifecycle START / END

RealtimeLaunchTraceDecoder 当前保留:

现有 launch_trace.py 仅在端点满足顺序与质量门禁时发布 Total;Mode A/C 修复仍带 repaired 来源,不得伪装成 clean endpoint。

3.2 ActivityTrace FrameLifetime

当前 FrameTime 已由独立于 kperf 的:

com.apple.instruments.server.services.activitytracetap
subsystem = com.apple.coreanimation
category  = IOMFBServer
name      = FrameLifetime

提供。其 event 含:

FrameLifetimeDecoder 已把 end_time 转换为 presentationTimestampNs,并有 sourceEpoch / reconnectGeneration / targetGeneration / foreground / continuity / source-gap 语义。

重要限制:当前 adapter scope 是 foreground-device,并不天然等价于“目标 App 的 frame”。

3.3 Process-control launch request

launch_requested_ns / launch_request_envelope.host_receive_monotonic_ns 是 Mac/Sidecar host monotonic clock 上的控制边界。

它可以作为:

但 C0 证明 host↔device clock bridge 之前,不允许直接参与 Hybrid Total 数学公式。

4. Phase C 固定拆成 C0 / C1 / C2

C0 · Feasibility & Attribution Gate

只研究、加实验观测和测试 fixture;不改主 Total。

必须证明三件事:

  1. Clock Gate:Hybrid START 与 FrameLifetime END 能落在同一 device mach clock / epoch;
  2. Start Gate:存在稳定且可归因到目标 App 的 START;
  3. End Gate:能把首个合格 FrameLifetime 归因到本轮目标 App,而不是任意前台设备 frame。

任一门禁失败,Phase C 停止在 research,现有 Total 保持不变。

C1 · Shadow Hybrid Total

C0 通过后:

C2 · Promotion Gate

只有 Lead AI 独立 E4 验收通过,Project Owner 再次明确批准,才允许:

C1 开发完成 不自动进入 C2。

5. START 语义与优先级

Phase C 不先假定 host launch request 就是最终 START。START 候选按证据等级研究:

S0 · direct lifecycle start

System Interface BEGIN mach ticks

S1 · repaired early lifecycle start

沿用当前 Mode C 的早期 BEGIN:

min(System Interface / dyld / UIKit early init BEGIN)

要求:

S2 · stable device process-start / resume marker(C0 研究目标)

C0 应检查现有 Dedicated Startup RAW / ProcessControl 可否得到:

的 process launch / exec / resume kernel marker。

不得预先假设某个 debugID。 Implementation AI 只能通过 fixture + 真机 census / Apple Instruments 参考识别后,将经证据确认的 marker 写入固定 profile。

若 S2 被证明,优先作为 Hybrid START。

S3 · host process-control launch request

只作为 diagnostics / experimental comparator:

launch_requested_ns (host monotonic)

除非 C0 建立并验证 host↔device clock bridge,否则:

HybridTotal = devicePresentationNs - hostLaunchNs

是禁止公式。

6. END 语义

目标 END:

首个可证明属于本轮目标 App 的 FrameLifetime presentation end_time

不是“ActivityTrace 的第一条 FrameLifetime”。

一个 frame 至少必须满足:

  1. event identity = com.apple.coreanimation / IOMFBServer / FrameLifetime;
  2. presentationTimestampNs > startTimestampNs;
  3. reconnectGeneration 与当前 cycle 相同;
  4. targetGeneration 与当前 launch round 相同;
  5. sourceEpoch 仍属于当前有效窗口;
  6. target PID 已 verified;
  7. target foreground 状态成立;
  8. decoder 无 source-gap / discontinuity / out-of-order;
  9. displayID 合法且未发生 display boundary change;
  10. 不来自上一轮残留、App rebind 前目标或 reconnect 前 source。

6.1 surfaceID 归因门禁

surfaceID 是 Phase C 的关键研究字段,但当前代码没有证明:

surfaceID -> target PID / target bundle

因此 C0 必须做正/负样本验证:

只有出现可重复的 surface / process 映射证据,才能把 END 标为 real。

若只能证明“目标 App verified foreground 时窗口内的第一条 foreground-device frame”,可以进入 candidate,但不能叫 real。

若同时存在多个无法消歧的 surface,结果必须 missing: ambiguous-first-presented-surface。

7. 时钟域与正式公式

7.1 唯一首选公式:device ↔ device

当 START 与 END 都是同一 device mach clock 的 ticks:

deltaTicks = endMachTicks - startMachTicks

deltaNs =
    floor(deltaTicks * timebaseNumer / timebaseDenom)

hybridTotalMs =
    deltaNs / 1_000_000

必须满足:

endMachTicks > startMachTicks
timebaseNumer > 0
timebaseDenom > 0
sameReconnectGeneration == true
sameClockEpoch == true
noClockReset == true

算法版本建议:

startup-hybrid-total.device-mach-framelifetime.v1

7.2 Cross-source clock proof

CoreProfile lifecycle mach ticks 与 ActivityTrace FrameLifetime mach ticks虽然都表现为 mach ticks,C0 仍必须证明:

未证明时:

quality = missing
reason  = cross-source-clock-unverified

7.3 Host ↔ device clock bridge

如果研究 S3 host launch request fallback,必须独立形成 clock bridge:

deviceNs ≈ a * hostMonotonicNs + b

并记录:

未达到 C0 误差门槛时,该 bridge 只能进 diagnostics,不能参与产品 Total。

8. 质量与失败语义

Phase C 新增 Hybrid provenance,至少区分:

quality含义
realSTART 与 END 均为直接 device timestamp,target attribution 与 clock gate 全部通过
candidatetimestamp 本身真实,但至少一项归因仍依赖已验证但非直接的 foreground/surface 规则
repaired使用 S1 或其他明确批准的 endpoint repair;必须带 repair reason 与 error bound
missing无法在不猜测的前提下得到值

禁止:

报告建议字段:

hybridTotalMs
hybridTotalQuality
hybridTotalReason
hybridTotalAlgorithmVersion

hybridStartSource
hybridStartMachTicks
hybridStartQuality

hybridEndSource
hybridEndMachTicks
hybridEndSurfaceID
hybridEndDisplayID
hybridEndQuality

clockDomain
clockProofGeneration
sourceEpoch
targetGeneration
reconnectGeneration

Legacy 字段继续保留:

legacyTotalMs
legacyTotalQuality
legacyTotalSource

C1 shadow 阶段禁止覆盖现有 totalDurationMs。

9. ActivityTrace 生命周期与资源模型

Phase C 不得重新引入 CoreProfile unified recording。

FrameTime 已选择

复用现有唯一:

ActivityTraceFrameLifetimeRawAdapter

Hybrid evaluator 只注册一个 one-shot observer,不创建第二条 ActivityTrace subscription。

FrameTime 未选择但 Startup 已选择

允许建立最小 Startup FrameLifetime observer,但必须:

建议初始上限:

startup frame observer timeout = 10s
reorder grace                  = 250ms
bounded pending candidates     <= 64
duplicate ActivityTrace streams = 0

这些是 C1 初始预算,不是无条件写死;E2/E4 可收紧,但不得为提高成功率无限延长。

10. 性能 / 轻量化门禁

Phase C 实施必须给出变更前后基准。

至少测:

目标预算:

项目门槛
新增 CoreProfile/kperf recording0
重复 ActivityTrace subscription0
Startup observer pending rows≤ 64
Startup observer lifetime≤ 10s
Start 同步路径额外 CPU wall timep95 ≤ 5ms
Hybrid evaluator 单 event 处理p95 ≤ 1ms
额外 RSS≤ 2 MiB
ActivityTrace 持续带宽实测应保持约当前 FrameLifetime 量级;若 > 0.10 MiB/s 则 FAIL
Session 磁盘增量需实测;不得因 shadow raw duplication 翻倍

如果现有 FrameTime adapter 已 active,Hybrid evaluator 必须零复制或近似零复制消费 normalized event;禁止再次序列化整条 raw 流只为计算一个首帧。

10.1 执行路径、复杂度、吞吐与并发边界

Hybrid evaluator 的热路径固定为:

normalized FrameLifetime event
    → O(1) identity / generation / clock / quality gates
    → append bounded candidate metadata
    → first-qualified END seals result
    → observer short-circuit / detach

效率约束:

这些效率门禁必须在 C1 的 before/after benchmark 中单独出表,不能只以“全量测试通过”代替性能证据。

11. C0 必做实验

C0-1 · Clock-domain proof

同一真机、同一 session 记录 CoreProfile lifecycle mach ticks 与 ActivityTrace end_time:

C0-2 · First-presented-frame attribution

至少:

输出每轮:

launch round identity
PID
foreground transitions
FrameLifetime candidate sequence
displayID
surfaceID
frameSeed
presentationTimestamp
selected END / reject reason
legacy initial-frame endpoint if present

要求 negative controls 0 次错误归因。

C0-3 · START candidate census

对 S0/S1/S2/S3 同场记录:

没有证据不得把某个 kernel event 命名为“process start”。

12. E2 反例矩阵

Implementation AI 必须补确定性 fixture / integration tests,至少覆盖:

  1. clean S0 + clean target FrameLifetime;
  2. S0 missing、S1 repaired;
  3. S0/S1 都 missing → Hybrid missing;
  4. END missing;
  5. frame 在 START 之前;
  6. duplicate same timestamp;
  7. out-of-order frame;
  8. ActivityTrace source-gap;
  9. discontinuity;
  10. wrong display;
  11. multiple ambiguous surface;
  12. target not foreground;
  13. stale previous-round frame;
  14. targetGeneration mismatch;
  15. sourceEpoch mismatch;
  16. reconnectGeneration mismatch;
  17. App A→B rebind 不得使用 A 的 frame;
  18. reconnect 后不得使用上一代 clock proof;
  19. PID rebind 后旧 PID frame 不得通过;
  20. lifecycle source-buffer-loss 但 ActivityTrace 正常;
  21. ActivityTrace loss 但 legacy Total clean;
  22. launch ack 失败;
  23. host launch request 存在但 clock bridge 未验证 → 不得计算 host/device Hybrid;
  24. FrameTime 已选 → 必须复用唯一 ActivityTrace subscription;
  25. FrameTime 未选 → startup one-shot observer timeout 后释放;
  26. Startup 未选 → 不得因为 Phase C 偷开 observer;
  27. Stop before first frame → missing + clean teardown;
  28. first qualifying frame 到达后后续 frames 不得改写 END;
  29. source restart 后 first frame 必须重新 warmup/归因;
  30. legacy totalDurationMs 在 C1 shadow 阶段逐字保持现有语义。

13. C1 代码边界建议

优先新增独立组件,避免继续膨胀 RealtimeLaunchTraceDecoder:

perfowl_collector_core/startup_hybrid_total.py
  HybridStartupTotalEvaluator
  HybridEndpoint
  HybridClockProof
  HybridTotalReport

职责:

RealtimeLaunchTraceDecoder 继续负责 lifecycle; FrameLifetimeDecoder 继续负责 FrameLifetime 解码; realtime.py 只负责 wiring / lifecycle / observer refcount。

禁止把 Hybrid endpoint 规则散落在多个 if 中。

14. E4 真机验收矩阵

C1 E2 通过后才打包进入 E4。

最低矩阵:

对象冷启动轮数
Fixture A20
App A20
App B20
App C20
negative controls≥10
reconnect/reboot 扩展≥5

每轮必须同时保存:

14.1 稳定性 Gate

publishableHybridRate >= 95% overall
publishableHybridRate >= 90% per app
falseAttributionCount = 0
crossGenerationJoinCount = 0
clockDomainViolationCount = 0

publishable 可以统计 real/candidate/repaired,但必须分层单列,不能只给一个混合百分比。

14.2 与 legacy clean subset 的同场对照

只在 legacy clean endpoint 同时存在的轮次比较:

deltaMs = hybridTotalMs - legacyTotalMs
absDeltaMs = abs(deltaMs)

此处是语义一致性比较,不把 legacy 自动当绝对真值。

初始 Gate:

median(absDeltaMs) <= max(25ms, 2 * refreshIntervalMs)
p95(absDeltaMs)    <= max(80ms, 5 * refreshIntervalMs)

若存在稳定偏差,必须解释该偏差是否来自“lifecycle Initial Frame END”与“实际 presentation END”的定义差异,而不是简单通过加常数校正。

禁止用经验 offset 把结果“调到更像 legacy”。

14.3 资源 Gate

同设备、同 App、同采集项配对比较 C1 vs baseline:

15. C2 晋升条件

只有以下全部成立,Lead AI 才能提出 C2:

  1. C0 Clock / Start / End attribution 全部 PASS;
  2. C1 E2 counterexample 全部 PASS;
  3. E4 稳定性达标;
  4. false attribution = 0;
  5. paired delta 满足 Gate 或有可证明的定义差异;
  6. 无 FrameTime / Startup / kperf / reconnect 回归;
  7. 资源预算 PASS;
  8. knowledge / formula / provenance 已更新;
  9. Project Owner 明确批准晋升。

否则:

legacy Total = 主值
hybrid Total = shadow / diagnostics

16. 明确停止 / 回滚条件

出现任一条件立即停止 Phase C 产品化:

回滚必须只关闭 Hybrid evaluator / one-shot observer;Phase A/B 架构保持不动。

17. 开发与提交要求

Project Owner 已于 2026-09-22 明确批准本方案;Implementation AI 现在可以开始 C0/C1,但不得自行进入 C2。

推荐拆分:

  1. test(startup): add hybrid total feasibility fixtures
  2. feat(startup): add shadow hybrid total evaluator
  3. docs(startup): record phase c shadow validation

若一个批次可保持范围清晰,也可以合并,但产品代码与 E4 结论不得混成一个“自证 PASS”提交。

Implementation AI 交付必须包含:

18. Lead AI 验收顺序

Implementation delivery
    ↓
Lead static/code audit
    ↓
E2 focused + full regression
    ↓
resource benchmark review
    ↓
signed/notarized test build
    ↓
E4 matrix
    ↓
Lead PASS / PARTIAL / FAIL
    ↓
Project Owner decides C2 promotion

19. 当前结论

> 本节的「当前状态」是 2026-09-22 方案批准时的快照,按 D2 不回改;其后的进展以文末 > Implementation Update · 2026-09-22 为准(C0 已 implemented · gate-open,C1 未开始,E4 未执行)。

Phase C 的正确第一步不是“把 launch command 和第一帧相减”,而是先证明:

START 可归因
+ END 可归因
+ 两者同一 device clock
+ round identity 不串代

因此本方案把 C0 Attribution/Clock Gate 设为硬前置。

当前状态:

---

Implementation Update · 2026-09-22(C0 取证与归因仪表化)

> 审计基线:5a06929c22db912db22866ed2c29109761f1b797(docs(startup): approve phase c c0 c1)。 > 本段只记录 C0。C1 未开始,C2 未进入。 本批未宣布任何 C0 PASS。

1. 本批范围与角色边界(重要)

Project Owner 在开工前明确裁定:C0 的正式真机证据不由 Implementation AI 自证。因此本批交付收缩为 「C0 仪表化 + E2 反例矩阵 + 真机取证能力」,然后停在 C0,交回 Lead AI:

Implementation AI(本批)      → C0 instrumentation + E2 + census/benchmark 取证工具   ← 已完成并停止
Test AI(下一步,未开始)      → 真机执行 C0-1 / C0-2 / C0-3,产出 E4 原始证据
Lead AI(未开始)             → C0 Gate 独立判定(PASS / PARTIAL / FAIL)

因此本批没有:自跑真机 E4、自建验收包/公证、把 C0 写成 validated、把 shadow 提升为正式 Startup Total。

2. 实际修改范围

文件性质说明
MacApp/Sidecar/perfowl_collector_core/startup_c0_feasibility.py新增(离线模块)C0 三闸仪表化 + Session 只读投影
MacApp/Sidecar/tests/test_startup_c0_feasibility.py新增§12 E2 反例矩阵,96 项
MacApp/scripts/startup-c0-census.py新增真机/回放 census 入口(Test AI 用)
MacApp/scripts/benchmark-startup-c0-feasibility.py新增时间/空间/吞吐 benchmark + 归因探针

产品活线零改动(逐字节断言,非承诺):

git diff HEAD -- MacApp/Sidecar/perfowl_collector_core/{realtime,recording,display_performance,launch_trace,adapters}.py
→ 空

startup_c0_feasibility.py 是新增的离线模块,没有任何调用方:它是一个纯 reader,不注册 tap、不订阅 ActivityTrace、不拥有 CoreProfile/kperf、不写 Session、不触碰 totalDurationMs。把「C0 只有离线读取能力」 这件事说清楚,是本批最重要的一条诚实边界——离线回放结构上无法满足下面 §5 列出的 5 项。

3. 关键实现决策与相对方案的偏差

偏差 1(最重要):END 侧 timebase 只能标 assumed-constant,这是发现而非缺陷。 FrameLifetimeDecoder.__init__(timebase_numer=125, timebase_denom=3) 是编译期常量,产品路径没有任何地方 把设备回报的 timebase 注入进去;adapters.py 里 CoreProfile 的 envelope 会带 device_mach_timestamp / mach_numer / mach_denom,ActivityTrace 的 envelope 不带。所以 END 侧的 125/3 只是「恰好对 arm64 成立 的假设」。仪表化据此把 provenance 显式分层(device-reported / assumed-constant / missing), Clock Gate 遇到非 device-reported 一律 fail-closed。

偏差 2:S2 从「Start Gate 要求」降级为「capability gap」。 方案 §5 把 S2(设备侧 process-start / resume 标记)列为 START 优先级之一。实现时确认:干净的 S0 已经满足 Start Gate,S2 是研究偏好而非门槛,且方案本身禁止在未做 census 前命名任何内核标记。因此 S2 缺仪器记入 capabilityGaps(不是 failures),报告 s2Status="not-instrumented",绝不猜测 debugID。把 「还没有仪器」写成「经验性否定结论」是不可接受的,两者在报告里保持分离。

偏差 3:Clock Gate 的速率/单调性按 (generation, source) 分组,不跨源合并。 两条流的时间锚点都打在到达时刻上,各带自己的 transport delay。最初把两源锚点合并成一个有序列表, 系统性地制造出假 clock-reset-detected。修正为按源分组后,test_source_arrival_offset_is_not_a_clock_reset 钉死该行为。

偏差 4:显式的人工标注通道。 方案 C0-2 要求 App A/B/C ×10 冷启动 + 10 个负对照。负对照「哪个 Session 是系统 UI / 别的 App / 覆盖层」 是工具无从推断的事实,因此 census 提供 --labels 注入;未标注时 falseAttributionCount 保持不可测, 不许猜。

偏差 5:有界保留(§10.1)与一处显式例外。 方案 §10.1 要求空间 O(K), K <= 64 且「不得保留第二份 FrameLifetime raw history」。30s/60fps 一轮是 1800 帧, 逐帧保留 14 个字段实测把单轮投影的常驻推高到超出预算,因此:

framesFrameLevelQualifiedBeyondSample 把全量人口压成 O(1) 计数;

绝不允许写成 end-no-qualifying-frame(那是对从未看过的帧下断言)。

显式例外:clockAnchors 仍按源完整保留(约 2 个标量/帧,~130 B/帧 → 30s ≈ 268 KB、120s ≈ 1.0 MB)。 Clock Gate 的速率证明依赖相邻锚点对的中位斜率与逐点单调性,抽稀锚点等于削弱 C0 唯一要建立的时钟证明。 本批选择保留证明强度、把成本显式记账(benchmark 单独出表),并在遗留项里挂 C1 复核; 这不属于「第二份 raw history」——它是 2 个标量,不含 payload / 身份 / surface / quality。

4. C0 E2 证据(96 项,全绿)

cd MacApp/Sidecar && PYTHONPATH=. <py> -m unittest tests.test_startup_c0_feasibility
→ Ran 96 tests in 0.240s / OK

§12 反例矩阵逐项覆盖(左为矩阵编号):

#项用例
1clean S0 + clean frametest_s0_clean_start_is_real、test_warmup_first_frame_is_accepted、test_fully_proven_observation_reports_all_gates_passed
2S0 missing / S1 repairedtest_s0_missing_s1_repaired、test_repaired_is_never_promoted_to_real、test_s1_phase_out_of_range_rejected、test_s1_not_surviving_rejected
3S0/S1 全缺test_all_start_sources_missing
4END missingtest_no_frames_observed_is_missing、test_end_never_claims_repaired
5frame 早于 STARTtest_frame_before_start_rejected、test_frame_equal_to_start_is_not_after_start
6重复时间戳test_duplicate_timestamp_selects_exactly_one
7乱序 frametest_selection_is_invariant_to_input_order
8source-gaptest_source_gap_frame_rejected
9discontinuitytest_discontinuity_frame_rejected
10错 displaytest_display_boundary_change_rejected
11多 surface 歧义test_ambiguous_surfaces_within_grace_collapse_to_missing、test_ambiguity_is_not_downgraded_to_candidate、test_single_surface_is_not_ambiguous、test_surface_proof_resolves_ambiguity、test_without_surface_proof_the_ceiling_is_candidate、test_surface_proof_reaches_real
12非前台test_not_foreground_frame_rejected
13上一轮陈旧帧test_stale_previous_round_frame_rejected
14–16target/source/reconnect 代际错配test_target_generation_mismatch_rejected、test_source_epoch_mismatch_rejected、test_reconnect_generation_mismatch_rejected
17App A→B rebindtest_app_rebind_frame_from_previous_target_rejected
18跨代复用 clock prooftest_previous_generation_proof_cannot_be_reused、test_reconnect_generation_gets_its_own_proof、test_proof_missing_for_a_second_reconnect_generation、test_each_generation_needs_both_sources
19PID 重绑后旧帧test_unverified_pid_blocks_selection
20lifecycle 丢源但 END 正常test_lifecycle_buffer_loss_does_not_promote_the_start
21ActivityTrace 丢失但 legacy cleantest_a_clean_legacy_total_cannot_rescue_a_missing_end
22launch ack 失败test_failed_launch_ack_never_becomes_a_start_or_a_device_delta
23host↔device 桥未验证test_host_device_delta_attempt_is_forbidden、test_host_clock_delta_is_recorded_and_labelled_not_a_device_delta
28seal 后不得改写 ENDtest_frames_beyond_grace_cannot_change_the_sealed_end
29源重启后首帧重新归因test_source_restart_may_not_inherit_the_previous_rounds_first_frame
30legacy Total 逐字保持test_c0_reports_the_legacy_total_without_rewriting_it、test_no_hybrid_total_value_is_emitted
§10.1有界保留 6 项test_diagnostics_are_capped_at_the_documented_bound 等

另有 Clock Gate 8 项(时间基不一致 / provenance 未证 / 锚点不足 / 窗口 <30s / 速率漂移 / 时钟回拨 / epoch 无配对 witness / 跨代复用)与 Start Gate 质量分层 2 项。

§12-24 / 25 / 26 / 27 本批不覆盖,且不是遗漏:这四项描述的是活线 observer 的接线行为 (FrameTime 已选时复用唯一 subscription、未选时 one-shot observer 超时释放、Startup 未选时不得偷开 observer、首帧前 Stop 的干净 teardown)。C0 没有活线路径,无法用离线 fixture 产生有意义的反例。 它们由 C1 实现后以活线测试覆盖——本批只把结构性约束作为断言钉住:benchmark 输出 realtimePyUnchanged=true / newActivityTraceSubscriptions=0 / newCoreProfileRecordings=0。

5. C0 离线结构性无法满足的 5 项(必须真机/人工补)

census 每次运行都会把这张表原样打印出来,防止下游把「离线测不到」读成「已经测过」:

  1. C0-1 配对同事件 witness:产品路径不记录任何「同一事件同时出现在 CoreProfile lifecycle 流与

ActivityTrace FrameLifetime 流」的 witness ⇒ cross-source-epoch-unproven 无法靠回放清除。 必须真机产出该 witness,或由 Lead AI 重新规定跨源时钟证明。

  1. C0-1 30s 窗口 + reconnect 复证:需要「选了 FrameTime 指标」(否则 ActivityTrace 根本不跑)

且「同一次采集内含 reconnect」的 Session。

  1. C0-2 负对照:哪个 Session 是系统 UI / 别的 App / 覆盖层只有操作者知道 ⇒ 需要 --labels,

否则 falseAttributionCount 保持不可测。

  1. C0-2 surfaceID → 目标 PID 映射:产品代码不证明该映射 ⇒ END 侧 real 不可达,

最强只能到 candidate。

  1. C0-3 S2 内核 process-start 标记:无仪器,且方案禁止未做 census 就命名 ⇒ not-instrumented。

6. 性能与资源 benchmark(§10 / §10.1)

/py MacApp/scripts/benchmark-startup-c0-feasibility.py --rounds 20 --json internal/startup-c0-benchmark.json
→ exit 0(三项预算全过)

合成 Session 规模 300 / 900 / 1800 / 3600 帧 × 5 轮,1800 帧 ≈ 真实 30s/60fps。

项目预算实测判定
单帧投影耗时 p95≤ 1 ms0.3685 ms(中位 0.1757)PASS
吞吐≥ 240 events/smin 2501.3 / median 5698.0PASS
C0 自有增量工作集≤ 2 MiB0.379 MiBPASS
单次完整评估(含 1891 事件 Session 投影)—6.752 ms / 次记录
诊断帧保留数 @300/900/1800/3600= K ≤ 6464 / 64 / 64 / 64与 F 无关
报告字节 @300/900/1800/3600与 F 无关18083 / 18084 / 18085 / 18085与 F 无关
新增 CoreProfile/kperf recording00PASS
重复 ActivityTrace subscription00PASS

RSS 归因必须分开说,否则是错告。逐阶段高水位拆分出:

harness 造 Session      0.047 MiB
投影(含读 Session)    5.348 MiB   ← 其中 validate_recorded_session 单独实测 4.980 MiB
闸评估                  0.012 MiB

validate_recorded_session 会把整份 Session 的每个事件物化进内存(本批 1891 事件),因此任何建立在它 之上的离线分析器都继承一个 O(session) 底噪。该函数属产品既存代码、本批逐字节未改。所以 §10.1 的 2 MiB 空间预算按 C0 自有增量判定(0.379 MiB,PASS),同时把未归因的 5.359 MiB 原样写进 rssAttributionMiB.analyzerIncrementalPeak 与 observations.analyzerIncrementalPeakWithinBudgetUnattributed=false, 任何人可复核这次拆分,不存在「把预算偷偷改小」。

7. 全量回归(E2)与 flake 归因

测试文件同一性(先证明失败文件与基线逐字节相同):

IDENTICAL  tests/test_sample_publisher_decoupling.py
IDENTICAL  tests/test_realtime_consumer_fairness.py
IDENTICAL  tests/test_pmd3_subscription_fairness.py
IDENTICAL  tests/test_pump_filter_active_fairness.py
IDENTICAL  tests/test_display_ingress_backpressure.py

基线探针:git archive 5a06929 MacApp fixtures | tar -x -C /tmp/probe。base = 853 项;ship = 949 项(+96)。

交错配对 ≥3 轮(本机多 AI 共用,负载摆动可达 20 倍,单次通过无意义):

轮shipbase
1944 / 3 fail853 / 2 fail
2949 / 6 fail853 / 2 fail
3949 / 5 fail853 / 3 fail

失败集合逐轮漂移,且同一个名字在基线也失败:

base 三轮全失败、ship 三轮全失败 ⇒ 基线既有;

对「只在 ship 出现的 3 个名字」做隔离配对复测(base/ship 各 4 轮,6 个用例):

     cases: spcad hbeat pmd3 wall-vs-active flood backpressure
ship-r1 :: P P P P F P        base-r1 :: P P P P F P
ship-r2 :: P P P P F P        base-r2 :: P P P P F P
ship-r3 :: P F P P F P        base-r3 :: P P P P P P
ship-r4 :: P P F F F F        base-r4 :: P P P P F P

负载/热漂移尾部,同一轮 base 也并非干净。

结论(不过度声明):可归因回归 = 0。所有失败都落在已知计时/调度敏感家族,且基线同场同样失败; spcad / hbeat / pmd3 三个名字仅在 ship 出现,隔离复测 7/8–8/8 通过、测试文件与基线逐字节相同、 本批改动是新增离线文件且 realtime.py 未改,判定为负载敏感而非本批引入;但「无真机、无负载隔离的 单主机」不足以对这三个名字做出统计显著性结论,因此它们保留为未归因项,交独立验收复核,本批不据此 声称「0 失败」。

8. 当前状态与遗留项

(test_no_hybrid_total_value_is_emitted 钉死),也不写 validated;

遗留项:

  1. clockAnchors 仍为 O(F)(~130 B/帧)。C1 复核是否把 Clock Gate 的速率证明改成流式摘要(同时保住

单调性与中位斜率),以严格满足 §10.1;

  1. scpad / hbeat / pmd3 三个未归因名字需独立验收在隔离主机复核;
  2. C0-1 配对 witness、C0-2 surfaceID→PID 证明需要可能存在的产品侧记录能力——若真机也无法产出,

建议由 Lead AI 重新规定跨源时钟证明与 END 归因的可达上限(当前 END 最强只能是 candidate);

  1. FrameLifetimeDecoder 的 125/3 仍是编译期常量。若真机 proof 显示设备回报值与常量不同,

需要一次公式入档的正式变更,而不是就地改常量。

Lead AI Independent C0 E2 Audit(2026-09-22)

独立验收对象:exact commit 80b0b162cdfb44ba480bff45b882fe4f718e33ac,审计基线 5a06929c22db912db22866ed2c29109761f1b797。该 range 只有 1 个提交、9 个文件;对 realtime.py、recording.py、display_performance.py、launch_trace.py、adapters.py 做 exact diff,结果均为空,确认 C0 未接产品活线。

独立复核证据:

阻塞缺陷 C0-FIX-01 · round foreground verification 未进入 End Gate

evaluate_c0_end_gate() 读取了 foregroundVerified,但没有把它用于 frame selection。Lead 构造反例:

foregroundVerified=false + frame 自身 foreground=true + 无 surface proof,当前结果仍为:

status      = passed
endQuality  = candidate
selectedEnd = true
failures    = []

这违反正式方案 §6 的「target foreground 状态成立」硬门禁。尤其当前 ActivityTrace adapter 的 foreground 来自 target 配置,缺省可为 true,因此不能用单个 frame 的 foreground=true 替代 round-level verified foreground 证据。

修复要求:

  1. foregroundVerified is not true 时 End Gate 必须 fail-closed,禁止产生 selected END;
  2. 新增独立 failure/reject provenance(建议 target-foreground-unverified),不要把“未证明”伪写成“明确不在前台”;
  3. 增加确定性反例:round foreground 未验证、frame foreground=true 仍必须 missing / failed;
  4. 明确 foregroundVerified 的证据来源,禁止从待选 FrameLifetime 自身循环证明。

阻塞缺陷 C0-FIX-02 · recorded-session 不能自动等价 E4

当前 evaluate_c0_feasibility() 仅凭:

origin == "recorded-session"

就把 evidence 标为 E4。Lead 使用 synthetic observation 独立复现:只要设置 origin="recorded-session",报告即输出 E4。这违反项目证据等级红线:E4 必须是真机证据,序列化 Session 形态本身不是 E4。

修复要求:

  1. recorded/replay/synthetic Session 默认不得自动升级 E4;
  2. 默认保持 E2,只有明确且可信的 true-device capture provenance 才可标 E4;
  3. provenance 必须可审计并随 census 输出,不能由任意 observation 字符串自报即升级;
  4. 增加测试:synthetic recorded session = E2;具备正式 true-device provenance 的 Session 才可 = E4。

Lead Gate 结论

最小修复范围仅限 C0 离线模块、C0 tests、census/provenance 输出及本 devlog/handoff;不得修改 realtime.py 或借此进入 C1。修复提交后由 Lead AI 复验上述两个反例、focused/full regression 与 benchmark;通过后才把 C0 状态切为 READY FOR FORMAL E4,再交 Test AI 真机执行。

Implementation Fix Update · 2026-09-22(C0-FIX-01 / C0-FIX-02)

Lead AI 对 80b0b162cdfb44ba480bff45b882fe4f718e33ac 的独立验收判定 C0 E2 = BLOCKED / REPAIR REQUIRED。本批只修上述两个阻塞缺陷:不进入 C1,不改 realtime.py 等产品活线,不解决 S2 / surfaceID→PID / clock witness,不启动真机 C0,不宣布 C0 PASS。

1. 缺陷与修复

C0-FIX-01 · round foreground verification 未进入 End Gate

修复前行为(Lead 复现,本机复跑确认):foregroundVerified=false 且 frame.foreground=true 时,evaluate_c0_end_gate() 仍返回 status=passed、endQuality=real、selectedEnd 非空、failures=[]。本机复跑比 Lead 记录更严重——得到 real 而非 candidate。

根因两处,缺一不可:

  1. evaluate_c0_end_gate() 读入了 foreground_verified,但它从未参与选择;选择只受 surface_proven 影响。
  2. collect_c0_observations_from_session() 用 first_frame["quality"] != "not-foreground" 反推 foregroundVerified——循环证明:待选的那一帧同时充当"允许选中它"的证人。

修复:

位置变更
evaluate_c0_end_gate()round 级 foregroundVerified is not True → 追加 fail-closed failure target-foreground-unverified;选择分支由 else 收紧为 elif foreground_verified:,无 proof 时 selectedEnd=null、selectionReason=null、endQuality="missing"
FAILURE_CLASSES新增 "target-foreground-unverified": unverified
FRAME_REJECT_ORDER不新增:这是 round 级事实,不是帧级 reject。帧级 not-foreground 仍表示"该帧自证不在前台",两者不得互相冒名
round row新增 foregroundVerified / foregroundVerifiedSource
End Gate 汇总新增 foregroundVerifiedRoundCount / foregroundUnverifiedRoundCount / foregroundVerificationAvailable
collect_c0_observations_from_session()删除循环推导,改为 foregroundVerified=False + foregroundVerifiedSource="missing",并追加 note foreground-verification-unavailable-in-recorded-session
常量新增 FOREGROUND_SOURCE_MISSING / FOREGROUND_SOURCE_INDEPENDENT_WITNESS

foregroundVerified 的证据来源(Lead 要求 4):只能来自独立于待选 FrameLifetime 的证人。Session manifest 只记录 identityStatus(身份),不记录前台;产品当前没有任何路径产生该证人。因此离线投影恒为 false、End Gate 恒报 target-foreground-unverified——这是缺仪器,不是"已证明不在前台"的经验负结论。

C0-FIX-02 · recorded-session 不得自动等价 E4

修复前行为:evaluate_c0_feasibility() 中 "evidence": "E4" if observation.get("origin") == "recorded-session" else "E2"。任意 origin="recorded-session" 的 observation(含全合成 fixture)即输出 E4。

修复:新增 resolve_c0_evidence_level(observation) -> (level, provenance),等级只由显式可审计的采集 provenance 决定,不再由字符串自报:

输入等级provenance
origin ∈ {replay, synthetic}E2(origin 否决,即使携带完整 witness)declared-non-capture-origin
无 captureProvenanceE2not-a-device-capture
kind != "true-device-capture"、witness 非 Mapping、缺 captureId、capturedAtNs 非正E2capture-witness-unusable
kind="true-device-capture" + trueDeviceWitness{captureId, capturedAtNs} 完整E4true-device-capture-witness

报告同时输出 evidence 与 evidenceProvenance;投影 observation 显式声明 captureProvenance: null("声明",不是"缺字段")。replay / synthetic 即使带 witness 也恒 E2:声明与证人自相矛盾的记录不构成可审计证据。

2. 实际修改范围(4 个文件)

文件变更
MacApp/Sidecar/perfowl_collector_core/startup_c0_feasibility.py两项修复主体(常量 / 解析器 / End Gate fail-closed / 投影去循环 / 汇总字段)
MacApp/Sidecar/tests/test_startup_c0_feasibility.py+13 / −1 测试(含 2 个 Lead 反例)
MacApp/scripts/startup-c0-census.pyrow/aggregate 保留 evidence、evidenceProvenance 与 foreground 计数;新增第 6 条 UNCOVERED;控制台新增证据列
site/devlog/p4-startup-phase-c-hybrid-total-plan.md本段

未改:MacApp/scripts/benchmark-startup-c0-feasibility.py(§10.1 空间语义未变,逐字节未动);internal/startup-c0-benchmark.json 为重跑产物。

3. 5 个产品活线文件隔离证明

realtime.py / recording.py / display_performance.py / launch_trace.py / adapters.py 相对 C0 原实现 80b0b16 与基线 13c913b:git diff --stat 为空,SHA-256 逐一 IDENTICAL。

文件SHA-256(前 16)结论
realtime.py8ee779bdf1e6d49dIDENTICAL
recording.py886d4b4c2fcf6391IDENTICAL
display_performance.py12e5daf3019d3bc0IDENTICAL
launch_trace.py78c8e215fbd16117IDENTICAL
adapters.py2eead9d1e14f1caeIDENTICAL

benchmark 另独立断言 productionHotPath.realtimePyUnchanged = true、新增 ActivityTrace 订阅 0。

4. C0 E2 证据(108 项全绿)

cd MacApp/Sidecar && PYTHONPATH=. <py> -m unittest tests.test_startup_c0_feasibility
Ran 108 tests in 0.343s
OK

新增 13 项 / 移除 1 项:

被移除的 1 项:C0FeasibilityReportTests.test_origin_drives_the_evidence_level。该断言钉死的旧值 origin="recorded-session" → E4 正是 Lead 判为缺陷的契约本身,必须随契约变更而改变;其覆盖由 test_origin_alone_never_promotes_past_e2 与两项反例测试接续,覆盖面只增不减(详见 §7 偏差 3)。

5. 全量回归与 flake 归因(E2,未放宽任何阈值)

轮次树用例数结果
R1ship(本批)9614 FAIL + 1 ERROR
R2ship(本批)9616 FAIL
R1base 13c913b9492 FAIL
R2base 13c913b9491 FAIL

证据一 · 失败集合逐次漂移(同一代码两轮):ship R1 挂 xctrace reap(ERROR)、pmd3×3、flood;ship R2 挂 display_ingress_backpressure、pmd3×2、flood、r8fix11、DisplayPipelineBenchmark。xctrace reap 与 pmd3 burst 在 R2 消失,三项新名字出现——失败集合不是代码属性。

证据二 · 基线同样漂移:base R1 挂 flood + DisplayPipelineBenchmark,base R2 只挂 flood。

证据三 · 交错隔离配对(3 轮 ship/base 交替,每轮 8 名全跑,ran=8/8):

name           ship   base   attributable?
xctrace-reap   PPP    PPP    no
pmd3-filter    PPP    PPP    no
pmd3-pump      PPP    PPP    no
pmd3-burst     PPP    PPP    no
flood-bound    FFF    FFF    no        <- 两树 6/6 全挂:稳定宿主 flake
ingress-bp     PFP    FPF    no        <- 两树都挂,但轮次不同
r8fix11-par    PPP    PPP    no
display-bench  PPP    PPP    no

interleaved ship/base pairs: 3
attributable regressions: 0

失败率:ship 10/1922 = 0.52%,base 3/1898 = 0.16%(两轮全量合计)。结论:0 项可归因回归;6 个名字曾在 ship 侧出现但经交错配对排除,已登记在案供 Lead 独立复查。

证据四 · 用例集合归属(loader 口径,非 grep -c 'def test_'):base 949 / ship 961,net +12。comm -23(ship 独有)= 13 项,全部位于 test_startup_c0_feasibility;comm -13(base 独有)= 1 项,即被契约变更取代的 test_origin_drives_the_evidence_level。

6. C0 benchmark 重跑(§10 / §10.1)

指标预算实测判定
collect 每帧 p95≤ 1.0 ms0.0650 msPASS
吞吐≥ 240 帧/smin 14719 / median 21690 帧/sPASS
额外 RSS≤ 2 MiBC0 自身增量 0.4258 MiBPASS
诊断帧保留O(K), K ≤ 64300/900/1800/3600 四档恒为 64PASS
报告体积不随 F 增长18407 → 18409 BPASS
产品活线逐字节不变realtimePyUnchanged=true,新增订阅 0PASS

rssAttributionMiB:sessionReaderBaseline 4.973 MiB(产品自身 validate_recorded_session 的 O(session) 下限)、analyzerIncrementalPeak 5.398 MiB、c0OwnedIncremental 0.426 MiB。未经分摊的峰值仍原样输出(analyzerIncrementalPeakWithinBudgetUnattributed=false)以保持可审计;重跑未修改 benchmark 脚本。

7. 相对原方案的偏差与过程记录

  1. 新增 foregroundVerifiedSource 字段:Lead 要求"明确 foregroundVerified 的证据来源",原 observation schema 无此字段,故新增并随 round row 输出。
  2. 投影行为收紧(显式登记):投影 foregroundVerified 由"从帧反推"改为恒 false,直接后果是所有离线 Session 的 End Gate 现在都记为 target-foreground-unverified、selectedEnd 为 null。这是去掉伪造 proof 的必然结果,不是回归;census 已把该现象登记为第 6 条 UNCOVERED,防止被误读为"已证明不在前台"的经验负结论。
  3. resolve_c0_evidence_level 保留一条升级路径:origin="recorded-session" + 完整真机 witness 仍可为 E4。理由:recorded-session 是真机采集的序列化形态,Lead 要求 2 允许"明确、可信、可审计的真机采集来源";而 replay / synthetic 属声明性非采集中间态,恒 E2。Lead 反例(合成的 recorded-session)因无 witness 而恒 E2。
  4. benchmark 未改动:§10.1 空间语义未变,仅重跑产出新 JSON。
  5. 过程偏差(工具):对同一文件连续两次批量写入时观察到前一次编辑静默丢失,改为逐次写入 + grep 复核,并在提交前以测试结果与 SHA-256 校验兜底。

8. 当前状态与遗留项

Lead AI C0 Fix Revalidation(2026-09-22)

独立复验对象:exact commit 66dfbb847fcd16d1acbe12f2d67108a3e2890428,父提交 13c913b44e90fba37af1932690985c7d6e539b4a。

1. 独立验证结果

2. C0-FIX-02 仍未闭合:结构化 witness 仍可自证 E4

当前 resolve_c0_evidence_level() 把以下普通 observation 字段视为足以升级 E4:

captureProvenance.kind = "true-device-capture"
trueDeviceWitness.captureId = 任意非空字符串
trueDeviceWitness.capturedAtNs = 任意正时间戳

但这些字段没有绑定到产品采集事实、Session 内容哈希、设备侧不可伪造事实或外部 Test/Lead attestation;仓库中除 C0 自身测试与该解析器外,也不存在另一个可信 producer。测试 _true_device_witness() 本身就是手工构造普通 dict。

Lead 独立反例:对 synthetic fixture 生成的 observation 直接注入:

captureProvenance = {
  kind: "true-device-capture",
  trueDeviceWitness: {
    captureId: "forged-by-fixture",
    capturedAtNs: 1700000000000000000
  }
}

当前机械报告立即输出:

evidence = E4
evidenceProvenance = true-device-capture-witness

因此原缺陷只从“一个 origin 字符串自报 E4”变成了“一个三字段字典自报 E4”。这仍不满足 Lead 审计要求中的“明确、可信、可审计的 true-device provenance”,也违反项目 E4 是执行/采集事实而非输入 JSON 形状的证据等级红线。

将该剩余缺陷命名为 C0-FIX-02B · mechanical report must not self-promote to E4。

3. C0-FIX-02B 修复决策

最小且最诚实的语义为:

  1. C0 离线 evaluator 自身永远不得把 observation 内容升级为 E4。 evaluate_c0_feasibility() 的机械报告最多标 E2;结构化 captureProvenance 可以保留为“capture claim / diagnostic provenance”,但不能决定证据等级。
  2. E4 属于 Test AI / Lead AI 的外层执行证据等级。 真机 C0-1/C0-2/C0-3 实际运行后,由 Test AI 交付 session/命令/设备采集上下文,Lead 再判该批证据为 E4;不得让被分析的数据自己给自己发 E4 证书。
  3. 如确实希望产物内携带 E4,应另设外部、hash-bound 的 test attestation 层,由正式 E4 harness 对输入 Session/labels 做内容绑定;该层不能是 observation 内可任意赋值的普通字段。本轮为最小修复,不要求先实现该扩展。
  4. 新增反例:即使 observation 带“结构完整”的 true-device-capture dict,机械 C0 report 仍必须为 E2;原 test_only_a_complete_true_device_witness_reaches_e4 必须删除或改写,因为它当前钉死的就是剩余缺陷。
  5. census 可继续显示 capture provenance claim,但必须与 evidence=E2 明确分列,禁止把 claim 渲染成 E4。

4. Lead Gate 结论

下一次 Implementation AI 只允许修 C0-FIX-02B 与对应 tests/census/docs;不得改产品活线、不得补 foreground 产品仪器、不得进入 C1。

Implementation Fix Update · 2026-09-22(C0-FIX-02B)

Lead AI 对 66dfbb847fcd16d1acbe12f2d67108a3e2890428 的独立复验给出 C0-FIX-01 = PASS / C0-FIX-02 = PARTIAL / C0-FIX-02B = REPAIR REQUIRED / C0 E2 = BLOCKED / READY FOR FORMAL E4 = NO(见上文《Lead AI C0 Fix Revalidation》)。本批只修 C0-FIX-02B,在基线 9ba46322ff00fda4e22fab1a49a6b3e35164a86f 上开工。不进入 C1,不改 5 个产品活线文件,不解决 foreground 产品仪器 / surfaceID→PID / paired witness / S2,不启动真机 C0,不宣布 C0 PASS,不宣布 READY FOR FORMAL E4。

1. 缺陷与修复(冻结原则)

修复前行为(本机在工程基线上复跑证实):resolve_c0_evidence_level() 由 observation 自带的 captureProvenance 结构决定等级——只要 kind="true-device-capture" 加任意非空 captureId、任意正 capturedAtNs,机械报告即输出 evidence=E4 / evidenceProvenance=true-device-capture-witness。仓库内除该解析器与自身测试外不存在第二个可信 producer,所以这只是把「字符串自证」升级成「结构化字典自证」。

本机用完整伪造 dict(captureId="forged-by-fixture"、capturedAtNs=1700000000000000000)对 6 个 origin 扫描:基线 9ba4632 上 4/6 个 origin 拿到 E4,修复后 0/6。

origin基线 evidence修复后 evidence修复后 claim
syntheticE2(origin 否决)E2declared-non-capture-origin
replayE2(origin 否决)E2declared-non-capture-origin
recorded-sessionE4(缺陷)E2true-device-capture-claim-unverified
true-device-captureE4(缺陷)E2true-device-capture-claim-unverified
unknownE4(缺陷)E2true-device-capture-claim-unverified
""(空 origin)E4(缺陷)E2true-device-capture-claim-unverified

冻结修复原则(逐字遵守):C0 离线 evaluator 自身不得根据 observation 内容把报告升级为 E4;机械 evaluate_c0_feasibility() 报告最高只能标 E2;captureProvenance 可继续作为 capture claim / diagnostic provenance 保留,但不能决定 evidence=E4。真正 E4 属于外层执行事实:Test AI 在真机执行 C0-1 / C0-2 / C0-3 并保留 Session、执行命令、设备采集上下文与 labels,随后由 Lead AI 根据该真实执行证据判定「这一批验收证据」为 E4。即被分析的数据不能给自己签发 E4;执行真机实验的人与验收者决定其证据等级。若未来确需报告文件内部携带 E4,须另设 hash-bound external test attestation——本轮为最小修复,不实现、不扩范围。

修复:

位置变更
resolve_c0_evidence_level()删除:等级语义整体撤出该函数
resolve_c0_capture_claim()新增,返回 str:只回答「payload 的 capture claim 有多完整」,返回 CAPTURE_CLAIM_* 命名空间——与 E* 等级命名空间刻意不相交
evaluate_c0_feasibility()evidence 恒为 EVIDENCE_RECORDED(E2);新增 evidenceAssignedBy="offline-evaluator"、evidenceTrueDeviceAssignedBy="test-ai-execution+lead-ai-verdict"、captureProvenanceClaim、captureProvenanceClaimPromotesEvidence=False;notes 增加一条明示 E4 归属
模块 docstring新增第 4 条设计规则「本模块不给自己评级」
常量新增 EVIDENCE_ASSIGNED_BY_OFFLINE_EVALUATOR / EVIDENCE_TRUE_DEVICE_ASSIGNED_BY / CAPTURE_CLAIM_{NONE,DECLARED_NON_CAPTURE,INCOMPLETE,TRUE_DEVICE_UNVERIFIED} / CAPTURE_CLAIM_PROMOTES_EVIDENCE=False;删除 4 个带等级语义的 PROVENANCE_* 常量
census rowevidenceProvenance → captureProvenanceClaim,与 evidence / evidenceAssignedBy 分列
census aggregate新增 evidenceAboveE2Count(机器可检的 0,非 0 即回归)、captureProvenanceClaimCounts、captureClaimPromotionCount
census 控制台 / notes证据等级与 claim 分两行打印;notes 明示 claim 不是等级、E4 归 Test/Lead

EVIDENCE_TRUE_DEVICE = "E4" 常量保留但本模块从不赋值:它作为「刻意缺席者的名字」存在,让读者与测试都能断言机械报告里绝不出现该等级。

2. 实际修改范围(3 个代码/测试文件 + 2 个文档)

文件变更
MacApp/Sidecar/perfowl_collector_core/startup_c0_feasibility.py修复主体
MacApp/Sidecar/tests/test_startup_c0_feasibility.py−1 / +4 → 净增 3 项,共 111 项
MacApp/scripts/startup-c0-census.py等级/claim 分列 + 两个机器可检计数
site/devlog/p4-startup-phase-c-hybrid-total-plan.md本段
internal/current-ai-handoff.mdC0 状态与 Lead 复验要点更新

未改:MacApp/scripts/benchmark-startup-c0-feasibility.py(逐字节未动);internal/startup-c0-benchmark.json 为重跑产物。

3. 5 个产品活线文件隔离证明

realtime.py / recording.py / display_performance.py / launch_trace.py / adapters.py 相对复验对象 66dfbb8、当前 main HEAD 9ba4632 与工作区:git diff --stat 三次均为空,SHA-256 逐一 MATCH。

文件SHA-256(前 16)结论
realtime.py8ee779bdf1e6d49dIDENTICAL
recording.py886d4b4c2fcf6391IDENTICAL
display_performance.py12e5daf3019d3bc0IDENTICAL
launch_trace.py78c8e215fbd16117IDENTICAL
adapters.py2eead9d1e14f1caeIDENTICAL

benchmark 另独立断言 productionHotPath.realtimePyUnchanged = true、新增 ActivityTrace 订阅 0、新增 CoreProfile 录制 0。

4. C0 E2 证据(111 项全绿)与测试集合差异

对象结果
C0 focused(ship)111 / 111 OK
C0 focused(基线 9ba4632)108 / 108 OK

用 unittest loader(非 grep -c 'def test_')取测试 ID 集合做差:108 → 111。

  1. test_lead_counterexample_complete_witness_still_stays_e2——核心反例:即使 observation 内人为提供完整 kind=true-device-capture + 非空 captureId + 正 capturedAtNs,机械报告仍必须 E2,且 claim 分列、captureProvenanceClaimPromotesEvidence=False;
  2. test_a_full_witness_cannot_promote_any_origin——对多个 origin 逐一附加完整伪造 witness 扫描,全部 E2;
  3. test_evidence_ownership_is_reported_not_self_assigned——断言报告声明 E4 归属,而不是默默省略;
  4. test_lead_counterexample_forged_witness_cannot_promote_through_the_census——census 层反例,并带非空泛探针:把 evidence="E4" 硬塞进 row 时 evidenceAboveE2Count 必须变成 1,证明前面那些 0 有意义。

保留(未放宽):recorded-session 无 provenance → E2;replay → E2;synthetic → E2;partial / invalid provenance → incomplete-capture-claim 且 E2。

5. 全量回归与 flake 归因(E2,未放宽任何阈值)

按门禁纪律做 base(9ba4632) → ship 交错配对 3 轮(共 6 次全量)。

轮次树ran失败集合大小 (F/E)耗时
1base9617 (4/3)241.7s
1ship96410 (6/4)315.9s
2base96117 (8/9)370.5s
2ship96418 (9/9)410.2s
3base96119 (10/9)501.6s
3ship96422 (10/12)835.1s
争议 IDbase 命中ship 命中
test_11_stop_during_drain_does_not_start_new_tap3/33/3
test_14_startup_only_mode_does_not_start_frame_continuation3/33/3
test_benchmark_shipping_policy_steady_120hz_7200_frames2/32/3
test_benchmark_real_cadence_120hz_10s1/32/3
test_pump_yields_after_burst_limit1/30/3

其中 test_11 / test_14 在两棵树上都 3/3 必挂(负载下确定性失败),test_pump_yields_after_burst_limit 在基线上反而更容易挂。这 5 项与既有 flake 家族一致(test_pmd3_subscription_fairness、DisplayPipelineBenchmark、test_frametime_continuation)。

6. C0 benchmark 重跑(§10 / §10.1)

指标本次预算结果
单帧投影 p950.0955 ms≤ 1 msPASS
吞吐 min10334 frames/s≥ 240PASS
C0-owned 增量 RSS0.3906 MiB≤ 2 MiBPASS
诊断帧保留 K恒定 64与帧数无关PASS
报告字节18409 → 18783—增 374 B(新增归属字段与 note)
realtimePyUnchangedtrue—PASS

7. 相对原方案的偏差与过程记录

  1. census 字段改名而非并存:evidenceProvenance → captureProvenanceClaim。改名而非并存,是因为旧名字本身在暗示「等级的依据」,并存会留下一个仍可按等级解读的入口。
  2. captureProvenanceClaimPromotesEvidence=False 作为字段输出:把「claim 不升级等级」从注释变成可断言的机器事实;census 侧同样落到 captureClaimPromotionCount。
  3. 两个过程性坑(已修,记录以备后人):
  1. 首轮探针整体作废重跑:因上一条第一项,第一次的 6 次全量运行中基线侧数据不可信,已全部作废、未用于本报告;§5 表格全部来自重跑。

8. 当前状态与遗留项