Skip to content

Use quartz_tracking_id for owner run-id and release_type classification - #87

Merged
HereThereBeDragons merged 3 commits into
developfrom
users/lpromber/quartz_tracking_id
Aug 27, 2026
Merged

Use quartz_tracking_id for owner run-id and release_type classification#87
HereThereBeDragons merged 3 commits into
developfrom
users/lpromber/quartz_tracking_id

Conversation

@HereThereBeDragons

Copy link
Copy Markdown
Collaborator

Summary

TheRock now propagates a quartz_tracking_id input on every workflow it
triggers, formatted as <github.run_id>;<release_type> (empty when tracking is
disabled). The github.run_id half is the top-level multi_arch_release.yml
orchestrator run that owns the whole release lineage, and the release_type
half is the channel it published to. Both values are authoritative, so we read
them straight from this field instead of reconstructing them.

This replaces the previous heuristic chains for both derivations. The owner
run-id no longer walks artifact_run_id inputs, artifact-bucket URL parsing, or
the immediate GitHub parent; the release_type no longer falls back to a
top-level release_type key or the RELEASE_TYPE env var. The orchestrator's
own record still owns itself via the existing base case (it generates the id but
does not carry it on its own inputs), and inputs.release_type is retained as
the direct-input fallback for that record and for manual dispatches.

Changes

  • Add parse_quartz_tracking_id() in therock_types.py as the single split
    point for the <run_id>;<release_type> field, shared by from_dict and the
    classifier.
  • derive_effective_owner_run_id() reads the owner from quartz_tracking_id;
    delete the artifact_run_id / URL-parsing / parent-walk reconstruction
    (_input_int, _input_url_run_id, _ARTIFACT_URL_RUN_ID_RE).
  • from_dict sources release_type from quartz_tracking_id first, then the
    inputs.release_type fallback.
  • Introduce KNOWN_RELEASE_TYPES mirroring the orchestrator's own enum, and
    extend the accepted set to include the dev-bkc and nightly-bkc channels
    (previously coerced to None). This is the input accept-list and is
    deliberately broader than the _TRACKED_RELEASE_TYPES publish subset.
  • derive_source_run_id (artifact-bucket run id) is unchanged; it is a
    separate concept and still reads the immediate GitHub parent before the owner
    is normalized.

Test plan

  • pytest tests/therock_classify_test.py tests/therock_types_test.py
  • Owner run-id: descendant reads quartz id; run-id parsed without the
    ;<release_type> suffix; missing/empty id returns None; orchestrator owns
    itself.
  • release_type: quartz wins over inputs.release_type; input fallback still
    works; dev-bkc / nightly-bkc pass through; unrecognized coerced to None.
  • classify() ordering: source_run_id still keys off the immediate parent.

@HereThereBeDragons
HereThereBeDragons requested review from a team and cgoea August 25, 2026 19:58

@cgoea cgoea left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@marbre marbre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Two findings from my agent. Posted the first at the function, whereas the second might not be valid and depends on how this is handled cross-repo. Might need a fallback for JAX or might not, but please check before landing:


Finding 2: Removing the artifact_run_id/URL-based owner fallback may regress owner resolution for external PyTorch/JAX release triggers

File: scripts/receive_therock/therock_classify.py:311 (derive_effective_owner_run_id)

The PR removes the artifact_run_id/URL-based owner fallback in favor of reading the owner solely from the propagated quartz_tracking_id. The deleted test test_falls_back_to_find_links_url_run_id documented that:

Upstream benc-uk dispatches that don't carry an artifact_run_id input
(e.g. the real PyTorch/JAX release triggers) still carry the top-level run
id baked into the artifact bucket path.

If TheRock cannot add a new quartz_tracking_id input to those externally-hosted workflows — the same constraint that historically prevented adding artifact_run_id or rocm_version there, per therock_types_test.py's own comment on test_pytorch_wheels_full.yml — those runs would now resolve to no owner at all.

The existing _is_ownerless_pytorch_leaf_for_release escape hatch (therock_update_status_json.py:898) only covers pipeline_type == "pytorch" (explicitly "the sole ownerless-acceptance path", line 906-907 comment). An equivalent externally-dispatched JAX release-trigger run has no fallback and would be silently excluded from status.json.

Caveat: this can't be fully confirmed from the Quartz repo alone — it depends on whether TheRock's paired change actually propagates the new quartz_tracking_id input to those specific external workflows. Worth confirming with the TheRock-side companion PR before/at merge.

Comment on lines +53 to +72
def parse_quartz_tracking_id(inputs: dict[str, Any]) -> tuple[int | None, str | None]:
"""Split the propagated `quartz_tracking_id` into (owner_run_id, release_type).

The top-level `multi_arch_release.yml` orchestrator stamps every workflow it
triggers with `quartz_tracking_id: "<github.run_id>;<release_type>"` (empty
when tracking is disabled). `github.run_id` is the orchestrator's own run, the
top-level owner of the whole release lineage, and `release_type` is the
channel it published to. Both are authoritative for every descendant run, so
they are read straight from here rather than reconstructed from artifact ids,
URLs, or the immediate GitHub parent.

Returns `(None, None)` when the input is absent or empty (CI runs, manual
TheRock dispatches, and the orchestrator's own record, which generates the id
but does not carry it on its own inputs).
"""
raw = inputs.get("quartz_tracking_id")
if not isinstance(raw, str) or not raw.strip():
return None, None
run_id_part, _, release_type_part = raw.partition(";")
return _parse_int(run_id_part.strip()), release_type_part.strip() or None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My review agent was flagging the following with regards to this function:


Malformed quartz_tracking_id is silently coerced to None instead of raising

File: scripts/receive_therock/therock_types.py:72 (the _parse_int helper it calls is at line 44; parse_quartz_tracking_id def at line 53)

def _parse_int(value: Any) -> int | None:
    if value in (None, ""):
        return None
    try:
        return int(str(value))
    except ValueError:
        return None


def parse_quartz_tracking_id(inputs: dict[str, Any]) -> tuple[int | None, str | None]:
    ...
    raw = inputs.get("quartz_tracking_id")
    if not isinstance(raw, str) or not raw.strip():
        return None, None
    run_id_part, _, release_type_part = raw.partition(";")
    return _parse_int(run_id_part.strip()), release_type_part.strip() or None  # line 72

_parse_int swallows ValueError and returns None for any non-numeric string. This violates the project's fail-fast convention: a malformed quartz_tracking_id (e.g. "123abc;nightly" instead of "123;nightly", producer-side bug) should be a loud failure, not a silent None.

Confirmed directly:

>>> parse_quartz_tracking_id({"quartz_tracking_id": "123abc;nightly"})
(None, "nightly")

Why it isn't caught upstream

release_type is parsed independently from the second half of the same string, in WorkflowRunRecord.from_dict (therock_types.py:761, parsing at lines 795-796). So release_typestill resolves to"nightly"` correctly even when the run-id half is garbage — the run looks "tracked" and nothing about it looks broken on the surface.

Where it actually bites

  • derive_effective_owner_run_id (scripts/receive_therock/therock_classify.py:311) calls parse_quartz_tracking_id again at line 327 and returns the None run-id as wr.trigger_workflow_run_id.
  • That flows into _gate_to_document_owner (scripts/receive_therock/therock_update_status_json.py:915):
    • owner = doc.trigger_workflow_run_id (line 926) — a real run id from the existing status.json document, not None/0.
    • parent = workflow_run.trigger_workflow_run_id (line 927) — None, because of the bug.
    • Falls into the parent in (None, 0) branch (line 939):
      workflow_run.workflow_run_id == owner is false (this is a leaf run, not the top-level orchestrator), and _is_ownerless_pytorch_leaf_for_release (line 898, restricted to pipeline_type == "pytorch" at line 909) doesn't rescue a non-pytorch leaf.
    • Result: _gate_to_document_owner returns False; the update is skipped with only an log.info at lines 947-952 — no warning, no error, no exception.

Net effect

A malformed quartz_tracking_id from any producer-side bug causes a real leaf run's data to be silently dropped from status.json, logged at info level indistinguishably from the legitimate "this run doesn't belong to this release" case. No existing test in therock_types_test.py or therock_classify_test.py exercises a non-numeric run-id half.

Suggested fix direction

parse_quartz_tracking_id should raise (e.g. ValueError) when the run-id half is present but non-numeric, distinguishing that from the legitimate "absent tracking id" case (None, None) — so a corrupted producer payload fails loudly instead of being silently absorbed into the ownerless-leaf gating path.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

addressed

@HereThereBeDragons

Copy link
Copy Markdown
Collaborator Author

discarding: "Finding 2: Removing the artifact_run_id/URL-based owner fallback may regress owner resolution for external PyTorch/JAX release triggers"
we own those workflows - so not a problem. with ROCm/TheRock#7665 we even have end to end testing that we dont forget a workflow

@HereThereBeDragons
HereThereBeDragons merged commit afe85d7 into develop Aug 27, 2026
2 checks passed
@HereThereBeDragons
HereThereBeDragons deleted the users/lpromber/quartz_tracking_id branch August 27, 2026 18:25
quartz-sync-github-app Bot pushed a commit that referenced this pull request Aug 27, 2026
afe85d7, Use quartz_tracking_id for owner run-id and release_type classification (#87), Laura Promberger (laura.promberger@amd.com), Thu Aug 27 20:25:51 2026 +0200
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.

3 participants