- ID-116's static rule failed on a row no package in this phase may touch. pa retired the
per-draw program pull, which unmasked GetTransformFeedbackProgram@DrawArrays (11 entries):
BARRIER_PULLED, on kWaitNone draw_vbo, and ruled out of P5e entirely by CONTRACT-P5E section
5.7, with a retiring phase of "P3b/P4b (Espryt), P7 (Magma)". The rule was wrong, not the code.
- A pull is now admitted if the field is BARRIER_PULLED, the verb has a stamp row, the field is
in the verb class's may-read mask, and EITHER the verb's op is statically barriered OR the
field's retiring phase does not name P5e. This table is only ever consulted on a record the
server already stamped BARRIERED - CountBarrierPull's unbarriered arm is [[noreturn]] and
fires first - so the pull is legal by construction and the only open question is whose debt it
is. The retiring-phase column is exactly that answer and was already in the table.
- A verb with NO stamp row still admits nothing under either disjunct: the server stamps only
MGP_VERB_OP_LIST's ops, so any other bit would be a row nothing can exercise. 111 -> 174 pairs.
- The phase column is matched as a TOKEN, not a substring, so a "P5" or a future "P5e2" cannot
answer for "P5e".
- All six of ID-125's survivors checked: GetFramebufferBindingSlot@ReadPixels and
GetTextureUnitObject@CopyTexImage2D by disjunct 1; GetTransformFeedbackProgram@DrawArrays
(P3b/P4b), GetTextureObject@CopyImageSubData (P7) and ValidateProgramName@ShaderStorageBlockBinding
(P9) by disjunct 2. GetTextureObject@CopyImageSubData holds by BOTH, asserted separately.
GetProgramForDraw@DrawArrays, GetBoundVertexArray@DrawArrays and
GetProgramForDispatch@DispatchCompute stay rejected.
- Magma's GetFramebufferBindingSlot@Clear is NOT admitted and cannot be: the retiring-phase
column is one string for both backends and it names P5e for Espryt. The DirectVulkan entries
get their own lane label instead (item 7), which keeps the Espryt allowlist about Espryt.
- StrictErrorsAlsoPromotesTheStickyForwards is RENAMED to
StrictErrorsReachTheStickyForwardsAndNameThemByField and restated. Not one of the seven sticky
forwards names P5e (P7, P7/P9, P7/P13, P9), so on a stamped verb they are all admitted now.
The claim that still has teeth is that the detector REACHES them - asserted by rsp moving and
by the marker naming the field and its phase, so "did not abort" cannot pass for "never
detected". The Fatal half keeps its own case next door on GetBoundVertexArray, a P5e row.
- Six new derivation controls, including one that makes GetTransformFeedbackProgram this phase's
debt and requires it to leave the unbarriered verb's allowlist - without which disjunct 2
could be a constant `true` and every other control would still hold.
- ra landed a hand-kept 13-row copy of CONTRACT-P5E section 7 in .github/workflows/test.yml, and
it was wrong in BOTH directions at once: it omitted GetFramebufferBindingSlot@ReadPixels (21
entries, the lane's largest survivor) and carried GetTextureObject@CopyImageSubData, which
resource_copy_region's kWaitNone makes a genuine unbarriered read of client memory. Neither
error is visible by reading the list. Both are obvious once the list is derived.
- gen_pipe_field_ownership.py now joins the three tables ID-84 already states the rule in -
kMGPipeFieldOwnership, kMGPipeWaitClasses (generated/PipeWire.inc) and kMGPipeClassFieldMask /
kMGPipeVerbClass (generated/PipeFillPoints.inc) - and emits kMGPipeAdmittedPullMask plus
MGPipeBarrierPullAdmitted(field, verb): 101 admitted pairs across 12 barriered verbs.
- The three inputs are READ, never restated, so the allowlist moves with the code: retiring a
verb's wait class narrows it with no edit anywhere, and a new BARRIER_PULLED row widens it only
on verbs that wait. A verb with no stamp row admits nothing - only MGP_VERB_OP_LIST's ops can
ever be the record a pull is reported against.
- --print-admitted gives the CI shell the SAME table the C++ answers from, which is what makes
the hand copy unnecessary rather than merely corrected.
- Three new negative controls (each source renamed away must stop the script - a missing source
yields a silently EMPTY allowlist, which reads as rigour and is blindness) and five derivation
controls that move an input and read the allowlist back.
- Red-once: dropping the wait-class conjunct from build_admitted fails the self-test by name -
"3 admission-derivation control(s) did not hold: unbarriering ReadPixels' op removes every
@ReadPixels pair; unbarriering ResourceCopyRegion removes every @CopyImageSubData pair; no pair
is admitted on an unbarriered verb (DrawArrays)" - and the new unit case fails with
"GetBoundVertexArray@DrawArrays is admitted on a verb no barriered op stamps".
- MGPipeBarriered(op, payload, applierState), IMPLEMENTED, not stubbed: the static wait-class
column plus the two payload-derived escalations the contract names (an open XFB span, a draw
carrying kDrawClientArrays). One function and two callers is the point - the emit table and
the sink must reach the same answer or the client runs on while the server reads a value that
has already moved. set_context_values now mirrors IsTransformFeedbackActive into the applier
state as well, because a predicate that read it out of gPipeInputs would be reading the very
block run-ahead stops filling.
- MGPipeApplierCurrentRecordIsBarriered() with the writer beside it. It answers true by default
and that IS the landed lockstep answer, not a stub: on a server without kCapRunAheadApply
every record is barriered and CONTRACT-P5C's two exemption scopes keep working unchanged.
- The sb applier fields (BoundShaderBuffers[3][84], the three windows, the writable masks and
ShaderBuffersSerial) and the pg record fields (the three binding tails, Signature,
BindingsSerial) with the two entry points MGPipeApplySetShaderBuffers /
MGPipeApplySetProgramBindings declared and ABORTING BY NAME.
- The by-handle backend seams in Managers.h with aborting bodies in one block: ResolveVaoTwin,
ResolveTextureTwin, ResolveProgramTwin, SyncTextureToBackendByHandle,
SyncMipmapsToBackendByHandle, and the FBO / RBO / program SyncToBackendByHandle overloads.
Five packages sit on opposite sides of these calls - tx2 writes what fb calls, fb writes what
tx2 needs, id rekeys the registries all three read - so the signature is fixed once here and
each family replaces a body. Abort and not null: a resolver that answered null renders a
blank draw and a sync that did nothing renders stale pixels, and both are green lanes.
- Coverage.def's GetBufferBindingPoint -> SetShaderBuffers row with BOTH of its PipeFill.cpp
switch arms and the pairing asserts, shape-only and inert. It lands with the contract package
because PipeFill.cpp belongs to the contract package for the whole phase - an emitter
enumerator whose dispatch arm lived in the family's worktree is the merge trap that file's
own comment was written about.
- FieldOwnership.def re-annotates the six object-class rows plus GetProgramForDispatch to
"P5e (Espryt unbarriered), P7 (Magma)", and the strict-abort case follows the string, which
IS the debt entry rather than decoration. kMGPipeMaxBufferBindingPoints is pinned against
BufferState.h's 84 where both are visible. gen_pipe_field_ownership's refusal count is 8.
set_context_values (opcode 79, MGPContextValues 96B, kCtxState) carries the active texture
unit, the max touched unit, the fifteen touched-binding-point counts and the five value-class
XFB rows, emitted at validate under the subsystem bit and hash-suppressed as a whole; the
emit gate and the residual-skip gate read the same answer so they can never disagree.
MGPipeApplySetContextValues writes gPipeInputs (the PackState shape). MGPAttribValue grows
24->56B to carry the frontend's converted three views, and MGPipeApplySetVertexAttribDefaults
finally writes them (the 'ignores MGPAttribValue::ValueClass' warning dies), so
GetCurrentVertexAttribute leaves the refusal set. The three texture shutters answer the
applier's own serials under a server-stamped verb (APPLIER_DERIVED), storage answer kept
verbatim elsewhere. FieldOwnership.def: nine value-class rows become derived RECORD_SUPPLIED,
the three shutters APPLIER_DERIVED, the nine object-class rows keep their phases;
FieldOwnershipTest pins that the remaining pulls are exactly the object-class list.
gen_pipe.py gains SCAN_EXEMPT_ACCESSORS with per-name reasons and retiring phases (it repairs
the --check gate the hd merge's two G6 probes had left red).
Evidence: unit 2175/2175; integration-split 111/111; both generators' --check and
--self-test green; rsp on the Xfb capture scenario 36 -> 22; red-once - gating the emission
off turns seven named scenarios red, restoring returns 111/111. CONTRACT-P5C section 5.3.