Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/split-reading-advisory.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Split-reading advisory
name: Split-reading ratchet (identity, manual dispatch)

# Source d'identite pour la garde absorbee par fast-lane-shadow (registre
# TRANCHE14 (ex-TRANCHE12 du registre avant renommage), issue #16762 — parapluie user « fusionner, pas empiler »).
Expand Down
43 changes: 43 additions & 0 deletions scripts/tests/test_fast_lane.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,49 @@ def test_delta_placeholders_are_resolvable():
assert "/tmp/b.json" in resolved and "/tmp/h.json" in resolved


def test_no_blocking_guard_is_read_as_advisory_by_pr_gate():
"""Un garde BLOQUANT ne doit pas etre classe advisory par `pr_gate`.

`pr_gate` range en advisory tout check-run dont le nom de job contient
`advisory`, OU dont le workflow d'origine sur disque porte `advisory` dans
son `name:` (`derive_advisory_jobs`). Un garde absorbe garde son workflow
d'origine comme cible d'identite (`job.name == Guard.name`) : si ce
workflow s'appelle encore « ... advisory » apres la promotion du garde en
bloquant, `pr_gate` range son rouge dans le seau advisory. Le merge reste
bloque par le job agrege de la voie rapide, mais le resume du gate nomme
ce job opaque au lieu du vrai garde, et classe le vrai garde comme un
simple signal. Mesure du 2026-09-26 : `Split-reading ratchet (base vs PR)`,
promu bloquant par #17044, sorti de `split-reading-advisory.yml` (workflow
`Split-reading advisory`) -- seule instance sur 40 gardes.
"""
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import fast_lane_registry
import pr_gate

advisory_jobs = pr_gate.derive_advisory_jobs()
assert advisory_jobs, "roster advisory vide : le controle serait aveugle"

guards = {}
for value in vars(fast_lane_registry).values():
if isinstance(value, list) and value and all(
isinstance(item, Guard) for item in value):
for guard in value:
guards[guard.name] = guard
assert len(guards) >= 30, f"registre lu partiellement : {len(guards)}"

misread = sorted(
name for name, guard in guards.items()
if guard.blocking and pr_gate._is_advisory_name(name, advisory_jobs))
assert misread == [], (
"gardes bloquants classes advisory par pr_gate (renommer le `name:` "
f"du workflow d'origine) : {misread}")

# controle positif : un garde advisory reste bien reconnu comme tel
advisory = [name for name, guard in guards.items() if not guard.blocking
and pr_gate._is_advisory_name(name, advisory_jobs)]
assert advisory, "aucun garde advisory reconnu : le predicat est muet"


def test_advisory_flags_match_the_source_workflows():
"""Le caractere advisory est une propriete du garde, pas du moteur.

Expand Down
Loading