Files
MobileGL/docs/ci/ci-cleanup-log.md
T

37 KiB

CI cleanup log

Every removal or replacement of a CI test, gate or lane is logged here with a one-line reason; decisions to keep a red case (and fix the code or the tooling instead) are logged too, so the next reader can see why a check still exists. Started in P13 (2026-10-06). The rule: a check is removed only when it is superseded or no longer relevant (tied to the pull build, or a finished migration-phase audit), never to hide a real bug. Goldens change only when the GL spec proves them wrong.

Removals

Date Check Workflow / job Reason Successor
2026-10-06 unit BufferTest.{ANonPersistentWriteMapOfAShadowBackedStoreStillFlushesThroughTheBackend, RespecifyingAShadowBackedStoreWhileItIsMappedPushesNoRangeDown} Test / unit P13 W6: they pinned the monolith frontend arm (ScopedMonolithFrontendArm) to assert how a shadow-backed map reaches the backend's own flush op - the arm is deleted; the record arm pushes the mapped span itself SplitBufferTest (persistent-map push, live-host-writes), PersistentCoherentMapScenario and the buffer integration lanes on monolith's record arm
2026-10-06 unit TextureTest.{ShadowReadbackRefusesALayoutItCannotProduceInsteadOfOverrunningTheBuffer, ShadowReadbackRefusesAPackStateItCannotHonour} Test / unit P13 W6: they pinned the frontend arm's CPU-shadow readback, whose pack-state limits they asserted; that path is deleted - the record arm reads the backend's image under a neutral pack and scatters every pack state itself PixelStoreSweepScenario, PackBufferReadbackScenario (every pack state, both backends, every arm)
2026-10-06 unit TextureTest.GetTexImageOfOneCubeFacePacksIntoAOneFacePixelPackBuffer, TextureViewTest.CubeMapViewOfAnArrayReadsTheFaceEachTokenNames Test / unit P13 W6: GL rules, but asserted through the deleted frontend arm's shadow readback; a unit process has no backend image to read moved, not dropped: CubeFaceReadbackScenario (integration-gpu on both backends plus the split arms) asserts the same two rules on a real context
2026-10-06 DirectVulkan.HandleRecycle.AbaControlHandles.* Test / integration-gpu (integration-monolith-control) P13 W6: it pinned MOBILEGL_PIPE_DATA_ARM=frontend - its knob defeats the identity half of Magma's frontend-arm keys, which the deleted arm owned; the record arm keys every object on the applier's {slot, gen} DirectVulkan.HandleRecycle.Handles.* (the same cases on the record arm)
2026-10-06 build explicit pull runtime control (the pull libMobileGL.so, -DMOBILEGL_PIPE_PUSH=OFF) Test / build-linux-monolith-control P13 W2 retires the pull build: CMake defaults to push and nothing ships pull (ID-P13-1) the same job builds the push monolith without MG_Remote (the FCL shape); its runtime_mode_proof --mode monolith is the zero-MG_Remote-symbol check
2026-10-06 Negative control (pull library) Test / retrace-split (every leg) its library was the pull build above Negative control (library without a transport): same script (renamed retrace_transport_control.sh) and evidence sentence, with the push library without MG_Remote; W1 ran both side by side on every leg
2026-10-06 DirectGLES.HandleRecycle.Legacy.*, DirectVulkan.HandleRecycle.Legacy.*, DirectVulkan.HandleRecycle.AbaControl.* Test / integration-gpu (integration-monolith-control) they ran MOBILEGL_PIPE_PUSH=0, the pre-handle arm, which P13 W3b removed with MOBILEGL_PIPE_LEGACY_MEMOS (ID-P13-3) HandleRecycle.Handles.* and DirectVulkan.HandleRecycle.AbaControlHandles.* (the ABA control against the handle arm that ships) stay
2026-10-06 DirectGLES.ResourceSubsystemControl.Off.*, DirectGLES.ResourceSubsystemOff.*, DirectGLES.ObjectSubsystemControl.{Off,Refused,RefusedTexture}.* Test / integration-gpu they cleared subsystem bits (masks 0x7f / 0x1ff / 0x9ff / 0x5ff) to run legacy arms; since W3b bits 0-13 are fixed on (ID-P13-3) one named-refusal control per lane, DirectGLES.SubsystemMaskRefusal.<Lane>: the same scenario and mask must go red with Fatal{PipeSubsystemsFixedOn} naming that mask (Harness/RefusedMaskControl.cmake); the On lanes now run 0x3fff
2026-10-06 SanityTest: DirectGLESSlotTable.{AnArmlessKnobCombinationStopsInsteadOfSkippingTheLane, TheArmlessCasesLeaveTheLogPathAndTheConfigAsTheyFoundThem, EglBringUpUnderTheArmlessKnobPairReturnsInsteadOfStopping} Test / unit they pinned the MOBILEGL_PIPE_LEGACY_MEMOS=0 + cleared-bit knob pair; the knob is gone and the mask is refused at startup the SubsystemMaskRefusal controls above
2026-10-06 SanityTest: DirectGLESTextureSync.AnAttachmentOnlyTexturesParametersReachTheDriverWithNoSamplerView Test / unit not a behaviour gap. At 0x3fff the parameter push is record-addressed (SyncTextureParamsToBackend reads the texture's applier record; nothing in it consults a sampler view), but the unit lane cannot create that record (NoP4aConsumer, as above), so the probe's handle half never had a record to read; its legacy half pinned the pre-handle push that W3b removed TextureParamsWithoutASamplerViewScenario (G9): its four cases take a WHITE-BOX reading of the driver-side parameters before any sample (TakeTheWhiteBoxReadingBeforeAnySample, ID-19), at the shipping mask on every lane - the same property, observed where records exist
2026-10-06 unit RenderStateSpans.{ResidualTripWireIsSilentUntilTheApplierOwnsTheBytes, ResidualTripWireHoldsAcrossAVerbClassThatDoesNotPublishTheBlock, ResidualTripWireFiresNamingTheCapability} and PeerLatchTest's SetResidualValueStateBlobSize row Test / unit P13 W3c deleted ResidualValueBlock and its applier trip wire (op 46 is a retired, declined row) integration-verify's new Negative control A2 (corrupted capability): the verify comparator must go red on a corrupted IsCapabilityEnabled; PipeWireCodecTest.ResidualValueBlockCrossesAsItsOwnBlob now pins that op 46 is declined; TrackerTest...AClipDistanceEnableReArmsTheResidualBlock now asserts the capability reaches the applier's block
2026-10-06 unit DirectGLESBufferDrawProbe.ALiveHostMapKeepsTheHandleArmProbeDirtyBetweenTwoDraws Test / unit P13 W6: it pinned the frontend arm's draw-time SyncPersistentMappedRange keeping a live host map's probe dirty; that per-draw hook is deleted - the record arm publishes a live map's span at push time (PersistentMapTracker) PersistentCoherentMapScenario and SplitBufferTest's persistent-map push / live-host-writes cases, on every arm
2026-10-06 unit DirectGLESSanity.{BindsAMultisampleTextureDespiteTheDefaultMipmapFilter, BindingZeroClearsPreviousNativeTextureBinding} Test / unit P13 W6: GL 4.6 8.17 / 8.17.1 rules, but asserted through the deleted frontend arm's unit walk (BindCurrentTextures over frontend binding slots); every library walks the units by handle now moved, not dropped: TextureUnitSamplingScenario (integration-gpu on both backends plus the split arms) asserts both rules on a real context
2026-10-06 unit DirectGLESTextureSync.UnitMemoRefusesToDriveATwinFromAnotherTexture Test / unit P13 W6: the borrowed-slot work list and its PairingsIntact check it pinned are deleted with the frontend arm (the 'Kept after investigation' entry below said it goes when monolith moves to the by-handle unit walk, which W6 did) DsaUpdateKeepsTheBoundUnitScenario (GL 4.6 8.1/8.5 semantics, every lane)
2026-10-06 unit GeneralBufferTest.{General_PersistentCoherentZeroCopyStressNoPerDrawReupload, General_PersistentCoherentFallbackSyncsPerDrawWhenBackendDeclines} Test / unit P13 W6: both drove the frontend arm's draw-time SyncPersistentMappedRange against a mock backend (zero-copy acquire vs the declined CPU-shadow fallback); the hook and the frontend's backend-acquired map are deleted - the record arm owns the map and pushes the span itself PersistentCoherentMapScenario, SplitBufferTest persistent-map cases; per-draw cost is tracked by the device fps/CPU numbers (DEBTS ID-P13-2)
2026-10-06 unit SubsystemDepsTest.{TheServerConsumerGateNeverArmsAFamilyTheTableRefuses, TheTwoDocumentedRefusalLanesStillRefuseAndTheFullMaskStillArms} Test / unit P13 W6: they swept the per-family resolvers over refused masks, which worked because a refused family returned false and ran the legacy arm; with one data arm a refused family stops (StopOnTransportWithoutRecordArm) on every library, and ConfigLoader already refuses those masks at startup DirectGLES.SubsystemMaskRefusal.<Lane> named-refusal controls; SubsystemDepsTest's table cases stay
2026-10-06 unit SplitBufferSet.TheWholeSetIsInertOnTheMonolithPath Test / unit P13 W6: it pinned that monolith ran none of the split buffer set - monolith runs the record arm now, so the set is live there by design the rest of SplitBufferSet (now exercised on monolith's record arm too)
2026-10-06 unit ContextEpochTest.RawDepthSamplerTakesADifferentObjectOnEachArmAndTheServerNeverTakesTheLegacyOne Test / unit P13 W6: it asserted the two raw-depth sampler arms were distinct objects; the monolith (legacy) arm is deleted, as its own comment filed for P13 ContextEpochTest.RawDepthSamplerOwnsANativeIdForEachContextGeneration (the one arm)
2026-10-06 unit MagmaPipeIdentityTest.{AnIdleSlotIsRetiredAndReusedWithANewGeneration, AReusedSlotDoesNotServeItsPredecessorsMemo, TheAbaControlKnobServesTheStaleMemoAcrossAReusedSlot, ALiveObjectKeepsItsSlotItsGenerationAndItsMemo} Test / unit P13 W6c: they drove MagmaPipeIdentityTables, Magma's {slot, gen} mint for the frontend arm's VAO draw memos, and its ABA-control claim rule; the mint, the memos and the MOBILEGL_PIPE_HANDLE_ABA_CONTROL knob (no consumer left) went with the frontend arm - the record arm keys every object on the applier's own handles HandleRecycleScenario's Handles arm (both backends) and the applier's slot/generation tests (SlotAllocatorTest)
2026-10-06 unit DirectVulkanSanity.MutableStorageImageViewsUseVulkanCompatibilityClasses Test / unit P13 W6c: it pinned VkTextureManager::AreStorageImageViewFormatsCompatible, which only the frontend arm's storage-image path called; that path and the helper are deleted the wire storage-image path's format checks (InvalidImageUnitScenario, ImageFormatQualifierScenario)
2026-10-06 unit VkClearManagerTest.{CollectGarbageRemovesExpiredTexturesAndTheirPendingClears, StalePendingClearsAreRejectedBeforePeriodicGarbageCollection} Test / unit P13 W6e: they drove Magma's frontend pending-clear queue, keyed on frontend texture objects and only fed by the frontend ClearNamedFramebuffer* / render-pass entries, which the verb port replaces in every mode; the queue and the entries are deleted the record arm's clears (ClearThenReadPixelsScenario, MonolithAttachmentClearScenario, LayeredAttachmentShapeScenario, both backends, every arm)
2026-10-06 unit FramebufferTest.WidenedDrawBufferIsIdentifiedPerDrawBufferSlotNotPerAttachmentPoint Test / unit P13 W6e: it pinned Espryt's ComputeAlphaWidenedDrawBufferMask over a frontend FramebufferObject; the record arm computes the same mask from the framebuffer record (IsAlphaWidenedColorSurface) and the frontend form had no caller ThreeChannelAttachmentScenario (widened RGB attachments end to end, both backends)
2026-10-06 unit DirectGLESSlotTable.{ANegativeLookupIsNotCachedAcrossAnotherHoldersAcquire, GetOrCreateToleratesANullStateObject} Test / unit P13 (# P13 ratchet gate): they pinned the slot table's frontend-keyed half - HandleOf's lifetime-id memo and the minting GetOrCreate(StatePtr)'s null-object parking - which minted handles off frontend lifetime ids from inside MG_Backend; that half is deleted (the table only receives client-minted handles now). The other ten DirectGLESSlotTable mechanics cases were RETARGETED at the handle entries (GetOrCreate(handle) / FindByHandle / ReleaseTwinByHandle), not removed the retargeted DirectGLESSlotTable cases, SlotAllocatorTest, and the link ratchet's P13 exit gate (no server object references the client allocator)
2026-10-06 unit RemoteGuards.{SlotTableHandleOfFromTheApplyThreadIsFatalByName, SlotTableMintingGetOrCreateFromTheApplyThreadIsFatalByName, AnAllocatorProbeInsideAnExemptionScopeFromTheApplyThreadIsFatalEvenAtTheOldDebtSites, BarrieredFrontendRegistryMembersRefuseBothLegacyScopes, LegacyRegistryWrapperCannotExposeFrontendKeysOnApply, AnExemptionScopeHeldOnTheGLThreadDoesNotExemptTheApplyThread} Test / unit (split) P13 (# P13 ratchet gate): they drove the apply-thread refusals hung on Espryt's frontend-keyed registry entries (HandleOf, GetOrCreate(StatePtr), NoteStateForHandle, StateForHandle, Find(object), begin()) and the two no-op marker scopes; the entries, the registry refusal and both scopes are deleted, so there is no apply-thread surface left to refuse RemoteGuards.AnAllocatorProbeFromTheApplyThreadOutsideEveryScopeIsFatalByName / BarrieredLegacyScopesCannotExemptAllocator (the allocator's own guard, kept) and the link ratchet's P13 exit gate
2026-10-06 unit ServerLoopEglTest.FrontendFramebufferDeathDeletesOnTheContextOwner Test / unit (split) P13 (# P13 ratchet gate): its pin was the refusal of the apply-thread GetOrCreate(StatePtr) mint of a framebuffer twin; that overload is deleted CtWireScenario's object_death cases (framebuffer death by handle on the server)
2026-10-17 Negative control (library without a transport) (with its Download/Unpack control runtime steps) Test / retrace-split (every leg) a full replay rerun on all 154 legs (~60 runner-min) that, since the per-role logs, only ever proved "no client log was written"; a broken control build once reddened every leg at the download and hid every real split replay in-test: run_trace_case.cmake's transport assertions now leave output/split-evidence.txt, which retrace_split_evidence.py checks on every leg; test_run_trace_case.py (pipe-gates) proves each assertion red on canned logs, including the no-client-log and env-dump-line shapes this control used to rely on
2026-10-17 Negative control (dropped draws) Test / retrace-split (every leg) a rerun of every leg with MOBILEGL_IPC_E2_DROP_DRAW, a production hook; its knob's own early return produced the DirectVulkan Fatal{RoleViolation, "gPipeInputs"} reds of 10-02 to 10-05 in-test on the OpenRA legs (both backends, inproc and spawn): MGTRACE_WIRE_EVIDENCE turns on the library's counters and run_trace_case.cmake requires DrawVbo records on the wire and draws on the server role (758 each locally); canned reds in test_run_trace_case.py
2026-10-17 scripts/ci/retrace_transport_control.sh, scripts/ci/retrace_drop_draw_control.sh, the retrace and drop-draw halves of control_smoke_test.sh and stub_ctest.sh, and scripts/ci/redcheck_control_smoke_test.sh Test / pipe-gates (R-16) the bodies of the two controls above and their smoke cases; the redcheck script had no caller and mutated the deleted scripts test_run_trace_case.py
2026-10-17 unit RemoteEmitTable.TheE2DropSwitchStartsDisarmed, and the MOBILEGL_IPC_E2_DROP_DRAW / MOBILEGL_IPC_E2_DROP_CLEAR knobs with their per-draw and per-clear branches in the shipped emitter (VerbPort.cpp) Test / unit (split); product code the knobs existed only for the retired dropped-draws control (the clear knob was set by nothing); the unit case only toggled the clear setter the wire-volume assertion in run_trace_case.cmake on the OpenRA split legs (DrawVbo records on the wire, draws on the server role)
2026-10-17 the 802-entry DirectGLES.Split. baseline rerun inside split_negative_controls.sh (skip-census lane junit-integration-split/isplit) Test / integration-split, every branch a rerun of entries 'Split lanes' had run minutes earlier on the same runner and library (~2.5 min); its logs also overwrote the lane's in the uploaded artifact the script tallies the lane step's split-baseline.xml and its exit code (split-baseline.rc) with the same three refusals; it still reruns when that step never ran (the 10-12/10-13 catches); the split-baseline census lane covers the names; smoke cases for the reuse, the fallback, a red exit code under a green JUnit and an empty arm
2026-10-17 Negative control B (omitted fill point) Test / integration-verify it re-ran PoisonOmissionScenario.WithoutOmissionCompletes with MOBILEGL_PIPE_POISON_OMIT=ReadPixels:GetPixelStoreParameters and accepted any red the in-lane DirectGLES/DirectVulkan.PoisonOmitted.PoisonOmissionScenario.OmittedFieldAbortsOnThatVerb entries: the same pair, and they also require SIGABRT with the named Fatal{UnmigratedPipeInput}; now required to pass by name
2026-10-17 Verify lane arming check (grep of pipe-verify-arming-*.log) Test / integration-verify the VerifyArming entries assert the armed line in-test; the grep only added "the entry did not skip" Verify lane control entries: junit_tally.py --require-entry-passed on the VerifyArming, VerifyCorrupted and PoisonOmitted entries of both backends (a skip fails)
2026-10-17 Negative control A (server-side read) and Negative control B (omitted stamp) Test / integration-verify-split the first re-ran the two VerifySplitReadCorrupted entries the lane had just run and grepped what they already assert in-test (at least two where=read reports in the server half); the second re-ran with the pair the in-lane VerifySplitPoisonOmitted entries already pin, and accepted any red Verify-split control entries: --require-entry-passed on VerifySplitArming, VerifySplitCorrupted, VerifySplitReadCorrupted and VerifySplitPoisonOmitted of both backends
2026-10-17 the pre-flip arm of Strict split lane (red-by-design while kMGPipeP5eRunAheadReady was false) and the "GREEN with rows outstanding" rule of Dual-block census lane Test / integration-split-strict dead: the constant is true, and dualblock-expected-fatals.txt has no rows, so neither branch could run the hard-green arm and its two-sided marker census, and the empty-census rule (rows == 0 requires ctest success), both kept
2026-10-17 scripts/ci/tcp_log_forwarding_control.py none no caller outside the archived planning notes none needed
2026-10-17 the compile of build-linux-split on the disaggregation branches (when build-guard proves the configurations identical) Test / build-linux-split it built the library build-linux builds there, from a configuration that differs only by the benchmarks (211 paired runs never disagreed); it delayed every split consumer by up to 9 minutes the build-guard job configures both lines on one runner and compares them with build_fingerprint.py (cache, compile commands, link statements, CTest files; benchmarks excluded; one shared FetchContent directory, a failed configure or one killed after 10 minutes retried once) and records its image and compiler; only the verdict identical lets the consumers take build-linux's artifacts, and only a Release one, while different (annotated as a warning) and unknown (a configure that failed twice, any error, too little evidence; a notice) keep both builds and the full split lanes; the guard job's own failure never fails the run; build-linux runs the link ratchet on every disaggregation build (artifact link-ratchet-primary) and integration-split reds on it when it takes that build; dev runs no guard and always builds
2026-10-17 Transport A/B (monolith vs inproc) (skip-census lanes arm-monolith, arm-inproc now optional) Test / integration-split with build-linux reused it repeats the integration job's two legs on the same library (79 paired runs, no one-sided red) the integration legs; Default-knob resolution check (disaggregation branches) reads 'Split lanes' own run and proves, from every passed entry's client log, strict=0, role-split-state=1 and run-ahead=1 unless pinned (split_log_paths.py ipc-config); A/B still runs when a default differs or the build is not reused, and the skip census then requires the two arm rows
2026-10-17 Unit tests on the split runtime (skip-census lane unit-split now optional) Test / integration-split with build-linux reused the test job runs the same unit lane on the same build (182 paired runs; the one recurring one-sided red was a fixed test race) the test job, which now carries MOBILEGL_ITEST_REQUIRE_GPU=1 and libegl-mesa0 on the three branches; the strict unit step is unchanged; without a reused build the skip census requires unit-split
2026-10-17 the integration-gpu entries that pin their own MOBILEGL_TRANSPORT (804 inproc, 1446 spawn, 131 monolith) and the 12 TcpServer fixture entries only they need, in the inproc-acceptance leg (both passes) Test / integration (inproc-acceptance) their pin overrides the only variable the two legs differ in, so they ran identically in both (173 paired runs; the one one-sided red was a port bind fixed by cde6512b) the monolith-control leg, which runs them on every branch; transport_pinned.py proves per run that the trimmed selection lost exactly that population and that the monolith-control leg ran every one; when it cannot, the leg runs everything under the JUnit stems integration-all and integration-staged-copy-all; skip census: the monolith-control lanes list their own names, the inproc-acceptance lanes drop the pinned ones, and two optional -all rows (the full names, the old skip lists) stand in for them on that fallback
2026-10-17 Strict split lane on the disaggregation branches (dev keeps it) Test / integration-split-strict with the role-split state defaulting on, its environment equals the dual-block census lane's, whose entries are a superset (31 paired runs after the flip, never red only in the strict lane) the dual-block step's first run leaves the knob at its default, proves per entry from its client log that strict, the dual block and run-ahead resolved on (ipc-config), writes the integration-split part of its JUnit as strict-split.xml (every name exactly once, junit_tally.py --select-from), and makes the strict lane's checks on it (hard green, two-sided marker census, StrictArming ran); a default that changed reruns the census with the knob set
2026-10-17 Magma split lane (strict, dual-block) on the disaggregation branches when the dual-block step proved its defaults Test / integration-split-strict the dual-block census run covers the integration-magma-split label in the same environment the dual-block census run
2026-10-17 the 75 retrace-split inproc rows other than OpenRA's, when build-linux-split reuses build-linux Test / retrace-split the retrace job's inproc-acceptance rows replay the same cases on the same library, strict and with the dual block and run-ahead on; no one-sided pair since 10-05 the inproc-acceptance rows, which now prove per leg from the client log that they run with strict=1, role-split-state=1 and run-ahead=1 (MGTRACE_EXPECT_IPC) and keep a refusal census; every remaining retrace-split leg proves its defaults (strict=0, role-split-state=1, run-ahead=1) and a changed default reds every leg with the rows to restore; trace_cases.py --self-test-split-matrix (disaggregation branches) proves every dropped row is an acceptance row; OpenRA's inproc rows stay for the wire evidence
2026-10-17 Transport resolution check's grep of one entry's log for the inproc resolution sentence Test / integration-split it checked one entry (DirectGLES.Split.PersistentMapArm.) after the fact in-test: the split fixture (Harness/ScenarioFixture.h) now fails every armed Split/Spawn/Tcp entry whose process did not resolve the transport its registration claims, or whose server is not where the claim says (a thread here for inproc, a process of its own for spawn and tcp), from the running process (SplitRuntimePeek, ClientSession::PeerServerPid()); SplitLaneHarness.TransportClaimRule (unit) proves the rule red on canned inputs; the step keeps the IPC default proof as Default-knob resolution check
2026-10-18 Negative controls (barrier, map push) (scripts/ci/split_negative_controls.sh; skip-census lane junit-integration-split/control) Test / integration-split it reran the split entries with MOBILEGL_IPC_VERB_BARRIER=0 and MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0, two product knobs that exist only for it; what was left without them (the ownership check and the baseline tally) repeats SplitLogPaths.PrivateAndDistinct and the lane step's own junit_tally.py --require-split-ran E1: RemoteWaitBoundaryControl.AnUnwaitedPublishIsSeenAsNoWait (unit, always on); E3(a): PersistentCoherentMapScenario.ThePushIsTheOnlyRouteAWriteTakesToTheServer on the inproc, spawn, tcp and small-ring split entries (always on)
2026-10-18 scripts/ci/wait_boundary_negative_control.py Test / integration-split E1's body inside the step above: the three boundary cases rerun with the barrier off RemoteWaitBoundaryControl.AnUnwaitedPublishIsSeenAsNoWait: the same ApplierReset published with no wait must read parked=0, the observation the owed waits read as parked=1
2026-10-18 scripts/ci/control_smoke_test.sh, scripts/ci/testdata/stub_ctest.sh, scripts/ci/testdata/split_private_log_smoke.sh, and the reset / results / assertion / evidence modes of split_log_paths.py Test / pipe-gates (R-16) smoke cases and helpers of the step above only none needed
2026-10-18 unit RemoteRunAhead.ClearingTheVerbBarrierDisarmsRunAheadEvenWithTheCapBit, and the MOBILEGL_IPC_VERB_BARRIER knob with its arm in the shipped client (ClientSession: the free-running EmitAndWaitTails return, the run-ahead latch term, the gPipeInputs guard's early return, the verb-barrier= field of the Config: IPC line) Test / unit (split); product code 0 was never a product mode, only E1's negative control, retired above; the unit case pinned that the control also disarmed run-ahead RemoteWaitBoundaryControl.AnUnwaitedPublishIsSeenAsNoWait; MOBILEGL_IPC_RUN_AHEAD=0 stays the lockstep A/B arm
2026-10-18 unit SplitBufferSet.AZeroBlockSizeTurnsThePushOffRatherThanMakingItUnlimited (and its skip stub in the non-disaggregated half), and the MOBILEGL_IPC_PERSISTENT_BLOCK_KB knob with its 0 arm in the shipped tracker (PersistentMapTracker::PushBlocksForChecked's early return and once-per-process warning, BufferObject::NotePersistentMapStateChanged's, the persistent-block= field of the Config: IPC line) Test / unit; product code 0 was never a product mode, only E3(a)'s negative control, retired above; the unit case pinned that 0 shipped nothing; the block size is now the constant 64 KiB (PersistentMapTracker::BlockBytes()) PersistentCoherentMapScenario.ThePushIsTheOnlyRouteAWriteTakesToTheServer

Kept after investigation

minecraft-1.17-main-menu-854 (Test retrace / retrace-split / retrace-verify, APK retrace), 2026-10-06

  • Symptom: every lane, both backends, SSIM 0.0186 against the golden; the frame is Minecraft's red loading-screen colour. Local repro on WSL llvmpipe: same SSIM, monolith and inproc.
  • Root cause: the trace was captured on an implementation that gave shaders and programs overlapping names (shader 1 and program 1 live at once, likewise shader 5 / program 5, calls 159-209). GL 4.6 core and ES 3.2 §7.1 put shader and program objects in one shared name space, so a conformant implementation never hands out such a pair. Since 5a0f13fdf / 168808d1a (2026-10-01/02) MobileGL advertises GL_ARB_shader_objects, and apitrace's glretrace then resolves every shader and program name through one ARB handle map (_handleARB_map): program 1 overwrote shader 1's entry, glAttachShader(1, 1) attached a program name (GL_INVALID_OPERATION at call 170), the blit program linked without a vertex shader, and nothing after it drew.
  • Classification: (b) retrace tooling - not a MobileGL bug and not a bad golden. The core entry points are typed (glAttachShader(program, shader)), so mapping each argument through its own type's map is lossless even when the capture's names collide; only the untyped *ObjectARB handle calls need the shared map.
  • Fix: MobileGL-Dev/apitrace 45843686 (branch mobilegl/android-trace-replay): typed GLprogram / GLshader arguments resolve through _program_map / _shader_map first and fall back to the ARB handle map only for names created by glCreate*ObjectARB; typed creators record both maps. Submodule bumped in the same MobileGL commit. Local: 1.17 passes on DirectGLES (monolith, inproc) and DirectVulkan (lavapipe).
  • Decision: keep the case. With typed mapping it checks GL-level correctness of MobileGL like any other fixture; the namespace overlap is a property of the capture that a spec-portable replay can absorb.
  • Side note (not changed): MobileGL advertises GL_ARB_shader_objects while its glCreateShaderObjectARB / glCreateProgramObjectARB entry points are stubs (MG_Impl/GLImpl/Exporting/Definitions.cpp). The string was added on purpose for KWin; whether to implement the ARB handle entry points is a separate decision.

SanityTest DirectGLESTextureSync.UnitMemoRefusesToDriveATwinFromAnotherTexture, 2026-10-06 (removed in W3b, then RESTORED)

  • First call (wrong): retired with the P2-mask probes as "its arm is gone". The orchestrator's review asked whether its failure at the shipping mask was a behaviour gap.
  • Finding: the code it pins is LIVE. The monolith arm (DISAGG builds under MOBILEGL_TRANSPORT=monolith, and the FCL build) still walks the frontend units with the borrowed-slot work list and its PairingsIntact check (UnitTexturesByHandle() is false on monolith). Its red at 0x3fff is not a product gap: at that mask the twin-sync body it observes reads applier records, and a unit-lane process cannot create them (MGPipeApplyResourceCreate declines under NoP4aConsumer), so the probe observed nothing.
  • GL-level replacement tried and measured: DsaUpdateKeepsTheBoundUnitScenario (A bound to unit 0; B respecified and filled by name; unit 0 must still sample A). Red-checked locally: it stays GREEN with PairingsIntact disabled, and still green with the frontend's by-name bind-generation bump ALSO removed, and with by-name mipmap / readback / parameter / copy calls added in the window. The hazard is no longer reachable through public GL: the by-name emulation restores the slot before any draw can replay the list. The scenario stays as a GL 4.6 8.1/8.5 semantics test on every lane, but it is NOT a guard of the pairing check and is not claimed as one.
  • Decision: the probe is restored, pinned to the P2 mask in its own process (the code under test is mask-independent; the mask only selects the sync body it observes). Red-checked locally: with PairingsIntact disabled it goes red at "the replay never reached the texture now in the slot" (the stale pairing was replayed instead of the texture the slot holds); restored, green. The resident-respecify assertion now runs first so a red names that damage when it occurs. It goes with the borrowed-slot list itself when W4c moves monolith to the by-handle unit walk.
  • P13 W6: monolith moved to the by-handle unit walk and the borrowed-slot list was deleted; the probe went with it (Removals table).

Infrastructure fixes (no check removed)

Date What was red Cause Fix
2026-10-06 Direct{GLES,Vulkan}.PoisonOmitted.PoisonOmissionScenario.OmittedFieldAbortsOnThatVerb (verify tree, local; P13 W5 S7) monolith now runs the record arm, which resolves GenerateMipmap's texture from the verb's handle and never reads the omitted GetActiveTextureUnit - the control could not go red the monolith lanes omit ReadPixels:GetPixelStoreParameters (the pair the split lane already uses), which the record arm still reads; verified red-for-its-reason on both backends. Same change in test.yml's integration-verify "Negative control B (omitted fill point)" step, which went green with the old pair on Test 37515697754
2026-10-06 integration-verify, 184 aborts Fatal{PipeVerifyDiffer, "GetPixelStoreParameters@ReadPixels"} (verify tree, local; P13 W5 S7) the verify read hook took the live context as the pack oracle inside the monolith verb port's neutral-pack readback window (it already used the applied pack for server-stamped verbs) MG_Record::MonolithPortApplyingForVerify(); the hook uses the applied pack payload in that window too
2026-10-06 ResourceEmit.TheLiveHostWritesWireFiresOnTheCallAPersistentMapProducerWouldSetItOn (verify unit, local; P13 W5 S7) the always-false HasLiveHostWrites pin is lifted wherever the record arm is built (it gives the bit a producer), and every library builds it now the case skips under MOBILEGL_BUILD_RECORD_ARM with the existing reason; PinLiveHostWritesNamesABuffer remains the successor
2026-10-06 every ctest invocation in integration / verify / split jobs exited 8 after the tests passed (integration-verify, integration-split*, integration (inproc), spawn_lane_parity.py) PipeCatalogueSourceRoot.cmake (a CTest include file) used if(... IN_LIST ...); CTest scripts run without policy CMP0057 on the pinned CMake 3.31.10, so the include errored use list(FIND) instead (MobileGL/MG_Test/Pipe/CMakeLists.txt)
2026-10-06 TcpServer.Start.P8aUnlocatedIoBlocks failed in 0.07 s on integration (monolith) the loopback TCP endpoints (40613, knob lanes 41613-41617) sat inside Linux's ephemeral port range; with thousands of loopback client connections in the lane, an outgoing socket can own the port the supervisor binds default endpoint moved to 30613 (knob lanes 31613-31617), below 32768
2026-10-06 spawn lanes on hosted runners: no Welcome within 5000 ms a cold eglInitialize on the hosted software stack took ~7 s, longer than the spawn handshake's Welcome wait the Welcome wait takes max(5000, MOBILEGL_IPC_COLD_START_MS) (ClientSession.cpp ColdHandshakeBudgetMs); the initial-caps wait stays 5000 ms, which InitialCapsStartup pins
2026-10-06 FencePollScenario on integration-verify-split the test took its before counter snapshot after glFenceSync, racing the apply thread that answers the fence snapshot taken before the work and the fence are queued (test bug, not a product bug)
2026-10-06 LogForwardChannel.APeerThatStopsReadingCostsWarnLinesNotTheCallersTime on integration-split-strict (run 37433779649) test race: when the channel's sender thread started late it dequeued its first line after the 16 KiB queue had already filled, so the lossy class recovered mid-flood and closed a first gap (4 drops) with its own notice - two notices, 1880 named vs 1884 counted. The channel did what its contract says (one notice per gap) the test parks the sender in its held write (WaitForAttempt) before the flood, so the flood makes exactly one gap; 100/100 local runs green
2026-10-06 TcpLane.EventForfeitPeer (EventForfeitPeer.StreamLogFloodWhileControlIsNotReadHoldsNoApplyThreadAndLosesNoError) on integration-split (run 37433779649) notices <= 8 was one machine's measurement: every time the socket takes another burst during the flood, the WARN class recovers and its gap closes with a notice; the loaded runner made 14. Every other F2 assertion held (drops named exactly, no ERROR lost, no forward held its thread) the bound is now kFloodRecords / 10 (40), still an order of magnitude below the regression it guards (373, one notice per ERROR line)
2026-10-06 DirectGLES.SubsystemMaskRefusal.ObjectSubsystemControlRefusedTexture flaky under ctest -j (a W3b control) the control globbed <stem>* for its logs, which also matched the longer-named sibling ...RefusedTexture; the shorter control deleted the sibling's log while it ran glob <stem>.* (Harness/RefusedMaskControl.cmake)
2026-10-06 MGPipe generators and hygiene gates and trace case matrix (fatal census) on the W3b/W3c push W3c's retired Wire_SetResidualValueState died through its own std::abort() (the census counts server-image aborts that bypass SessionFail), and W3b's mechanical MGB_CTX rewrite reached a string in FieldOwnership.def that the generator copies into PipeFieldOwnership.inc the row dies through SessionFail(ResidualBlockSize, ...); the .def text is restored so the generated file is unchanged
2026-10-06 skip census: Direct{GLES,Vulkan}.HandleRecycle.Handles.* and ...AbaControlHandles.* leak cases pass -> SKIPPED W3b stopped pinning MOBILEGL_PIPE_PUSH on those lanes (bits 0-13 are fixed on), and the scenario's LanePinnedALiveAllocator read "no pin" as "no allocator". A real regression in coverage, caught by the census on its first full run an unpinned HandleRecycle lane runs the full mask and has the allocator; the cases run (and pass) again. The census also retired the PeerLatchSite/SetResidualValueStateBlobSize row W3c deleted
2026-10-06 skip census on the W6a/b push (run 37534648608): DirectGLES.*CubeFaceReadbackScenario.CubeMapViewOfAnArrayReadsTheFaceEachZOffsetNames SKIPPED, baseline new (8 lanes) the new case skips where the backend does not advertise GL_ARB_texture_view (Espryt on the CI's ES driver refuses glTextureView rather than emulate it by copying); a legitimate capability skip, not a lost case the 8 lane entries are recorded as skip in scripts/data/skip_census_baseline.json; the Magma lanes run the case