ci: point the feat-cmux-next acpmux channel at each daemon-tested tree

Merged
TE
10d ago
+392-1

Merge held for Leo's OK on trust and security. This adds point-feat-channel to the jobs that get the R2 credentials (the artifacts environment allowlist in tests/test_ci_production_secrets_protected_env.py), and Linux fleet hosts run the build that this channel names (acpmux host self-update, #24232). Codex xhigh review: SHIP at 94897124 (the first, at 0e002721, blocked on a malformed channel file being overwritten without a compare; fixed).

Summary

Leo: "BRO CANT YOU JUST LIKE SUSPEND SHIT AFTER A TOOL CALL/TURN THEN JUST GO AND AUTOUPDATE OUR TEAMMATES NEED ACPMUX UPDATING TOO..."

Leo: "how do we get cmux next users (esp just the team rn) to update to the latest acpmux daemon!?"

Split out of #24232 to keep that PR under the size limit and to review the trust change on its own. #24232's self-update reads this channel; until this lands it finds no channel and changes nothing.

  • After a feat-cmux-next push whose cmux-tui tree is published and daemon-tested, the new point-feat-channel job in cmux-tui-artifacts.yml points cmux-tui/channels/feat-cmux-next.json at that tree. The file holds the tree key, the commit and the sha256 of each cmux-tui-acpmux-<target>.
    • Runs only in manaflow-ai/cmux on push to refs/heads/feat-cmux-next, in environment: artifacts, with permissions: contents: read and persist-credentials: false.
  • scripts/ci/cmux-tui-point-channel.sh moves the pointer only forward:
    • it writes when the GitHub compare status from the named commit to this one is exactly ahead, or when there is no channel file yet;
    • it leaves the pointer and exits 0 on behind, identical, diverged, a failed compare, a non-JSON compare answer, a failed channel read, a channel file that names no valid commit (not JSON, no or a malformed commit), or a tree without the daemon-tests.json marker;
    • it writes with a compare-and-swap on the bytes it compared (upload-r2-object.py --replace-sha256, or --write-once for the first file). If another run wrote first, it reads and compares again, up to 5 times.
  • No concurrency group: GitHub keeps one pending job per group and replaces it with whichever queues next, which can be an older push's. The compare-and-swap makes overlapping runs safe instead.

Leo-ask: ask-48bbaec1d4
Leo-ask: ask-061e3574a6
Leo-ask: ask-98502f19a4

Changelog

  • Internal: CI publishes a feat-cmux-next channel file that Linux hosts read to keep their acpmux daemon on the newest daemon-tested build.

Tests

  • tests/test_cmux_tui_point_channel.py runs the real script with a fake curl and a fake uploader: first write, forward move, every refusal above, and three race orders. Against the old script from #24232's first head, 15 of its checks fail, including "older run loses the race and moves the pointer back" and a downgrade on a failed compare. Registered as linux-guard, with a step in ci-guards.yml.
  • tests/test_ci_production_secrets_protected_env.py lists the new artifacts job and checks it gets only the R2 upload secrets.

Observed / Not run

  • Observed: test_cmux_tui_point_channel.py, test_ci_production_secrets_protected_env.py and validate_test_execution_registry.py pass on this branch.
  • Not run: the job itself, which runs only on a feat-cmux-next push.

No capture: CI only.

Agent session: Air-Blue

šŸ¤– Generated with Claude Code