From 956967fbdcd4cd75c6174f30b1a599c08eadd882 Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Sat, 12 Sep 2026 23:57:42 -0700 Subject: [PATCH] fix(ci): apps/ contract JSON edits run the Python lane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _PY_SKIP includes apps/, so a change to apps/shared/src/gateway-events.json (or apps/desktop/src/lib/desktop-slash-registry.json) alone classified as python:false and tests/tui_gateway/test_gateway_event_contract.py — the only side that checks emitters against the JSON — never ran. "Either side drifting turns both red" was true locally and false in CI for that direction. A table of cross-language contract files now forces python:true alongside frontend; two classifier rows pin it (they fail without the allowlist). --- scripts/ci/classify_changes.py | 12 +++++++++++- tests/ci/test_classify_changes.py | 10 ++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/scripts/ci/classify_changes.py b/scripts/ci/classify_changes.py index aee7d724a6..558ccc12d5 100644 --- a/scripts/ci/classify_changes.py +++ b/scripts/ci/classify_changes.py @@ -91,6 +91,16 @@ _PY_RELEVANT_SITE = ( "website/docs/", "website/scripts/", ) +# Cross-language contract files: data committed under a frontend tree that a +# pytest pins against the Python side (emitter inventory, command registry). +# Editing only the JSON in an apps/-only PR would otherwise skip the one test +# that can catch the drift, so these force the Python lane too. +_PY_RELEVANT_CONTRACT_FILES = { + # tests/tui_gateway/test_gateway_event_contract.py + "apps/shared/src/gateway-events.json", + # tests/hermes_cli/test_desktop_slash_registry.py + "apps/desktop/src/lib/desktop-slash-registry.json", +} # CI-sensitive files: eslint config, workflow files, composite actions. # Changes here can influence what code the autofix job executes and pushes to @@ -147,7 +157,7 @@ def _is_nix(p: str) -> bool: def _py_irrelevant(p: str) -> bool: - if p.startswith(_PY_RELEVANT_SITE): + if p.startswith(_PY_RELEVANT_SITE) or p in _PY_RELEVANT_CONTRACT_FILES: return False return ( _is_docs(p) diff --git a/tests/ci/test_classify_changes.py b/tests/ci/test_classify_changes.py index a04a4dc4af..c3c12e9c9e 100644 --- a/tests/ci/test_classify_changes.py +++ b/tests/ci/test_classify_changes.py @@ -99,6 +99,16 @@ CASES = { _lanes(python=True, site=True), ), "frontend → no uv_lock": (["apps/desktop/src/store/profile.ts"], _lanes(frontend=True)), + # Cross-language contract JSON under apps/: the pytest that pins it against + # the Python side must run even when nothing else in the PR is Python. + "gateway-events contract JSON → python + frontend": ( + ["apps/shared/src/gateway-events.json"], + _lanes(python=True, frontend=True), + ), + "desktop slash-registry JSON → python + frontend": ( + ["apps/desktop/src/lib/desktop-slash-registry.json"], + _lanes(python=True, frontend=True), + ), # The published CIMD document is asserted about by the Python suite, so a # lone edit there must not skip the lane that would catch a bad edit. "cimd document → python + site": (