[Test, CI] (tools/trace_replay, workflows): give retrace-split the negative control it was cloned without, match ConfigLoader's whole INFO sentence rather than a KEY=VALUE an env dump also prints, read the three-arm names file the identity step was writing and discarding, and refuse an unknown manifest key that silently empties a CI matrix

This commit is contained in:
2026-09-11 15:30:17 -04:00
parent 8b425a9718
commit 949ed1f037
3 changed files with 207 additions and 18 deletions
+28 -4
View File
@@ -252,17 +252,41 @@ if(DEFINED ENV{MOBILEGL_TRANSPORT} AND NOT "$ENV{MOBILEGL_TRANSPORT}" STREQUAL "
"retrace with no library log cannot be counted as a split retrace.")
else()
file(READ "${mobilegl_log}" split_log)
string(FIND "${split_log}" "MOBILEGL_TRANSPORT=inproc" split_armed_at)
# THE DISTINCTIVE PART OF ConfigLoader's INFO LINE, not the bare KEY=VALUE - review finding
# M-5. ConfigLoader.cpp:71 logs `Config: Accepted env variable: %s=%s` for EVERY MOBILEGL_*
# variable, unconditionally, in every build including the pull one. That line is MGLOG_D,
# so at the INFO level CI and the gate use it is compiled out - but at
# MOBILEGL_LOG_ACTIVE_LEVEL=..._DEBUG it reads `Config: Accepted env variable:
# MOBILEGL_TRANSPORT=inproc` and satisfied the old substring search. Observed GREEN on a
# crafted pull-build log. The person most likely to hit that is the one who rebuilds at
# DEBUG to debug a split failure. The sentence below exists only in
# ConfigLoader::InitTransport's InProcess arm, which exists only under
# MOBILEGL_BUILD_DISAGGREGATED.
set(split_expected_marker "MOBILEGL_TRANSPORT=inproc - the MGPipe record stream")
string(FIND "${split_log}" "${split_expected_marker}" split_armed_at)
if(split_armed_at EQUAL -1)
# Say which transport was actually asked for. ConfigLoader REFUSES spawn / unix: /
# pipe: BY NAME and stays on monolith (they are P6's), so a run that set one of those
# has a different diagnosis from one that set inproc against a monolith library, and
# the old message named `inproc` either way.
set(split_refusal "")
if(NOT "$ENV{MOBILEGL_TRANSPORT}" STREQUAL "inproc")
set(split_refusal
" NOTE: this run asked for '$ENV{MOBILEGL_TRANSPORT}', which P5 does not "
"implement - ConfigLoader recognises spawn / unix: / pipe: and REFUSES them by "
"name, staying on monolith. Only 'inproc' can resolve in P5.")
endif()
message(FATAL_ERROR
"MOBILEGL_TRANSPORT=$ENV{MOBILEGL_TRANSPORT} is set for ${split_case} and the library "
"never reported resolving it. ConfigLoader::InitTransport logs one line at INFO when "
"it selects InProcess, and that line exists only in a build configured with "
"never reported resolving it: ${mobilegl_log} carries no "
"\"${split_expected_marker}\". ConfigLoader::InitTransport logs that line at INFO "
"when it selects InProcess, and it exists only in a build configured with "
"-DMOBILEGL_BUILD_DISAGGREGATED=ON - in a build without it the whole parser is "
"compiled out and the variable is accepted and ignored, which is exactly the 'the "
"split lane ran monolith and went green' failure. Check that the SPLIT runtime "
"artifact is the one at ${MOBILEGL_LIBRARY}, and that MOBILEGL_LOG_ACTIVE_LEVEL "
"admits INFO.")
"admits INFO (at WARN or above the line is compiled out and this reds for no "
"defect).${split_refusal}")
endif()
# The refusal census. Recorded on every split run, pass or fail.
file(STRINGS "${mobilegl_log}" split_fatals REGEX "Fatal\\{")
+44
View File
@@ -8,11 +8,48 @@ from pathlib import Path
TRACE_CASES_JSON = Path(__file__).with_name("trace_cases.json")
CI_BACKENDS = ("DirectGLES", "DirectVulkan")
# Every key a case or the defaults block may carry. An UNKNOWN key is a hard error rather than a
# silent no-op, which is review finding N-4: `"split": true` mistyped as `"splitt": true` loaded
# clean, the split subset became [], the GitHub matrix became {"include":[]}, and `retrace-split`
# was skipped with no red anywhere. Every other way of getting `split` wrong already raised
# (`"ci": false`, a backend list without DirectGLES, a non-bool value) - the typo was the one hole,
# and it is the shape that makes a whole CI job quietly stop existing.
#
# Adding a key means adding it here, deliberately, in the same commit. That is the point.
KNOWN_CASE_KEYS = frozenset({
"name",
"trace_archive",
"trace_file",
"golden",
"alternate_golden",
"target_call",
"width",
"height",
"ssim_threshold",
"crop_x",
"crop_y",
"crop_width",
"crop_height",
"coherent_as_flush",
"timeout_seconds",
"ci",
"ci_backends",
"verify",
"split",
"avoid_angle_llvmpipe_explicit_lod_bias",
})
def load_trace_case_manifest(path=TRACE_CASES_JSON):
with Path(path).open("r", encoding="utf-8") as file:
manifest = json.load(file)
defaults = manifest.get("defaults", {})
unknown_defaults = sorted(set(defaults) - KNOWN_CASE_KEYS)
if unknown_defaults:
raise ValueError(
f"unknown key(s) in the defaults block: {', '.join(unknown_defaults)}. "
f"Known keys are {', '.join(sorted(KNOWN_CASE_KEYS))}"
)
cases = []
seen = set()
for case in manifest.get("cases", []):
@@ -20,6 +57,13 @@ def load_trace_case_manifest(path=TRACE_CASES_JSON):
name = merged.get("name")
if not name:
raise ValueError("trace case is missing name")
unknown = sorted(set(case) - KNOWN_CASE_KEYS)
if unknown:
raise ValueError(
f"unknown key(s) for {name}: {', '.join(unknown)}. A mistyped flag loads clean and "
f"turns its whole CI subset into an empty matrix, which GitHub skips with no red. "
f"Known keys are {', '.join(sorted(KNOWN_CASE_KEYS))}"
)
if name in seen:
raise ValueError(f"duplicate trace case: {name}")
seen.add(name)