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.
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).
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.
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.
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.
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.
- §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.
- 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.
- 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.
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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)
- 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
- 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
- §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
- 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)
- 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"
- 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
- 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
- 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)
- 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
- 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
- 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
- the trailer rewrite the user asked for is recorded (origin 1135c664 -> 3c80cd62, same trees)
- CONTRACT-P7 §12 transcribes the debt lines from magma-b2.md §6, magma-b3.md §7.2,
verify-split.md §6 and ph-f.md §4
- the status page's gate table, landed table, running table and next steps follow
- 144 commits from 785fed0b0 onward were rewritten to drop the Co-Authored-By trailer the
project forbids; origin/feat/disaggregated moved from 1135c664 to 3c80cd62 (same trees)
- the old->new map is ~/w7/logs/sha-map-20260922.txt; every 7..40-hex citation in the
Disaggregated docs and the MG_Remote contracts that matched an old SHA is replaced by the
same-length prefix of its rewrite; no other content changes
The fix round's commits changed what §1.5 says the audit checks and what
§4.1 says the runner reads, so the note is brought up to the tree:
- §0: rows 11-19 for the fix round.
- §1.5: the three holes (a site in a comment or string, the branch-blind
8-line window, a .def row with a trailing comment), what the audit does
now, and the eight --self-test fixtures run first in the CI step.
- §4.1: the spawn server-log fail-closed and its demonstration (runner at
aab01275 rc 0 on a run whose server log was removed; this runner rc 1,
the CMake Error quoted). inproc also writes mobilegl.server.log and is
still read if(EXISTS); only spawn was tightened, as the review asked.
- §5: the fix round's gate on package tree 88d1a913, pre-merge: split
build rc 0; G1 rc 0 .text 0xa52203 nm 0/0; census 79; audit self-test
8/8, tree 53/53/0; ratchet unchanged at 186; parity rc 0; unit
2420/2420, integration-magma-split 90/90, integration-magma-spawn 69/69;
OpenRA DirectVulkan SPLIT / SPAWN ssim 1.000000, 0 px, 0 MGWIRE-FLOOR.
Fable review of the B3 rework, note for CONTRACT-P7 §12. On the
disaggregated build VulkanRenderer::WaitForFrameSerial waits the FIRST
in-flight record with frameSerial >= serial, calls OnSubmitsCompletedUpTo
and returns true. With the §3.1 clamp, a later record carrying the same
serial (S2, the Present submission - the two-submissions-per-serial shape
of §2.2) keeps the floor below `serial`, so the function returns true
while IsFrameSerialComplete(serial) is false. The only caller,
WaitForTimerQueryResult, re-checks IsTimerQueryResultReady, so today it
degrades to a spurious timeout, not a wrong read.
The fix belongs to B4 and is not made here: after OnSubmitsCompletedUpTo,
return only if IsFrameSerialComplete(serial), else restart the scan (the
call erases from the vector being iterated, so restart, never continue).
Fable review of the B3 rework, nit: §7.2 cited the comment as
VulkanRenderer.cpp:13400-13403, which is the package tree's line; on the
landed tree pipe@6207c9c9 it is 13530-13533. The bullet now names the
comment by where it sits (above the fence-wait loop in
VulkanRenderer::WaitForFrameSerial) and gives both lines, the function name
being the reference.
Fable review of the B3 rework, should-fix: §5's table and prose (unit 2420,
integration-split 226, magma 90/69/70, full 527, ratchet 186) were read on
the package tree before the merge, but read as if they described what
landed; and the quoted parity output ("1 entry not registered on the tcp
arm by name") is the package script's, which did not land.
- The initial gate is labelled package tree 0d425499, pre-merge; the
review-round gate package tree 774bc17f, pre-merge.
- A landed-tree column/paragraph from the integrator's gate on
pipe@6207c9c9: unit 2429 / integration-split 304 /
integration-magma-{split,spawn,tcp} 96/75/71 / full 535; G1 rc 0 .text
0xa52203 nm 0/0; census 79; ratchet 173; parity rc 0; audit 53 rows 53
sited 0 unlogged; OpenRA DirectVulkan inproc + spawn retrace ssim
1.000000, 0 px, 0 unsound-serial-complete lines. The landed lane counts
include other packages' entries.
- The parity quote is replaced by the landed wording ("N server-env-knob
entrie(s) excluded from the TCP comparison only"), and §4.2 / §5 name
the landed list MAGMA_SERVER_ENV_KNOB_NO_TCP (compare_arms(no_tcp=),
CMake mglItestServerEnvKnobArm), into which the integrator folded
MAGMA_NOT_OVER_TCP.
Fable review of the B3 rework, nit: MGL_WIRE_DECLINE_AT logged "Magma wire
draw declined [Site]" from every site, but the Tex*, Shape* and Upload*
rows are reached through SyncTextureResourceByHandle, whose callers are not
only the draw/dispatch texture preparation: the descriptor resolver,
framebuffer attachments, CopyTexSubImage, mipmap generation and
CopyImageSubData each Fatal right after a failed sync, and texture
readback falls back to the unbacked shadow. Those counters are per sync,
not per draw - a draw sampling three unsyncable textures counts three, a
failed attachment sync counts once and is then a Fatal.
- WireDeclineTally.h: the line is "Magma wire decline [Site]: ...", and
the macro's comment says the texture rows are per sync and names the
callers. Disaggregated-only header; no test or script matches the old
text (git grep).
- magma-b3.md §1.5: says the counters are per sync and that the log lines
quoted in §1.3 / §1.5 carry the old wording.
Fable review of the B3 rework, nit: the comment over the ShapeImageFlags-
Unsupported site called it "the one Shape* exit that left no line on the
builds that ship". At 0d425499 SyncWireTextureShape had five such exits:
ViewOf (bare return false), NoLevels (bare return false), preserve-flush
(bare return false), image flags (MGLOG_D, compiled away in Release) and
preserve-copy (bare return false). The comment now names all five.
Comment-only, inside the disaggregated-only SyncWireTextureShape; pull
build unaffected.
Fable review of the B3 rework, should-fix: run_trace_case.cmake read the
server log only `if(EXISTS ...)`. Under spawn the server process writes its
own file, and the lines the runner counts out of it - the applier Fatal{
lines and the MGWIRE-FLOOR unsound-serial-complete line, which only the
server's VulkanRenderer::OnSubmitsCompletedUpTo emits - are nowhere else,
so a server that died before its first line read as "0 lines" and went
green. The client log was already fail-closed, and so was the tcp arm's
forwarded server log; plain spawn was not.
The plain-spawn branch of the transport block now FATALs when
mobilegl.server.log does not exist, beside the tcp arm's identical check.
Demonstration: the SPAWN ctest command line with TRACE_REPLAY_EXE replaced
by a wrapper that runs the real replay and then deletes
output/mobilegl.server.log (541 lines):
runner at aab01275 -> rc 0, "Fatal{ lines across ... : 0",
"MGWIRE-FLOOR unsound-serial-complete lines: 0" (green, half unseen)
this runner -> rc 1:
CMake Error at run_trace_case.cmake:321 (message):
OpenRA DirectVulkan: MOBILEGL_TRANSPORT=spawn but the run wrote no
.../output/mobilegl.server.log, so the server role's Fatal{ and
MGWIRE-FLOOR lines cannot be counted. A spawn retrace with no
server log cannot be counted as a clean one.
MobileGLTraceReplay.OpenRA.DirectVulkan.SPLIT / .SPAWN unmodified: both
pass, ssim 1.000000, 0 px, 0 MGWIRE-FLOOR lines.
Fable review of the B3 rework, should-fix: the audit had no negative
control, so a green run could not say it would have been red. It now takes
--self-test, which writes each inline fixture as a one-file renderer tree in
a temp dir, runs the audit on it and checks both the rc and the line the
audit must print (so a red is red for the fixture's reason):
comment-only site (//) -> rc 1, "has NO SITE"
comment-only site (/* */) -> rc 1, "has NO SITE"
string-literal site -> rc 1, "has NO SITE"
other-branch log -> rc 1, "with no MGLOG_W/E in its own block"
nested-branch log -> rc 1, same
log only in a /* */ comment above -> rc 1, same
nearest log is MGLOG_D -> rc 1, same
good sites (AT form, bare Count under
its own MGLOG_E_ONCE, def row with a
trailing comment) -> rc 0, "0 unlogged, 0 unknown"
8/8, rc 0. Mutants: with the strip disabled 5 of 8 fail (the four
comment/string reds go green and the good fixture's commented row is
lost); with the old 8-line window in place of the block walk 2 of 8 fail
(other-branch, nested-branch). Against the audit as it stood at aab01275,
six of the seven red fixtures passed and the good one failed.
.github/workflows/test.yml: the "Wire declines audit (B3)" step runs
--self-test and then the tree audit, the way the next step runs
trace_cases.py --self-test-transport-matrices before it computes matrices.
Fable review of the B3 rework, should-fix: the 8-lines-above MGLOG_W/E window
was branch-blind - a Count() in `if (x == 2) { ... }` whose only log sat in a
preceding `if (x == 1) { ... }` passed, as did a log in a nested branch just
above. All 12 bare sites in the tree are under their own line today, so this
was a gate hole, not a present defect.
has_own_log() walks upwards from the Count line (still capped at 8 lines):
blank and deeper-indented lines (a log's continuation lines, a nested block)
are passed over, only a line at the Count's own indentation can be its log,
and the first line indented less than the Count - the block's opening, a
sibling's `} else {` - ends the walk.
WireDeclines.def is now read through the same comment/string strip, and ROW
tolerates spaces inside the parentheses: `MGL_WIRE_DECLINE(Name) // note`
used to fail `\)\s*$`, dropping the row, and its real site was then
reported as naming no row.
Tree: 53 rows, 53 with sites, 53 sites, 0 unlogged, rc 0 (unchanged).
Fixtures the previous commit passed and this one reds: other-branch log,
nested-branch log (rc 0 -> 1); a def row with a trailing comment plus its
site (rc 1 -> 0).
Fable review of the B3 rework, must-fix: a row was "sited" by any line the
AT_SITE / COUNT_SITE regex matched, including a // comment, a /* */ block or
a string literal - `// MGL_WIRE_DECLINE_AT(GhostRow, "...");` satisfied the
audit for a row nothing counts, and an MGLOG_W inside a comment above a bare
Count() satisfied the log rule.
wire_declines_audit.py now blanks //...$ (with backslash-newline
continuation), /* ... */, "..." and '...' (raw strings R"d(...)d" and
C++14 digit separators handled) out of each source before any match. Every
character but the newline becomes a space, so the text keeps its length and
line count and each report still cites the real line.
Tree: 53 rows, 53 with sites, 53 sites, 0 unlogged, rc 0 (unchanged).
Fixtures that the previous audit passed and this one reds (rc 1): a
comment-only site (//), a comment-only site (/* */), a string-literal site,
a log only in a /* */ comment above a bare Count. The branch-blind window
and the .def trailing-comment row are the next commit.
- §2.9 (new): the lane-marker/backend skips and their verified Skipped lines, the 4-byte row stride and its validation-layer red-once, the whole-call shape decision (the round-1 partial effect: a scaled or X-mirrored COLOR|DEPTH blit wrote its colour and then errored on its depth) with its red-once, the split once-sites, the empty-side decline, MsFlip1 and the exact-one parity tail check, each red-once as run.
- §2.6: MsFlip goes red on a device whose renderbuffer and texture D24S8 map to different VkFormats (cross-format Y decline); §5 item 2 says to check it on the Redmi.
- §2.8: the round-1 bufferRowLength=0 note and the per-aspect decline are marked superseded by §2.9.
- §6: item 1 cites VulkanRenderer.cpp:10066 (the vkCmdBlitImage; :10060 is the vkCmdResolveImage) and states the scale partial effect as closed; item 5 states the X/cross-format-Y partial effect as closed and that its INVALID_OPERATION is a rule I (a) refusal of a legal blit; item 4 counts six knob entries; new item 6 (monolith DirectVulkan flipped/scaled multisample depth blit, VulkanRenderer.cpp:9594/:9608, a wire-vs-monolith divergence where the wire arm is the correct one, P13/G1-bound) and item 7 (Espryt flipped/scaled multisample depth resolve, P3b/P4b); stale WireFramebuffer.inc line numbers refreshed.
- §7 is two labelled rows: this tree (p7/magma-b2@4442ea6d, measured) and the landed tree (pipe@3b66d1b1, integrator-measured), instead of numbers pinned to 5d896170, which is not an ancestor of the landed tree.