From 872370ba9dffe7632b0004d2287ee80408e2fd88 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Tue, 22 Sep 2026 02:17:18 -0400 Subject: [PATCH] [docs, MG_Remote] (P6->P6.5): the end state is TCP across machines, and the transport stack has two axes The end state is re-ruled: client and server may sit on different machines, OSes and architectures, joined over TCP. The AVF pVM / AF_VSOCK end state the P6 end-state review assumed is withdrawn (retraction at its head, form D added to its table, the vsock probe and both external unknowns struck). The transport stack becomes two independently selectable axes, negotiated in the handshake and mixable: control plane (ITransport: fork / unix: / tcp://host:port) and data plane (ILink: ShmLink / StreamLink). On one machine control over TCP with data over shared segments is a legal pair; ShmLink brings its own AF_UNIX aux rendezvous for SCM_RIGHTS, so ITransport narrows to control frames. `auto` is decided by a successful segment delivery, never by inspecting addresses, and a fall-back is named. Nothing above Transport/ may branch on the link kind. ARCHITECTURE.md gains 11.9 for this; CONTRACT-P6.md gains 10.3. ROADMAP: P6.5 and Ph get rows (both were referenced by the contract and absent from the stage table); the IPC track becomes P6 -> P6.5 -> Ph -> P12 -> P9 -> P10 -> P11(same-machine arm). Every later row is reconciled against the tree: items already landed are struck (client vertex arrays, client-minted query handles, credit default 1, SEG_EVENT overflow mechanism), the unreachable P7 gate (`nm | grep glslang` on a server image that IS libMobileGL.so) is replaced by the 184-symbol ratchet share, fixed-width wire form moves from P7 to P6.5, P12 is cut down per the review (server-owned display, no Surface passing), and the debt table's stale claims are corrected: class C is down to two slots, not 15 and not 511; PACK-PBO and the 2 MiB reply cap are P9's, not P6's. Verified against the tree and recorded honestly: the contract's three hs rows (LinkTerms, Refuse, the fingerprint split) never landed - protocol.fbs has neither - so CURRENT_STAGE_PROGRESS.md's claim that S6 ran red is withdrawn and the rows move to P6.5; the 184-symbol ratchet gate does not exist in CI; the server process never initialises PipeStats, so gate 8's `srv=0 srvpark=0` is a structural zero (fix in progress in the tree, not in this commit). check_doc_citations.py: 159 citations, one pre-existing basename ambiguity. --- MobileGL/MG_Remote/CONTRACT-P6.md | 45 ++++++++++++++++--- MobileGL/MG_Remote/Transport/StreamLink.h | 5 +++ docs/Disaggregated/ARCHITECTURE.md | 29 ++++++++++-- docs/Disaggregated/CURRENT_STAGE_PROGRESS.md | 14 ++++-- docs/Disaggregated/P6-ENDSTATE-REVIEW.md | 23 +++++++--- docs/Disaggregated/ROADMAP.md | 47 ++++++++++++-------- 6 files changed, 129 insertions(+), 34 deletions(-) diff --git a/MobileGL/MG_Remote/CONTRACT-P6.md b/MobileGL/MG_Remote/CONTRACT-P6.md index e2528bf0..778002c8 100644 --- a/MobileGL/MG_Remote/CONTRACT-P6.md +++ b/MobileGL/MG_Remote/CONTRACT-P6.md @@ -81,12 +81,13 @@ Two consequences, and the second is why this file can exist without changing beh > it would not make Windows work; it would only put asio headers inside `Transport/`, which > `ITransport.h` keeps dependency-light on purpose. **Revisit at P6.5**, where > `asio::generic::stream_protocol` carries a raw (family, type, protocol) triple and therefore -> gives AF_VSOCK from the same implementation - and where `ITransport` lets an `AsioTransport` +> gives AF_VSOCK from the same implementation (2026-09-22: the end state's link is TCP, not +> AF_VSOCK - §10.3 - and the argument is the same for `asio::ip::tcp`) - and where `ITransport` lets an `AsioTransport` > land beside `SocketTransport` without touching a caller. -| `LinkTerms{dataPlane, wireForm, maxReplyBytes, cmdWindowBytes, stageWindowBytes}` | Appended to `Hello`/`Welcome`. `dataPlane` has exactly **one** legal value in P6, `SharedSegments`; `wireForm` exactly one, `StructImage`. Anything else is refused **by name**. The four sizes are **stated by the SERVER**. | any other value → `Refuse{ProtocolMismatch}` | the handshake | `hs` | -| `Refuse{code, detail, peer values}` | Appended `CtrlMsg` union tag. A handshake disagreement is an **answer**, not an abort (§5.1). | — | both sides | `hs` | -| `wireFingerprint` / `buildFingerprint` | The single `abiFingerprint` splits. §4. | mismatch → `Refuse`, never `Fatal` | the handshake | `hs` | +| `LinkTerms{dataPlane, wireForm, maxReplyBytes, cmdWindowBytes, stageWindowBytes}` | Appended to `Hello`/`Welcome`. `dataPlane` has exactly **one** legal value in P6, `SharedSegments`; `wireForm` exactly one, `StructImage`. Anything else is refused **by name**. The four sizes are **stated by the SERVER**. | any other value → `Refuse{ProtocolMismatch}` | the handshake | `hs` → **not landed** (verified 2026-09-22: `protocol.fbs` has no `LinkTerms`); re-homed to P6.5 `nd`, §10.3 | +| `Refuse{code, detail, peer values}` | Appended `CtrlMsg` union tag. A handshake disagreement is an **answer**, not an abort (§5.1). | — | both sides | `hs` → **not landed** (no `Refuse` in `union CtrlMsg`); re-homed to P6.5 `wf`, §10.3 | +| `wireFingerprint` / `buildFingerprint` | The single `abiFingerprint` splits. §4. | mismatch → `Refuse`, never `Fatal` | the handshake | `hs` → **partially landed** (explicit build stamp, `abiMajor`/`abiMinor` checked, real pids; the split itself and the `PipeFields.def` layout digest are not); re-homed to P6.5 `wf`, §10.3 | | `FatalCode` | **Unchanged**, 7 values (`protocol.fbs:248-256`). `table Fatal` appends `family: string`. §5.2. | — | — | `dl` | All schema edits are **append-only**. A FlatBuffers table field's id is its vtable slot and an enum @@ -625,6 +626,38 @@ Negative controls, each run red once: 6. `ARCHITECTURE.md:9` and `MG_Backend/MGPipe/PipeInputs.h:281`, `:744`, `:957`, and `P5F-WIRE-COMPLETENESS §1.4` — "the server does not link `MG_Impl`". **False at this head.** §12. +### 10.3 Amendments of 2026-09-22 — the end state re-ruled + +1. **The end state is TCP across machines, OSes and architectures**, not an AVF pVM over + `AF_VSOCK`. `docs/Disaggregated/P6-ENDSTATE-REVIEW.md` carries the retraction at its head; its + §3 gains form **D**. Same-machine `spawn` (AF_UNIX + shared segments) stays as the local form. +2. **The transport stack has two independent axes.** The control plane (`ITransport`: `fork` + inherited fds / `unix:` / `tcp://host:port`) and the data plane (`ILink`: `ShmLink` / + `StreamLink`) are chosen separately, negotiated in the handshake, and may be mixed — on one + machine, control over TCP with data over shared segments is a legal pair. Callers above + `Transport/` see `ITransport` + `ILink` and nothing else; branching on the link kind above that + line is a purity-gate failure (the `lk` grep gate, widened). Design: `ARCHITECTURE.md` §11.9. +3. **§8.2's "`ITransport` is not extended" is amended in one respect**: descriptor passing leaves + the control plane and becomes the shared-segment data plane's *delivery*. `ShmLink` brings its + own AF_UNIX aux rendezvous, named in `Welcome`, and `SCM_RIGHTS` travels on that and nowhere + else. Rule G is unchanged: a transport that declares no descriptor passing (TCP) passes none, + and the data plane that needs it must bring its own channel or not be selected. `auto` + selection is decided by a **successful delivery**, never by inspecting addresses, and a + fall-back to `Stream` is named in the log and the stats line. +4. **§2's three `hs` rows** (`LinkTerms`, `Refuse`, the fingerprint split) did not land in `hs`; + `protocol.fbs` carries neither `LinkTerms` nor a `Refuse` member of `CtrlMsg`. They are P6.5's + (`nd`, `wf`), and S6 in §9 moves with them. `CURRENT_STAGE_PROGRESS.md`'s earlier claim that + S6 had been run red is withdrawn. +5. **Fixed-width wire form is no longer negotiable-later.** Two different binaries from two + compilers are the end state, so the `PipeFields.def`-derived layout digest, the fixed-width + rewrite of `DynamicBackendParameters` / `MGPCaps` / the `RenderStateParameters` blob, and the + `buildFingerprint`-only-under-`Dial == Fork` policy are P6.5 `wf`, taken off P7. +6. **`Ph` gains pairing/authentication**: a `Hello` without a pairing token is refused on any + non-loopback listener. `Ph` precedes P12's non-loopback listen. +7. **"The 511 class-C entries" in §11** is the P5-joint census + (`docs/Disaggregated/notes/p6/census-classC.md`). At this head the `MGR_UNMIGRATED_*` lists are + empty; `SetSwapInterval` (P10) and `DeleteTransformFeedback` (P9) are the two that remain. + --- ## §11 Not P6 @@ -634,7 +667,9 @@ readback and the reply-slot pool (P9); `DynamicBackendParameters`' fixed-width r `MOBILEGL_IPC_POLL_ESCALATE` (P10); remaining monolith-only frontend-object / twin-registry glue (P3b/P4b) and the named P7 functionality debts; Windows `pipe:` / `unix:`; the 511 class-C entries. -**The stream data plane is P6.5**, and it must land before P11 and before P9 picks a mechanism. +**The two-axis transport stack — control × data, TCP-capable, cross-build — is P6.5** and is the +IPC track's next stage (§10.3). P9 builds its reply semantics on P6.5's message replies rather than +on a slot pool, and P11's T0/T1 are refused by name on a stream data plane. **Untrusted-guest hardening is `Ph`**, and it must land before any shipping server app accepts a connection from a guest it did not produce — including the `Fatal`-policy flip (§5.2), the handle-slot budget, and the caps in §12. diff --git a/MobileGL/MG_Remote/Transport/StreamLink.h b/MobileGL/MG_Remote/Transport/StreamLink.h index 4537dc6d..4f7db242 100644 --- a/MobileGL/MG_Remote/Transport/StreamLink.h +++ b/MobileGL/MG_Remote/Transport/StreamLink.h @@ -9,6 +9,11 @@ // ILink's second implementation, DECLARED BY c6 AND IMPLEMENTED BY NOBODY. // Authority: CONTRACT-P6.md §8.4. Its phase is P6.5. // +// The link it exists for is TCP across machines (end state re-ruled 2026-09-22, +// CONTRACT-P6.md §10.3, ARCHITECTURE.md §11.9), and it is one axis of two: the +// control plane (ITransport) is chosen independently, so tcp control + shm data +// on one machine is a legal pair and nothing above Transport/ may tell which. +// // WHY A HEADER FOR SOMETHING THAT DOES NOT EXIST. ILink's adequacy - "can this // seam name what a byte stream needs?" - is the one claim c6 makes that an // argument cannot settle and a compile can. If ILink cannot express progress diff --git a/docs/Disaggregated/ARCHITECTURE.md b/docs/Disaggregated/ARCHITECTURE.md index bfd1435f..451615d5 100644 --- a/docs/Disaggregated/ARCHITECTURE.md +++ b/docs/Disaggregated/ARCHITECTURE.md @@ -428,6 +428,28 @@ server 没有第二份 `BufferObject`,不存在"staging → server 侧 shadow" fence 完成度必须来自**真的逐 fence 退休**,不是 present 水位(DirectGLES 的 `g_completedFrameSerial` 只在 `Present()` 里前进,帧中 fence 会退化成帧计数推断——`DirectVulkan.cpp` 写明这是被修掉的 bug)。无 present 循环下 `retiredTail` 会饿死:DirectGLES 的 server 加**非 present fence tick**(距上次 `Present` 超过 8 ms 或每 4096 条已 apply 记录插一个 `glFenceSync`);P8 加一个无 present 的 split 用例。P5b 已把五条 sync 槽搬上 apply 线程(§17.5)。 +### 11.9 传输栈的两根轴(P6.5,2026-09-22 定) + +终局:client 与 server 可以在不同机器、不同 OS / 架构上,经 TCP 连接;同机 `spawn` 保留。为此传输栈拆成**两根独立可选、握手协商、可混搭**的轴,上层只见两个接口: + +| 轴 | 接口 | 实现 | 选项 | +|---|---|---|---| +| **控制面** | `ITransport`(`Transport/ITransport.h`,只承载 FlatBuffers 控制帧,**不再承载描述符传递**) | `SocketTransport` | `fork`(继承 fd,今天的 spawn)、`unix:`(sm 的独立启动)、`tcp://host:port`(跨机;同机也可用) | +| **数据面** | `ILink`(`Transport/ILink.h`,热路径:记录预留 / 提交、watermark、reply、event、span 解析) | `ShmLink`(共享段 + `RingControl` 页 + 门铃)、`StreamLink`(分块封帧、watermark 变消息、reply 变自带 seq 的消息、发送窗口) | `shm`、`stream`、`auto` | + +规则: + +- **配对在会话建立时选定一次,之后不变**(缝是 setup-time 的,`CONTRACT-P6.md` §8.2)。`Hello` / `Welcome` 里的 `LinkTerms{dataPlane, delivery, wireForm, maxReplyBytes, cmdWindowBytes, stageWindowBytes}` 由 **server 陈述**尺寸、client 请求可被钳制。 +- **共享段的交付与控制面解耦**:`ShmLink` 自带一个 AF_UNIX aux 汇合名,在 `Welcome` 里公布,`SCM_RIGHTS` 只走它。于是同机上"控制面 TCP + 数据面共享段"是合法配对,控制面走什么与数据面走什么互不牵连;`ITransport` 收窄为纯控制帧(`auxFd = -1` 已是"这条链不传 fd"的诚实答案)。 +- **`auto` 的判据是段实际交付成功**——client 连 aux、收到 fd、`Adopt` 通过 `fstat` 校验——而不是看对端地址是不是 loopback。回落到 `stream` 必须具名进日志与 stats 行(`ARM` 证明的形状,ID-124),不能静默降级。 +- **上层零链路种类分支**:`SessionProducer` / `SessionConsumer` / `ServerLoop` / `PipeWireEncoder`、`ClientSession.cpp` 的 `kSegEvent` 挂载、`ResourceTracker.h` 的 writeback 解析都只经 `ILink`;`ShmLink` / `StreamLink` / `RingControl` / `ReplySlotPool` / `EventRingConsumer` / `m_shm.` 只允许出现在 `Transport/` 与其测试(lk 的 grep 门加宽)。角色 / 拓扑谓词(`MGPipeSplitActive()`、`MGPipeBlocksAreDistinct()`、`MGPipeBackendIsLocal()`)回答的是"谁在哪个进程",不是"用的什么链路"。 +- **门铃归数据面**:共享段上是 futex / condvar(同内核跨进程可用),stream 上是消息本身;控制面不参与热路径。 +- **跨机意味着两端是不同二进制**:`wireFingerprint`(`PipeFields.def` 派生的逐成员布局摘要 + 目录摘要 + 字节序 / 指针宽度)永远比较,`buildFingerprint` 只在 `Dial == Fork` 下比较;不一致是 `Refuse`,不是 abort。 +- 配置面(命名待 P6.5 定):`MOBILEGL_TRANSPORT` 仍是**拓扑**(monolith / inproc / spawn,G1 相关);新增 `MOBILEGL_IPC_CONTROL=fork|unix:|tcp://host:port`(取代 `MOBILEGL_IPC_SERVER_PATH` 的角色)与 `MOBILEGL_IPC_DATA=auto|shm|stream`。 +- **代价要量**:`ILink::ReserveRecord` 在 VD32 下是 ~850–3550 次/帧的虚调用,客户端线程已 ~94% 占用;`lk` 的门对 inproc 结果与逐线程 CPU 逐字不变,P6.5 再加 2×2 矩阵车道({unix, tcp} × {shm, stream})与混搭对 (unix + shm) 的逐线程 CPU 差。 + +TCP 上的两个数量级差别(RTT 毫秒级、带宽 30–100 MB/s)使 §13.1 的每一条 `kWaitReply` 行和 §14 的 `SEG_STAGE` 预算从"记录项"变成"可行性数";见 `ROADMAP.md` P6.5 行的必测数与开放问题 19–23。 + ## 12. persistent map 与 ≥16 MiB 采纳 `AcquirePersistentMap` 是永久的地址空间捐赠(返回 host-visible coherent 指针;≥16 MiB 可变 store 由 `TryAdoptLargeStorage` 自动走到,实测 MC 26.3 p99 163→21 ms、40→115 fps、省 ~400 MB)。**整个 monolith 改造期一动不动**(D-B4)。 @@ -449,7 +471,7 @@ fence 完成度必须来自**真的逐 fence 退休**,不是 present 水位( ### 13.1 稳态零 roundtrip 与不可避免的阻塞点 -零 round trip:全部 draw/clear/blit/copy/dispatch/barrier/XFB 跨度/bind/CSO/`set_*`/上传/`present`;全部 caps 站点;`glGetError`/`glFinish`/`glFlush`;fence 与 query 的创建及非阻塞轮询;`glGetTexImage`(DirectGLES);`glReadPixels` → pack PBO(fire-and-forget + client 侧 `MarkGpuWritten`,P6+);`glEndTransformFeedback`;`eglSwapBuffers`;`*IndirectCount`;restart/multi-draw。 +零 round trip:全部 draw/clear/blit/copy/dispatch/barrier/XFB 跨度/bind/CSO/`set_*`/上传/`present`;全部 caps 站点;`glGetError`/`glFinish`/`glFlush`;fence 与 query 的创建及非阻塞轮询;`glGetTexImage`(DirectGLES);`glReadPixels` → pack PBO(fire-and-forget + client 侧 `MarkGpuWritten`,P6+);`glEndTransformFeedback`;`eglSwapBuffers`;`*IndirectCount`;restart/multi-draw。**TCP 终局(2026-09-22)**:每一条 `kWaitReply` 行在跨机链路上就是一次 RTT——`ResourceCreate`、`SetTextureParams`、纹理半边的 `ResourceSubData` 都在此列(`CONTRACT-P5E.md` §2.5)——所以逐帧 `kWaitReply` 次数是 P6.5 的必测数,与本节的 roundtrip 计数器同源;MC 加载区块那一阵的几百次创建在 1–5 ms 一次下是可感知的卡顿,要么减少这一列,要么让它们异步(P9)。 不可避免(全部罕见):握手一次;surface 生命周期与首次 `MakeCurrent`+`InitCapabilities` 每 surface 至多一次;`glReadPixels` → 客户内存(像素进 `SEG_REPLY`);`glGetTexImage`(DirectVulkan);GPU-write pending 的 buffer 首次 CPU 读;`glClientWaitSync(timeout>0)`、`GL_QUERY_RESULT` 未完成、`glBeginConditionalRender`(谓词只解析一次);`glBufferStorage` 的 ack;`MapPersistent`(仅 T1);纹理拉取(§8.4);client 侧索引扫描当源 EBO 在 pending 集里;ring/stage 耗尽与 present credit。 @@ -474,7 +496,7 @@ fence 完成度必须来自**真的逐 fence 退休**,不是 present 水位( - `eglSwapBuffers` → `present{frameSerial}` → publish + 敲门铃 → 返回,除非超出 credit。**`present` 与 `eglSwapBuffers` 严格 1:1**:两个后端的帧边界排空只在 `Present` 内发生,批量会饿死它们。 - **`MOBILEGL_IPC_PRESENT_CREDIT` 默认 1**(P10 提出,P5e 落地,range 1..8):延迟叠加,server 的 `Present` 末尾已在 `vkWaitForFences` 上等 2–3 帧,credit 2 就是端到端 4–5 帧;只有实测吞吐收益能抵掉延迟代价才调高。Magma 从不注册 `SetSwapInterval`,IPC credit 是它唯一的显式限帧器。 - **P5e:credit 是 run-ahead 的唯一稳态背压,字节不是**(`CONTRACT-P5E.md` §2.4)。`MGPPresent::FrameSerial` 从"0,由 server 盖自己的帧数"改成**由 client 铸造、1 起算**——一个 credit 只能在付账方能推进的 id 空间里计量,而付账方是 client;`ServerVerbSink::OnPresent` 在 `Present()` 返回之后调 `ServerSession::ReturnPresentCredit(FrameSerial)`,一次 swap 一个 credit(那个函数自 v1 写下以来一直没有生产调用者,这是它的第一个)。credit 1 = client 在 server 应用并交换第 N 帧时发布第 N+1 帧的记录:一帧重叠,最多一帧附加延迟。等待发生在**编码之前**——先编码再 park 会把一次 SEG_CMD 预留持有整整一帧 server 时间。run-ahead server 上 `FrameSerial == 0` 是 `Fatal{ProtocolCorruption, "Present.FrameSerial"}`。 -- 预算(~850 draw + ~0.36 MB pmap/帧):SEG_CMD 每帧 ~70 KB 对 8 MiB,SEG_STAGE ~1 MB/帧对 32 MiB,SEG_REPLY 不变。`WaitForCmdSpace` 与 stage bell 是安全网而不是节奏器,两者退出时都排空 SEG_EVENT。stats 行与 wire ledger 多一个 `credit-waits`:credit 1 下它是 0 就说明 server 从来不在帧的关键路径上,接近帧数就说明它一直是。 +- 预算(~850 draw + ~0.36 MB pmap/帧):SEG_CMD 每帧 ~70 KB 对 8 MiB,SEG_STAGE ~1 MB/帧对 32 MiB,SEG_REPLY 不变。跨机 TCP 上这 ~1 MB/帧对的是 30–100 MB/s 的链路而不是内存,60 fps 即 60 MB/s,贴着 Wi-Fi 上限(`ROADMAP.md` 开放问题 19、20)。`WaitForCmdSpace` 与 stage bell 是安全网而不是节奏器,两者退出时都排空 SEG_EVENT。stats 行与 wire ledger 多一个 `credit-waits`:credit 1 下它是 0 就说明 server 从来不在帧的关键路径上,接近帧数就说明它一直是。 - 线程——client:**v1 不加线程**,编码在 GL 线程上直接写 ring;外来线程的 sync/query 读从 `RingControl` 无锁回答,必须发射的少数取 `ctrlMutex` 走 `AuxRequest`(SPSC ring 不允许第二个 producer)。server:`mgl-srv-io`(封帧、`SCM_RIGHTS`、doorbell、CTRL RPC)、`mgl-srv-apply`(**终身持有原生 context**,`MakeCurrent` 的缓存失效风暴变启动期一次性)。 - **核心放置**:全库无亲和性控制。规则:报总 CPU 工作量差(client tracker + encode + decode + server apply vs monolith `PrepareForDraw`);复用 `ShaderCompilePool` 的大核探测把 `mgl-srv-apply` 绑到大核(`MOBILEGL_IPC_SERVER_AFFINITY`,默认 auto)。 - 拆机顺序:publish + server 排空并 ack → 停 apply 线程 → 关 transport → client 排空 compile pool → `MobileGL::Destroy()` → 释放 sync/query handle(P5 落地形状见 §17.3)。 @@ -484,6 +506,7 @@ fence 完成度必须来自**真的逐 fence 退休**,不是 present 水位( ### 15.1 启动与握手 - server 定位:`MOBILEGL_IPC_SERVER_PATH`(主要)→ `dladdr(&MobileGL::Initialize)` 同目录的 `libMobileGLServer.so`(兜底;集成测试静态链接 `MobileGL_s`、trace replay 的可执行文件不在库目录)。 +- **端点种类(P6.5 ct,2026-09-22)**:`fork`(继承 fd,本节其余各条描述的形状)、`unix:`(sm 的独立启动,`SocketTransport::Listen` / `ConnectTo`,两条连接)、`tcp://host:port`(跨机;同机也可用,此时数据面仍可协商为共享段,§11.9)。TCP keepalive / 心跳失败**由传输层报告为挂断**,进 dl 的 device-lost 闩——它不是 apply 超时,dl 的"绝不取自超时"不因此松动。 - 启动:`socketpair(AF_UNIX, SOCK_STREAM)` + `fork`/`execve`,fd 3 = socket。无文件系统 socket 路径、无 abstract namespace。 - **子进程强制 monolith**(修无界 fork 链):spawn 时构造显式 envp 剔除 `MOBILEGL_TRANSPORT` 与全部 `MOBILEGL_IPC_*`;`mobilegl_server_main` 在到达 `Init()` 之前把 `MG_Config::Transport` 硬置为 `Monolith`。两条都做。`MG_Test/Wire` 测试:进程树只多出恰好一个子进程。 - `Hello{abi, backendType, buildFingerprint, configBlob}` → `Welcome{四个段}`。`configBlob` 转发 client 解析好的 `MG_Config::Features`;`buildFingerprint`(git hash + `PipeCalls.def` hash)不匹配 → `Fatal{AbiMismatch}`;segment 尺寸尚未混入 fingerprint(ID-47 债)。 @@ -500,7 +523,7 @@ fence 完成度必须来自**真的逐 fence 退休**,不是 present 水位( ### 15.3 Linux / Windows / 崩溃 -- Linux/X11:`Window` 是 XID,`nativeToken:u64` 直接送;Wayland 维持不支持;WSL/CI 永不开窗(`EGL_PLATFORM=surfaceless`)。Windows:`HWND` 进 `nativeToken`,Vulkan 可行,WGL/ANGLE 对外进程 HWND 不受支持 → headless only;transport 默认 named pipe。Windows 机器不是正确性门。macOS 不拆分。 +- Linux/X11:`Window` 是 XID,`nativeToken:u64` 直接送;Wayland 维持不支持;WSL/CI 永不开窗(`EGL_PLATFORM=surfaceless`)。Windows:`HWND` 进 `nativeToken`,Vulkan 可行,WGL/ANGLE 对外进程 HWND 不受支持 → headless only;transport 默认 named pipe。Windows 机器不是正确性门。macOS 不拆分。**2026-09-22**:TCP 终局下 Windows / 桌面 client 成为真实形态,`pipe:` / `unix:` 的 Windows 具名拒绝由 TCP 替代;"不是正确性门"与"macOS 不拆分"在 client 平台范围(`ROADMAP.md` 开放问题 22)定下前维持。 - server 死:client 读到 EOF/EPIPE → device-lost 闩锁(GL 调用 no-op、`eglSwapBuffers` 返回 `EGL_FALSE`+`EGL_CONTEXT_LOST`、`glGetGraphicsResetStatus` 返回 `GL_UNKNOWN_CONTEXT_RESET`);`MOBILEGL_IPC_RESPAWN=1` 时重启并全量重推(默认关)。client 死:server 读到 EOF → 立即销毁原生 context 并退出;`MOBILEGL_IPC_IDLE_EXIT_S`(默认 30)只作最后保险。 ## 16. 构建布局 diff --git a/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md b/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md index 507fbfc8..b6247456 100644 --- a/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md +++ b/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md @@ -50,9 +50,17 @@ server 路径(`94e2f2e0`、`15bd9a67`、`1039502e`、`2afa0002`)。 | 8 | **性能只记录**,但三个数强制:socket 门铃 vs condvar、`SEG_STAGE` 字节/帧、chunking 后记录/帧 | ⏳ **未采集**,`MEASUREMENTS.md:342` 仍说 chunking 后分布不存在 | 负控(各跑红一次):S1 不可解析镜像(sm)、S2 kill server(dl)、S3 未洗环境(sm)、S5 窗口 token -到达(cp)、S6 `dataPlane=StreamOnly`(hs 的 Refuse)、S7 裸 abort(dl 普查门)、S8 `SessionFaultCount()==0` +到达(cp)、S6 **未跑——`LinkTerms.dataPlane` 不存在于树上**(`protocol.fbs` 无 `LinkTerms` / `Refuse`,hs 只落了 build stamp、`abiMajor/Minor` 补检与真实 pid;此处此前写"已跑红一次"是错的,随契约 §2 三行移交 P6.5,契约 §10.3)、S7 裸 abort(dl 普查门)、S8 `SessionFaultCount()==0` 整轮(t6)。 +### 2.1 收官前另欠(2026-09-22 核出) + +- server 进程侧的 `PipeStats` 半边是**结构性零**:`ServerMain` 不跑 `MobileGL::Initialize`,`PipeStats::Init()` 从未在 server 进程执行,~80 处 `if (Enabled())` 永远为假,`srv=0 srvpark=0` 长得和"从没等过"一模一样(`PipeStats.h:256` 自己写明了这一点)——门 8 的"socket 门铃 vs condvar"因此没有 server 半边。修法是在 server 进程里于 config 加载与角色声明之后初始化它,汇总行落 `.server.log`,由车道断言而非注释假设(工作区中进行中,未提交)。 +- 184 符号棘轮 CI 门(契约 §12.1):`test.yml` / `scripts/` 里**没有**。 +- 契约 §2 表 0 分给 hs 的 `LinkTerms` / `Refuse` / `wireFingerprint` 拆分:**未落地**,移交 P6.5(`ROADMAP.md` P6.5 行,契约 §10.3)。 +- `MOBILEGL_IPC_IDLE_EXIT_S`(`ARCHITECTURE.md` §15.3 默认 30):未被解析。 +- `TextureParamsWithoutASamplerView` 的"P6 inspection forwarder"债(`MEASUREMENTS.md` §7.2):场景代码已无 P6 引用,是否已由 fc / cp 关闭**待核**。 + --- ## 3. 真机验收(Redmi `2f7cbe2e`) @@ -88,7 +96,7 @@ G1 守卫下 pull 构建不变。 - **出口门 7、8**(真机配对 A/B、三个性能数)——待采集,见 §2。 - **`DirectVulkan` 真机分离路径分歧**——Magma × 真实 GPU,非 P6。 -- **P6.5**:数据面流式(`ILink`/`StreamLink` 已声明未接线)、AF_VSOCK、`SEG_STAGE` 送窗口复活。 -- **Ph**:让 `Session::Fail` 可返回的策略翻转(需在每个依赖 `[[noreturn]]` 的站点造真实返回路径)。 +- **P6.5**:传输栈两轴化(控制面 `ITransport` × 数据面 `ILink`,握手协商、可混搭)+ TCP 跨机 + wire 定宽与布局摘要;`StreamLink` 已声明未接线;`SEG_STAGE` 送窗口复活。终局已改为 TCP 跨机跨平台(2026-09-22),AF_VSOCK 撤回;见 `ROADMAP.md` P6.5 行、`ARCHITECTURE.md` §11.9。 +- **Ph**:让 `Session::Fail` 可返回的策略翻转(需在每个依赖 `[[noreturn]]` 的站点造真实返回路径)+ 配对 / 认证;前置于 P12 的非 loopback 监听。 - **P12**:真窗口跨进程(`ANativeWindow*` 是客户端进程内指针,`SetWindowHandle` 至今具名拒绝)。 - **seq/op 未穿 SessionFault 帧**:90 个站点不逐一穿线,消息本身已带 op,帧只带 code/family/message。 diff --git a/docs/Disaggregated/P6-ENDSTATE-REVIEW.md b/docs/Disaggregated/P6-ENDSTATE-REVIEW.md index 54d66ae6..5ddeca60 100644 --- a/docs/Disaggregated/P6-ENDSTATE-REVIEW.md +++ b/docs/Disaggregated/P6-ENDSTATE-REVIEW.md @@ -12,6 +12,14 @@ > abort 计数 93→92、`m_windowHandle` 的注入点形状、以及 `MGPipeSplitActive()` 的命名冲突。 > 正文已就地更正。a6 另发现四处本文未及的阻塞项(apply 线程在第一条记录前 abort、控制面两端都没接、 > 控制回复等待无期限、`SurfaceReply` 装不下 result)。**以 [`notes/p6/a6-audit-v1.md`](notes/p6/a6-audit-v1.md) 为准。** +> +> **2026-09-22 更正(终局改判)**:本文假设的终局——client 在 AVF pVM、链路 `AF_VSOCK`——**撤回**。现定终局: +> client 与 server 可在**不同机器、不同 OS / 架构**上,经 **TCP** 连接;传输栈拆成控制面(`ITransport`)× 数据面(`ILink`) +> 两根独立可选、握手协商、可混搭的轴(同机可控制面 TCP + 数据面共享段)。后果:§3 加一行 **D TCP**(约束集与 C 相同—— +> 无 fd 传递、无共享页——但 RTT 毫秒级、带宽 30–100 MB/s);§3.1、§7.3、§8.1、§8.2 的 vsock 条目撤回;§6 第 3 行 +> "P7 不变、定宽只是协商值"改为**定宽 + 布局摘要是 P6.5 的第一个包**;"形态 B 不需要 P6.5"不再是有效场景,**P6.5 上关键路径**; +> §5.2 的 `LinkTerms` / `Refuse` / 指纹拆分经树上核实**未由 hs 落地**,归 P6.5。以 `ROADMAP.md` 的 P6.5 / Ph 行与 +> `ARCHITECTURE.md` §11.9 为准;本文其余部分作为审查记录不再改。 --- @@ -129,13 +137,16 @@ P6 该做的**不是**把它改成闩锁(那需要在每个 `[[noreturn]]` 站 | **A 同内核两进程**(P6 的 spawn) | 进程 | `AF_UNIX` | `SCM_RIGHTS` + memfd/ASharedMemory + mmap | ✅ 今天就成立 | | **B 容器类 guest**(DroidSpace / Winlator / Termux,共享内核) | 命名空间 / 沙箱 | `AF_UNIX` | 同上(含 `AHardwareBuffer_sendHandleToUnixSocket`,API 26) | ✅ **整套 P6 机制逐字可用** | | **C AVF pVM** | 内核 | `AF_VSOCK`,**仅此** | 无。无 SCM_RIGHTS、无共享页、无 dma-buf | ❌ 需要 P6.5 | +| **D 跨机 TCP**(2026-09-22 定的终局) | 机器 / OS / 架构 | `TCP`,仅此 | 无 | ❌ 需要 P6.5;且两端是**不同二进制**,wire 定宽 + 布局摘要成硬前提 | -**这是本次审查最令人愉快的一条结论:形态 B 的终局,从"P6 + 修订后的 P12"就能到达,不需要 P6.5。** +**这是本次审查最令人愉快的一条结论:形态 B 的终局,从"P6 + 修订后的 P12"就能到达,不需要 P6.5。**(2026-09-22:形态 B 不再是操作性场景;终局是 D,P6.5 在关键路径上。) 同内核意味着 `AF_UNIX` + memfd + `SCM_RIGHTS` 全部照旧。 Winlator 在自己 app 内跑 VirGL / Vortek 渲染服务,是"终局减去 VM"的一个**已出货存在性证明**。 ### 3.1 [外部未验证] AVF 形态有一个可能致命的外部约束 +> **撤回(2026-09-22)**:终局不再是 AVF,本节只作历史记录,探针不做。 + 审查给出的判断是:**一个普通(untrusted)Android app 根本无法参与 AVF。** 两道独立的闸,任一成立即致命: @@ -296,13 +307,13 @@ red-once:**改成从超时置位闩锁,则配对的正控制"server 落后 |---|---|---|---| | 1 | **P6(修订)** | 十个包,仍然可交付,仍然只落离屏 | — | | 2 | **P6.5(新)stream 数据面** | `StreamLink` 作为 `ILink` 的第二实现:分块封帧、watermark 变消息(**规则逐字保留**——late-never-early、`>=` 不是 `==`、倒退是 Fatal,只有机制变)、reply 变成自带 seq 的真消息(于是 **删掉** slot 池、`seq & mask` 取模、stamp 自检与 `ReplySlot.h:56-62` 的 P9 漂移风险)、`SEG_STAGE` 的编码器局部分配器变成发送窗口、**每方向一条专用读线程**(否则 event-ring 的流控死锁以 write/write 互阻的形式原样复活) | **必须在 P11 之前**,且**约束 P9 的机制选择** | -| 3 | **P7 不变** | 定宽 payload 重写是**跨架构**前提,不是跨进程前提;`hs` 让它变成一个协商出来的 `wireForm` 值而不是新机器 | — | +| 3 | **P7 不变** | 定宽 payload 重写是**跨架构**前提,不是跨进程前提;`hs` 让它变成一个协商出来的 `wireForm` 值而不是新机器。**2026-09-22 改判:跨架构现在就是终局,定宽 + 布局摘要归 P6.5 wf,P7 不再持有它** | — | | 4 | **P9 重定范围** | 从"`SEG_REPLY` 异步 slot 池"改成"**异步 reply 语义**",机制推到 P6.5 之后 | 否则 P9 造一个阶段的工作量给 stream 删掉 | | 5 | **P11 加一条具名拒绝** | `SEG_ADOPT` 的档位是**只对共享映射成立**的;在非 shm 链路上点名 T0/T1 是具名拒绝并强制 T2 | 在 P6.5 之后 | | 6 | **P12 修订,而且更小** | **删掉 Surface 传递那一半**(Java `Surface` → Messenger/AIDL → `MobileGLServerService` → `ANativeWindow_fromSurface`,以及那 ~15–25 MB 的额外 ART)。server app 拥有自己的 SurfaceView,client 根本没有窗口,**于是 minSdk 26 没有扁平化 `ANativeWindow` 的 NDK API——那条逼得 P5–P11 必须无窗口的约束——彻底不再成立,因为什么都不需要被扁平化。** 新增:一个追加的 `WindowKind::ServerOwned`、两个后端各一条 `CreateEGLWindowSurface` 臂、**第二个 `m_windowHandle` 注入点**(§2.5;a6 精确化为:`ActivateEGLSurface` 每次 make-current 用 `surfaceState->Window` 覆写 server 的窗口,最小 latch 点在 `RegisterEGLWindowSurface` `BackendObject.cpp:232-238`,另需改 `sameHandle` 去重键 `BackendObject_DirectGLES.cpp:962-967`)、DirectGLES 进程全局 `g_Display`/`g_Surface`/`g_Context` 的去全局化、以及 DirectGLES 的 `kEventSurfaceChanged` Width/Height 缺口(Espryt 只发布格式,`DirectGLES.cpp:15793-15805`,server 拥有显示时 client 的默认 FBO 会永远停在 `MG_Impl/Init.cpp` 的 512×512 占位值)。**Magma 近得多**:它的旋转 / preTransform 补偿本来就整个在 server 侧、按 server 自己的 surface 取键 | 形态 C 需要 P6.5 + Ph;**形态 B 两个都不需要** | | 7 | **Ph(新)不可信 guest 加固** | 当前路线图里**没有家**。内容:把 `Session::Fail` 的**策略**翻成每会话闩锁(P6 收口站点,Ph 改它们做什么——注意这需要在每个站点发明真实返回路径,不是一个函数翻一下);handle slot 预算(guest 能跨 13 个 kind 各逼一次 `1<<20` 条目的 vector resize,而 `BackendSlotTable` 的两条拒绝是 `MOBILEGL_ASSERT`,release 下展开为空,留下一个**静默的 null twin**);readback 尺寸门挪到 server 侧、且在 resize **之前**加绝对上限;`StagedTextureStore` 的 resize 按该 level 宣告的范围设界;`ArchiveVector` 按 `count * sizeof(element)` 设上限;`SEG_EVENT` 溢出策略不能再是"一个仅仅在自己门铃上 park 的 guest 60 秒内杀掉宿主渲染器" | **必须在任何出货的 server app 接受一个不是它自己产生的 guest 的连接之前** | -**顺序小结**:`P6 → {P7 ∥ P6.5 ∥ Ph}`;P6.5 在 P11 与 P9 机制选择之前;Ph 在任何出货 server 之前。 +**顺序小结**:`P6 → {P7 ∥ P6.5 ∥ Ph}`;P6.5 在 P11 与 P9 机制选择之前;Ph 在任何出货 server 之前。**2026-09-22**:IPC 跑道改为 `P6 → P6.5 → Ph → P12 → P9 → P10 → P11(同机臂)`,P7 与 P3b/P4b 在 monolith 跑道上并行。 --- @@ -330,6 +341,8 @@ red-once:**改成从超时置位闩锁,则配对的正控制"server 落后 ### 7.3 `AF_VSOCK` 探针(一小时,设备上) +> **撤回(2026-09-22)**:终局改为 TCP 跨机;对应的测量变成 TCP loopback 与跨机臂上的 RTT / 吞吐(`ROADMAP.md` 开放问题 19)。 + 从一个普通 app 调 `socket(AF_VSOCK)`,抓 avc denial;量一次 guest↔host 的 1 MiB 吞吐与单向延迟。 §3.1 那条外部约束不做这个探针就不能当前提。 @@ -343,8 +356,8 @@ red-once:**改成从超时置位闩锁,则配对的正控制"server 落后 ## 8 仍然未决(不要当成已答) -1. **[外部未验证]** 普通 Android app 能否成为 pVM 的 vsock 对端(§3.1)。它不改结构,改的是终局能承诺什么。 -2. **[外部未验证]** pKVM 下手机上的 `AF_VSOCK` 吞吐与单向延迟。树里、文档里、脚本里对 vsock / AVF / virtio / gfxstream / virgl +1. ~~**[外部未验证]** 普通 Android app 能否成为 pVM 的 vsock 对端(§3.1)。它不改结构,改的是终局能承诺什么。~~ 撤回(2026-09-22,终局改为 TCP)。 +2. ~~**[外部未验证]** pKVM 下手机上的 `AF_VSOCK` 吞吐与单向延迟。~~ 撤回(2026-09-22;换成 TCP 跨机的 RTT 与吞吐,`ROADMAP.md` 开放问题 19)。树里、文档里、脚本里对 vsock / AVF / virtio / gfxstream / virgl **零引用**(已 grep);公开数字都是服务器级 x86 的 iperf3,这个配置下的延迟数字**根本不存在**。 3. server image 能否不链 `MG_Impl`。`PipeInputs.h:281/:744/:957` 与 `P5F-WIRE-COMPLETENESS` §1.4 断言它, `SPAWN-PLAN:77` 与 `CONTRACT` §3.3 挂着它。读不出来,只能试链(§7.2)。 diff --git a/docs/Disaggregated/ROADMAP.md b/docs/Disaggregated/ROADMAP.md index cebd4553..6196c5bf 100644 --- a/docs/Disaggregated/ROADMAP.md +++ b/docs/Disaggregated/ROADMAP.md @@ -4,6 +4,8 @@ > **P5f 后续 Magma run-ahead 已完成**(`194382c9`,2026-09-20):主机真实排队、credit、负控及 Vulkan 同步验证通过,Redmi 同包 Magma 开/关与 GLES 三臂 FCL 世界实测通过。见 [报告](notes/p5f/magma-runahead.md)。P6 / P7 全阶段状态不因此改变。 +> **终局(2026-09-22 改判)**:client 与 server 可以在**不同机器、不同 OS / 架构**上,经 **TCP** 连接;同机的 `spawn`(AF_UNIX + 共享段)保留为本机形态。传输栈拆成**两根独立可选的轴**——控制面(`ITransport`:`fork` 继承 fd / `unix:` / `tcp://host:port`)与数据面(`ILink`:共享段 `ShmLink` / 字节流 `StreamLink`)——由握手协商、可以混搭(同机可以控制面走 TCP、数据面走共享段以降开销),上层只见 `ITransport` + `ILink`,**不得按链路种类分支**。此前 [`P6-ENDSTATE-REVIEW.md`](P6-ENDSTATE-REVIEW.md) 假设的 AVF pVM / `AF_VSOCK` 终局撤回(该文顶部有更正)。这一改判把 **P6.5 从条件项变成 IPC 跑道的关键路径**,把 wire 定宽 + 布局摘要从 P7 / hs 的"以后"变成 P6.5 的第一个包,把 Ph(含配对 / 认证)变成 P12 非 loopback 监听的前提;设计见 `ARCHITECTURE.md` §11.9。 + ## 通用纪律(每个 commit) - 默认 ALL target 必须完整构建;禁止提交热路径插桩(CI grep 门)。 @@ -14,7 +16,7 @@ - **拆分不借机顺手修 `dev` 的 bug**:句柄化过程中发现的 `dev` 侧缺陷记成独立条目、独立 PR(开放问题 15、17)。 - 过程(用户 2026-09-16,ID-66):不过度验证;轮次间不做对抗性审查,每个 P 阶段收官由 Codex 审一次,发现进入下一阶段首轮;只读 / 非核心任务派给 Codex;实现方与审查方错开模型族。 -两条跑道分开:**monolith 跑道** P0 → P0.5 → P1 → P2 → P3a → P4a → P3b/P4b → P7 → P8 → P13,每段可独立交付、可随时中止;**IPC 跑道** P5 → P5b → P5c → P5d → P5e → **P5f** → P6 → P9 → P10 → P11 → P12。目标顺序:先完整的 separate-thread rendering(P5b,已达成),再让 `inproc` 变成只经 wire 交换的诚实两角色(P5c),再把它的 CPU 代价压到可接受(P5d),然后退役 draw path 上的 lockstep(P5e:client 发了就走,server 只从记录带来的句柄解析对象),最后才是 separate-process transport(P6,此时只是传输替换)。 +两条跑道分开:**monolith 跑道** P0 → P0.5 → P1 → P2 → P3a → P4a → P3b/P4b → P7 → P8 → P13,每段可独立交付、可随时中止;**IPC 跑道** P5 → P5b → P5c → P5d → P5e → **P5f** → P6 → **P6.5 → Ph → P12** → P9 → P10 → P11(同机臂)。目标顺序:先完整的 separate-thread rendering(P5b,已达成),再让 `inproc` 变成只经 wire 交换的诚实两角色(P5c),再把它的 CPU 代价压到可接受(P5d),然后退役 draw path 上的 lockstep(P5e:client 发了就走,server 只从记录带来的句柄解析对象),然后是 separate-process transport(P6,此时只是传输替换)。P6 之后(2026-09-22 定):传输栈两轴化并能跨机(P6.5),server 能安全地接受不是它自己产生的连接(Ph),server 成为拥有显示的常驻应用(P12),异步反向通道与节奏(P9、P10)建立在 P6.5 的消息式 reply 之上,同机的 ≥16 MiB 采纳(P11)最后。 ## 阶段 @@ -32,15 +34,17 @@ | **P5d** `inproc` 性能专项 | ✅ `cb06538c`、`56a77348`、`1f8de61b` | 一二轮:persistent-map 推送三级臂(mprotect 脏页追踪 + 哈希抑制 + 绑定过滤 `PushDrawConsumers`)、barrier 批处理 `MOBILEGL_IPC_BATCH_WAITS` + 延期销毁队列、自旋时钟 64 合 1、零页注册 + shadow 页对齐分配。三轮(按符号化 profile 逐项切,四包 + 一份 lockstep 可行性研究):apply 空转轮询零锁(控制邮箱原子影子位)、`Doorbell::Wait` 校准自旋稳态不读时钟、wait/park 计数进 stats;`OnApplyThread()` 内联为线程指针比较、三个 scope 深度计数器退掉 `thread_local`;shadow 分配尺寸补页、追踪范围向外对齐、边块哈希消失、脏页排空修复;image unit 高水位、残余填充 memo、server stamp 常量表;`generate_mipmap` 不再免等(apply 读残余输入)、death 测试围栏 | 三轮设备(Redmi,CPU 定频):inproc **64.3 → 103-106 fps**(p50),client 线程 CPU 15.0 → 9.2 ms/帧、apply 12.4 → 7.0-7.4;monolith 同场景 115(120 Hz vsync 封顶的运行)/ 206(一次未封顶,渲染线程 5.0 ms/帧 大核);配对比较以逐线程 CPU/帧为主,见报告"数字"节;unit 2203/2203、`integration-split` 111/111(两条曾 flaky 的用例复跑 6/6);双生成器、include 闭包、dirty-surface、doc 引用绿。未完成:R-1 序列化(研究结论:留给 P3b/P4b 后的 P11 `gPipeInputs` 版本化)、线程放置(内核忽略亲和)、`SetHashSuppressor` 哈希等小项。报告:[`P5D-INPROC-PERFORMANCE.md`](P5D-INPROC-PERFORMANCE.md) | P5b | | **P5e** 退役 Espryt draw path 的 lockstep | ✅ **已收官(2026-09-19)**,附一条具名未决:E1 对照需按 ID-114 重新定义 | 契约 `MG_Remote/CONTRACT-P5E.md`(规则 F:**未设障**记录的 apply 不得读任何 client 内存;ID-84 限定它只约束未设障记录);裁定 **ID-80..136**(`~/w7/notes/p5e/INTEGRATOR-DECISIONS-P5E.md`)。**十二个包,三波**:wave 1 **c0e**(契约 + 线上行:`PipeCalls.def` 第五列 `WaitClass`、`set_program_bindings` opcode 80、`kCapRunAheadApply` 位 10 仅 DirectGLES 臂、`kDrawClientArrays`、子系统位 13、两个旋钮)→ **id**(registry 按 `{slot, gen}` 重键、by-handle resolver、分配器守卫);wave 2 **vi / sb / pg / tx2 / fb** 五个 per-draw 家族 ∥ **ra**(等待规则、present credit、`gPipeInputs` 变 server 角色内存),加 **fix1**(设备发现的 monolith 臂回归,ID-107);wave 3 **pa**(program 家族离开前端)、**mv**(multi-draw + 五个档位的门禁条目)、**gl**(门禁机制本身 + 两处潜伏崩溃)、**ra2**(翻开关后暴露的竞态)。**`kMGPipeP5eRunAheadReady` 与 `kMGPipeP5eClientWaitRuleLanded` 均已翻**。最大的那次迁移(逐 draw 的 `GetProgramForDraw`)**没有改动任何线上结构**:记录早就带着逐 link 的 `ProgramArchive`,缺的是仍去问前端对象的读者。报告 [`P5E-RUNAHEAD.md`](P5E-RUNAHEAD.md) | 出口门已逐条跑过(BRIEF-P5E §3,2026-09-19 在集成树上,run-ahead 已武装):**item 1** unit 在 strict 两臂均 **2256/2256**;**item 2/3** `integration-split` **179/179**、逐条普查零 `Fatal{`、`Admitted{` 恰为八行;**item 4(a)** `RUN_AHEAD=0` 作为配对对照 **179/179 绿**;**item 4(b)** `VERB_BARRIER=0` **变红**(车道 62/179);**item 4(c)** Magma 逐字记下 `run-ahead requested, server does not publish kCapRunAheadApply - running lockstep`,而 Espryt 对照记下 `run-ahead ARMED`;**item 5** 在集成树上重跑 red-once(ID-121 重排后的形式):倒掉 pa 的臂得 `GetProgramForDraw@DrawArrays`、倒掉 mv 的臂得 `GetBoundVertexArray@DrawArrays`,**恰好各一个具名对**,还原后各自转绿;**item 7** `MOBILEGL_IPC_AUDIT=1` **179/179**。**唯一未过的是 E1 对照脚本本身**(ID-122):已修掉它两个遮蔽性缺陷(选中了一个在本车道永远跑不起来的阳性对照用例;ctest 与日志助手对“谁被选中”意见不一致),但它索要的 `Fatal{BarrierViolation}` 在整次运行里 **出现 0 次**:`BATCH_WAITS` 默认值 1 下那个重叠不发生,而 run-ahead 武装后 `VERB_BARRIER=0` 还会顺手关掉 run-ahead(ID-114),它产生的那条臂**既不是 lockstep 也不是 run-ahead**。E1 需要重新定义它要证伪什么,不是再调阈值;在想清楚之前不动它的计数规则,否则只是换一种伪绿。G1 仍由 CI 断言(ID-123) | P5d | | **P5f** 一切状态上 wire | ✅ **已收官(2026-09-20)**;验收代码 Windows `c42577a4` / WSL `cfca93c7885f` | f0 普查、f1 双块、fc 控制帧、fe Espryt 字段、fm Magma record consumers、fs 静态世代/角色及 liveness、fr registry、fv 反向回调均已合并。字段归属 **41 RECORD_SUPPLIED / 6 APPLIER_DERIVED / 0 BARRIER_PULLED / 16 FATAL**;strict / dualblock 预期 marker 集合均空。控制帧与静态量工作已完成,不再列为 P6 待实现项 | unit **2310 = 2300 PASS + 10 skip**;GPU **1377** 零失败;ordinary / strict split **180 = 176 PASS + 4 skip**;双块 **212 = 206 PASS + 6 精确具名 skip**;双后端 RSP 门 **2 PASS / 0 skip**、逐帧 rsp=0。G1 `.text` 10806051、symbols 27815 恒等且 0/0/0/0;G2 3016 同名;G14 3646→3744 无删名。逐包与收官修复均有 red-once;Claude 异族终审 P1/P2 已修;Redmi 六 clean-boot 臂 **60 PASS / 6 skip / 0 failed**、36 个窗口 rsp=0。详见 [`close-report`](notes/p5f/close-report.md) | -| **P6** spawn transport | ⏳ **全部包已落地(2026-09-21,头 `16bfab10`);出口门 1–6 达成,7/8 待采**(真机配对 A/B + 三个性能数) | 十包全落地:**a6** 进程装配/链接边界审计 → **c6** 规范契约 + 数据面缝惰声明 → **lk** `RingControl` 按写者重组 → **so** `SocketTransport`(AF_UNIX SOCK_STREAM + SCM_RIGHTS,12 条契约用例)→ **sm** 两个独立启动的进程(非 fork,name 汇合、共享匿名段,四守卫接线)→ **cp** EGL 控制帧跨进程并应答(`InitCapabilities` wire kind 11)→ **hs** build stamp 显式 present 入指纹 + `abiMajor/Minor` 补检 + 真实 pid → **dl** device-lost 闩(取自描述符挂断绝不取自超时)+ `Session::Fail` 漏斗(`FatalFamilies.def` 词表 + 90 站点归一 + `SessionFault` 帧命名家族)+ Fatal 普查门 → **st** fb-slot memo 具名 Fatal → **t6** `integration-spawn` 车道(102/102)+ 名集合结构性一致门 + per-role 日志(`.client.log` / `.server.log`)。Android CI 新增 `spawn-acceptance` 臂,App 从 `nativeLibraryDir` 解析 server 路径。真机 Redmi `2f7cbe2e` 上 `OpenRA.DirectGLES` spawn ssim=1.0 连跑三次 + 6 case 绿;`DirectVulkan` 真机分离路径不确定分歧(inproc 与 spawn 同表现→ Magma × 真实 GPU,非 P6,桌面 lavapipe 为 1.0)。边界仍为 pbuffer / surfaceless / 离屏;真窗口归 P12。契约 [`MG_Remote/CONTRACT-P6.md`](../../MobileGL/MG_Remote/CONTRACT-P6.md);a6 产出 [`a6-audit-v1.md`](notes/p6/a6-audit-v1.md)、[`a6-link-experiment.md`](notes/p6/a6-link-experiment.md)(**server 不能不链 `MG_Impl`**:184 符号,P7 101 / P3b-P4b 14 / 共有 60 / P6 自己 6);终局重审 [`P6-ENDSTATE-REVIEW.md`](P6-ENDSTATE-REVIEW.md) | 出口门(契约 §9)1–6 ✅:G1 pull 0/0/0/0、`.text` 恒 `0xa52203`;`integration-spawn` 与 split 名集合一致(可比 102==102)且同数绿;进程树运行时恰多一子进程、结束为零;每条 spawn 条目记子进程 pid 与 `transport=spawn`(`--require-spawn` 门);每包 red-once。**7/8 待采**:真机 reboot-clean 同热窗口配对 A/B、三个强制性能数(socket 门铃 vs condvar、`SEG_STAGE` 字节/帧、chunking 后记录/帧)尚未正式记录 | -| **P3b / P4b** 深化(Espryt) | 待排 | 按存储属主键控的发射游标与 view 索引重映射;`g_fboTextureSyncList`;`ResolvedTextureBindingMemo` / `SamplerPassMemo` / image sweep / program registry 重键;XFB scatter 搬到 client;删 fragColor 重推导 workaround 与 `g_broadcastMemo*`;raw-depth-fetch sampler 的 monolith 清理(transport 原生臂已由 P5f fs 落地);回读 / pack state;P4a 记下的 R-3 / R-4 / R-5 / R-7 / R-10 / R-11;`ProgramArtifacts.h` 的 NDK 尺寸钉 | 纹理 / program 场景;CTS `texture_*` / `shader_image_*` / `packed_pixels` 在 0.5 pp 内;每一个 Iris trace;`TextureUploadShapeScenario` 升级成门 | -| **P7** DirectVulkan(Magma)全量迁移 | 部分已提前落地,阶段未收官 | `38919d45` 已补实际游戏的 server buffer consumers 和 Android 旋转 blit([报告](notes/p5f/magma-inproc-fix.md));`194382c9` 又完成 Magma run-ahead、GPU 延迟退休与 VAO 身份碰撞修复([报告](notes/p5f/magma-runahead.md));其余工作:其余子系统:`SetupDrawSnapshot` 探测字段塌成 dirty mask;占位纹理原生化;具名 UBO host payload(D-B8);内部 shader 烘焙;`VertexInputStateFactory` 内容寻址 CSO;D18 容器纪律保留 | 集成 + trace 在 Magma 的 push 与 split 下全绿;verify 零分歧;`nm -D libMobileGLServer.so \| grep glslang` 为空;CTS 0.5 pp 内。**再基线检查点:中点完成子系统 < 40% 立即重定基线** | -| **P8** emulation 下放 + 索引宿主镜像 + 协议广度 | 待排 | `MG_Impl/Pipe/HostResolve.cpp`(client 数组范围、最大索引扫描、`*IndirectCount` 解析,逐站点 reconcile);`Server/IndexHostMirror`;CopyImage 镜像搬到 client;viewport-array 回放验证;`generate_mipmap` 计划 + CPU 回退纹素;大 blob carrier(开放问题 11);无 present fence tick;`kCapDriverOrderedXfbCapture` | `'^DirectGLES\.Split\.'` 与 `'^DirectGLES\.'` 逐名相同;trace split 双后端 SSIM ≥ 0.99 含两个 `coherent_as_flush` fixture;`ClientArrayAfterComputeWriteScenario`;`create-indirect` 上 `roundtrips-per-frame` 读零;`index-mirror-bytes` 逐用例发布 | -| **P9** 反向通道 | 待排 | `SEG_REPLY` 异步 slot 池;PBO 回读 fire-and-forget;`OnGpuWritten` 收窄;`OnBufferWriteback` 批处理 + epoch 排序;`OnXfbScatterReady`;`OnTextureWriteback`;`OnMipLevelsGenerated`;纹理拉取四条缓解 + 终止符;`OnGlError` 有序;`OnSurfaceChanged`;`OnLog` 分级;`SEG_EVENT` 溢出策略;class-C 的 readback 尾 | 回读 / XFB 场景在 split 下绿;`TextureRemintPullScenario`(含无解用例);拉取计数逐 trace 发布;两条故障注入 | -| **P10** sync / query / present 节奏 | 待排 | client 铸造 query handle;轮询入口成门铃点 + `MOBILEGL_IPC_POLL_ESCALATE`;fence 完成度来自逐 fence 退休;非 present fence tick;`present` 1:1;credit 默认 1;roundtrip 计数器与输入延迟直方图;class-C 的 query / swap-interval 尾 | query / XFB / `AsyncCompile` 场景在 split 下绿;trace 上 draw / state / upload 路径 roundtrip 读零;零 timeout 轮询有界退出;配对 A/B 记录 | -| **P11** persistent map 与 ≥16 MiB 采纳 | 待排 | POST 探针档位选择(T0 主攻,Adreno 可选 T1,T2 回退);`SEG_ADOPT` 生命周期绑 `completedFrameSerial`;**`gPipeInputs` 版本化 / 双缓冲**(P5d 研究:draw barrier 延后一个 verb 的前提,须在 P3b/P4b 的句柄键控 twin 表之后)。**P5e 的更正**:P5e 退役 draw lockstep **没有**需要它——ra2 实测证明字段**值**已由 `SuppliedFieldMask` 分区,当时那次竞态在**元数据标量**上,修法是让守卫测事实而非断言未来(ID-135)。本行保留采纳存储的一般版本/时序问题;契约 §3.2 的 per-role stamp 已由 P5f 落地,不再是待办 | `LargeArenaAdoptionScenario` 在所选档下绿;26.3 与两个 Create fixture SSIM ≥ 0.99;Adreno 830 上 p99 帧时与峰值 RSS 对采纳基线(163→21 ms / 40→115 fps / ~400 MB)回归不超过 10% | -| **P12** Android 生产窗口路径 | 待排 | `android:process=":mgl"` Service 收 Java `Surface`;server 生命周期绑 Activity;FCL env 与 plugin APK 开关表接线 | Minecraft 经 FCL 在 spawn 模式下于 Adreno 830 双后端入世界;杀 server 产生干净 device-lost latch | -| **P13** 退役 pull 路径 | 待排 | 删 `SnapshotFromGLContext()` 非 verify 分支、`MGB_CTX`、`MOBILEGL_PIPE_PUSH`、`MOBILEGL_PIPE_LEGACY_MEMOS`;保留 `MOBILEGL_PIPE_VERIFY`;MGPipe recorder;删 `set_residual_value_state`;在计数器活着的情况下重调幸存缓存容量 | `static_assert(sizeof(ResidualValueBlock) == 0)`;三道纯度门在非 verify 构建上转绿;recorder 金标建立;monolith 逐线程 CPU 不差于 P0 基线 | +| **P6** spawn transport | ⏳ **全部包已落地(2026-09-21,头 `16bfab10`);出口门 1–6 达成,7/8 待采**(真机配对 A/B + 三个性能数)。收官前另欠(2026-09-22 核出):server 进程侧 `PipeStats` 从未初始化(`srv=0 srvpark=0` 是结构性零,门 8 无 server 半边;修复进行中)、184 符号棘轮 CI 门(契约 §12.1);契约 §2 分给 hs 的 `LinkTerms` / `Refuse` / 指纹拆分**未落地**,移交 P6.5(负控 S6 随之) | 十包全落地:**a6** 进程装配/链接边界审计 → **c6** 规范契约 + 数据面缝惰声明 → **lk** `RingControl` 按写者重组 → **so** `SocketTransport`(AF_UNIX SOCK_STREAM + SCM_RIGHTS,12 条契约用例)→ **sm** 两个独立启动的进程(非 fork,name 汇合、共享匿名段,四守卫接线)→ **cp** EGL 控制帧跨进程并应答(`InitCapabilities` wire kind 11)→ **hs** build stamp 显式 present 入指纹 + `abiMajor/Minor` 补检 + 真实 pid → **dl** device-lost 闩(取自描述符挂断绝不取自超时)+ `Session::Fail` 漏斗(`FatalFamilies.def` 词表 + 90 站点归一 + `SessionFault` 帧命名家族)+ Fatal 普查门 → **st** fb-slot memo 具名 Fatal → **t6** `integration-spawn` 车道(102/102)+ 名集合结构性一致门 + per-role 日志(`.client.log` / `.server.log`)。Android CI 新增 `spawn-acceptance` 臂,App 从 `nativeLibraryDir` 解析 server 路径。真机 Redmi `2f7cbe2e` 上 `OpenRA.DirectGLES` spawn ssim=1.0 连跑三次 + 6 case 绿;`DirectVulkan` 真机分离路径不确定分歧(inproc 与 spawn 同表现→ Magma × 真实 GPU,非 P6,桌面 lavapipe 为 1.0)。边界仍为 pbuffer / surfaceless / 离屏;真窗口归 P12。契约 [`MG_Remote/CONTRACT-P6.md`](../../MobileGL/MG_Remote/CONTRACT-P6.md);a6 产出 [`a6-audit-v1.md`](notes/p6/a6-audit-v1.md)、[`a6-link-experiment.md`](notes/p6/a6-link-experiment.md)(**server 不能不链 `MG_Impl`**:184 符号,P7 101 / P3b-P4b 14 / 共有 60 / P6 自己 6);终局重审 [`P6-ENDSTATE-REVIEW.md`](P6-ENDSTATE-REVIEW.md) | 出口门(契约 §9)1–6 ✅:G1 pull 0/0/0/0、`.text` 恒 `0xa52203`;`integration-spawn` 与 split 名集合一致(可比 102==102)且同数绿;进程树运行时恰多一子进程、结束为零;每条 spawn 条目记子进程 pid 与 `transport=spawn`(`--require-spawn` 门);每包 red-once。**7/8 待采**:真机 reboot-clean 同热窗口配对 A/B、三个强制性能数(socket 门铃 vs condvar、`SEG_STAGE` 字节/帧、chunking 后记录/帧)尚未正式记录 | +| **P6.5** 传输栈两轴化 + 跨机 | 待排,**IPC 跑道关键路径**(2026-09-22 定) | 包:**wf** wire 定宽与布局摘要——`wireFingerprint` = `PipeFields.def` 派生的逐成员 name / `offsetof` / `sizeof` 摘要 + 有序目录摘要 + 记录头布局 + 两个 blob codec 版本 + `kOpCount` + 字节序 / 指针宽度,**保留** `sizeof(MGPCaps)` / `sizeof(DynamicBackendParameters)`(wire 事实)、删 `sizeof(GLFunctionsTable)`;`buildFingerprint` 只在 `Dial == Fork` 下比较;`DynamicBackendParameters` / `MGPCaps` / `RenderStateParameters` 整块 blob 的定宽化(两端是不同编译器产的不同二进制,`long` / padding / 位域差异都是静默读错状态);`Refuse{code, detail, 对端值}` 控制消息,握手路径零 abort → **ct** 控制面端点种类(`fork` 继承 fd / `unix:` / `tcp://host:port`;`DialMode{No, Fork, Connect}` 与 `MGPipeShouldDial()` 按契约 §3 补齐;TCP keepalive 失败**作为传输层报告的挂断**进 dl 的闩,不是 apply 超时)→ **nd** 数据面协商(`LinkTerms{dataPlane, delivery, wireForm, maxReplyBytes, cmdWindowBytes, stageWindowBytes}` 入 Hello / Welcome,四个尺寸由 **server** 陈述;`dataPlane ∈ {SharedSegments, Stream}`;`auto` 的判据是**段实际交付成功**而不是地址判断,回落必须具名入日志与 stats;链路工厂在会话建立时选定一对,之后不变——缝是 setup-time 的,契约 §8.2)→ **sd** 共享段交付与控制面解耦(`ShmLink` 自带 AF_UNIX aux 汇合名、在 `Welcome` 里公布,`SCM_RIGHTS` 只走它;于是**控制面 TCP + 数据面共享段**在同机是合法配对;`ITransport` 收窄为纯控制帧,描述符传递归数据面)→ **sl** `StreamLink`(分块封帧;watermark 变消息且**规则逐字保留**——late-never-early、`>=` 不是 `==`、倒退是 Fatal;`appliedSeq` 修正案 + flush-on-idle;reply 变自带 seq 的消息,本链路上删 slot 池 / 取模 / stamp 自检;`SEG_STAGE` 变发送窗口,三个 cursor 要么完整复活要么不用、不留中间态;program archive 与 `draw_vbo` range 尾分片;`GetCaps` 两个 blobref 变消息;每方向每进程一条专用读线程)→ **t65** 车道。上层纯度:`SessionProducer` / `SessionConsumer` / `ServerLoop` / `PipeWireEncoder`、`ClientSession.cpp` 的 `kSegEvent` 挂载与 `ResourceTracker.h` 的 writeback 解析都只经 `ILink`。设计 `ARCHITECTURE.md` §11.9 | 门:inproc / spawn 车道结果数与逐线程 CPU 逐字不变(`ILink::ReserveRecord` 虚调用代价**实测**,`RingProducer::Reserve` 失去内联是具体风险);纯度 grep——`ShmLink` / `StreamLink` / `RingControl` / `ReplySlotPool` / `EventRingConsumer` / `m_shm.` 只出现在 `Transport/` 与其测试,上层零链路种类分支;**2×2 矩阵车道**(控制面 {unix, tcp} × 数据面 {shm, stream},loopback)名集合与 spawn 一致且同数绿,每条目记 `control=… data=…` 的 arm 证明(ID-124 的形状);跨机臂一条真 trace 逐像素;wf 三条 red-once(临时树里同宽成员互换 → 摘要变而 stamp 不变;`wireMajor = 99` → 两端具名拒绝、server exit 0、client 不回落 monolith;仅 stamp 不同的对端在 `Dial != Fork` 下连接成功——正控制);**必测数**:逐帧 `kWaitReply` 次数(`ResourceCreate` / `SetTextureParams` / 纹理半边 `ResourceSubData` 都在此列,TCP 上每次即一个 RTT)、`SEG_STAGE` 字节/帧对链路带宽、`PRESENT_CREDIT` 1..3 配对、混搭(tcp + shm)对(unix + shm)的逐线程 CPU 差 | +| **Ph** 不可信对端加固 + 配对 | 待排,**P12 非 loopback 监听之前** | `Session::Fail` 的策略翻成每会话闩(每个依赖 `[[noreturn]]` 的站点造真实返回路径,不是一个函数翻一下;P6 dl 已把站点收口到一处);handle slot 预算(`BackendSlotTable` 的两条拒绝从 `MOBILEGL_ASSERT` 变 release 下的具名拒绝,杜绝静默 null twin);readback 尺寸门挪 server 侧且在 resize **之前**设绝对上限;`StagedTextureStore` 按该 level 宣告范围设界;`ArchiveVector` 按 `count * sizeof(element)` 设上限;`SEG_EVENT` 溢出不再能让一个仅仅不排空的对端 60 秒杀掉宿主渲染器;**配对 / 认证**(`Hello` 带配对令牌,无令牌只允许 loopback;令牌够不够、要不要 TLS 见开放问题 21);段 / 窗口尺寸由 server 钳制(P6.5 nd 已陈述) | 非 loopback 监听在无令牌时具名拒绝;畸形帧 / 超界计数 / 不排空对端的模糊臂下 server **不 abort、会话闩住、下一连接照常服务**;`Session::Fail` 站点普查门继续零新增;契约 §12.2 五处无界分配各一条 red-once | +| **P3b / P4b** 深化(Espryt) | 待排 | 按存储属主键控的发射游标与 view 索引重映射;`g_fboTextureSyncList`;`ResolvedTextureBindingMemo` / `SamplerPassMemo` / image sweep / program registry 重键;XFB scatter 搬到 client;删 fragColor 重推导 workaround 与 `g_broadcastMemo*`;raw-depth-fetch sampler 的 monolith 清理(transport 原生臂已由 P5f fs 落地);回读 / pack state;P4a 记下的 R-3 / R-4 / R-5 / R-7 / R-10 / R-11;`ProgramArtifacts.h` 的 NDK 尺寸钉;链接实验分给它的 **14 个符号**(D12) | 纹理 / program 场景;CTS `texture_*` / `shader_image_*` / `packed_pixels` 在 0.5 pp 内;每一个 Iris trace;`TextureUploadShapeScenario` 升级成门 | +| **P7** DirectVulkan(Magma)全量迁移 | 部分已提前落地,阶段未收官 | `38919d45` 已补实际游戏的 server buffer consumers 和 Android 旋转 blit([报告](notes/p5f/magma-inproc-fix.md));`194382c9` 又完成 Magma run-ahead、GPU 延迟退休与 VAO 身份碰撞修复([报告](notes/p5f/magma-runahead.md));其余工作:其余子系统:`SetupDrawSnapshot` 探测字段塌成 dirty mask;占位纹理原生化;具名 UBO host payload(D-B8);内部 shader 烘焙;`VertexInputStateFactory` 内容寻址 CSO;D18 容器纪律保留。**P6 真机发现(2026-09-22 归此)**:`DirectVulkan` 分离路径在 Redmi 上分歧且不确定(0.976–0.989,inproc 与 spawn 同表现,pbuffer monolith 1.0)——Magma × 真实 GPU;树上 `@P7` 具名拒绝清单(multisample-blit、depth-stencil-mipmap、vertex-format-conversion、texel-buffer-native-format、unaligned-*-range、uniform-buffer-byte-tail / dynamic-offset、copy-image-in-place、Magma 无 `StateObjectDeathOps`);链接实验分给 P7 的 **101 个符号**(D12)。`DynamicBackendParameters` 定宽重写**不再是 P7 的**——它是跨平台 wire 的前提,归 P6.5 wf | 集成 + trace 在 Magma 的 push 与 split 下全绿;verify 零分歧;真机 DirectVulkan split ssim 回到 1.0;184 符号棘轮(契约 §12.1)下降 P7 的 101 个——原 "`nm -D libMobileGLServer.so \| grep glslang` 为空" 不可达,D12 裁定 server 镜像就是整个 `libMobileGL.so`;CTS 0.5 pp 内。**再基线检查点:中点完成子系统 < 40% 立即重定基线** | +| **P8** emulation 下放 + 索引宿主镜像 + 协议广度 | 待排 | `MG_Impl/Pipe/HostResolve.cpp`(~~client 数组范围~~ 已由 `beba0256` 落地为 owned buffer;最大索引扫描、`*IndirectCount` 解析,逐站点 reconcile);`Server/IndexHostMirror` **待重裁**(树里 0 处;a6 §6 实测宿主索引 span 无 producer、client 索引已是 owned buffer——按 `kCapNeedsHostIndexBytes` 的真实消费者重新裁定,不照抄 `ARCHITECTURE.md` §10.3);multi-draw client indices(`MultiDrawElements+CLIENT_INDICES` 仍具名拒绝);CopyImage 镜像搬到 client;viewport-array 回放验证;`generate_mipmap` 计划 + CPU 回退纹素;`texture-remint-pull` 仿真下放(15 处具名拒绝);大 blob carrier 只剩 **program archive 与 `draw_vbo` range 尾**(a6 §6;与 P6.5 sl 共用同一分片);`kCapDriverOrderedXfbCapture`(0 处);~~无 present fence tick~~ 只记在 P10 | `'^DirectGLES\.Split\.'` 与 `'^DirectGLES\.'` 逐名相同;trace split 双后端 SSIM ≥ 0.99 含两个 `coherent_as_flush` fixture;`ClientArrayAfterComputeWriteScenario`;`create-indirect` 上 `roundtrips-per-frame` 读零;`index-mirror-bytes` 逐用例发布 | +| **P9** 反向通道 | 待排,**P6.5 之后**(2026-09-22 重定范围) | **异步 reply 语义**,机制建立在 P6.5 的消息式 reply 之上(不再造 `SEG_REPLY` slot 池——池今天就有,stream 链路会删它);2 MiB reply cap 与 chunked readback(契约 §10.2.3 从 P6 改判至此,ID-47);PACK-PBO 回读 fire-and-forget + client 侧 `MarkGpuWritten`(ID-57,P6 未做);十个回调里未武装的五个:`OnXfbScatterReady`、`OnTextureWriteback`、`OnTexturePullRequest`、`OnMipLevelsGenerated`、`OnLog` 分级(`ClientSession.cpp:429`;`OnBufferWriteback` / `OnGpuWritten` / `OnSurfaceChanged` / `OnGlError` / `OnCapsInvalidated` 已武装);`OnGpuWritten` 收窄;`OnBufferWriteback` 批处理 + epoch 排序;`OnGlError` 有序(CONTRACT-P5C §4.2);纹理拉取四条缓解 + 终止符;XFB 命名空间(`DeleteTransformFeedback` 的 server 侧泄漏——按裁定无行、最后两个 class-C 之一)。~~`SEG_EVENT` 溢出策略~~ 机制已由 P5e 落地(`ARCHITECTURE.md` §11.7),剩余的"不排空对端杀宿主"归 Ph | 回读 / XFB 场景在 split 下绿;`TextureRemintPullScenario`(含无解用例);拉取计数逐 trace 发布;两条故障注入 | +| **P10** sync / query / present 节奏 | 待排 | ~~client 铸造 query handle~~(已是:`QueryCreate` 为 `kWaitNone`);轮询入口成门铃点 + `MOBILEGL_IPC_POLL_ESCALATE`(0 处;TCP 上是首要杠杆之一);DirectGLES 的 fence 完成度来自逐 fence 退休(`g_completedFrameSerial` 仍只在 `Present` 前进;Magma 那半已由 run-ahead 落地);非 present fence tick(唯一记载处);`present` 1:1(已是);~~credit 默认 1~~(已是默认,`ConfigLoader.cpp:414`);**`PRESENT_CREDIT > 1` 从未量过**(重审 §8.7)——带延迟链路上的首要杠杆,inproc 臂上即可取;roundtrip 计数器与输入延迟直方图(今天只有 `MapPersistentRoundtrips`);`SetSwapInterval`(最后一个手写 class-C,`EmitTables.cpp:1665`) | query / XFB / `AsyncCompile` 场景在 split 下绿;trace 上 draw / state / upload 路径 roundtrip 读零;零 timeout 轮询有界退出;credit 1..3 在 TCP loopback 与跨机臂上的配对记录;配对 A/B 记录 | +| **P11** persistent map 与 ≥16 MiB 采纳 | 待排,**同机臂专属、已让位**(2026-09-22) | T0 / T1 只对共享映射成立:`dataPlane = Stream` 上点名 T0 / T1 是具名拒绝并强制 T2(重审 §6 第 5 项),今天 `MOBILEGL_IPC_ADOPT_TIER` 0/1 已是 Fatal-at-use、`kSegAdopt` 只有枚举;前置开放问题 3。POST 探针档位选择(T0 主攻,Adreno 可选 T1,T2 回退);`SEG_ADOPT` 生命周期绑 `completedFrameSerial`;**`gPipeInputs` 版本化 / 双缓冲**(P5d 研究:draw barrier 延后一个 verb 的前提,须在 P3b/P4b 的句柄键控 twin 表之后)。**P5e 的更正**:P5e 退役 draw lockstep **没有**需要它——ra2 实测证明字段**值**已由 `SuppliedFieldMask` 分区,当时那次竞态在**元数据标量**上,修法是让守卫测事实而非断言未来(ID-135)。本行保留采纳存储的一般版本/时序问题;契约 §3.2 的 per-role stamp 已由 P5f 落地,不再是待办 | `LargeArenaAdoptionScenario` 在所选档下绿;26.3 与两个 Create fixture SSIM ≥ 0.99;Adreno 830 上 p99 帧时与峰值 RSS 对采纳基线(163→21 ms / 40→115 fps / ~400 MB)回归不超过 10% | +| **P12** Android 生产窗口路径 | 待排,**Ph 之后** | **按重审 §6 改小**:~~Service 收 Java `Surface`~~ 删掉 Surface 传递那一半——server app 拥有自己的 SurfaceView,client 根本没有窗口,于是 minSdk 26 没有扁平化 `ANativeWindow` 的 NDK API 这条约束不再成立;`WindowKind::ServerOwned`;两个后端各一条 `CreateEGLWindowSurface` 臂;`m_windowHandle` 四处写点 + `sameHandle` 去重键(a6 §6);DirectGLES `g_Display` / `g_Surface` / `g_Context` 去全局;`kEventSurfaceChanged` 的 Width / Height 缺口(Espryt 只发布格式,server 拥有显示时 client 默认 FBO 会停在 512×512 占位值);client 侧不再无条件发 `SetWindowHandle`(`BackendObject_Remote.cpp:215`——今天 FCL 里开 spawn,第一次 `eglCreateWindowSurface` 就在 server 进程 abort);server app 监听 `unix:` 与 `tcp://`(后者 Ph 之后);server 生命周期绑 Activity;cached-app freezer(SPAWN-PLAN §8.2);多 context(契约 §11);FCL env 与 plugin APK 开关表接线 | 两个门:(a) Minecraft 经 FCL **同机 spawn** 在 Adreno 830 双后端入世界,杀 server 产生干净 device-lost latch;(b) **另一台机器上的 client 经 TCP** 在 Redmi 上进世界(数据面 stream),并记录 P6.5 的必测数 | +| **P13** 退役 pull 路径 | 待排 | 删 `SnapshotFromGLContext()` 非 verify 分支、`MGB_CTX`、`MOBILEGL_PIPE_PUSH`、`MOBILEGL_PIPE_LEGACY_MEMOS`;保留 `MOBILEGL_PIPE_VERIFY`;MGPipe recorder;删 `set_residual_value_state`;在计数器活着的情况下重调幸存缓存容量;建立模块 target 与边界(D12:`SOURCE_FILES` 是一张平表喂两个库 target,无模块可链)| `static_assert(sizeof(ResidualValueBlock) == 0)`;三道纯度门在非 verify 构建上转绿;recorder 金标建立;monolith 逐线程 CPU 不差于 P0 基线 | CTS 周转单独计价(`gl44to46` 约 56,271 例):逐阶段只跑该阶段可能影响的具名块;完整 caselist 只在架构边界与合并 `dev` 之前跑,放 CI 不放关键路径。 @@ -113,6 +117,7 @@ P5c 当时移交的对象类 BARRIER-PULLED、transport registry 前端键、EGL - **P5f 出口(2026-09-20)**:双块和 strict 空棘轮、逐帧 rsp=0、零 BARRIER_PULLED、主机全门、异模型族审查修复和 Redmi 六 clean-boot 臂全部完成;P6 前提解除,实施未开始。 - **CI / inproc 收尾出口(2026-09-21)**:`feat/disaggregated` 主产物拆分编译 + inproc 主验收全绿——unit 2328 零失败、`integration-gpu` 双 transport 各 1455 零失败、retrace 77 例 monolith 77/77 且 inproc 的唯一间歇项(`bsl-esc-menu-854` DirectVulkan,lavapipe 固有 texture-handle 注册停顿越过旧 30 s barrier 预算)在预算修正为 120 s 后隔离 10/10 绿、18 项 CI 门全绿、双 ABI APK 与 AVD 生命周期验证通过;合入头 `e1bf3677`,最终矩阵以远端 CI 为准。 - **P6 全部包落地(2026-09-21,头 `16bfab10`)**:a6/c6/lk/so/sm/cp/hs/dl/st/t6 十包合入 `feat/disaggregated`;三种传输(monolith/inproc/spawn)桌面与真机两进程 retrace 逐像素对上 golden;device-lost 闩把杀 server 从 123 s 错误 `BarrierTimeout` 变 5.7 s 正确 `DEVICE LOST`;`Session::Fail` 漏斗把裸 abort 93→4。出口门 1–6 ✅,第 7 项(真机配对 A/B 热窗口)与第 8 项(三个强制性能数)待采,**未宣布收官**。逐项见 `CURRENT_STAGE_PROGRESS.md`。 +- **终局改判(2026-09-22)**:AVF pVM / `AF_VSOCK` 终局撤回,改为 TCP 跨机跨平台 + 控制面 × 数据面两轴传输栈;P6.5 上关键路径,Ph 前置于 P12 的非 loopback 监听;P6 核出三项漏项(server 进程 `PipeStats` 结构性零、184 棘轮门、hs 的三行契约未落地)与 `CURRENT_STAGE_PROGRESS.md` 里一条错误的 S6 陈述(已改);class-C 已归零到两个(`SetSwapInterval`、`DeleteTransformFeedback`)。 - 仍是方向、不据此伪造新日历:全功能 split(P8 之后)、纯度门在非 verify 构建上转绿(P13)。 再基线检查点仅剩一条:**P7 中点完成子系统 < 40% 立即重定基线**(P3a 的检查点发现不了 Magma 特有的超期)。 @@ -121,15 +126,15 @@ P5c 当时移交的对象类 BARRIER-PULLED、transport registry 前端键、EGL | 债务 | 去向 / 当前口径 | |---|---| -| P5 的 27 个普通 inproc wrong-answer(历史计数) | 22(14 layered + 3 packed depth/stencil + 5 framebuffer recycle)→ P4b/P7 texture readback;3 → P7 query;1 inspection → P6;1 FBO/RBO delete 用例在 r1 定向验证中通过,完整像素因果未隔离。最终计数以 `MEASUREMENTS.md` §7.2 的同名比对为准 | +| P5 的 27 个普通 inproc wrong-answer(历史计数) | 22(14 layered + 3 packed depth/stencil + 5 framebuffer recycle)→ P4b/P7 texture readback;3 → P7 query;1 inspection(`TextureParamsWithoutASamplerView`)→ 原记 P6,场景代码里已无 P6 引用,疑由 P5f fc / P6 cp 顺手关闭、**待核**;1 FBO/RBO delete 用例在 r1 定向验证中通过,完整像素因果未隔离。最终计数以 `MEASUREMENTS.md` §7.2 的同名比对为准 | | `rsp` residual inputs | **P5f 已关闭残余读取**:字段归属 41 record / 6 derived / 0 barrier / 16 fatal;strict 与双块 marker 表均为空,双后端逐帧 RSP 门 2 PASS / 0 skip,Redmi 36 个统计窗口 rsp=0。P5e 的“rsp 只计被采纳设障 pull”是历史计数规则,八对 admitted 的历史观察不再是当前允许集合 | -| `SEG_REPLY` 2 MiB 单槽 payload cap | 更大 readback 需要 P6+ chunking 或专用 carrier(ID-47) | +| `SEG_REPLY` 2 MiB 单槽 payload cap | → **P9**(契约 §10.2.3 改判,ID-47);stream 链路上 reply 本就是消息,cap 变成 P6.5 nd 的 `maxReplyBytes` 窗口 | | `GetCaps` 的两个 blobref | 目前不骑 record;一旦运输,必须有 server→client carrier rule,不能套 `SEG_STAGE` | -| PACK-PBO readback | P5 具名拒绝;真实形状是 server 写 buffer resource、client `MarkGpuWritten`,P6(ID-57) | -| ABI fingerprint | 不混 segment sizes;改变 8/32/16 MiB + 256 KiB ledger 时仍欠这项 | +| PACK-PBO readback | P5 具名拒绝;真实形状是 server 写 buffer resource、client `MarkGpuWritten`;**P6 未做,→ P9**(ID-57) | +| ABI fingerprint | → **P6.5 wf / nd**:尺寸不再进指纹而进 `LinkTerms` 由 server 陈述;指纹改成 wire 布局摘要(hs 只落了 build stamp 显式化与 `abiMajor/Minor` 补检,`wireFingerprint` / `buildFingerprint` 拆分与 `PipeFields.def` 摘要这一半没做) | | 默认 32 MiB staging | 目标负载单次 128 MiB 上传装不进默认 stage;**内容侧分块已落地**(buffer 范围走查 `1e7c372e`、纹理整宽 slab `9469d48e`,预算 `MGPipeStageChunkBytes()` = 默认 segment/4 = 8 MiB),故普查 / Redmi 的显式 256 MiB profile 不再是这两条路径的必需;未接入分片的 record 类型与专用 carrier 仍归 P8(开放问题 11) | | P5b 的 inproc 依赖 | 历史的 scoped client binding、mip registry 查询与 FBO death mailbox 已经 P5c/P5f 改为记录、句柄和控制/事件路径;P6 核验并装配已有载体,不再重做这些迁移 | -| 未迁移与仿真路径 | 15 个 class-C 槽(query / sync 尾 / `GetTexImage` / `SetSwapInterval`)→ P9 / P10;~~client vertex arrays~~(已实现:`beba0256` 起 wire 复制到 owned buffer 并保留 baseVertex/baseInstance/drawID,本轮补齐 monolith 臂 `62bfe461..e258a822`)、multi-draw client indices、RGB 三通道 CPU mip、renderbuffer copy endpoint、未绑定 named clear、`texture-remint-pull` 仿真保留具名拒绝 → P8 / P9;Magma split compute / image 的“82 个错答”是 P5b 历史普查计数,不是当前失败清单;P5f 后续已补应用 buffer consumers 与 Android 旋转 blit,Magma inproc 已能运行所测 MC 世界;后续 run-ahead 已完成([报告](notes/p5f/magma-runahead.md));XFB、部分不对齐范围、placeholder/native-format 及进一步性能工作仍归 P7([报告](notes/p5f/magma-inproc-fix.md)) | **P5e 补 → CI 收尾更正**:client vertex arrays 曾是 run-ahead 下的具名拒绝(ID-82)与预期红车道 `integration-clientarrays-split`(ID-134);`beba0256` 起已实现,`347bb90c` 已把该车道翻转为**硬绿门**并纳入主 GPU/split 标签,本轮补齐 monolith 臂(`62bfe461..e258a822`);staging 仍归 P8 +| 未迁移与仿真路径 | **class-C 已归零到两个**(2026-09-22 核):`EmitTables.cpp` 的 `MGR_UNMIGRATED_*` 列表全空,只剩手写的 `SetSwapInterval`(P10)与按裁定无行的 `DeleteTransformFeedback`(P9);契约 §11 / SPAWN-PLAN §8 的"511 class-C entries"是 P5 joint 树上的旧普查(`notes/p6/census-classC.md`),不是当前数;~~client vertex arrays~~(已实现:`beba0256` 起 wire 复制到 owned buffer 并保留 baseVertex/baseInstance/drawID,本轮补齐 monolith 臂 `62bfe461..e258a822`)、multi-draw client indices、RGB 三通道 CPU mip、renderbuffer copy endpoint、未绑定 named clear、`texture-remint-pull` 仿真保留具名拒绝 → P8 / P9;Magma split compute / image 的“82 个错答”是 P5b 历史普查计数,不是当前失败清单;P5f 后续已补应用 buffer consumers 与 Android 旋转 blit,Magma inproc 已能运行所测 MC 世界;后续 run-ahead 已完成([报告](notes/p5f/magma-runahead.md));XFB、部分不对齐范围、placeholder/native-format 及进一步性能工作仍归 P7([报告](notes/p5f/magma-inproc-fix.md)) | **P5e 补 → CI 收尾更正**:client vertex arrays 曾是 run-ahead 下的具名拒绝(ID-82)与预期红车道 `integration-clientarrays-split`(ID-134);`beba0256` 起已实现,`347bb90c` 已把该车道翻转为**硬绿门**并纳入主 GPU/split 标签,本轮补齐 monolith 臂(`62bfe461..e258a822`);staging 仍归 P8 | E2 wire 内容控制 | draw-drop 是 OpenRA 的有效控制(758 draws,SSIM 0.000036);clear-drop 被全屏 overdraw 掩盖,不能作控制 | | max record bytes | 实测 reduced / OpenRA `maxrec=784 B`,默认 cap 4 MiB;只代表所测负载,后续索引 / indirect 尾仍须记录 | | 树外脚本 | 普查跑器、`wsl_p5_gate.sh`、Redmi 定频行都在 `~/w7/notes/`,git merge 不会传播 | @@ -141,7 +146,7 @@ P0 已回答的不再列出(spike A 的域、spike B 的分档、`posix_spawn` 1. **client 侧 dirty 走查的真实每 draw CPU 代价。** 已答(P2–P4a):推送没有在拉取基线之下净减少;Release 下 P2 边界 +6–12%,P3a 在 VAO 切换密的 rd12 上再加 +17–19 pt,P4a 在 Espryt 上 +3.4–5.7 pt(`MEASUREMENTS.md` §3–§5)。用户 2026-09-08 接受,性能自此只记录。 2. **真实语料上纹理重铸拉取的发生率。** 已答(P4a):可忽略,保留 LRU 维持默认 0——79 例 × 两后端 780 个统计窗口里共 2 次(`iris-photon`、`iris-derivative` 各 1,只在 DirectGLES)。但 P5b 下这条路径是具名 Fatal,正是这两条 trace 加 `create-indirect` GLES 的首阻塞(P9)。 -3. **spike B 的 `untrusted_app` 域复核。** 两台设备的分档在 `shell` 域测得;从应用进程再跑一次 `extmem_probe`(spike A 的 exec 钩子已可用)。P11 前做。 +3. **spike B 的 `untrusted_app` 域复核。** 两台设备的分档在 `shell` 域测得;从应用进程再跑一次 `extmem_probe`(spike A 的 exec 钩子已可用)。P11 前做。**2026-09-22 降级**:只对同机臂的 T0 / T1 有意义,stream 数据面不需要。 4. **渲染状态的 wire 粒度。** 已答(P2):16 个边界 / 15 个 chunk,7 pipeline 396 B + 8 dynamic 772 B;CSO LRU 64 暂定,P13 重调。 5. **无存储的 capability。** 已答(P2):`FramebufferSrgb`、`DepthClamp`、`TextureCubeMapSeamless` 三个都补了真存储,`sizeof(RenderStateParameters)` 仍 1168。 6. **具名 UBO host payload 的形状(D-B8)。** Magma 在 26.3 世界每帧重打包 331 KB 具名 UBO 字节,Espryt 为 0。要么冻结第二变长尾形状,要么走备选(Magma 直接描述符绑定常驻 `VkBuffer` range,独立 `dev` PR)。P7。 @@ -149,11 +154,17 @@ P0 已回答的不再列出(spike A 的域、spike B 的分档、`posix_spawn` 8. **一份反射归档能否服务三个消费者。** Espryt 那一半已答(P4a):能且不需要复制。Magma 的两个消费者(`DirectVulkan.cpp` 为 `glGetProgramResource*` 重跑反射)未答。P7。 9. **viewport-array 回放能否塞进一次 `draw_vbo`**:各遍之间观察到的状态是否与今天一致未验证。P8。 10. **`ResidentSubData` 的不对称。** P3a 原样保留:`SubDataResident` 是 `kOptional`,Magma 未补实现、`kCapResidentSubData` 未接线。P7 / 独立 `dev` PR。 -11. **`SEG_STAGE` 的上限。** 内容侧已答(2026-09-20):**分块已实现**——buffer 范围走查(`1e7c372e`)与纹理整宽 slab(`9469d48e`)按 `MGPipeStageChunkBytes()`(默认 32 MiB 的 1/4 = 8 MiB)切成多条 `resource_subdata`,所以单次 128 MiB 上传不再需要显式 `MOBILEGL_IPC_STAGE_MB=256`;单片仍超 arena 或该 record 类型未接入分片时仍是 `Fatal{RingOverrun, "SEG_STAGE"}` 兜底。**仍未答**:未接入分片的 record 类型(宿主索引 span、`SetGlobalConstants` 的整个 UBO 等)的更大 blob carrier 设计,以及 MC in-world / Create 的占用分布。P8。 +11. **`SEG_STAGE` 的上限。** 内容侧已答(2026-09-20):**分块已实现**——buffer 范围走查(`1e7c372e`)与纹理整宽 slab(`9469d48e`)按 `MGPipeStageChunkBytes()`(默认 32 MiB 的 1/4 = 8 MiB)切成多条 `resource_subdata`,所以单次 128 MiB 上传不再需要显式 `MOBILEGL_IPC_STAGE_MB=256`;单片仍超 arena 或该 record 类型未接入分片时仍是 `Fatal{RingOverrun, "SEG_STAGE"}` 兜底。**仍未答(2026-09-22 收窄)**:a6 §6 实测没走查的只剩 **program archive**(唯一无界 blob)与 **`draw_vbo` 的 `NumDraws*12` range 尾**;宿主索引 span 无 producer(划掉),`set_global_constants` 有走查。二者的分片是 P6.5 sl 与 P8 共用的同一件事,stream 发送窗口对着它们定尺。MC in-world / Create 的占用分布仍未量(门 8 的树上工作正在补)。 12. **P13 之后 split-only 渲染 bug 的 server 侧第二意见。** verify 构建 + recorder 只覆盖推送内容,不覆盖后端对它的解释。 13. **烘焙后的内部 shader 能否在没有活 `ProgramObject` 的情况下表达 uniform location 与 UBO 布局。** 未做原型。P7。 14. **推送模型改变哪些按拉取模式调过的缓存命中率。** 幸存者容量在 P13 重调。一条线索:设备上 26.3 Espryt 的 `sve` ≈ draw 数(每 draw 重发一次 sampler-view 集合),桌面只有 ~0.07/draw;列入 P3b/P4b 优化清单。 15. **monolith 的 `*IndirectCount` 不调 `SyncGpuWrites()` 是不是潜在缺口。** 独立 `dev` 问题,拆分不得借机顺手修。 16. **索引宿主镜像的实际内存占用。** MC / Sodium / Iris 语料里 element-array buffer 总量未测;若显著超 64 MiB,退化路径的频率与代价必须实测。P8。 17. **`create-indirect` fixture 在 Adreno 830 上的失败**是 `dev@81b17c0b` 就有的(基线 APK 复现),不是本分支造成;`rd12` + Magma 在两台 Adreno 830 上的 `scudo::reportMapError` 崩溃同样是 `dev` 侧。两者排除在设备 A/B 之外、留在桌面语料里;P8 要在 `create-indirect` 上断言 `roundtrips-per-frame == 0`,所以 `dev` 的修复在别人的关键路径上。 -18. **split 两侧的负载平衡。** P5e 解锁出来的新问题:VD32(~3550 draws/帧)下 apply 线程 **11-12 ms**、client **15.7 ms**,**client 是瓶颈且打满 ~94%**。把工作从 client 挪到 apply 会直接降瓶颈——这在 lockstep 下毫无意义(两侧串行相加),**run-ahead 才使它成为一个杠杆**。供选:编码侧的 emitter、tracker 走查、持久映射的脏页追踪(`change_protection` 在侧写里占 1.3%)。需先重新侧写:等待消失后尾部各项的分母都变了。排在 P5e 之后 +18. **split 两侧的负载平衡。** P5e 解锁出来的新问题:VD32(~3550 draws/帧)下 apply 线程 **11-12 ms**、client **15.7 ms**,**client 是瓶颈且打满 ~94%**。把工作从 client 挪到 apply 会直接降瓶颈——这在 lockstep 下毫无意义(两侧串行相加),**run-ahead 才使它成为一个杠杆**。供选:编码侧的 emitter、tracker 走查、持久映射的脏页追踪(`change_protection` 在侧写里占 1.3%)。需先重新侧写:等待消失后尾部各项的分母都变了。排在 P5e 之后;无主,2026-09-22 建议挂在路线图推完后的优化阶段,P6.5 的 2×2 矩阵车道顺带重新侧写 +19. **链路带宽预算与压缩。** TCP 终局下 `SEG_STAGE` 字节/帧对的是 Wi-Fi / USB(量级 30–100 MB/s),不是内存;`ARCHITECTURE.md` §14 的 ~1 MB/帧预算在 60 fps 是 60 MB/s,已贴着 Wi-Fi 上限。是否对 stage 载荷做 LZ4 类压缩、纹理上传是否按内容哈希在 server 侧去重,要等门 8 的分布出来再定。P6.5 契约写下第一行之前必答。 +20. **大单次上传的停顿。** 128 MiB 一次上传在 50 MB/s 上是 2.5 s;内容侧分块解决的是"装不装得下",不是"要等多久"。跨机臂上要么接受并记录,要么给上传做异步化(与 P9 的语义一起想)。不假装解决。 +21. **配对 / 认证的形式。** 令牌足够还是要 TLS?局域网上的 GL 命令流不含凭据,但一个能被随便连的渲染 server 是一条远程代码路径。Ph 定。 +22. **client 平台范围。** 默认先 Linux + Android(现有 CI 能验),Windows client 第二批(`ShmSegmentWin32` 在;`pipe:` 具名拒绝作废、TCP 替代),macOS 仍不拆分。这决定 `ARCHITECTURE.md` §15.3 "Windows 机器不是正确性门"要不要改。 +23. **半开连接的检测。** Wi-Fi 掉线不产生挂断事件;dl 的闩取自描述符挂断,TCP 上需要 keepalive / 心跳超时并**由传输层报告为挂断**——这与"绝不取自 apply 超时"不矛盾,写清楚免得重吵。P6.5 ct。 +24. **E1 对照的重定义(ID-122)无主。** 建议并入 P6.5 的门设计:S8 的好路径断言(`SessionFaultCount() == 0`)已是它想表达的形状,缺的是一个能被证伪的负控。