- 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
- 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
Rework round 2 of 4 after the D2 review (fable, ID-P7-8), which found that this gate's
numbers were right and its SUBJECT was wrong.
The scatter wrote 40 2x2 rects at x=((i*7)%32)*2, y=((i*5)%32)*2 into a 64-px atlas.
Both strides are surjective onto 0..31 over 40 iterations - rect 9 lands at x=62, rect 19
at y=62 - so the rects' union box covered the WHOLE LEVEL, and the server's subRectEligible
(Managers.cpp:8486-8491) requires !dirtyRegion.CoversWholeLevel, a BOUNDING-BOX test
(MipmapStorage.h:30-33). Both scatter textures were rect-INELIGIBLE on every arm before
:8649's unpack-ring policy was ever consulted. The box-versus-rect decision the scenario
exists to pin was never reached for the two textures it scatters into, and the only
texture that could move under any red-once was the contiguous control band - which is
exactly what the old substitute red-once's box=6 rect=3 jobs=12 was.
kScatterMargin insets the scatter by one rect: same 40 writes, same coarse stride, union
box bounded at (2,2)..(62,54). The gold row is UNCHANGED at emit=9 box=9 rect=0 jobs=9 on
all four arms - but it now means what it says.
THE RED-ONCE IS NOW ZERO-PATCH, which is stronger than the throwaway source edit it
replaces: MOBILEGL_ESPRYT_DISABLE_UNPACK_RING=1 alone gives box=3 rect=6 jobs=183 with
bytes/f[tex] falling from 104448 to 9024, while all 26 pixel cases stay green. BOTH
SCATTER TEXTURES moved - box=3 is the contiguous band alone, rect=6 is the plain atlas
AND the atlas written through the glTextureView, and jobs=183 = 3 + 6x30 confirms thirty
rects per scatter emission. The same knob was green before the inset, which is the
evidence that CoversWholeLevel was short-circuiting the decision.
The three prose sites are rewritten accordingly: the scenario's gold-table rationale, the
MEASUREMENTS.md 13.1 reading and the package note's red-once section now explain
attempts 1-3 as mutations of a decision the client already makes correctly, and attempt 4
by CoversWholeLevel rather than by the ring.
Also PipeStatsWindow gains LastFrom{Client,Server}LogSince, and the gate reads its two
role windows since a mark taken before the counted workload. The server writes an EMPTY
teardown window after the counted one, so "the last line in the file" is one shutdown
away from reporting four zeroes as the workload's shape. Moving to a marked read exposed
a second latent defect in the same assertion: ASSERT_TRUE(clientWindow.found) over the
whole file was satisfied by the "counters ON" BANNER in all three split arms, claiming a
window had been read when none had. The assertion is now on the window that actually
carries the tex[] bracket.
P3b/P4b R-11 / D-D4, landing under the P7 program (PLAN-PH-P34B-P7.md 1.2, wave 2-D
package D2). P4a recorded the emission shape rather than gating it because the
per-storage-owner cursor with view/owner remapping was the next phase's and gating an
unfinished shape pins a non-answer. That work landed, so the RecordProperty block is
now EXPECT_EQ against a gold row MEASURED on this cursor, and the workload carries a
third texture written through a glTextureView so the remap is inside the counted
window.
The gold row, identical on monolith / inproc / spawn / tcp:
emit=9 box=9 rect=0 jobs=9, client emitter 9
keyed on the workload constants by static_assert. P4a's emit=6 box=6 rect=0 jobs=6
was a two-texture workload with no client emitter and is not comparable.
The client half is read from MGPipeTextureEmitter::SubDataCount() rather than from
ctu=, and that is a correction: under spawn and tcp the two roles are two processes
whose PipeStats windows close on different Present cadences (measured ctu=13 against
emit=9, and usually not yet written when the case reads), so ctu == emit is not a
well-posed comparison there. The log field is kept as a record and asserted only
where the transport says the two are window-aligned - asking the NUMBER was the first
mistake, because the server publishes a readable ctu=0 under spawn and the comparison
silently became 0 == 9. PipeStatsWindow gains LastFromClientLog/LastFromServerLog.
Split/spawn/tcp arms added as explicit per-arm blocks rather than through
mgl_itest_register_split_arms: the macro hands every arm the shared environment, and
this case needs a lane marker, PipeStats period 1, a push mask and above all a
MOBILEGL_LOG_FILE_PATH private to the arm - the library opens the log "w", so two
entries sharing a path truncate each other and the failure looks exactly like "the
counter was never emitted".
Red-once (R-16): the prescribed flip of summedArea*4 >= unionArea*3 leaves the gate
GREEN, and that is a finding. Two gates downstream dominate it - the server needs
dirtyRectCount >= 2, and UnpackRingAvailable() zeroes the rect list by design ("one
box, one job", the existing Mali-cliff mitigation). So rect=0 is the policy's
intended output, not an accident of the scatter pattern. The red-once that bites
splits the union box in two AND disables the unpack ring: box=6 rect=3 jobs=12
against the gold, while 26 pixel cases stay green. Four attempts and their reasons
are in the note.
The Mali frame-time delta D-D4 asks for beside the gold is NOT schedulable - one
Redmi, an Adreno, no Mali part - and is recorded as a declared deviation in the
scenario header and MEASUREMENTS.md 13.3 rather than modelled.
Also corrects the three places that said the client emitter had not landed: the
scenario header, the CMake probe's comment, and gates-v1.md's re-run table.
TextureEmit.h's EmitOneLevel has been incrementing it.
The device gate: Redmi 2f7cbe2e, reboot-clean, paired A/B in one thermal
window (arms interleaved, best-of-3 then best-of-2), rd12 + DirectGLES.
inproc vs spawn client CPU p50 7.880/7.889 vs 7.876/7.869 (-0.15%) and
7.987/7.989 vs 7.992/8.009 (+0.16%) - a tie inside the 0.2-4.2% within-
arm spread, sign flipping with arm order, recorded and not gated.
monolith is ~30% dearer. 22/22 runner exits clean, 44/44 PINNED, zero
Fatal.
The three mandatory numbers: socket doorbell vs condvar is a tie too -
client 121.1 waits/frame identical across transports, server 10 866-11
963 (inproc) vs 10 415-10 416 (spawn) waits/frame, and the contract's
'converting that into ~4 blocking reads may be cheaper' did not pay off;
the only column where the socket is worse is clipark/f (6.07 vs 5.60/5.75).
SEG_STAGE bytes/frame: 130.8 KB median / 8.01 MB steady (OpenRA), 816.2
KB / 1.53 MB (rd12). Records/frame post-chunking: 211/206 and 7 497/7
504. maxrec stays 1808 - the 8 MiB chunk budget is never reached. Both
framings reported throughout (the startup window runs ~7x the steady
state) rather than the flattering one.
MEASUREMENTS.md gains section 12 with the full protocol and tables; the
6.3 'no post-chunking distribution exists' gap now points there.
CURRENT_STAGE_PROGRESS.md marks gates 7/8 met and records the closeout
work plus two structural limits (spawn client windowed fields are zero
by construction - OnPresent runs in the server process - though its run
totals are valid stores; the stats dump is role-derived). ROADMAP marks
P6 closed in the stage table, the header and the milestone.
Evidence: notes/p6/gate7-device-ab.md, gate8-doorbell-device.md,
gate8-wire-counters.md, git-worktree-fix.md. check_doc_citations: 82
citations in the three documents, 0 problems.
MEASUREMENTS 7.3 records what 82683d4a did, so the 30 s in that row stays as
written; a note under the table now says which value is live and where the
reason for the change is argued, so a reader looking up the barrier budget by
grep does not come away with the superseded number.
Every place that stated "P5 does not chunk" as current behaviour except the
Fatal texts (previous commit) now records the stage chunk budget and what it
does not cover.
- CONTRACT-P5.md section 5: the STAGE_MB row names MGPipeStageChunkBytes() =
clamp(segment/4, 4096, segment), the two buffer walks (1e7c372e) and one
texture level's whole-width slabs (9469d48e, assembled by
StagedTextureStore::AdoptRun), and the Fatal that stays the backstop for a row
with no cut; the RING_MB row says the record bound is about the record's own
bytes.
- BRIEF-P5.md's R-10 section is no longer headed "does not chunk": it keeps the
record bound and the maxrec proof obligation unchanged and records that
content is cut, with the encoder Fatal as the fallback.
- ROADMAP.md's staging debt row and open question 11, ARCHITECTURE.md's
record-bound bullet and SEG_STAGE table note, README.md's knob row,
MEASUREMENTS.md section 6.3 and CURRENT_STAGE_PROGRESS.md's open item: the
explicit MOBILEGL_IPC_STAGE_MB=256 profile is no longer needed for the two cut
paths, and the carrier design for the rest stays P8.
- Historical results (notes/**/p5-results/, p5b/) are left exactly as recorded.
Section 11's matrix ran at VD12, where BOTH monolith and run-ahead hit the 120 Hz panel
ceiling - so that section answers "can it reach the ceiling", not "which is faster". At render
distance 32 the load rises to ~3550 draws/frame (4.2x) and neither arm is near any cap (the
game's own enableVsync:false / maxFps:260, and the measured max is only 37-71). That is the
comparable round.
- Five runs per arm, interleaved, CPU clocks pinned (checked before AND after, both PINNED),
GPU held at pwrlevel 0, fan on; 75-150 s in-world settle before a 40 s window - VD32's chunk
streaming runs far longer than VD12's and reusing the 20 s settle would have counted loading
as steady state.
- monolith p50 median 58.5 (range 56.3-67.9), inproc run-ahead p50 median 59.9 (range
56.8-61.1), client CPU 16.19 vs 15.72 ms/frame. Level, run-ahead marginally ahead, and with
half monolith's spread.
- Against the lockstep it replaces: p50 +69%, client CPU -40%, apply CPU -43%. The heavier the
load the more it is worth, which is what the mechanism predicts: rendezvous count follows
draw count, ~900 per frame at VD12 and ~3600 at VD32.
- Both arms are client-thread saturated (~94%), so the client ms/frame column is each arm's
real bottleneck and the two are directly comparable.
New section 11.1 records an OPPORTUNITY rather than a defect: apply spends 11-12 ms against
the client's 15.7 ms, so the two sides are unbalanced and moving work from client to apply
lowers the bottleneck directly. Under lockstep that was meaningless (the two sides add
serially); run-ahead is what turns it into a lever. Left to a later phase.
options.txt restored from .p5e-backup to renderDistance:12; the device is unpinned, fan off,
GPU back to governed.
- CURRENT_STAGE_PROGRESS.md gains section 2.6: the four packages (pa / mv / gl / ra2), the
admission rule's three disjuncts and which real entry forced each one, coverage going from
116 to 179 entries plus 1357, the race the flip exposed and its root cause, and the finding
that a hard-green strict lane is necessary and NOT sufficient (ID-132). Code head is now
25fba0d5.
- MEASUREMENTS.md gains section 11: the device matrix. The section leads with clock pinning
because the first matrix was run without it and had to be thrown away - monolith's OWN arm
moved 4.43 -> 7.07 ms/frame between two runs, and the SLOWER run was the COOLER one: the
governor had dropped policy0 from 2745 to 748 MHz. It records pin_redmi.sh's write order and
read-back verification, and why pin_device.sh refusing to guess this machine's serial is
correct rather than a gap. Conclusion: at both pinned tiers monolith and run-ahead each hit
the 120 Hz panel ceiling and only lockstep cannot reach it.
- ROADMAP.md's P5e row and status line now say twelve packages landed, run-ahead armed.
The phase is NOT closed: which arm is faster ABOVE the panel ceiling is unanswered (this
device cannot hold a higher clock), and BRIEF-P5E section 3's three negative controls and
section 5's per-package red-once reruns have been reordered by ID-121 to after the lane goes
green, so they have not been executed yet.
- P5D-INPROC-PERFORMANCE.md: the round-2 diagnosis is corrected against the
symbolized call graph (the apply thread's mutex time was the idle poll, not
the backend pendingMutex), the four round-3 packages and the two race fixes are
described, the numbers table carries the two device caveats (monolith is
120 Hz vsync-capped in most runs; the kernel ignores thread affinity, so the
client thread runs on a mid core), and the lockstep-feasibility research says
why the deferred draw barrier waits for P3b/P4b and P11.
- MEASUREMENTS.md section 9: the per-arm table with per-thread CPU ms/frame as
the primary metric, the interleaved session and the wait/park counters.
- ROADMAP.md: the P5d row is the three-round shape; P11 gains the gPipeInputs
versioning item the research points at.
- CURRENT_STAGE_PROGRESS.md, README.md, ARCHITECTURE.md (env table: the
generate_mipmap exception to batched waits, the calibrated spin, the affinity
readback): head 1f8de61b, the gate numbers and ruling ID-79.
ROADMAP marks P5c closed at the triage head and P6 next; CURRENT_STAGE_PROGRESS carries
the current-head gate table (unit 2187/2187, integration-split 111/111, the census
classification with every newly-red entry evidenced by its Fatal name, the three named G1
resizes, the 0xDD audit, the per-frame rsp measurements, and the two items deliberately
not done locally: the Redmi retest and the 79-trace census); MEASUREMENTS gains section 8
with the per-gate evidence. CONTRACT-P5C takes the amendments ratified at gt's landing
and at the regression triage: per-level extent is retired at the sites rather than
guarded on the accessor, the strict CI lane is two-sided (unit green gate plus
expected-red scenario lane with the marker asserted), the drain points are two classes
(the EGL RPC returns beside EmitAndWait), and oversized writebacks are client-sliced at a
quarter of the event ring.
- README status, the ROADMAP P1 row with the measured site and accessor counts, and the
ARCHITECTURE correction from 293 to the 277 arrow sites the tree actually has
- MEASUREMENTS gains the P1 scale table, the two classes of finding the verify lane
produced (nine missing fill rows, three fields a backend moves inside its own verb) with
the push-on-mutation decision and its three hooks, and the acceptance numbers
- the sentence read as if 836 of the 92 immediate calls were RecordError; 836 is RecordError's share of all 926 calls, and most of the 92 immediate ones are RecordError
- README.md: what MGPipe is, the one-paragraph architecture, the P0 status line, the file and code map, and the commit range where the design competition and the three adversarial review rounds live
- ARCHITECTURE.md: the design as decided, one reason per decision - handles and generations, the 71-call catalogue by class with flags and cap bits, record and payload conventions, the tracker, texture subdata and dirty ownership, shader state and the P0.5 header extraction, the reverse channel, the backend strangler, the server side and the index host mirror, the transport as landed in MG_Remote, the persistent-map tiers as measured, roundtrips, present and threads, process and platform delivery, build shapes and purity gates, the five-part verification gate, and the knob tables marked landed versus planned
- ROADMAP.md: P0..P13 as one table of what lands, the gate and the dependency, the two tracks and milestones, the day-43 GO/NO-GO checklist with both exits, the re-baseline checkpoints, and the questions still open after P0
- MEASUREMENTS.md: spike A on both devices, the spike B tier matrix, the four-trace boundary-counter baselines on both backends, the desktop and corpus facts, and the harness traps with the exact commands
- every file:line kept is verified at 458ccde1 and the citation lint is clean; everything else cites a symbol plus a file
- dropped on purpose: the v1/v2 revision archaeology, rejected alternatives, per-subsystem day estimates, the Feat/CS-Delta-IPC reuse audit and the reviewer back-and-forth