- ADrawAfterTheEarlyReclaimFollowsTheNewStoreNotTheMemoizedHandle rides the same split/spawn
fixture as the three gauge cases and the tcp arm does not carry it (magma-m2.md §9.3); the
integration tree keys this list by exact tail, so the fourth name goes in beside the three
- 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
- 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
- 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)
- 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
- 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
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.
- 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"
- 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
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.
- BlitWireFramebuffers runs colour first. A scaled COLOR|DEPTH blit out of a multisample framebuffer scaled and wrote its colour and then recorded INVALID_OPERATION on its depth, and an X-mirrored one mirrored its colour and left its depth alone - partial effects GL 18.3.1 does not allow. The shape decline (scale, X mirror, cross-format Y mirror) moves into DeclineWireDepthStencilResolveShape, which BlitWireFramebuffers asks for every depth/stencil aspect that would take the multisample resolve arm before any aspect runs; ResolveWireDepthStencil asks it too for any other caller. Default read/draw framebuffers are left to the lambda (a default read is never multisampled; a default draw behind one is the region Fatal, and resolving it early would move its write index).
- The X decline and the cross-format Y decline get their own MGLOG_E_ONCE sites; one site used to cover both, so after the first X decline a cross-format Y decline logged nothing.
- An empty rectangle on one side only (64x48 onto 0x48) is a size mismatch and now takes the scale decline (INVALID_OPERATION) instead of returning silently; empty on both sides stays a silent no-op.
- DirectVulkan.{Split,Spawn}.MsFlip1. forces MGITEST_MAGMA_FORCE_SHADER_DEPTH_RESOLVE=1, so the shader arm min-corner rectangle under a flip runs on this host; split+spawn only and named in MAGMA_SERVER_ENV_KNOB_NO_TCP.
- spawn_lane_parity.py: every server-env-knob tail must match exactly one split key, so a dead or over-broad tail fails the gate instead of riding silently.
- The flipped-resolve case gains a COLOR|DEPTH scale leg (error, colour untouched, depth untouched) and an empty-destination leg (error, depth untouched).
- Red-once, each on split + spawn (+ tcp MsFlip.) and restored: pre-pass disabled -> all five MsFlip/MsFlip1 entries fail "the declined COLOR|DEPTH scale must not have written its colour either" (read {255,0,0,255}, want {0,0,255,255}); round-1 silent empty-side return -> all five fail the empty-destination leg (error 0, want 1282); shader arm handed sx0/sy0 instead of the min corner -> MsFlip1 fails on both arms ("768 of 768 depth values differ from 0.75", "928 of 3072 stencil values are wrong; first at (20, 4): got 255, want 99") while MsFlip. stays green; a dead ".MsFlip2." tail -> parity rc 1 "matches 0 split entrie(s)".
- The split once-sites have no lane red-once: the cross-format Y decline needs a device whose renderbuffer and texture D24S8 map to different VkFormats, which lavapipe is not.
The B3 rework's parity hunk and B2's round-1 hunk described the same asymmetry
under two names; the merge kept B2's compare_arms(no_tcp=) and added .StaleSerial.
to MAGMA_SERVER_ENV_KNOB_NO_TCP. One line of the package tree's other mechanism
(`not_on_arm = not_on_arm or {}`) survived outside the conflict hunks and would
have been a NameError on the first run; it goes, and the note's two mentions of
MAGMA_NOT_OVER_TCP now name the list that exists.
MGITEST_MAGMA_FORCE_STALE_BUFFER_SERIAL is read by the server. The tcp
arm's server is the lane fixture (scripts/ci/tcp_server_fixture.py),
started once from its own environment, so an entry-level ENVIRONMENT never
reaches it: DirectVulkan.Tcp.StaleSerial.* ran the unforced case under a
name that claimed the knob and could never red (review ID-P7-34, item 1).
The entry is now registered only when the arm is Split or Spawn, and
spawn_lane_parity.py grows a second named asymmetry beside
MAGMA_INPROC_ONLY: MAGMA_NOT_OVER_TCP, key prefixes the reference arm has
and the tcp arm does not by name. It comes off the reference for the tcp
arm alone, so the same entry missing from spawn is still an error. B2 adds
its own knob entries to the same tuple in its tree.
integration-magma-tcp 71 -> 70 entries (68 cases + the two fixture
entries); split 90, spawn 69 unchanged. spawn_lane_parity.py build-split
rc 0; tcp_lane_tools_test.py 6/6.
Integrator merge onto pipe: B2's round-1 mechanism (`mglItestServerEnvKnobArm` in
CMake, `compare_arms(no_tcp=)` in the parity script) already covers this shape, so
`.StaleSerial.` joins MAGMA_SERVER_ENV_KNOB_NO_TCP instead of the separate
MAGMA_NOT_OVER_TCP the package tree introduced.
The B3 review (ID-P7-34) counted 12 of the 52 rows with no site at all -
TexViewFormat, TexNoApplierRecord, TexRecordDeadOrStale and the nine Shape*
rows were declared and never counted - and ten sites that counted with no (MGLOG_D included)
line, so "a name, a tally and a decline line" did not describe the tree.
- SyncWireTextureShape: all nine Shape* exits now count; the ViewOf exit
and the preserve-flush exit were bare `return false` and are now
MGL_WIRE_DECLINE_AT; the image-flags exit logged only MGLOG_D, which a
Release build compiles away, and is promoted likewise.
- The preserve-copy exit was the one Shape exit with no row: appended as
ShapePreserveCopyFailed (rows are append-only), 53 rows.
- SyncTextureResourceByHandle / UploadPendingWireLevels: the count-only
sites without a log of their own are promoted to MGL_WIRE_DECLINE_AT;
the ones already under a W/E _ONCE line keep that line and gain the count.
- scripts/ci/wire_declines_audit.py: fails on a row with no site, a site
naming no row, or a bare Count() with no MGLOG_W/E within 8 lines above
it. WireDeclineTally.h (the macro's definition) is not a site. Wired into
the job that runs the fatal census.
Audit before: 52 rows, 40 with sites, 10 unlogged under the W/E rule (rc 1). After: 53 rows,
53 with sites, 0 unlogged (rc 0). Forced red (ShapeNoVkFormat made true for
1x1 textures, reverted): Split.Fm.F1WireScenario.VertexIdSampler... fails on
pixels with ShapeNoVkFormat=2 / TexShapeSync=2 in the shutdown tally.