Files
computer-playbook/utils/github/variant/instructions.py
kevinveenbirkenbachandClaude Opus 5 4193da1cb2 fix(ci): replay the instructions on a row that runs in the guide's mode
The replay is a second deploy on the same runner, and mark() only ever checked the variant number of a row, never its mode. So the marker landed on whichever row of the smallest variant came first, which for 38 of 98 marked rows was a swarm one: that runner would have had to bring a compose stack up beside a swarm stack.

Two places needed it. The row now has to run in the mode guide_deployable names, and only rows in that mode count as deployed when the search looks for the smallest variant - without the second half the search settles on a variant this sweep runs in swarm alone and the marker falls away silently.

Measured over the full matrix: 98 marked rows become 71, swarm drops from 38 to 0, compose rises from 47 to 59. The 27 roles that lose the replay entirely are the ones this sweep deploys in no compose row of an eligible variant; getting them back means forcing such a row into the sweep, which is a change to matrix selection rather than to this marker.

mark() had no tests. It has eight now, including the two failure modes the old code showed under a negative control: a swarm row carrying instructions=compose, and a compose row left unmarked because a swarm-only variant won the search.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 22:21:13 +02:00

69 lines
2.7 KiB
Python

"""Which matrix entry replays its role's README instructions.
The replay used to be a job of its own, picking one random role per run. It
rides on a deploy row instead: the role's smallest variant among the rows this
sweep actually deploys, marked with ``instructions`` (the mode the replay runs
in) and a 📖 in the job title. :mod:`utils.roles.guide` decides which variant
that is; this module is what turns the decision into matrix entries.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
from utils.roles.guide import guide_deployable, guide_variant
from utils.symbol_glossary import to_emoji
if TYPE_CHECKING:
from collections.abc import Mapping, Sequence
from typing import Any
def redundant(entry: Mapping[str, str]) -> bool:
"""Whether the sweep drops this row as coverage an earlier row already has."""
if entry["priority"] == "true":
return False
return entry["clone"] == "true" or entry["covered"] != "0"
def mark(
entries: list[dict[str, str]],
variants_per_app: Mapping[str, Sequence[Mapping[str, Any]]] | None,
) -> list[dict[str, str]]:
"""Hand one entry per role the replay, and give its label the 📖.
Only the first entry of the chosen variant: a priority row runs every mode
and onion state it offers, and replaying the same README block in each of
them proves nothing the first replay did not. The glyph goes between the
variant number and the ⭐ of a priority row, with no space between the two:
they are one marker block, not two axes.
The row has to run in the guide's own mode. The replay is a second deploy
on the same runner, so hanging it on a swarm row would ask that runner to
bring a compose stack up beside a swarm one. Only rows in that mode count
as deployed here either, so the variant search cannot settle on one that
this sweep runs in swarm alone.
"""
star = f" {to_emoji('priority')}"
deployed: dict[str, set[str]] = {}
for entry in entries:
app = entry["apps"]
if not redundant(entry) and entry["mode"] == guide_deployable(app):
deployed.setdefault(app, set()).add(entry["variant"])
marked: set[str] = set()
for entry in entries:
app = entry["apps"]
if app in marked or redundant(entry):
continue
variant, mode = guide_variant(app, variants_per_app, deployed.get(app, set()))
if not mode or entry["variant"] != variant or entry["mode"] != mode:
continue
entry["instructions"] = mode
entry["label"] = (
entry["label"].removesuffix(star)
+ f" {to_emoji('instructions')}"
+ (to_emoji("priority") if entry["priority"] == "true" else "")
)
marked.add(app)
return entries