[MG_Pipe, MG_Impl, MG_Remote, MG_Backend] (Disaggregated): P5c rv - set_context_values retires the value-class BARRIER_PULLED rows

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.
This commit is contained in:
2026-09-17 09:27:36 -04:00
parent 04650ca35e
commit 82b1f743a7
33 changed files with 899 additions and 278 deletions
+20 -1
View File
@@ -462,6 +462,25 @@ def check_field_lists_cover_struct_members(field_lists, payloads, header_texts=N
ACCESSOR_READ_RE = re.compile(r"\b(?:MGB_CTX|pGLContext)\s*->\s*(\w+)")
# The scanner's NAMED exemptions: accessors a backend reads through MGB_CTX-> / pGLContext->
# that are NOT PipeInputs fields and never will be, each with the reason written down. A name
# here is a DEBT ENTRY, not a silence: it exists so the gate can tell "scoped, named, phased"
# from "forgot the row".
#
# P5c (the tx/ev/hd merge): the G6 frontend-keyed registry's framebuffer arm - two probes a
# backend makes inside MGPipeFrontendKeyedRegistryScope (CONTRACT-P5C.md section 3.1's second
# named exemption: the registry probes ride the scope, an unwrapped probe still aborts, and
# the scope retires with the twin tables at P3b/P4b). They are object-registry lookups, not
# PipeInputs state reads, so no Coverage.def row can ever describe them - a row there is a
# field in the fill table, and these have no storage to fill.
SCAN_EXEMPT_ACCESSORS = {
"GetFramebufferObject": "P5c G6 registry probe (the default framebuffer's object), inside "
"MGPipeFrontendKeyedRegistryScope; retires with the twin tables (P3b/P4b)",
"FindFramebufferObjectByLifetimeId": "P5c G6 registry probe, inside "
"MGPipeFrontendKeyedRegistryScope; retires with the twin tables (P3b/P4b)",
}
def scan_live_accessors(accessors, backend_dir=None, verbose=True):
"""Every accessor a backend reads through MGB_CTX-> or pGLContext-> (comments and
strings masked) must have a Coverage.def row - a read without a row is a PipeInputs
@@ -479,7 +498,7 @@ def scan_live_accessors(accessors, backend_dir=None, verbose=True):
masked = mask_comments_and_strings(read(path))
for match in ACCESSOR_READ_RE.finditer(masked):
read_names.setdefault(match.group(1), set()).add(os.path.relpath(path, REPO_ROOT))
unknown = sorted(n for n in read_names if n not in known)
unknown = sorted(n for n in read_names if n not in known and n not in SCAN_EXEMPT_ACCESSORS)
if unknown:
sys.exit("Coverage.def: accessor(s) read by a backend with no row: %s"
% ", ".join("%s (%s)" % (n, ", ".join(sorted(read_names[n]))) for n in unknown))