Skip to main content

M11: Multi-Repo + Conflict Scenarios

2026-02-21T14:36:10Z by Showboat 0.6.0

M11 fixes the critical watcher bug (bd list --status open → bd ready join) and adds agent instructions for cross-repo dependencies, merge conflict resolution, and worktree isolation.

Act 1: Watcher Bug Fix — the key diff

git diff scripts/beads-watcher.sh | head -60
diff --git a/scripts/beads-watcher.sh b/scripts/beads-watcher.sh
index 4db24a0..5543c65 100755
--- a/scripts/beads-watcher.sh
+++ b/scripts/beads-watcher.sh
@@ -1,7 +1,11 @@
#!/usr/bin/env bash
# beads-watcher.sh — Tier 1 Watcher: routes ready beads by label.
#
-# Uses `bd list --status open --json` to find actionable beads (includes labels).
+# Uses a two-call join to find actionable beads:
+# 1. `bd ready --json` — IDs of beads with no unresolved blockers
+# 2. `bd list --status open --json` — full bead data including labels
+# 3. jq join — keeps only ready beads, preserving label metadata
+#
# Groups beads by compound label key, outputs WAKE lines.
# Unlabeled beads → WAKE eng-mgr (triage, Tier 4).
#
@@ -9,11 +13,6 @@
# WAKE line with sorted, dash-joined key: `WAKE dev-frontend <id>`.
# Single-label beads are unchanged: `WAKE dev <id>`.
#
-# NOTE: We use `bd list --status open` instead of `bd ready` because
-# `bd ready --json` does not include the labels field. For M2 (no
-# dependencies), the result set is equivalent. When dependencies are
-# introduced (M3+), this should be revisited to add blocker filtering.
-#
# Output format:
# WAKE <compound-label> <id1> [<id2> ...]
#
@@ -22,13 +21,24 @@

set -euo pipefail

-ready_json=$(bd list --status open --json 2>/dev/null)
-
-# Exit silently if no ready beads
-if [ -z "$ready_json" ] || [ "$ready_json" = "[]" ] || [ "$ready_json" = "null" ]; then
+# Get IDs of truly ready beads (respects deps via bd ready)
+ready_ids_json=$(bd ready --json 2>/dev/null)
+if [ -z "$ready_ids_json" ] || [ "$ready_ids_json" = "[]" ] || [ "$ready_ids_json" = "null" ]; then
exit 0
fi

+# Get full bead data (with labels) for all open beads
+all_open_json=$(bd list --status open --json 2>/dev/null)
+if [ -z "$all_open_json" ] || [ "$all_open_json" = "[]" ]; then
+ exit 0
+fi
+
+# Join: keep only beads whose ID is in the ready set, preserving labels
+ready_json=$(echo "$ready_ids_json" "$all_open_json" | jq -s '
+ (.[0] | map(.id)) as $ready_ids |
+ [ .[1][] | select(.id | IN($ready_ids[])) ]
+')
+
# Labeled beads: sort labels, join with "-" as compound key, group by compound key
labeled_output=$(echo "$ready_json" | jq -r '
[ .[] | select((.labels // []) | length > 0) ]

Act 2: M2 Regression Check — 8 existing watcher tests still pass

uv run pytest tests/test_m2_watcher_routing.py -v 2>&1
============================= test session starts ==============================
platform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/mhild/src/durandom/openclaw/b4arena/.venv/bin/python
cachedir: .pytest_cache
rootdir: /Users/mhild/src/durandom/openclaw/b4arena
configfile: pyproject.toml
collecting ... collected 8 items

tests/test_m2_watcher_routing.py::TestWatcherBasicRouting::test_single_labeled_bead PASSED [ 12%]
tests/test_m2_watcher_routing.py::TestWatcherBasicRouting::test_different_labels_separate_wake PASSED [ 25%]
tests/test_m2_watcher_routing.py::TestWatcherBasicRouting::test_unlabeled_routes_to_eng_mgr PASSED [ 37%]
tests/test_m2_watcher_routing.py::TestWatcherBasicRouting::test_no_ready_beads_no_output PASSED [ 50%]
tests/test_m2_watcher_routing.py::TestWatcherGrouping::test_same_label_grouped PASSED [ 62%]
tests/test_m2_watcher_routing.py::TestWatcherGrouping::test_multi_label_bead_compound_key PASSED [ 75%]
tests/test_m2_watcher_routing.py::TestWatcherEndToEnd::test_claimed_beads_excluded PASSED [ 87%]
tests/test_m2_watcher_routing.py::TestWatcherEndToEnd::test_realistic_mixed_scenario PASSED [100%]

============================== 8 passed in 15.70s ==============================

Act 3: M11 Tests — dependency blocking, watcher integration, SOUL.md content

uv run pytest tests/test_m11_multi_repo_conflicts.py -v 2>&1
============================= test session starts ==============================
platform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/mhild/src/durandom/openclaw/b4arena/.venv/bin/python
cachedir: .pytest_cache
rootdir: /Users/mhild/src/durandom/openclaw/b4arena
configfile: pyproject.toml
collecting ... collected 19 items

tests/test_m11_multi_repo_conflicts.py::TestCrossRepoDeps::test_dep_add_blocks_ready PASSED [ 5%]
tests/test_m11_multi_repo_conflicts.py::TestCrossRepoDeps::test_closing_blocker_unblocks PASSED [ 10%]
tests/test_m11_multi_repo_conflicts.py::TestCrossRepoDeps::test_dep_chain_three_beads PASSED [ 15%]
tests/test_m11_multi_repo_conflicts.py::TestWatcherRespectsBlockers::test_blocked_bead_excluded_from_wake PASSED [ 21%]
tests/test_m11_multi_repo_conflicts.py::TestWatcherRespectsBlockers::test_unblocked_after_close_appears_in_wake PASSED [ 26%]
tests/test_m11_multi_repo_conflicts.py::TestMultiRoundDispatch::test_round_one_only_unblocked PASSED [ 31%]
tests/test_m11_multi_repo_conflicts.py::TestMultiRoundDispatch::test_round_two_after_close PASSED [ 36%]
tests/test_m11_multi_repo_conflicts.py::TestMergeConflict::test_soul_has_conflict_section PASSED [ 42%]
tests/test_m11_multi_repo_conflicts.py::TestMergeConflict::test_soul_mentions_conflict_markers PASSED [ 47%]
tests/test_m11_multi_repo_conflicts.py::TestMergeConflict::test_soul_has_rebase_continue PASSED [ 52%]
tests/test_m11_multi_repo_conflicts.py::TestMergeConflict::test_soul_has_escalation PASSED [ 57%]
tests/test_m11_multi_repo_conflicts.py::TestMergeConflict::test_soul_old_vague_text_removed PASSED [ 63%]
tests/test_m11_multi_repo_conflicts.py::TestWorktreeWorkflow::test_soul_has_worktree_add PASSED [ 68%]
tests/test_m11_multi_repo_conflicts.py::TestWorktreeWorkflow::test_soul_has_worktree_remove PASSED [ 73%]
tests/test_m11_multi_repo_conflicts.py::TestCrossRepoDecomposition::test_soul_has_cross_repo_section PASSED [ 78%]
tests/test_m11_multi_repo_conflicts.py::TestCrossRepoDecomposition::test_soul_uses_dep_add PASSED [ 84%]
tests/test_m11_multi_repo_conflicts.py::TestCrossRepoDecomposition::test_soul_mentions_repo_in_description PASSED [ 89%]
tests/test_m11_multi_repo_conflicts.py::TestParallelBranches::test_soul_has_branch_naming PASSED [ 94%]
tests/test_m11_multi_repo_conflicts.py::TestParallelBranches::test_soul_has_bead_id_in_branch PASSED [100%]

============================= 19 passed in 19.22s ==============================

Act 4: Full Suite — 145 tests, 0 failures

uv run pytest tests/ -v --tb=no -q 2>&1 | tail -5
tests/test_m5_multi_project.py ...............                           [ 66%]
tests/test_m6_openclaw_integration.py ................... [ 79%]
tests/test_m7_live_bootstrap.py .............................. [100%]

======================= 145 passed in 155.88s (0:02:35) ========================