ci(base autofix): land the files of untouched areas when another area moved

Merged
TE
16d ago
+132-5

The base autofix almost never lands on feat-cmux-next, so its mechanical repairs (settings exports, defaults snapshot, CI target graph, namespace ratchet rows, webviews formatting) stay stale and show up as base reds on every PR. defaults-snapshot in cmux-next guards is red for this reason right now: the settings exports and schemas/defaults/cmux-next.json are behind the CmuxNextSettings sources.

Between 2026-10-19 10:00 and 2026-10-20 10:00 UTC, 4 of ~50 completed cmux-next base autofix runs landed (248 more were replaced while queued). The failed runs I checked all ended in "Push the repairs" with:

feat-cmux-next 6c0365c7453e changed this repair's inputs since 222bd45469c4 (actions settings shortcuts webviews); the newer run repairs it.
feat-cmux-next d5b20ab9a211 changed this repair's inputs since 7c13458751d5 (settings webviews); the newer run repairs it.
feat-cmux-next b137834bfce0 changed this repair's inputs since 8295cf4fb98e (actions graph settings shortcuts); the newer run repairs it.

The Mac export plus the autofix job take several minutes, and the branch moves every few minutes. When any area the repair covers had input changes in that window, the whole repair was dropped. graph reads all of Packages/, so a repair that carried the target graph basically never landed. Neither did the settings export that rode along with it.

Now each repaired file is judged on its own. A file lands on the moved tip only when none of its areas had input changes since HEAD_SHA and the tip didn't edit that file itself. Everything else waits for the next run, as before. The safety rule the loop already had still holds for every file it pushes: its inputs are unchanged, so the output from HEAD_SHA is exactly right at the tip. The kept files go on as a plain git apply --index of their diff (renames off), with no 3-way merge, so a changed context fails the run the way a conflict did before. The defaults snapshot never lands this way: defaults_guard.py also reads *Enabled flags and keybind lines across the CmuxNext sources, and no area tracks those. A run that lands only part of the repair still fails after the push. Both jobs take "since" from the last successful run, and a diff from HEAD_SHA might not flag a left-out file again (an output no input area claims, or a change that was reverted later). The red run keeps "since" at the last whole repair, so the next run regenerates a superset; areas that already landed come out with no diff.

This doesn't make defaults-snapshot green on its own. The settings export lands once a run finishes with no CmuxNextSettings change during its window, and that's now possible because the graph and webviews areas no longer drag it down.

Verification

python3 tests/test_cmux_next_base_autofix_finishes.py (it runs the real "Push the repairs" script against a local bare remote):

  • On d17b100bd089 (the red test on base ec83df89ccf4): test_the_unaffected_part_of_a_repair_lands_while_the_affected_part_waits fails with 1 != 0 : ::error::feat-cmux-next ... changed this repair's inputs since ... (settings); the newer run repairs it.
  • On the head (adbb84ea9108): 14 tests OK. That includes the new partial-repair tests and every existing one. The partial-repair tests cover: it stays partial when the base moves again, it never overwrites an output the tip edited, the snapshot never lands alone, and the run stays red. The existing tests still cover: an input change blocks its own files, an unknown output never re-applies, and a conflict fails without pushing.
  • An independent review of 5f39c3eb94f6 found that exiting 0 after a partial push could lose repairs, and that the snapshot depends on more than settings and actions. adbb84ea9108 fixes both, plus rename handling and a stale partial note.

This hasn't run against the real branch yet. The first push to feat-cmux-next after merge will.

Proof

Not UI: this only changes the base-autofix push step in a workflow and its test.

Changelog

none

🤖 Generated with Claude Code