Skip to content

fix(queue): unstall batch construction -- porcelain parse + pre-push regeneration - #740

Merged
matt82198 merged 2 commits into
mainfrom
fix/queue-batch-push-unstall
Aug 3, 2026
Merged

matt82198 merged 2 commits into
mainfrom
fix/queue-batch-push-unstall

Conversation

@matt82198

Copy link
Copy Markdown
Owner

Fixes the merge-queue stall that grew the board to 38 open PRs while the AesopMergeQueue daemon reported PASSED on every pass.

Why nothing was merging

Three independent causes, two fixed here:

1. dirty_paths off-by-one (fixed). It sliced the porcelain line at a fixed column (line[3:]). git() strips its output, so an unstaged modification arrives as M path, not M path, and the slice ate the first character — tests/CLAUDE.md parsed as ests/CLAUDE.md. Every registered generated file then read as an unregistered edit, so worktree_is_safe() answered working tree is dirty forever and no integration branch could be built at all. Reproduced live against the deployed tree. The status field is now matched, not sliced, which is correct for both the raw and stripped forms.

2. Batch union fails a gate every member passed (fixed). A batch is a tree no member ever tested. When two individually-green members each add a test file, the suite counts in tests/CLAUDE.md are correct on both branches and wrong on their union. The pre-push hook ran the drift gate and fail-closed, so the batch push died with [DRIFT] Test suite count mismatch in tests/CLAUDE.md: Python: CLAUDE.md says 235, actual is 236 and the queue was left holding a branch it could never publish (git_failed row, 2026-08-03T08:00:09Z). regenerate_on_batch now runs the generators on the batch branch before the push and commits ONLY paths in the GENERATED_PATHS registry.

3. #712 poisons every batch (not fixed here; #712 held as queue-rejected). #712 wires import_resolution_check into ci.yml as a hard 'Sibling import guard' step. The checker on main does not yet recognize the sanctioned sys.path idiom and flags tools/merge_queue.py:68-69, failing ci (0) on every integration branch. #712's own green check predates merge_queue.py landing on main, so it reads individually-green while poisoning each batch it joins. #724 fixes the checker — land #724 first, then re-admit #712.

No gate is weakened

Same generator the gate itself calls; the gate still runs on the pushed branch and in CI; a generator that fails, is missing, or writes an unregistered path commits nothing and the push fails closed exactly as before (regenerator_failed / regenerator_overreach exception rows).

Bonus defect

The registry names --fix, not --regenerate: the pre-push hook's own failure text advises a flag verify_test_suite_count.py rejects (unrecognized arguments). A test now invokes each generator's real argument parser rather than trusting the string.

Tests

122 in tests/test_merge_queue.py (8 new), all proven to fail against the pre-fix module:

  • OLD parse of stripped form: ['ests/CLAUDE.md'] vs NEW: ['tests/CLAUDE.md']
  • OLD has REGENERATORS: False

test_merge_queue.py + test_merge_train.py: 164 passed.

🤖 Generated with Claude Code

…regeneration

Two independent defects left the merge-queue advancer reporting PASSED every
pass while merging nothing; the board grew to 38 open PRs.

1. dirty_paths sliced the porcelain line at a fixed column (line[3:]). git()
   strips its output, so an unstaged modification arrives as 'M path' rather
   than ' M path' and the slice ate the first character of the path
   ('ests/CLAUDE.md'). Every registered generated file therefore read as an
   unregistered edit, worktree_is_safe answered 'working tree is dirty'
   forever, and no integration branch could be built at all. The status field
   is now matched, not sliced, which is correct for both forms.

2. A batch is a tree no member ever tested: when two individually-green members
   each add a test file, the suite counts in tests/CLAUDE.md are right on both
   branches and wrong on their union. The pre-push hook ran the drift gate and
   fail-closed, so the batch push died with '[DRIFT] Test suite count mismatch'
   and the queue held a branch it could never publish. regenerate_on_batch now
   runs the generators on the batch branch before the push and commits ONLY
   paths in the GENERATED_PATHS registry.

No gate is weakened: the same generator the gate calls is used, the gate still
runs on the pushed branch and in CI, a generator that fails or writes an
unregistered path commits nothing and the push fails closed as before.

The registry names --fix, not --regenerate: the pre-push hook's own failure
text advises a flag verify_test_suite_count.py rejects, so a test invokes each
generator's real argument parser rather than trusting the string.

Tests: 122 in test_merge_queue.py (8 new), all proven to fail against the
pre-fix module.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@matt82198 matt82198 added merge-queue Queued for the merge-queue advancer daemon merge-priority Jump the merge queue labels Aug 3, 2026
tools/CLAUDE.md is already 151 lines on main (the linter counts
content.split("\n"), so a trailing newline is the 151st element). ci.yml's
"CLAUDE.md linter gate (scope invariant)" step therefore fails ci (0) on every
PR branched after the file crossed the cap -- #693 and this branch both hit it
while main itself stayed green, because that gate does not run on push to main.

Folds alert_bridge.py and dep_graph.py onto one row -- the same pairing this
file already uses for launch_tui.py / orchestrator_status.py. No entry is lost.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@matt82198
matt82198 merged commit 272c44b into main Aug 3, 2026
12 checks passed
@matt82198
matt82198 deleted the fix/queue-batch-push-unstall branch August 3, 2026 08:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-priority Jump the merge queue merge-queue Queued for the merge-queue advancer daemon

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant