From f51aa6a9b5ce514e15f8e337777f522fd5cc6fa2 Mon Sep 17 00:00:00 2001 From: kshitij <82637225+kshitijk4poor@users.noreply.github.com> Date: Tue, 11 Aug 2026 21:11:07 +0530 Subject: [PATCH] =?UTF-8?q?fix(ci):=20repair=20red=20main=20=E2=80=94=20bu?= =?UTF-8?q?sy-mode=20test=20+=20missing=20checkout=20in=20skills-index=20w?= =?UTF-8?q?orkflows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three separate reds on main. Two are fixed here; the third needs no code. 1. tests/gateway/test_multiplex_busy_input_mode.py (blocks every merge) Fails "Python tests / Run tests slice 5/12" and therefore "All required checks pass". Semantic merge conflict between two PRs merged ~1h apart: a31be480 fix(gateway): respect routed profile busy modes (added the test) c8f235a1 feat(gateway): allow selective multiplex profile serving (added the gate) c8f235a1 taught _profile_name_for_source to reject a route whose target profile is not in the served set (profiles_to_serve). Each PR was green on its own base; neither ran against the other's merge result. The test asserts a route to profile "research" resolves to that profile's busy mode, but never patches profiles_to_serve — so it reads the runner's REAL on-disk profiles. "research" is not among them, the route is rejected before the busy-mode snapshot is consulted, and the assertion gets the gateway default: WARNING gateway.run: Rejecting profile route 'research-chat': target profile 'research' is not served AssertionError: assert 'interrupt' == 'steer' Patch profiles_to_serve for the assertion — the same seam every sibling test in tests/gateway/test_profile_resolution.py already patches (test_route_inside_allowlist_resolves, test_route_outside_allowlist_rejects). This also removes an ambient-state dependency: the test previously passed or failed based on which profiles happened to exist on the machine running it. Verified passing under an empty HERMES_HOME. Test-only. The serving gate from c8f235a1 is correct and left intact. 2. Skills-index workflows: local action used without actions/checkout check-freshness has failed on all 12 of its last 12 scheduled runs: ##[error]Can't find 'action.yml', 'action.yaml' or 'Dockerfile' under '.../.github/actions/get-app-token'. Did you forget to run actions/checkout before running your local action? ./.github/actions/get-app-token is a LOCAL composite action and cannot resolve without the repo on disk. skills-index-freshness.yml had no checkout step at all. The step is gated on `status != 'ok'`, so the watchdog broke exactly when it was supposed to file its issue — the live index is currently 521.4h stale (limit 26h) and nobody was told. An audit of all workflows for this bug class found one more instance: skills-index.yml's `trigger-deploy` job, which re-triggers the docs deploy so a refreshed index reaches the live site. Its sibling `build-index` job checks out; this one did not. That is plausibly why the index went stale in the first place. Both are fixed; the audit now reports zero remaining jobs that use a local action without a prior checkout. Pinned to the same actions/checkout SHA used by the other 35 call sites. 3. "Publish inline E2E evidence" — no fix needed Failed once at 13:33Z on a transient TLS error reaching api.github.com ("certificate is not valid for any names") while installing a gh extension. The last 25 runs of that workflow are 25/25 success. Infra blip, not a code defect. --- .github/workflows/skills-index-freshness.yml | 8 ++++++++ .github/workflows/skills-index.yml | 7 +++++++ .../gateway/test_multiplex_busy_input_mode.py | 18 ++++++++++++++++-- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/workflows/skills-index-freshness.yml b/.github/workflows/skills-index-freshness.yml index 9e4b2767be..ff2bc393aa 100644 --- a/.github/workflows/skills-index-freshness.yml +++ b/.github/workflows/skills-index-freshness.yml @@ -23,6 +23,14 @@ jobs: timeout-minutes: 10 environment: trusted-automation steps: + # `Get GitHub App token` below is a LOCAL composite action + # (./.github/actions/get-app-token), so the repository must be on disk + # before it can be resolved. Without this checkout the job dies with + # "Can't find 'action.yml' ... under .github/actions/get-app-token" + # every time the probe is non-ok — i.e. exactly when the watchdog is + # supposed to file its issue. + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Probe live index id: probe run: | diff --git a/.github/workflows/skills-index.yml b/.github/workflows/skills-index.yml index 5415499e02..cf6812630e 100644 --- a/.github/workflows/skills-index.yml +++ b/.github/workflows/skills-index.yml @@ -63,12 +63,19 @@ jobs: timeout-minutes: 15 environment: trusted-automation steps: + # Required: `Get GitHub App token` is a LOCAL composite action + # (./.github/actions/get-app-token) and cannot resolve without the repo + # checked out. `build-index` above already does this; this job did not, + # so the scheduled deploy re-trigger never fired. + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Get GitHub App token id: app-token uses: ./.github/actions/get-app-token with: client-id: ${{ vars.APP_CLIENT_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} + - name: Trigger Deploy Site workflow env: GH_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/tests/gateway/test_multiplex_busy_input_mode.py b/tests/gateway/test_multiplex_busy_input_mode.py index d23c3c062f..c7cfbfe1f7 100644 --- a/tests/gateway/test_multiplex_busy_input_mode.py +++ b/tests/gateway/test_multiplex_busy_input_mode.py @@ -1,7 +1,8 @@ """Profile-specific busy-input behavior for multiplexed gateways.""" import asyncio -from unittest.mock import AsyncMock, MagicMock +from pathlib import Path +from unittest.mock import AsyncMock, MagicMock, patch import pytest @@ -336,7 +337,20 @@ def test_profile_route_and_nonmultiplexed_resolution_preserve_boundaries(): ] source = _event(profile=None).source - assert runner._effective_busy_input_mode(source) == "steer" + # `_profile_name_for_source` rejects a route whose target profile is not in + # the served set (`profiles_to_serve`). Without this patch the test reads + # the runner's real on-disk profiles, so "research" is unserved on any + # machine that does not happen to have it — and the route is rejected + # before the busy-mode snapshot is consulted. Sibling coverage in + # tests/gateway/test_profile_resolution.py patches the same seam. + with patch( + "hermes_cli.profiles.profiles_to_serve", + return_value=[ + ("default", Path("/profiles/default")), + ("research", Path("/profiles/research")), + ], + ): + assert runner._effective_busy_input_mode(source) == "steer" runner.config.multiplex_profiles = False source.profile = "research"