Skip to content

prevent cross-architectural leakeage in matrix_job_re - #76

Merged
cgoea merged 6 commits into
developfrom
users/cgoea/group_by_arch
Aug 14, 2026
Merged

prevent cross-architectural leakeage in matrix_job_re#76
cgoea merged 6 commits into
developfrom
users/cgoea/group_by_arch

Conversation

@cgoea

@cgoea cgoea commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Motivation

status.json's matrix-cell key for PyTorch/JAX fan-out builds is parsed purely from job names as (py, ref) — it carries no GPU architecture. When a single build cell (e.g. py 3.12 | torch release/2.10) nests test jobs for multiple architectures (e.g. gfx942 and gfx1101), all of those jobs collapse into one shared, worst-of variant.

That conflated variant then gets broadcast onto every architecture's test leaf by _refresh_same_run_fanout_tests, so one architecture's failure silently drags down another architecture's otherwise-passing result (and vice versa) in status.json, even though the two GPUs' actual test outcomes are independent.

closes #75

Technical Details

  • Added _TEST_ARCH_JOB_RE / _job_matches_arch to detect which architecture (if any) a job names in its own "Test | <arch>" segment, so a job can be classified as either arch-agnostic (the cell's shared build step) or scoped to one specific architecture.
  • _variants_from_jobs, _derive_variants, and _create_leaf now accept an optional arch parameter that filters the job list down to that architecture's own jobs plus any arch-agnostic jobs before deriving matrix-cell variants.
  • _refresh_same_run_fanout_tests now re-derives each existing test leaf's variants scoped to its own architecture, instead of reusing the build leaf's arch-blind variant list wholesale. It also rolls the leaf's status up from those scoped variants (previously it copied the raw run conclusion directly, which doesn't reflect the arch-specific outcome either).
  • _merge_run_into_document now re-derives a per-architecture leaf when a single event legitimately reports more than one target architecture, closing the same conflation risk (and a related object-aliasing hazard) on the primary write path, not just the same-run refresh path.

Test Plan

  • Added test_completed_fanout_build_does_not_leak_status_across_architectures, which sets up two architectures (gfx942 passing, gfx1101 failing) nested under the same (py, torch) build cell and asserts each architecture's test leaf reflects only its own outcome. also added test_multi_arch_test_event_does_not_leak_or_alias_across_architectures.
  • Verified the new test fails against the pre-fix code (gfx942's leaf incorrectly flips to failure) and passes with the fix applied.
  • Ran the full scripts/receive_therock test suite and checked for regressions against develop.

Test Result

  • pytest scripts/receive_therock/tests/therock_update_status_json_test.py: 99 passed
  • pytest scripts/receive_therock/tests/: 401 passed

Submission Checklist

@cgoea
cgoea requested a review from a team August 12, 2026 18:34
@cgoea
cgoea changed the base branch from main to develop August 12, 2026 18:35
…by_arch

# Conflicts:
#	scripts/receive_therock/tests/therock_update_status_json_test.py
#	scripts/receive_therock/therock_update_status_json.py
@cgoea
cgoea changed the base branch from develop to main August 13, 2026 16:53

@HereThereBeDragons HereThereBeDragons left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

branch needs to be merged into develop

variants = _derive_variants(workflow_run, arch=arch)
status = _run_status(workflow_run)
if arch is not None and variants:
status = Variant.rollup_status(variants, status)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think here is the same question like in the other pr: _run_status should be part of the variants status, not the fallback?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch here is only ever set when the run reports multiple architectures, so _run_status (workflow_run) is a whole-run aggregate across all of them. Folding it into the rollup would broadcast one shared conclusion onto every architecture, and that's what we're trying to fix. added a comment to clarify

statuses.append(leaf.status)
candidate = leaf.model_copy(
update={
"status": rollup_statuses(statuses, leaf.status),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leaf.status does decide here, just earlier and conditionally "if single_arch: statuses.append(leaf.status)", which is intentional. that's what keeps a whole-run failure from being masked when there's only one architecture, without broadcasting it when there are several.

# Extracts the arch a job's own "Test | <arch>" segment names, if any, so
# jobs from different architectures nested under the same cell are never
# grouped together as if they were one architecture's result.
_TEST_ARCH_JOB_RE = re.compile(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coudl use _GPU_FAMILY_RE from therock_classify.py

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't reuse _GPU_FAMILY_RE, it's unanchored, and job names in this pipeline commonly carry a runner-label segment that embeds its own gfx-shaped substring alongside the real "Test | <arch_something>" segment. Scanning unanchored would pick up both as separate "architectures" for the same job and reintroduce the leakage we're trying to fix. I did pull the token shape out into a shared GPU_FAMILY_TOKEN constant in therock_classify.py so the two regexes can't drift independently.

# derived from the run's full, arch-blind job list -- into every target
# arch's slot. Re-derive a leaf scoped to each arch so one architecture's
# result can never be attributed to another's.
multi_arch = len(targets) > 1 and cls.pipeline_type in _VARIANT_AXIS_KEY

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right now we should not hit this branch as we currently only have: each test has a single gpu, not multiple different gpus.

as we might have in the future such test, claude suggest to add the following regression test:

def test_tmp_multi_arch_test_event_does_not_leak_or_alias_across_architectures() -> None:
    # TEMP (review): pins the multi_arch branch in _merge_run_into_document.
    run = _variant_run(
        pipeline_type="pytorch",
        pipeline_phase="test",
        architectures=["gfx942", "gfx1101"],
        run_id=902,
        conclusion="failure",
        jobs=[
            _job("py 3.12 | torch release/2.10 / Test | gfx942"),
            _job(
                "py 3.12 | torch release/2.10 / Test | gfx1101",
                conclusion="failure",
            ),
        ],
    )
    doc = StatusDocument()
    tusj._merge_run_into_document(doc, run, tusj._create_leaf(run))

    gfx942 = doc.pipelines.pytorch.test["linux"]["gfx942"]
    gfx1101 = doc.pipelines.pytorch.test["linux"]["gfx1101"]
    assert gfx942.status is Status.success
    assert gfx1101.status is Status.failure
    assert gfx942 is not gfx1101
    assert gfx942.variants is not gfx1101.variants

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

@cgoea
cgoea changed the base branch from main to develop August 14, 2026 09:48

@HereThereBeDragons HereThereBeDragons left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see the one comment otherwise lgtm

# test jobs get refreshed into already-existing per-arch test leaves):
# this pins _merge_run_into_document's own multi_arch branch, for a
# single *test*-phase event that itself reports more than one
# architecture in cls.architectures. No dispatcher today fans a single

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the "no dispatcher" part probably gets stale. either remove or otherwise at least add some date to it so one knows how old the statement is

@HereThereBeDragons

Copy link
Copy Markdown
Collaborator

(maybe double check pr description is up to date)

@cgoea
cgoea merged commit 2524fba into develop Aug 14, 2026
3 checks passed
@cgoea
cgoea deleted the users/cgoea/group_by_arch branch August 14, 2026 16:48
quartz-sync-github-app Bot pushed a commit that referenced this pull request Aug 14, 2026
2524fba, prevent cross-architectural leakeage in matrix_job_re (#76), Ciprian Goea (ciprian.goea@amd.com), Fri Aug 14 19:48:12 2026 +0300
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants