From 6212b5e4afd37494698dd03013af64c1e99a8571 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Wed, 15 Jul 2026 02:36:03 -0400 Subject: [PATCH] fix(ci): route root npm manifest changes into the Python lane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The change classifier treated package.json / package-lock.json as python-irrelevant, so a lockfile-only PR skipped the Python lane entirely. But several Python invariant tests read these files (assistant-ui tap cluster, electron pin, lazy-deps, lockfile churn) — so a lockfile change can break the Python suite. #63970 merged green (Python skipped on the PR) then reddened main (push fails open and runs everything). Drop root npm from the _py_irrelevant denylist so lockfile changes run Python, honoring the classifier's own contract: never skip a lane a change could break. Root npm still triggers the frontend lane as before. --- scripts/ci/classify_changes.py | 6 +++++- tests/ci/test_classify_changes.py | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/ci/classify_changes.py b/scripts/ci/classify_changes.py index 00ed02d6589..d9b55fb049f 100644 --- a/scripts/ci/classify_changes.py +++ b/scripts/ci/classify_changes.py @@ -56,7 +56,11 @@ def _is_docs(p: str) -> bool: def _py_irrelevant(p: str) -> bool: - return _is_docs(p) or p in _ROOT_NPM or p.startswith(_PY_SKIP) or p.startswith(_DOCKER_META) + # Root npm manifests are NOT python-irrelevant: several Python invariant + # tests read package.json / package-lock.json (tap-cluster, electron pin, + # lazy-deps, lockfile churn), so a lockfile-only change can break the Python + # suite. Omitting them here is what let #63970 merge green then redden main. + return _is_docs(p) or p.startswith(_PY_SKIP) or p.startswith(_DOCKER_META) def _is_scan(p: str) -> bool: diff --git a/tests/ci/test_classify_changes.py b/tests/ci/test_classify_changes.py index e1db0ccf20d..5a7f281c720 100644 --- a/tests/ci/test_classify_changes.py +++ b/tests/ci/test_classify_changes.py @@ -50,8 +50,10 @@ CASES = { "uv.lock → python": (["uv.lock"], _lanes(python=True)), "ts package → frontend": (["apps/desktop/src/app.tsx"], _lanes(frontend=True)), "ui-tui → frontend": (["ui-tui/src/entry.ts"], _lanes(frontend=True)), - # Lockfile bump shifts every TS package's tree, but not the Python suite. - "root lockfile → frontend, not python": (["package-lock.json"], _lanes(frontend=True)), + # Lockfile bump shifts every TS package's tree AND feeds Python invariant + # tests that read package-lock.json (tap-cluster, electron pin, lazy-deps). + "root lockfile → frontend + python": (["package-lock.json"], _lanes(frontend=True, python=True)), + "root package.json → frontend + python": (["package.json"], _lanes(frontend=True, python=True)), "website → site": (["website/docs/intro.md"], _lanes(site=True)), # SKILL.md reads like docs, but the skill-doc tests read skills/, so a # skill edit must still run Python.