fix(ci): repair red main — busy-mode test + missing checkout in skills-index workflows

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.
This commit is contained in:
kshitij
2026-08-11 21:11:07 +05:30
parent 936dd7346f
commit f51aa6a9b5
3 changed files with 31 additions and 2 deletions

View File

@@ -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: |

View File

@@ -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 }}

View File

@@ -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"