fix(ci): replay the mesh state of the row that failed

failed_selections reproduced mode, onion state, distro and architecture
but not the mesh axis. These tokens feed the priority line, where an
unpinned axis offers both states, so a failed direct swarm row came back
as itself and as a meshed sibling: two jobs to reproduce one.

Only a mode the axis covers takes the pin. pinned_vpn_states returns an
empty list for a compose row pinned to the mesh, and an empty list drops
the row from the matrix -- the class ff75343aba already had to fix once
for held runs.

The fixture had drifted from what the matrix emits: row_label built
titles with no mesh glyph while axes.assign writes one for every swarm
and compose row, so parse_label fell back to its False default and the
new &direct assertion would have been right by accident. row_label and
deploy_job_name now place the glyph under the same condition as
axes.assign, and a meshed row has a case of its own, which nothing
covered before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5 committed 2026-10-19 03:25:39 +02:00
1 parent cfe20f0726
commit 4915a401d4
3 files changed
+37 -8

No files matched your search

+10 -1
View File
@@ -1,13 +1,20 @@
"""Turn a run's deploy jobs back into selection tokens.
A deploy job title carries the whole row it deployed -- role, variant, mode,
onion state, distro, filesystem, architecture -- and
onion state, mesh state, distro, filesystem, architecture -- and
:mod:`utils.github.variant.selection` is the grammar that writes it back down.
The architecture is replayed like the distro rather than left to the rotation:
it is the machine the job ran on, not a preference the deploy may fall back
from, so the title states what it actually was.
The mesh state is replayed the same way, and as the boolean the title carried
rather than only when it is true. These tokens feed the priority line, where
an unpinned mesh axis offers both states: a failed direct swarm row came back
as itself *and* as a meshed sibling, spending two jobs to reproduce one. The
pin halves that to the arm that actually failed. Only a mode the mesh axis
covers takes it, so a compose token stays as short as it was.
The filesystem is the one axis a token built here leaves out. The title states
the kind the matrix *assigned*, which a deploy is allowed to fall back from
when the host cannot serve it, so the title does not prove what the job ran on.
@@ -24,6 +31,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from utils.github.variant import axes, selection
from utils.github.variant.vpn import VPN_DEPLOY_MODES
if TYPE_CHECKING:
from collections.abc import Iterable, Mapping
@@ -68,6 +76,7 @@ def failed_selections(jobs: list[dict], *, strict: bool = False) -> list[str]:
label.tor,
label.distro or None,
architecture=label.architecture or None,
vpn=label.vpn if label.mode in VPN_DEPLOY_MODES else None,
)
)
)
@@ -15,9 +15,9 @@ from tests.utils.ci.run_name import render
from utils.github.variant.pools import ARCHITECTURES, DISTROS, FILESYSTEMS
def _job(mode: str, app: str, conclusion: str) -> dict:
def _job(mode: str, app: str, conclusion: str, *, vpn: bool = False) -> dict:
return {
"name": deploy_job_name(mode, app, "0,1"),
"name": deploy_job_name(mode, app, "0,1", vpn=vpn),
"status": "completed",
"conclusion": conclusion,
}
@@ -46,10 +46,12 @@ the effective one, while the architecture is the machine the job really ran
on."""
_FAILED_TOKENS = (
f"web-app-x#0,1@swarm+clearnet{_AXES} web-app-y#0,1@compose+clearnet{_AXES}"
f"web-app-x#0,1@swarm+clearnet{_AXES}&direct"
f" web-app-y#0,1@compose+clearnet{_AXES}"
)
"""What _JOBS failed at, exactly: x in swarm, y in compose, both on variant
shard 0,1, both on the clearnet and both on the same distro."""
shard 0,1, both on the clearnet and both on the same distro. Only the swarm
row states its mesh state, because the mesh axis covers no other mode."""
_RUN_URL = "https://github.com/o/r/actions/runs/55" # nocheck: url
_SOURCE_CONFIG = {
@@ -156,7 +158,15 @@ class TestTriggerMain(unittest.TestCase):
_rc, calls = self._run(["--failed"], run={"_jobs": both})
self.assertEqual(
calls[0][3],
f"web-app-x#0,1@compose+clearnet{_AXES} web-app-x#0,1@swarm+clearnet{_AXES}",
f"web-app-x#0,1@compose+clearnet{_AXES}"
f" web-app-x#0,1@swarm+clearnet{_AXES}&direct",
)
def test_a_meshed_swarm_row_comes_back_meshed(self) -> None:
meshed = [_job("swarm", "web-app-x", "failure", vpn=True)]
_rc, calls = self._run(["--failed"], run={"_jobs": meshed})
self.assertEqual(
calls[0][3], f"web-app-x#0,1@swarm+clearnet{_AXES}&vpn"
)
def test_never_deployed_priority_roles_join_the_retrigger(self) -> None:
+12 -2
View File
@@ -23,6 +23,7 @@ from utils.github.variant.axes import (
LOCAL_GLYPH,
TOR_DEPLOY_MODES,
)
from utils.github.variant.vpn import VPN_DEPLOY_MODES
from utils.roles.display import display_names
from utils.symbol_glossary import to_emoji
@@ -58,14 +59,16 @@ def row_label(
variant: str = "",
*,
tor: bool = False,
vpn: bool = False,
priority: bool = False,
distro: str = DISTROS[0],
filesystem: str = FILESYSTEMS[0],
architecture: str = ARCHITECTURES[0],
) -> str:
"""The ``matrix.label`` axes assigns to one row: mode glyph, tor glyph on
the modes that carry the onion axis, distro, filesystem and architecture
glyphs, display name, and the priority star."""
the modes that carry the onion axis, mesh glyph on the modes that carry
the mesh axis, distro, filesystem and architecture glyphs, display name,
and the priority star."""
deploy_mode = _MODE_NAMES[mode]
glyphs = to_emoji(deploy_mode)
glyphs += (
@@ -73,6 +76,11 @@ def row_label(
if deploy_mode in TOR_DEPLOY_MODES
else LOCAL_GLYPH
)
glyphs += (
to_emoji("vpn" if vpn else "direct")
if deploy_mode in VPN_DEPLOY_MODES or deploy_mode == "compose"
else ""
)
glyphs += to_emoji(distro) + to_emoji(filesystem) + to_emoji(architecture)
label = f"{glyphs}{display_names().encode(app, variant)}"
return f"{label} {to_emoji('priority')}" if priority else label
@@ -84,6 +92,7 @@ def deploy_job_name(
variant: str = "",
*,
tor: bool = False,
vpn: bool = False,
priority: bool = False,
distro: str = DISTROS[0],
filesystem: str = FILESYSTEMS[0],
@@ -112,6 +121,7 @@ def deploy_job_name(
app,
variant,
tor=tor,
vpn=vpn,
priority=priority,
distro=distro,
filesystem=filesystem,