fix: has_content_conflict_failure reads wrong CRDT key — auto-spawn mergemaster never fires

The function was calling `read_content(story_id)`, which returns the
story's *description* text (e.g. "Bug: Coder exits code 0 with
uncommitted work — force a commit-only respawn..."). It then scanned
that for "Merge conflict" / "CONFLICT (content):", which obviously
never matched, so the auto-spawn-mergemaster-on-content-conflict guard
in `pool/auto_assign/merge.rs` always saw `false` and skipped.

The actual gate output (where the merge runner stores the failure
message including conflict markers) lives at
`format!("{story_id}:gate_output")` — that's the key
`pipeline/advance/mod.rs:207` writes to. Read from there instead.

Witnessed: 954's merge hit a real `CONFLICT (content)` in
tests_regression.rs at 08:57:40, no mergemaster spawned, story stayed
in MergeFailure.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
dave
2026-05-13 09:03:25 +00:00
parent 6a015d6202
commit c228ae1640
@@ -72,9 +72,11 @@ pub(super) fn has_content_conflict_failure(
if !is_merge_failure { if !is_merge_failure {
return false; return false;
} }
// The projection does not carry the reason string; read the raw content // The projection does not carry the reason string; read the gate output
// from the CRDT content store and scan for conflict markers. // (where the merge runner persists the failure message) and scan for
crate::db::read_content(story_id) // conflict markers. NB: the key is `{story_id}:gate_output`, not `{story_id}`
// — the latter is the story's *description* text and would never match.
crate::db::read_content(&format!("{story_id}:gate_output"))
.map(|content| { .map(|content| {
content.contains("Merge conflict") || content.contains("CONFLICT (content):") content.contains("Merge conflict") || content.contains("CONFLICT (content):")
}) })