Commit Graph
3645 Commits
Author SHA1 Message Date
swung0x48 efa19cb16f [docs] (P7): ID-P7-45 - X2 lands: the InitialCapsStartup flake was the fixture pairing loopback sockets by accept order 2026-09-22 22:20:50 -04:00
swung0x48 9a4752adba [docs] (P7): X2 - note for the InitialCapsStartup flake: TCP accept order, not the caps bring-up
- docs/Disaggregated/notes/p7/x2-caps-flake.md: the failure text (Fatal{ProtocolCorruption,
  "StreamLink"} invalid data frame header, SIGABRT), the mechanism (ConnectTo/AcceptPair pairs
  two loopback TCP connections by accept order and the kernel reorders them under load: 5 of
  3000 in a raw-socket probe), the TEST verdict against the product's DataBind rendezvous, the
  before/after loop counts (2/500, 5/500, 3/500 -> 0/500 x3 under the same load) and the gate
  numbers (unit 2435/2435, census 79, ratchet 173, G1 .text 0xa52203 and +0/-0 symbols)
- open: AcceptPair/ConnectTo over tcp:// are still callable and still pair by order; refusing
  them by name is a product change with its own red-once
2026-09-22 22:20:24 -04:00
swung0x48 e730a91206 [MG_Test] (P7): X2 - SocketTransportTest's TCP case uses the DataBind rendezvous too
- TcpCarriesControlAndIndependentDataWithKeepalive had the same assumption as the
  InitialCapsStartup fixture: ConnectTo/AcceptPair over loopback TCP, paired by accept order;
  when the kernel reordered the two connects the bytes sent on the client's data socket arrived
  on the server's control socket and recv(serverData, MSG_WAITALL) hung until the 60 s kill -
  3 of 500 runs under the same load, 0 of 500 afterwards
- the case now opens the control connection, accepts it, then opens the data connection with a
  DataBind nonce and decodes it on the accepted side, exactly the shape the product uses on TCP;
  it keeps its NODELAY, keepalive and ShareFd-unsupported checks on both control transports and
  its independent-data check on the bound data sockets, and asserts that a control-only TCP
  transport owns no data descriptor (TakeDataFd == -1)
2026-09-22 22:20:24 -04:00
swung0x48 f91d0f2c4b [MG_Test] (P7): X2 - InitialCapsStartup pairs its TCP sockets by DataBind nonce, not by accept order
- the fixture rendezvoused with ConnectTo/AcceptPair over loopback TCP, which pairs the two
  connections by the order the listener accepts them; under host load the kernel delivers two
  back-to-back loopback connects to the accept queue out of connect order (measured 5 of 3000
  with 20 CPU hogs), the peer's control socket became the client's data socket, the first control
  frame hit the StreamLink reader and the process died of Fatal{ProtocolCorruption, "StreamLink"}
  invalid data frame header - 2 of 200 and 2 of 500 runs of ANullInitialSnapshot..., 5 of 500 of
  DelayedTcpSnapshot..., every one in 3 of the last 4 integration gates on the loaded host
- the flake is in the TEST: PH-7 (4) already took by-order pairing out of the product on TCP
  ("never paired by arrival order"); the fixture now does what ServerMain's ListenerSource does -
  ConnectControl is accepted before ConnectDataConnection is opened, and the data connection
  names itself with a DataBind nonce that the peer decodes and matches in constant time
- 0 of 500 for both cases under the same load afterwards; AHealthyPeer... shares the fixture and
  is covered by the same change; no product bytes touched
2026-09-22 22:20:24 -04:00
swung0x48 bf8e605fd0 [docs] (P7): ID-P7-44 - the integrator's own reviews land the F fix round and the B3 r3 / B2 r4 rounds, with two small debts recorded 2026-09-22 22:16:07 -04:00
swung0x48 137c911a94 [docs] (P7): ID-P7-43 - M2 lands with a must-fix routed to M2 round 2, and HANDOFF-2026-09-22.md lists every mechanical step left for the next integrator 2026-09-22 22:08:23 -04:00
swung0x48 63347c1682 [docs] (P7): ID-P7-42 - M2 and the F fix round pass their gates, B3 round 3 and B2 round 4 join the tree, and the verify counts are the integration tree's 2026-09-22 22:05:21 -04:00
swung0x48 4b96f55d32 [docs, MG_IntegrationTest] (P7): magma-b2.md carries review round 4 - the transport gate loses a conjunct nothing reaches, and the debt lines cite by symbol
- review round 4 nit: the second gate of the flipped multisample resolve case read `!SplitLane::IsSplitLane() && !PeekSplitRuntime().transportResolved`; the marker term is dead - with the marker set and no transport resolved, the fixture's SetUp already skipped through SplitLane::SkipReasonForSplitOnlyAssertions() -> SplitRuntimeSkipReason(), so Ready() is false and the gate is never reached; in every reachable state it equals `!PeekSplitRuntime().transportResolved`, which is what it now says (the SplitLane.h include goes with it), and the comment no longer describes an unreachable branch; behaviour unchanged - monolith entries still Skipped with the same text, the Full entries still Passed
- review round 4 nit: magma-b2.md §6 items 1, 2, 3 cited WireFramebuffer.inc by line numbers that round 3 had already moved; they now name the arm inside BlitWireFramebuffers's `blit` lambda and the MGLOG_E_ONCE / RecordTextureCopyError text, and the monolith cross-reference names VulkanRenderer::BlitFramebuffer's vkCmdResolveImage + vkCmdBlitImage instead of pipe line numbers
- §2.11 records the round: the should-fix (window primed magenta/0.625, the one-shot wrong-surface demonstration and its readings), the two nits, and a round 4 line under §7 with this tree's readings
- test and docs only; no backend source touched (G1 unaffected)
2026-09-22 22:03:23 -04:00
swung0x48 e385ea96c8 [MG_IntegrationTest] (P7): the window leg of the flipped multisample resolve case primes the default framebuffer with values no other surface in the test holds
- review round 4 should-fix: round 3 primed the window blue at depth 0.5, the same colour and depth the user framebuffer `resolved.fbo` was primed with and still held after its own declined blit, so a glBindFramebuffer(GL_FRAMEBUFFER, 0) that landed on the user framebuffer, or a default-framebuffer readback that resolved the wrong surface, read the priming it was meant to reject and the leg passed vacuously
- the window is now primed magenta at depth 0.625 - the user framebuffer is blue at 0.5, the source red/green at 0.25/0.75 - and the three probes expect exactly that
- shown once and restored: with the probes pointed at `resolved.fbo` instead of 0, all three arms (`DirectVulkan.{Split,Spawn,Tcp}.MsFlip.`) fail on both aspects at (1, 1): colour reads {0,0,255,255} against {255,0,255,255} ("must not have written its colour at (1, 1)"), depth reads 0.5 against 0.625 ("must have left its depth alone at (1, 1)"); under round 3's priming the same probes on that surface were green
- test only; no backend source touched (G1 unaffected)
2026-09-22 22:03:23 -04:00
swung0x48 c8fc4fb712 [docs] (P7): magma-b3 - fix round 3: the audit's guard-aware walk, the tcp-naming server-log fatal, the EVIDENCE guard, and the round's gate
- §0: rows 28-31 for this round
- §1.5: the two walk holes the third review found (a log under `#if 0` accepted, an indented
  `#else` walked through), the fail-open-for-one-guard rule, and the two new fixtures' readings
  on the round-2 audit and on this one; 16/16, tree 53 / 53 / 0; the probe shapes that are not
  fixtures
- §4.1: the merged server-log fatal names MOBILEGL_IPC_CONTROL; demo 1 re-run on the new runner
- §4.5: the EVIDENCE empty-pattern guard; the stub's executable bit restored
- §7.2: the B4 sentence gives both numberings (package tree :13404 / :13471, landed tree
  :13533 / :13600); two debts recorded - the tcp pid-arm-proof check still runs before the
  marker check, and LOG_WINDOW counts the blank and `#if` lines it skips
- §5: the round's gate on the code head; no product file, so G1 is unaffected; lanes not re-run
2026-09-22 22:03:23 -04:00
swung0x48 3b8bf9ec25 [scripts] (P7): the pull-library control refuses an empty grep -F pattern in EVIDENCE, and the stub ctest is executable again
- every line of EVIDENCE is a grep -F pattern and an empty line matches everything: a trailing
  newline or a blank line between the two sentences would turn hole 2 into "any red will do".
  The smoke's "red without the transport-resolution message" case catches that (22/23), but
  only when somebody runs it; a `case` after the assignment now refuses a blank line or a
  leading/trailing newline with ::error:: and rc 1, before the selection is counted or the
  library is swapped. The red-check's perturbation line is untouched; smoke 23/23
- scripts/ci/testdata/stub_ctest.sh went 100755 -> 100644 in the round-2 commit that added
  its retrace-evidence-nolog mode (a Windows-mount artefact); restored with
  `git update-index --chmod=+x`. The smoke copies it and chmods the copy, so nothing ran
  differently
2026-09-22 22:03:23 -04:00
swung0x48 10220b564e [tools] (P7): the merged server-log fatal names MOBILEGL_IPC_CONTROL, so the tcp arm's red still says tcp
- the round-2 merge folded "TCP session has no forwarded server log" into the one server-log
  check for every transport, and its message named only MOBILEGL_TRANSPORT - which is `spawn`
  for the tcp arm too (tcp = spawn + MOBILEGL_IPC_CONTROL=tcp://), so the tcp arm's missing
  forwarded log read as a plain spawn red
- the message carries MOBILEGL_IPC_CONTROL='...' after the transport (empty for inproc and
  plain spawn); message only, no check moved
2026-09-22 22:03:23 -04:00
swung0x48 bd849b2821 [tools] (P7): the audit's block walk is fail-open only for the disaggregated guard, and an indented #else stops it
- stepping over `#endif` accepted a log that is compiled out: `#if 0` / `MGLOG_W(...)` /
  `#endif` / `Count(...)` read as logged, and so did a log under `#ifdef
  MOBILEGL_VERBOSE_DECLINES` - a Count that counts every time and logs in no shipped build
- the walk now counts the `#endif`s it crosses; a same-indent log met with one outstanding
  counts only if every opener enclosing it, reached by continuing upward, is the whole-line
  `#if MOBILEGL_BUILD_DISAGGREGATED` (`&& X` is not it). `#if`/`#ifdef`/`#ifndef` with no
  `#endif` outstanding is the Count's own guard and is still stepped over, so the column-0
  `#if/#endif` fixture stays green; the comment says the walk is fail-open for that one
  guard and nothing else
- `#else`/`#elif` stopped the walk only at column 0, as a line of lesser indentation; one at
  the Count's own indentation walked straight through to the log above it. PP_STOP now
  returns False at any indentation, before the indent test
- two red fixtures, both green on the round-2 audit: "log only under a #if 0 above the
  Count" and "log only on the other side of an INDENTED #else at the Count's indentation";
  16/16, the tree stays 53 / 53 / 0
2026-09-22 22:03:23 -04:00
swung0x48 9cea514010 [docs] (P7): ph-f.md §6/§7 record the F fix round - the fingerprint refusal is one-directional and an un-redeployed phone shows as "no Welcome", the unix pairing window and the two pre-auth exposures are §12 debts, the token minimum is TCP-only, and the token examples are 16+ bytes
- ph-f.md: §0 rows F-a..F-d with package-tree SHAs; §2.2 states the asymmetry (new server + old client -> Refuse{WireFingerprint}; old server + new client -> the old AcceptPair closes both after 2000 ms and the client sees `no Welcome ... (rc=6)`, no Refuse frame); §6 the four fix commits with their red-once lines; §6.4 the unix arrival-order pairing (250 ms / 2000 ms) as a local-peer debt with the SELinux assumption named, and the two pre-auth exposures; §7 the gates on 2b2a0ae0
- CONTRACT-P7 §12: the two pre-auth exposures (fork before Hello with a 10 s wait; ValidatePeerHandshake before AuthenticatePeerToken sends the fingerprint and build stamp to an unauthenticated peer), the unix pairing debt, and the fingerprint asymmetry, for PH-7 (5)
- PLAN-PH-P34B-P7: PH-7 (3) says the minimum is checked at the TCP listen; PH-8 says "ignored, server-sized" rather than "clamped"; the no-token listen row's remaining-work cell no longer claims the smoke is unreferenced
- device-window-1-runbook §2 step 3: the un-redeployed-phone symptom, and where to look first
- ROADMAP §6 and peer-loss-probe: `MOBILEGL_IPC_TOKEN=devtoken` (8 bytes, which now exits 72) becomes a 25-byte token in every example
2026-09-22 21:55:39 -04:00
swung0x48 8c8fc31952 [MG_Remote, MG_Test, ci] (P7): the token compare runs a fixed 64-byte width, an ignored window ask is logged once, a nonce that could not be minted is refused by name, and a garbage first frame while busy is MalformedHello rather than Busy
- AuthToken.h: ConstantTimeTokenMatch loops kAuthTokenCompareBytes (64) iterations with both operands read as zero past their ends - its trip count no longer tells a peer the configured token's length; a token longer than 64 is still compared to its last byte (SocketTransportTest pins the 70-byte case)
- ServerSession.cpp: an ask in Hello.linkTerms above the granted terms logs one MGLOG_W naming both sides ("the ask is ignored and the session is server-sized"); the production client asks for nothing, so a session that was never mis-configured never logs it; SessionHandshakeTest's 64 GiB case requires the line (red before: absent)
- ServerSession.cpp: a MintNonce failure sends Refuse{LinkTerms} "stream data plane unavailable: the server could not mint a data nonce" before returning the fault it is (still exit 67, still counted) instead of a bare close
- ServerMain.cpp: a first frame with the wrong magic or over 1 MiB while a session is live is Refuse{MalformedHello} "first frame is not a control frame", drained before the close so the refusal is not RST away; Busy stays the answer for a well-formed frame that is not a DataBind
- tcp_supervisor_smoke.py: garbage_first_frame_while_busy (magic XXXX on a live session -> code 8; red before: code 7)
- fatal census unchanged: 79 abort sites, 3 refusal words (the new refusals go through the enum, not a literal)
2026-09-22 21:54:46 -04:00
swung0x48 c69d8dfdc8 [MG_Remote, MG_Test, ci] (P7): sha256(protocol.fbs) is pinned to MOBILEGL_PROTOCOL_CONTROL_REVISION, so a control-schema edit without a bump is red in the unit lane and in flatc-check instead of a silently absent field
- the revision is a hand-bumped integer mixed into wireFingerprint and nothing tied it to protocol.fbs's content; scripts/ci/protocol_revision_pin.py holds {revision -> sha256(protocol.fbs)} in protocol_revision_pins.json and refuses a schema whose digest is not the current revision's, or a revision with no row
- registered as ProtocolSchema.RevisionPinsDigest (label unit, MG_Test/Wire/CMakeLists.txt, --self-test proves both perturbations red before it says green) and as a step of CI's flatc-check job, the one that regenerates the header on every schema edit
- --write records a bump's row and refuses to re-pin an existing revision to a different digest, which is what a schema edit without a bump looks like
- mg_protocol_base.h says where the pin lives beside the revision it pins
- red-once: protocol.fbs touched with one trailing comment, revision left at 1 -> "protocol.fbs has sha256 a7b5c7fb... but MOBILEGL_PROTOCOL_CONTROL_REVISION is still 1, which is pinned to 7fc859f7..." rc=1; restored, green
2026-09-22 21:54:46 -04:00
swung0x48 0293aebb17 [MG_Remote, ci] (P7): a bound session closes its data-connection source, so a later DataBind is refused by name instead of queued into a child that stopped reading, and the single-session listener closes with it
- ServerMain.cpp: RunSession takes the descriptor its data-connection source reads from (the child's hand-off end under --serve, the listener itself without it) and closes it the moment Accept returns; the source object goes with it
- the supervisor's hand-off send is MSG_DONTWAIT (FdPassing::SendFd dontWait), so a peer that stopped reading answers at once; "peer gone" on a datagram pair (ECONNREFUSED, ENOTCONN) is an answer the caller names, not a logged fault
- before: every DataBind after the bind sat in the child's receive queue with no reply, its TCP connection held open until the session ended, and past the queue limit (net.unix.max_dgram_qlen 10 on the phone; ~288 datagrams of sender buffer on this host) the supervisor blocked in sendmsg for the rest of the session - no accepts, no Busy, no reaping
- before, without --serve: the listener stayed open after the data connection bound, so a second client or a retry completed a TCP handshake nobody would accept and waited out its 20 s connect budget instead of the ECONNREFUSED it got before PH-7 (4)
- tcp_supervisor_smoke.py: data_bind_after_bound (12 extra DataBinds on a bound session each get Refuse{Authentication} "data connection could not be handed to the live session", and a fresh control connection is still Busy) and single_session_listener (a connect after `ready` is ECONNREFUSED); connect_control retries ECONNREFUSED at startup for pair() and held_session() alike
- red-once at da313010: smoke TimeoutError on the first extra's receive; probe with qlen+2 fire-and-forget DataBinds: 288 queued silently, then the supervisor stopped accepting (fresh control: connect timed out) while still alive; single-session connect after ready succeeded
2026-09-22 21:54:46 -04:00
swung0x48 9ae1e6c04e [docs] (P7): ID-P7-41 - M2 is on the integration tree with its second leak named, three reviews land with fixes, and window 1b's instant failures are the pairing window over the LAN 2026-09-22 21:48:27 -04:00
swung0x48 7d1315271a [docs] (P7): magma-m2.md names the one server-side-knob parity list its three entries joined at merge 2026-09-22 21:46:08 -04:00
swung0x48 5d8a2b99fd [docs] (P7): magma-m2.md records M2 - the wire arm's orphaned VkBuffers are bounded (25,935 -> ~1,050 peak, bsl spawn server 825 -> 546 MiB), and the host maps M1 attributed to them are lavapipe descriptor sets
Before/after on host with M1's sampler and probe for bsl-esc-menu-854 and iris-bsl-in-world on
monolith / inproc / spawn (pixels identical on every arm), the mechanism with citations, the
knob's semantics, the red-once table, the gates, and what remains: the wire arm's descriptor-set
growth between BeginFrame rewinds (27,377 live sets == 28,134 maps; now bounded only because
M2's forced syncs let the drain rewind the cursors), CollectGarbage/pruneWire never reached on
the wire arm (B4), the frame-serial proof deferred until B3's floor fix, the tcp arm's gauge
reach, the ServerSpawn.cpp touch and the knob for the integrator to ratify, and the Redmi
acceptance run.
2026-09-22 21:46:08 -04:00
swung0x48 f0356dbe61 [MG_Backend, MG_IntegrationTest] (P7): the wire watermark's sync point also fires above 1024 parked stores, so small orphans that never reach the byte budget are bounded by count
Measured on bsl-esc-menu-854 (spawn, lavapipe) with the byte watermark alone: the dead VkBuffers
at the end fell from 25,935 to 32, but one stretch with no submission still parked 12,498 stores
in 39.5 MB - under 64 MiB, so nothing forced a sync. A fixed ceiling
(VkBufferManager::kWireDeferredCountCeiling = 1024, not a knob) now rides the same
WaitForSubmitIndex call; MOBILEGL_IPC_WIRE_DEFERRED_MB=0 still turns both triggers off.
MagmaWireReclaimScenario gains the case: 3000 respecify-and-draw rounds of a 256-byte store in one
frame (750 KB, far below the lane's 8 MiB). Red before this commit on inproc and spawn (live peak
3001 vs a bound of 1027), green after (1025, two forced syncs).
2026-09-22 21:46:08 -04:00
swung0x48 9328bdc735 [MG_Backend, MG_Util, MG_Test, MG_IntegrationTest, scripts] (P7): integration-magma-split and -spawn carry MagmaWireReclaimScenario, which reads the server's wbuf[] gauges and reds on a wire arm that keeps orphaned buffer stores until the frame ends
Rule J's red-once for M2. The server role's VkBufferManager publishes four PipeStats gauges
(push builds only, so the pull image is untouched): wire buffer records alive, and the run
maxima of live wire VkBuffers and of parked bytes, plus the watermark's forced-sync count -
maxima because the defect lived inside one frame and a swap-time sample reads after the frame
boundary's own sweep. Two cases, each inside a single frame: 1024 undrawn respecifies of one
4 KiB buffer (live peak <= 4 x wire buffers), and 48 respecify-and-draw rounds of a 1 MiB store
under the lane's MOBILEGL_IPC_WIRE_DEFERRED_MB=8 (parked peak <= budget + one store, every strip
its own colour). Red at base (ec46a550's defer path, counted): 1025 vs 4 live, 49,287,168 vs
9,437,184 bytes and 49 vs 11 live, on both arms; green after: 1 live, 9,437,184 bytes / 9 live
with 5 forced syncs. The knob's negative control (=0) reds the second case with the same
49,287,168 bytes. Inproc and spawn only: the tcp server is the lane-wide fixture supervisor,
whose environment and log the entry cannot reach - named in spawn_lane_parity.py as
MAGMA_NOT_ON_TCP (the ID-P7-14 shape), and PipeStatsTest pins the four short names.
2026-09-22 21:46:08 -04:00
swung0x48 0acee60a3b [MG_Remote] (P7): the spawn launcher passes MOBILEGL_IPC_WIRE_DEFERRED_MB through to the server child, the one MOBILEGL_IPC_* knob its environment scrub keeps
BuildChildEnv drops every MOBILEGL_IPC_* entry, so the server-owned watermark meant something
under inproc and silently nothing under spawn - measured: the spawn server parked 47 MiB against
a lane budget of 8 with zero forced syncs, because it had parsed the default out of an
environment that no longer carried the variable. The knob names no endpoint, role or segment
size, so neither anti-recursion catch (Dial=No, ServerMain's scrub check of TRANSPORT /
SERVER_PATH / RING_MB / STAGE_MB) is weakened; it is listed by name, not by widening the prefix.
2026-09-22 21:44:06 -04:00
swung0x48 c569c916c0 [MG_Backend] (P7): when the orphaned wire buffer stores still parked exceed MOBILEGL_IPC_WIRE_DEFERRED_MB (64 by default), the server takes the host-access sync point mid-frame and reclaims them all
The defer-path sweep frees an orphan once its last submission has retired, but inside one long
frame a store that was drawn from is named by recorded, unsubmitted work, and nothing submits it
until the frame ends. The knob is read once through MG_Config::Ipc like its siblings; above it
the park calls WaitForSubmitIndex(GetSyncPointSubmitIndex(), flush) - the call
WaitForWireBufferHostAccess makes - and sweeps again, which empties the list because no entry can
be tagged past the sync point just waited out. A sync point that cannot complete dies through
the existing Fatal{ResourceUnavailable, "buffer-write-sync"} site, now one helper shared with the
host write (fatal_census: 79 abort sites, unchanged). 0 is the negative control.
2026-09-22 21:44:06 -04:00
swung0x48 b81a8827b5 [MG_Backend] (P7): a wire buffer store that glBufferData orphans is destroyed on the defer path as soon as no GPU command can still name it, instead of waiting for a frame boundary
RespecifyWireBuffer (every wire glBufferData) and DestroyWireBuffer parked the old VkBuffer in
the per-frame-slot buckets, which only BeginFrame and the idle drain empty. A snapshot-exiting
pbuffer replay delivers one present per run (ID-P7-32), so on bsl-esc-menu-854 the split server
held 25,923 dead stores. The wire arm now keeps its own flat list: a store whose last-use serial
is 0 (never named by a GPU command) is destroyed at the park; any other is tagged with the
renderer's sync-point submit index and destroyed by the sweep every park runs, once that index
has completed or the renderer is idle. The frame-serial floor is deliberately not a proof here
(it cannot move mid-frame, and on this base it is the floor B3 found unsound). The transient
arena's releases and the monolith OnRespecify path are unchanged.
2026-09-22 21:44:06 -04:00
swung0x48 41b392298b [docs] (P7): ID-P7-40 - window 1b's TCP matrix runs on the user's route, and the B3, V1 and B2 fix rounds are on the integration tree 2026-09-22 21:38:13 -04:00
swung0x48 11edc8e3ac [docs, MG_Backend] (P7): magma-b2.md carries review round 3 - the transport gate, the default draw framebuffer in the pre-pass, the shape-only scope of "a declined call writes nothing", seven knob tails, and three new debt lines
- §2.10 (new): the skip gate is the process's resolved transport, with the Skipped/Passed lines as measured (monolith + DirectGLES Skipped, Split/Spawn/Tcp.Full Passed); why VerifySplit. cannot be measured on this branch (a -DMOBILEGL_PIPE_VERIFY=ON build of this tree aborts every split entry's bring-up in MGPipeApplyResourceRespecify on the apply thread - the verify+split debt the verify-split package relaxes) and its measurement on a throwaway detached worktree of the landed head plus commit a (Passed); the default draw framebuffer joining the pre-pass, with the red-once (round-2 guard restored -> Split/Spawn MsFlip. read the source's red/green in the window); the two wording fixes.
- §2.9 items 1 and 3 and §6 items 1 and 5: the entries that now RUN the case (Full. x3, VerifySplit. on the landed tree), the corrected default-draw sentence, and "a declined call writes nothing" scoped to SHAPE declines - the capability decline in ResolveWireDepthStencil is still per aspect, rule I (a).
- VulkanRenderer.h: the DeclineWireDepthStencilResolveShape comment says the same (comment only).
- §6 item 4 and §7: seven server-env-knob tails on the landed tree, naming .StaleSerial. (this branch predates B3 and measures six).
- §6 items 8-10 (recorded, not fixed): a legal same-size MSAA-FBO -> default-framebuffer depth/stencil blit is a session Fatal (multisample-depth-resolve-region); a scissor that empties the destination returns silently even for shapes GL still errors on; MS->MS blits decide per aspect, so a COLOR|DEPTH call can copy colour and decline depth.
- §7 is one measured row for this tree (p7/magma-b2@1bf48cfb + this commit's comment, remeasured on the final head) and names the landed tree as the integrator's gate, without numbers or SHAs.
2026-09-22 21:36:08 -04:00
swung0x48 24da1e0f6d [MG_Backend, MG_IntegrationTest] (P7): the default draw framebuffer is asked the multisample depth/stencil shape question before any aspect runs, so a scaled COLOR|DEPTH resolve onto the window writes nothing
- BlitWireFramebuffers' round-2 pre-pass left a default DRAW framebuffer to the per-aspect lambdas on the belief that a default draw behind a multisample read was ResolveWireDepthStencil's region Fatal whatever the shape. It is not: that arm calls DeclineWireDepthStencilResolveShape BEFORE its destination.isDefault region check, so a scaled (or X-mirrored) COLOR|DEPTH blit out of a multisample framebuffer onto the window ran the colour lambda first (BlitWireColorToDefault wrote the swapchain image) and then recorded INVALID_OPERATION on its depth - the partial effect magma-b2.md §2.9 item 3 declared closed.
- The guard drops !draw->IsDefault, and the pre-pass resolves both sides as READS (isWriteTarget=false): only their format and samples are consulted, and DefaultFramebufferReadIndex is const, so nothing re-points the default framebuffer at the acquired image before a write.
- The flipped-resolve case gains a leg: the window is primed blue at depth 0.5, the multisample source (red below, green above) is blown up over the whole of it with COLOR|DEPTH, the call must be INVALID_OPERATION, and three probes (corner, centre, far corner) must read the priming on both aspects through glReadPixels - the only way the harness's pbuffer default framebuffer can be looked at.
- Red-once (split + spawn, restored): the round-2 guard (&& !draw->IsDefault) put back -> DirectVulkan.{Split,Spawn}.MsFlip. fail "the declined COLOR|DEPTH scale onto the window must not have written its colour at (1, 1)" reading {255,0,0,255} (the source's bottom band), and {0,255,0,255} at (64, 48) and (126, 94), for {0,0,255,255}; the INVALID_OPERATION assertion still held, which is the partial effect exactly.
- Verified: the 107 multisample blit/resolve and depth/stencil readback entries on the three wire arms (MsFlip/MsFlip1/MsBlit/MsResolve0/1, Full x3 for both readback scenarios) and the monolith DirectVulkan.DepthStencilReadback* entries pass, pre-existing skips unchanged.
2026-09-22 21:36:08 -04:00
swung0x48 6f1c6d26ee [MG_IntegrationTest] (P7): the flipped multisample resolve case skips on the transport the process resolved, not on the lane marker, so the whole-binary census entries run it again
- MGITEST_SPLIT_LANE marks the CURATED split lanes, not the transport: DirectVulkan.{Split,Spawn,Tcp}.Full. (and the VerifySplit. lane where it is registered) run inproc/spawn/tcp WITHOUT it on purpose, and the round-2 marker gate skipped the case there with a message about a monolith arm that was not running - before round 2 it ran and passed on them.
- The gate is now the process's resolved transport (PeekSplitRuntime().transportResolved, i.e. MG_Config::Transport != Monolith), which is the very fork VulkanRenderer::BlitFramebuffer takes to reach BlitWireFramebuffers; the marker on its own still keeps a curated lane running the case, and its fixture's arming assertion says whether that lane got the transport it asked for.
- Verified on build-split: DirectVulkan.DepthStencilReadbackMatrixScenario.AFlipped… still Skipped ("the monolith DirectVulkan transport … refuses a flipped depth blit …"); DirectGLES.{,ForcedDepthStencilEmulation.}…AFlipped… still Skipped (Espryt reason); DirectVulkan.{Split,Spawn,Tcp}.Full.…AFlipped… Passed (all three were Skipped before); DirectVulkan.{Split,Spawn}.{MsFlip,MsFlip1}. and Tcp.MsFlip. Passed.
2026-09-22 21:36:08 -04:00
swung0x48 0bc59ab239 [MG_IntegrationTest] (P7): the unarmed-expected file stops misquoting tier 3s count
- the first class said its 22 names were "the same 13 entries per backend that tier 3 measured as reds", which is wrong twice: 13 was the whole count, not a per-backend one, and those 13 (AdvertisedLimitsScenario x8, SpirvShaderBinaryScenario x4, ProgramPipelineScenario's reserved name) are spread across this class and the next
- the sentence now says what tier 3 actually measured and why it is the same property seen from the other side
2026-09-22 21:36:08 -04:00
swung0x48 16b1d031a9 [docs] (P7): the note's lane tables carry the V1 fix round's own numbers
- integration-verify goes 1136 to 1138 (273 skip): the new CorruptedFieldIsReportedOnTheServerRead case is discovered by the ambient Verify. registration too, where it skips for want of the CORRUPT knob - the same shape CorruptedFieldIsReported already has there
- integration-verify-split is 1072/1072 with 117 skip, re-measured on the final head
- 0 gains a row for the fix round, one line per finding, pointing at the section each landed in
2026-09-22 21:36:08 -04:00
swung0x48 c0f7aa9bd6 [docs, MG_Impl] (P7): the pack blind spot is one value, not the field
- 2.2 and the hook's own comment both said the comparator can no longer see a client that pushed a WRONG pack state on the server's ReadPixels. Too broad: PipeApplier.cpp reads savedPack THROUGH THE ACCESSOR, and therefore through the hook, BEFORE it installs the neutral value, so the pushed pack is compared against the live one right there
- a correct push is equal and returns; a wrong push that is not exactly the neutral pack fails both compares and is still Fatal; only a wrong push that equals {SwapBytes 0, LSBFirst 0, RowLength 0, ImageHeight 0, Skip* 0, Alignment 1} is invisible, and only while the application's own pack differs from it
- notes/p7/verify-split.md 2.2 and 6 say so, and the comment above ServerReadsInsideTheNeutralPackWindow says so
- the measured evidence is the read-side control's own server half: 2 to 3 where=read reports per readback, which is the savedPack read plus the backend read
2026-09-22 21:36:08 -04:00
swung0x48 3947a344b4 [docs] (P7): CONTRACT-P7 6 and 8 stop contradicting themselves about verify x split
- 6 opened with "verify is registered on monolith only", which stopped being true when wave 3 landed the split arm, and cited CMakeLists.txt:1684-1760 for a block that starts around :1715; it now reads as the gate's STARTING POINT, cites the guard by name rather than a stale range, and names the block that registers the split arm
- 8's (7) marker said "done" flat, a sentence away from the midpoint tally that lists it as not done; it is now dated to wave 3 V1 and says the two sentences are about different moments
- no SHA citation touched
2026-09-22 21:36:07 -04:00
swung0x48 9e5effa9d9 [MG_IntegrationTest, docs] (P7): the spawn server does have MG_Impl - what it has not is a live context
- the verify-split block and notes/p7/verify-split.md 3.3 both said the spawn server runs no compare "because MG_Impl is not in it", which is false and sent a reader looking for a link-time gap: MobileGLServer is an executable over ServerEntry.cpp linked against the WHOLE library (top-level CMakeLists.txt), PipeFill.cpp included, so MGPipeVerifyReadHook is present and is called on every backend read
- the true mechanism: the server image's main reaches MG_Backend::InitServerRoleForSpawn() and never MG_State::Init(), so MG_State::pGLContext is null and the hook returns at its ctx == nullptr line before comparing anything
- the inproc-only conclusion is unchanged; what changes is the shape of the fix, which is a cross-process compare rather than a link edit
- CONTRACT-P7 12 records that debt by name, and the note's 6 cites it
2026-09-22 21:35:39 -04:00
swung0x48 30d3595213 [ci] (P7): the verify-split artifact keeps the green lane run, not the controls that overwrote it
- both negative-control steps re-run 12 ambient VerifySplit. entries with a knob exported, and an ambient entry writes to its own per-entry path under verify-split-logs/ which the library opens "w" - so the upload at the end of the job collected twelve CONTROL logs sitting under the LANE's names
- if: always() made it worse rather than better: a failure investigation is exactly when the overwritten half is the half somebody needs
- the arm proof is now followed by a cp -a to verify-split-logs-lane/ (plus the lane's JUnit), and the upload takes both trees - the green run the arm proof read, and whatever the controls left behind
2026-09-22 21:35:06 -04:00
swung0x48 b4f830942b [MG_IntegrationTest, ci] (P7): the verify-split arm proof is a per-entry census, not a floor
- the landing shape was a count - at least 850 armed of at least 1000 client logs - which leaves the remaining 155 unnamed: the lane could lose fifty arms, gain fifty skips, and the floor would not move
- the rule is now per entry and two-sided, the one dualblock-expected-fatals.txt already rides: each client log must carry the arming line, or belong to an entry ctest reported SKIPPED, or be named in the new Harness/verify-split-unarmed-expected.txt
- a gtest skip is the recognised no-verb marker and is NOT named, because the skip set moves with the driver - naming it would ratchet on lavapipe rather than on the comparator
- both other directions fail: a listed entry that armed, and a listed name with no client log in this run
- split_log_paths.py gains the verify-split-arming mode; the lane step gains --output-junit so a skip can be told from a pass; test_split_log_paths.py gains six controls covering the four ways the census can be wrong
- measured on the host over 1064 private client logs: 909 armed, 99 unarmed and skipped, 56 unarmed and named in five classes - caps/limits/extension advertisement 22, shader and program object surfaces 16, object state written and read back or a call rejected before it becomes a verb 14, framebuffer completeness queries 2 (DirectGLES only; DirectVulkan skips both), the poison parent that only forks 2
2026-09-22 21:35:06 -04:00
swung0x48 2424c8209d [MG_IntegrationTest] (P7): the split poison control says which role fired, not merely that someone did
- ReadChildLog concatenated the child's two role halves and the assertion searched the union, so VerifySplitPoisonOmitted. would have been just as green if the stamp the knob withheld had been the CLIENT's - which is the case it exists to rule out, the mechanism under test being the server-side verb stamp honouring MOBILEGL_PIPE_POISON_OMIT
- kOmittedPairs carries FiresOnTheServer; ReadChildLogHalves keeps Client, Server and the union apart; the split pair now asserts the Fatal in the child's SERVER half under MOBILEGL_BUILD_DISAGGREGATED, the monolith pair keeps the union because it has one role
- measured on both backends: client half 0 Fatal{UnmigratedPipeInput lines, server half 1 each - the union search could not tell them apart
- monolith PoisonOmitted. entries stay green (2/2), split VerifySplitPoisonOmitted. stay green (2/2)
2026-09-22 21:35:06 -04:00
swung0x48 e9b3f5fe04 [MG_Impl, MG_IntegrationTest, ci] (P7): the compare-at-read hook gets a negative control of its own
- MGPipeVerifyReadHook honours MOBILEGL_PIPE_VERIFY_CORRUPT: it perturbs the ORACLE after CopyField, and AGAIN after the ID-49 neutral-pack overwrite, because that overwrite replaces the pack half wholesale and CorruptStorage perturbs an array's element 0 - which is the pack half
- until now the knob only ever reached EntryCompare, so every red it could produce was the client thread's where=entry and the hook that runs on the server's apply thread at every backend read had no falsifier at all
- new entry per backend, DirectGLES/DirectVulkan.VerifySplitReadCorrupted., with CORRUPT=GetPixelStoreParameters and VERIFY_FATAL=0 - the field is in the kReadback fill mask, so the client entry compare would otherwise abort the process before the server reached the read
- the case reads the SERVER role's half of its private log alone: with the knob armed a union search over both halves would be satisfied by the arm that is not under test
- PipeStatsWindow.h gains ReadServerLogSince for that
- test.yml grows the matching control step - run the two entries, then re-read both server halves from outside for the where=read report
- measured: 2/2 green, server halves 3 and 2 lines, client halves 0 lines; revert-and-run with the two corruption blocks removed gives 2/2 red and both server halves 0 lines
- the lane goes 1070 to 1072
2026-09-22 21:35:06 -04:00
swung0x48 ca8cbe5c34 [MG_Pipe, MG_Remote, MG_Impl] (P7): the ID-49 neutral read_pixels pack has one spelling
- MG_Pipe/MGPipeTypes.h gains inline MGPipeNeutralReadPixelsPack() next to MGPPixelPackState, whose owner it is; the applier that installs the neutral state and the comparator whose oracle it is now call the same function
- MG_Remote/Server/PipeApplier.cpp read_pixels takes the constant from there instead of building it field by field
- MG_Impl/Pipe/PipeFill.cpp drops ServerReadPixelsNeutralPack, the re-typed second copy: a drift between two hand-typed spellings costs a FALSE DIVERGENCE on the server read, not a build break, which is the direction that fails quietly
- notes/p7/verify-split.md 2.2 says one spelling and why the old reasoning (do not reach into MG_Remote/Server from MG_Impl) did not survive the failure-direction argument
2026-09-22 21:35:06 -04:00
swung0x48 f4b0662d7e [docs] (P7): magma-b3 - fix round 2: the audit's anchored log, char prefix and walk stops, the server-log fatal after the ARMED check on every transport, the pull-library control, and the round's gate
- §0: the previous round's note commit gets its own row (20), and rows 21-27 for this round
- §1.5: the three audit holes the second review found and the fixtures that pin them, with
  each new fixture's reading on the previous audit and on this one (three false greens, two
  false reds, one that stays red on purpose); 14/14, tree 53 / 53 / 0
- §4.1: the server-log fatal now sits after the marker and ARMED checks and covers inproc;
  the four fail-closed demonstrations with the fatal at its new position, and the case where
  the old order reported the server-log message for a launch-failure shape
- §4.5 (new): the pull-library control had refused its own red since P6's per-role log rename
  - read from Log.h and the runner, then measured with the real ctest - and the one-place fix
- §7.2: the landed-tree line of the stale WaitForFrameSerial comment corrected; two debts
  recorded: the census sits after the replay's exit-code fatal, and B4's restart must not
  read `record` after OnSubmitsCompletedUpTo erases it
- §5: the round's gate readings on the code head
2026-09-22 21:28:02 -04:00
swung0x48 d80dc21299 [MG_Backend] (P7): comment-only - the tally header names the macro that exists, and the def says the wire arm declines, not the draw
- WireDeclineTally.h cited `MGL_WIRE_DECLINE_FALSE`, which does not exist; the statement pair
  a site actually writes is `MGL_WIRE_DECLINE_AT(Site, "why", ...); return false;`, and the
  bare-Count sites stand under a W/E of their own, which the audit holds them to
- WireDeclines.def's banner said "EVERY WAY A MAGMA WIRE DRAW CAN DECLINE", contradicted by
  the header's "a decline is not always a skipped draw" paragraph: the Tex*/Shape*/Upload*
  rows count per texture sync, reached from the descriptor resolver, attachments,
  CopyTexSubImage, mipmap generation, CopyImageSubData and readback as well as from a draw.
  The banner now says the wire arm, and carries the per-sync sentence with a pointer to the
  header
- both files are disaggregated-only (the def is included only from the guarded header), and
  the edits are comments: the pull build's .text and symbol set are unchanged (G1)
2026-09-22 21:28:02 -04:00
swung0x48 46bda06226 [scripts] (P7): the pull-library control accepts the no-client-log sentence a pull build has produced since the per-role log rename
- retrace_pull_library_control.sh required run_trace_case.cmake's "never reported resolving
  it", the marker-search sentence. Since P6's one-log-per-role rename a pull library never
  reaches that search: it has one role and writes MOBILEGL_LOG_FILE_PATH unchanged
  (output/mobilegl.log, Log.h's pull arm of RoleLogPath), the runner reads
  output/mobilegl.client.log and stops one check earlier with "the run wrote no <client log>,
  so there is no evidence the transport ever resolved" - so the control's hole-2 check
  refused its own red and the step exited 1 on every pull-library run
- measured on this tree with the real ctest, build-linux's pull library over build-split's
  frozen split library, SPLIT_TRANSPORT=inproc: control rc 1, "::error::the split retrace
  went red (ctest exit 8) ... never says the library did not resolve the transport", the
  runner's fatal at the no-client-log check. With this change the same run passes for its
  own reason on both inproc and spawn
- EVIDENCE carries both sentences as grep -F's newline-separated patterns, so the evidence
  line the red-check perturbs is unchanged; both are the transport-identity assertion
  refusing the same library for the same reason, and neither is a loader failure, a missing
  fixture, a timeout or an SSIM drop
- stub_ctest.sh gains retrace-evidence-nolog, the no-client-log fatal CMake-wrapped across
  lines the way the real one arrives; control_smoke_test.sh expects it to PASS (23/23); the
  red-check still reds "red without the transport-resolution message"
2026-09-22 21:28:02 -04:00
swung0x48 4d54027f82 [tools] (P7): a split retrace with no server log is a fatal on every transport, checked after the marker and the ARMED sentence
- the spawn server-log fatal from the previous round sat BEFORE the marker check and the
  `spawn ARMED ... pid` check, so a launch or handshake failure - no server process, no ARMED
  line - reported "the run wrote no server log" instead of the more specific "resolved, but
  carries no spawn ARMED", and sent the reader to the wrong process. It now sits just before
  the census; the tcp arm's "no forwarded server log" check, which had the same placement,
  moves with it
- the inproc row demands the server log too. Under inproc every server-role line is routed
  by thread role to the `.server.log` sink, opened lazily on the first such line, and at the
  INFO level this lane demands ServerLoop writes one when mgl-srv-apply starts - so a clean
  inproc run always has the file, and "no file" read as "0 lines" was a green Fatal{ and
  MGWIRE-FLOOR census of the role that emits both. The two census reads are unconditional
  now: the fatal above them is what makes the file exist
- fail-closed demonstrations, OpenRA DirectVulkan, the replay wrapped to damage one log after
  a real run: inproc with the server log deleted went rc 0 on the previous runner (both
  censuses printed 0) and is now a fatal at the census; spawn with the server log deleted is
  the same fatal; spawn with the server log deleted AND the ARMED line removed reports the
  ARMED message, where the previous runner reported the server-log one; spawn with only the
  ARMED line removed reports the ARMED message. Undamaged, OpenRA DirectVulkan and DirectGLES
  SPLIT and SPAWN stay green, 0 unsound lines
2026-09-22 21:28:02 -04:00
swung0x48 b0d4d730ba [tools] (P7): the audit's block walk stops at a same-indent exit and steps over a column-0 #if
- a same-indent `case`/`default:`/`break;`/`return`/`continue;`/`goto`/`throw` line between a
  log and a bare Count ends the walk: control cannot flow from that log to the Count, so it
  is not the Count's log. A `case 1: MGLOG_W; break; case 2: Count` switch with its labels at
  statement indentation, and a log above a `return` with the Count under a same-indent label,
  both read as logged before
- `#if`/`#ifdef`/`#ifndef`/`#endif` lines are passed over: a log and its Count that straddle a
  `#if MOBILEGL_BUILD_DISAGGREGATED` are one block on both sides of the preprocessor, and the
  column-0 line ended the walk for no defect. `#else`/`#elif` still end it - a log on the other
  side of one is in a different build, not this one
- four fixtures: same-indent return (red), same-indent switch (red), log across a #else (red,
  and red on the previous audit too - it pins that #else still stops), Count under its log
  across #if/#endif (green; a false red before). 14/14 fixtures; the tree stays 53 / 53 / 0
2026-09-22 21:28:02 -04:00
swung0x48 576fc09a31 [tools] (P7): the audit's strip reads a prefixed character literal as a character, not as a digit separator
- L'"', u'"', U'"' and u8'"': the `'` after an identifier character was taken for a C++14
  digit separator, the `"` inside it opened a phantom string, and the rest of the line was
  blanked - a site on that line vanished and its row read as NO SITE (fail-closed: a false red)
- CHAR_PREFIX accepts a u8/u/U/L prefix before `'` the way RAW_PREFIX does before `"`, with
  a non-identifier character (or the start of the text) in front of it, so a real separator
  (0xAB'CD, 1'000) is untouched
- self-test fixture with L'"' and u8'"' ahead of two AT sites on their own lines: rc 0; it
  was rc 1 on the previous audit. The tree has no prefixed character literal today (53 / 53 / 0)
2026-09-22 21:28:01 -04:00
swung0x48 9d5f5012c7 [tools] (P7): a site's log is a statement that begins with MGLOG_W/E, not a line that mentions one
- the wire declines audit's LOGGED pattern was unanchored, so a guarded one-liner at the
  Count's indentation (`if (g) MGLOG_W("x");`, `g ? MGLOG_W("x") : (void)0;`) counted as
  the site's own log and the site read as logged - a decline counted every time but logged
  only sometimes, which is the unlogged site the check exists to refuse
- anchored to the statement start; the block walk matches the line, not searches it
- self-test fixture "guarded one-liner log at the Count's indentation" (both shapes) reds
  with the NO_LOG sentence; it was green on the previous audit. The tree stays 53 / 53 / 0
2026-09-22 21:28:01 -04:00
swung0x48 bc3ebe7442 [docs] (P7): ID-P7-39 - origin advances to 87584d0b, F lands with fixes, and the status page says what each package's fix round is closing 2026-09-22 21:27:16 -04:00
swung0x48 87584d0b01 [docs] (P7): ID-P7-38 - B2 round 2 and the B3 fix round land with fixes, F's gate is green, E1's census is on the tree
- the two ROADMAP row segments E1 changed that did not merge onto the integrator's rows
  are re-applied by hand (host census results, P9 exception list empty, wave 3 items done)
- the running table names the fable rounds B2 r3 and B3 fix r2 and the F review
2026-09-22 21:13:16 -04:00
swung0x48 99882304f6 [docs] (P7): E1's census pages cite the rewritten commits
- the census and §7.2 pages were written against 1135c664 before the trailer rewrite; the
  citations now name its rewrite 3c80cd62 and the other remapped commits
2026-09-22 21:11:19 -04:00
swung0x48 b05406b5d9 [docs, tools] (P7): CURRENT_STAGE_STATUS §5 and the ROADMAP P3b/P4b and P7 rows mark the §7.2 re-run and the Iris census done at 1135c664, with the P3b/P4b gate "every Iris trace" now pointing at host results and an empty P9 exception list 2026-09-22 21:11:19 -04:00