diff --git a/scripts/ci/classify_changes.py b/scripts/ci/classify_changes.py index 70d69c5553..7200475a2e 100644 --- a/scripts/ci/classify_changes.py +++ b/scripts/ci/classify_changes.py @@ -451,6 +451,22 @@ _E2E_LANES: dict[str, tuple[str, ...]] = { "hermes_cli/web_routers/status.py", ), } + + +def _with_package_inits(paths: tuple[str, ...]) -> tuple[str, ...]: + """Importing a/b/c.py runs a/__init__.py and a/b/__init__.py first, so a routed module + routes the package inits above it. A shared hub's inits run whenever the hub is imported, so + they are routed too; only an init that is itself a hub stays out.""" + root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + inits = [f"{'/'.join(parts[:i])}/__init__.py" + for p in (*paths, *sorted(_SHARED_HUBS)) if p.endswith(".py") + for parts in [p.split("/")[:-1]] for i in range(1, len(parts) + 1)] + return tuple(dict.fromkeys([*paths, *(i for i in inits if i not in _SHARED_HUBS + and os.path.isfile(os.path.join(root, i)))])) + + +for _lane in ("e2e_upgrade", "e2e_desktop_update"): + _E2E_LANES[_lane] = _with_package_inits(_E2E_LANES[_lane]) # The upgrade journeys are their own lane; editing one does not start ``e2e``. # The update suite shares apps/desktop/e2e/ with the core suite but not its specs. _E2E_LANE_EXCLUDES = { diff --git a/tests/ci/test_update_ci_routing.py b/tests/ci/test_update_ci_routing.py index 1fa3e06180..7863d9a79a 100644 --- a/tests/ci/test_update_ci_routing.py +++ b/tests/ci/test_update_ci_routing.py @@ -650,6 +650,8 @@ def _imports(path: Path) -> frozenset[str]: base = ".".join([*parts, base] if base else parts) names.add(base) names.update(f"{base}.{a.name}" for a in node.names) + # Importing a.b.c runs a/__init__.py and a/b/__init__.py first. + names |= {".".join(n.split(".")[:i]) for n in names for i in range(1, n.count(".") + 1)} found = set() for name in names: target = _module_file(name) diff --git a/tests/ci/test_update_transitive_routing.py b/tests/ci/test_update_transitive_routing.py index 6aeab38360..e2d21445c0 100644 --- a/tests/ci/test_update_transitive_routing.py +++ b/tests/ci/test_update_transitive_routing.py @@ -17,6 +17,9 @@ from tests.ci.test_update_ci_routing import _REPO, _ci_run, _consumers_reached, # backup is the update transaction's pre-build step, not a build dependency. @pytest.mark.parametrize("path", [ "hermes_cli/local_runtime/processes.py", + # Importing processes runs the package init: v2026.9.24's update died there on a name + # the init's eager imports needed from an already-loaded module. + "hermes_cli/local_runtime/__init__.py", "agent/deadline.py", "agent/memory_provider.py", "pm/plugins_state.py",