Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions engdocs/architecture/dispatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,18 @@ resolution and predicates: `bdReadyPoolDemandShell(limitFlag)` reads the
canonical `gc.routed_to=<target>` route with `--include-ephemeral`, and
the temporary migration predicate reads `gc.run_target=<target>` only on
`gc.kind=workflow` roots that predate root `gc.routed_to` stamping. The
work-query form appends `--sort oldest --limit=1` to the canonical probe
work-query form appends `--sort hybrid --limit=20` to the canonical probe
and prints the first match, then filters the migration probe to roots with
empty `gc.routed_to`. That is an intentional routed-queue policy:
unassigned routed pool work is FIFO before priority, so newer
high-priority work does not jump ahead of older ready work already queued
for the same target. The count form unions canonical and migration
probes and deduplicates by bead ID before piping through `jq 'length'`.
empty `gc.routed_to`. The `hybrid` sort is the routed-queue ordering policy
(ADR-0035): fresh work (`< 48h`) is ordered by bead priority, so a newly
routed P1 is claimed ahead of an older P2/P3, while work `>= 48h` old drains
strictly oldest-first, preserving the age-based anti-starvation drain the
prior `--sort oldest` was chosen for. `--limit=20` is an anti-self-block
lookahead (a self-blocked head falls through to ready work behind it), not a
priority window. The count form unions canonical and migration probes and
deduplicates by bead ID before piping through `jq 'length'`; it passes no
`--sort` (order is irrelevant to a length), so the worker-claim ordering does
not perturb the reconciler's spawn count.
Targets resolve to `Agent.PoolName` when set and
`Agent.QualifiedName()` otherwise, so pool instances and pool templates
land on the same routed queue.
Expand Down Expand Up @@ -260,7 +265,7 @@ regressions.
worker and reconciler must also share the temporary migration predicate
for `gc.run_target=<target>` on `gc.kind=workflow` roots with empty
`gc.routed_to`; only the worker's first-row form adds native
`bd ready --sort oldest --limit=1` selection to the canonical probe.
`bd ready --sort hybrid --limit=20` selection to the canonical probe.
Any pool-demand predicate change to one (added filter, modified target
resolution, new state) MUST be reflected in the other. Diverging the two
re-introduces the protocol-mismatch class — the reconciler
Expand Down Expand Up @@ -372,7 +377,7 @@ name = "coder"
pool = { min = 1, max = 3, check = "echo 2" }
# Default sling_query: bd update {} --set-metadata gc.routed_to=coder
# Default work_query: bd ready --include-ephemeral --metadata-field gc.routed_to=coder
# --unassigned --exclude-type=epic --json --sort oldest --limit=1,
# --unassigned --exclude-type=epic --json --sort hybrid --limit=20,
# then a temporary gc.run_target workflow-root migration fallback
```

Expand Down
81 changes: 48 additions & 33 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1912,7 +1912,7 @@ func TestEffectiveWorkQueryDefault(t *testing.T) {
if strings.Contains(got, `--include-ephemeral`) {
t.Errorf("EffectiveWorkQuery() default must be bd 1.0.4-compatible without --include-ephemeral: %q", got)
}
if !strings.Contains(got, `bd ready --metadata-field "gc.routed_to=$target" --unassigned --exclude-type=epic --json --sort oldest --limit=20`) {
if !strings.Contains(got, `bd ready --metadata-field "gc.routed_to=$target" --unassigned --exclude-type=epic --json --sort hybrid --limit=20`) {
t.Errorf("EffectiveWorkQuery() missing tier 3 pool-demand probe: %q", got)
}
if !strings.Contains(got, "-- mayor") {
Expand All @@ -1934,7 +1934,7 @@ func TestEffectiveWorkQueryDefault(t *testing.T) {
func TestEffectiveWorkQueryBD105CompatibilityOptIn(t *testing.T) {
a := Agent{Name: "mayor"}
got := a.EffectiveWorkQueryForBeads(BeadsConfig{BDCompatibility: BeadsBDCompatibility105})
if !strings.Contains(got, `bd ready --include-ephemeral --metadata-field "gc.routed_to=$target" --unassigned --exclude-type=epic --json --sort oldest --limit=20`) {
if !strings.Contains(got, `bd ready --include-ephemeral --metadata-field "gc.routed_to=$target" --unassigned --exclude-type=epic --json --sort hybrid --limit=20`) {
t.Errorf("EffectiveWorkQueryForBeads(bd-1.0.5) missing include-ephemeral routed probe: %q", got)
}
if !strings.Contains(got, `bd ready --include-ephemeral --assignee="$id" --json --limit=1`) {
Expand Down Expand Up @@ -2307,13 +2307,13 @@ func TestEffectiveWorkQueryControlDispatcherClaimsLegacyUnassignedRoute(t *testi
out := runEffectiveWorkQuery(t, a, nil, `#!/bin/sh
set -eu
case "$*" in
*"ready --include-ephemeral"*"--metadata-field gc.routed_to=gascity/control-dispatcher"*"--unassigned"*"--exclude-type=epic"*"--json"*"--sort oldest"*"--limit=20"*)
*"ready --include-ephemeral"*"--metadata-field gc.routed_to=gascity/control-dispatcher"*"--unassigned"*"--exclude-type=epic"*"--json"*"--sort hybrid"*"--limit=20"*)
printf '[]'
;;
*"ready --metadata-field gc.routed_to=gascity/control-dispatcher"*"--unassigned"*"--exclude-type=epic"*"--json"*"--sort oldest"*"--limit=20"*)
*"ready --metadata-field gc.routed_to=gascity/control-dispatcher"*"--unassigned"*"--exclude-type=epic"*"--json"*"--sort hybrid"*"--limit=20"*)
printf '[]'
;;
*"ready --metadata-field gc.routed_to=gascity/workflow-control"*"--unassigned"*"--exclude-type=epic"*"--json"*"--sort oldest"*"--limit=20"*)
*"ready --metadata-field gc.routed_to=gascity/workflow-control"*"--unassigned"*"--exclude-type=epic"*"--json"*"--sort hybrid"*"--limit=20"*)
printf '[{"id":"ga-legacy-route"}]'
;;
*)
Expand All @@ -2326,7 +2326,11 @@ esac
}
}

func TestEffectiveWorkQueryRoutedQueueUsesNativeOldestSortAcrossReadyTiers(t *testing.T) {
func TestEffectiveWorkQueryRoutedQueueUsesNativeHybridSortAcrossReadyTiers(t *testing.T) {
// ADR-0035 (vc-zv4y): Tier 3 delegates ordering to bd's NATIVE --sort
// (hybrid), not a jq-side re-sort, and returns bd's first row. This pins the
// native-sort composition and the first-row-only contract; the sort policy
// itself is asserted by TestEffectiveWorkQueryRoutedQueueUsesHybridSortHonoringPriority.
a := Agent{Name: "worker", Dir: "hello-world"}
got := a.EffectiveWorkQuery()
for _, want := range []string{
Expand All @@ -2342,19 +2346,19 @@ func TestEffectiveWorkQueryRoutedQueueUsesNativeOldestSortAcrossReadyTiers(t *te
}, `#!/bin/sh
set -eu
case "$*" in
"ready --metadata-field gc.routed_to=hello-world/worker --unassigned --exclude-type=epic --json --sort oldest --limit=20")
printf '[{"id":"older-no-history","priority":2,"created_at":"2026-05-20T06:09:30Z","no_history":true}]'
"ready --metadata-field gc.routed_to=hello-world/worker --unassigned --exclude-type=epic --json --sort hybrid --limit=20")
printf '[{"id":"first-routed","priority":2,"created_at":"2026-05-20T06:09:30Z","no_history":true}]'
;;
*)
printf '[]'
;;
esac
`)
if !strings.Contains(out, "older-no-history") {
t.Fatalf("EffectiveWorkQuery() did not pick oldest routed work: %q", out)
if !strings.Contains(out, "first-routed") {
t.Fatalf("EffectiveWorkQuery() did not return bd's first routed row (native hybrid sort): %q", out)
}
if strings.Contains(out, "newer-durable") {
t.Fatalf("EffectiveWorkQuery() returned more than first oldest routed work: %q", out)
if strings.Contains(out, "second-routed") {
t.Fatalf("EffectiveWorkQuery() returned more than the first routed row: %q", out)
}
}

Expand All @@ -2380,26 +2384,37 @@ func TestGeneratedBdReadCommandsStayBd104StorageCompatible(t *testing.T) {
}
}

func TestEffectiveWorkQueryRoutedQueueUsesOldestBeforePriority(t *testing.T) {
a := Agent{Name: "worker", Dir: "hello-world"}
out := runEffectiveWorkQuery(t, a, map[string]string{
"GC_SESSION_ORIGIN": "ephemeral",
}, `#!/bin/sh
set -eu
case "$*" in
*"ready --metadata-field gc.routed_to=hello-world/worker"*"--unassigned"*"--exclude-type=epic"*"--json"*"--sort oldest"*"--limit=20"*)
printf '[{"id":"older-p2","priority":2,"created_at":"2026-05-20T06:09:30Z"}]'
;;
*)
printf '[]'
;;
esac
`)
if !strings.Contains(out, "older-p2") {
t.Fatalf("EffectiveWorkQuery() did not pick oldest routed work across priorities: %q", out)
func TestEffectiveWorkQueryRoutedQueueUsesHybridSortHonoringPriority(t *testing.T) {
// ADR-0035 (vc-zv4y): the canonical Tier-3 routed predicate selects bd's
// `hybrid` sort so fresh work (<48h) is ordered by priority — a P1 created
// "now" ranks ahead of an older P2/P3 — while aged work (>=48h) still drains
// oldest-first (anti-starvation preserved). gascity's contract is SELECTING
// hybrid on the routed tier; bd owns the ORDER BY, and the end-to-end rank
// (P1 49 -> 1) is re-measured live post-deploy (ADR-0035 AC 3), which a mock
// bd cannot reproduce. This replaces the former ...UsesOldestBeforePriority
// test, which pinned the priority-blind FIFO this change removes.
mayor := Agent{Name: "mayor"}
cases := []struct {
name string
got string
}{
{"bd104", mayor.EffectiveWorkQuery()},
{"bd105", mayor.EffectiveWorkQueryForBeads(BeadsConfig{BDCompatibility: BeadsBDCompatibility105})},
}
if strings.Contains(out, "newer-p0") {
t.Fatalf("EffectiveWorkQuery() returned newer high-priority routed work before oldest: %q", out)
for _, tc := range cases {
// Canonical routed tier honors priority for fresh work via hybrid.
if !strings.Contains(tc.got, `--unassigned --exclude-type=epic --json --sort hybrid --limit=20`) {
t.Errorf("%s: routed tier must select bd --sort hybrid: %q", tc.name, tc.got)
}
// ...and must NOT revert to the priority-blind FIFO on the routed tier.
if strings.Contains(tc.got, `gc.routed_to=$target" --unassigned --exclude-type=epic --json --sort oldest`) {
t.Errorf("%s: routed tier still uses priority-blind --sort oldest: %q", tc.name, tc.got)
}
// The retiring migration probe (ga-dhf44) deliberately stays --sort
// oldest; the fix does not touch workquery.go:54.
if !strings.Contains(tc.got, `gc.run_target=$target" --metadata-field "gc.kind=workflow" --unassigned --exclude-type=epic --json --sort oldest --limit=20`) {
t.Errorf("%s: migration probe must remain --sort oldest (unchanged): %q", tc.name, tc.got)
}
}
}

Expand All @@ -2410,7 +2425,7 @@ func TestEffectiveWorkQueryRoutedFallbackUsesNativeOldestSort(t *testing.T) {
}, `#!/bin/sh
set -eu
case "$*" in
*"ready --metadata-field gc.routed_to=hello-world/worker"*"--unassigned"*"--exclude-type=epic"*"--json"*"--sort oldest"*"--limit=20"*)
*"ready --metadata-field gc.routed_to=hello-world/worker"*"--unassigned"*"--exclude-type=epic"*"--json"*"--sort hybrid"*"--limit=20"*)
printf '[]'
;;
*"ready --metadata-field gc.run_target=hello-world/worker"*"--metadata-field gc.kind=workflow"*"--unassigned"*"--exclude-type=epic"*"--json"*"--sort oldest"*"--limit=20"*)
Expand Down Expand Up @@ -2821,7 +2836,7 @@ func TestPoolDemandPredicateSharedWithWorkQuery(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
wq := tt.agent.EffectiveWorkQuery()
demand := tt.agent.EffectivePoolDemandQuery()
workPredicate := bdReadyPoolDemandShell("--sort oldest --limit=20", false)
workPredicate := bdReadyPoolDemandShell("--sort hybrid --limit=20", false)
if !strings.Contains(wq, workPredicate) {
t.Errorf("EffectiveWorkQuery() missing shared predicate %q in %q", workPredicate, wq)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sh -c 'case "$GC_SESSION_ORIGIN" in ephemeral|"") ;; *) exit 0 ;; esac; probe_pool_demand() { target="$1"; [ -z "$target" ] && return 1; r=$(bd ready --metadata-field "gc.routed_to=$target" --unassigned --exclude-type=epic --json --sort oldest --limit=20 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; legacy_candidates=$(bd ready --metadata-field "gc.run_target=$target" --metadata-field "gc.kind=workflow" --unassigned --exclude-type=epic --json --sort oldest --limit=20 2>/dev/null); r=$(printf "%s" "$legacy_candidates" | jq '\''[.[] | select((.metadata["gc.routed_to"] // "") == "")] | .[:1]'\'' 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; legacy_ephemeral_candidates=$({ bd query --json '\''ephemeral=true AND status=open'\'' --limit=0 2>/dev/null | jq --arg target "$target" '\''[.[] | select((.assignee // "") == "") | select(((.metadata["gc.routed_to"] // "") == $target) or (((.metadata["gc.routed_to"] // "") == "") and ((.metadata["gc.run_target"] // "") == $target) and ((.metadata["gc.kind"] // "") == "workflow"))) | select(((.issue_type // .type // "") != "epic")) | select(([ (.dependencies // [])[] | select((.type // .dep_type // "") as $t | ($t == "blocks" or $t == "waits-for" or $t == "conditional-blocks")) | select((.status // .depends_on_status // "") != "closed") ] | length) == 0)] | sort_by(.created_at // "") | .[:20]'\'' 2>/dev/null; } || printf "[]"); r=$(printf "%s" "$legacy_ephemeral_candidates" | jq '\''.[0:1]'\'' 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; return 1; }; probe_pool_demand "$1"; probe_pool_demand "$2"; printf "[]"' -- rig/control-dispatcher rig/workflow-control
sh -c 'case "$GC_SESSION_ORIGIN" in ephemeral|"") ;; *) exit 0 ;; esac; probe_pool_demand() { target="$1"; [ -z "$target" ] && return 1; r=$(bd ready --metadata-field "gc.routed_to=$target" --unassigned --exclude-type=epic --json --sort hybrid --limit=20 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; legacy_candidates=$(bd ready --metadata-field "gc.run_target=$target" --metadata-field "gc.kind=workflow" --unassigned --exclude-type=epic --json --sort oldest --limit=20 2>/dev/null); r=$(printf "%s" "$legacy_candidates" | jq '\''[.[] | select((.metadata["gc.routed_to"] // "") == "")] | .[:1]'\'' 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; legacy_ephemeral_candidates=$({ bd query --json '\''ephemeral=true AND status=open'\'' --limit=0 2>/dev/null | jq --arg target "$target" '\''[.[] | select((.assignee // "") == "") | select(((.metadata["gc.routed_to"] // "") == $target) or (((.metadata["gc.routed_to"] // "") == "") and ((.metadata["gc.run_target"] // "") == $target) and ((.metadata["gc.kind"] // "") == "workflow"))) | select(((.issue_type // .type // "") != "epic")) | select(([ (.dependencies // [])[] | select((.type // .dep_type // "") as $t | ($t == "blocks" or $t == "waits-for" or $t == "conditional-blocks")) | select((.status // .depends_on_status // "") != "closed") ] | length) == 0)] | sort_by(.created_at // "") | .[:20]'\'' 2>/dev/null; } || printf "[]"); r=$(printf "%s" "$legacy_ephemeral_candidates" | jq '\''.[0:1]'\'' 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; return 1; }; probe_pool_demand "$1"; probe_pool_demand "$2"; printf "[]"' -- rig/control-dispatcher rig/workflow-control
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sh -c 'case "$GC_SESSION_ORIGIN" in ephemeral|"") ;; *) exit 0 ;; esac; probe_pool_demand() { target="$1"; [ -z "$target" ] && return 1; r=$(bd ready --include-ephemeral --metadata-field "gc.routed_to=$target" --unassigned --exclude-type=epic --json --sort oldest --limit=20 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; legacy_candidates=$(bd ready --include-ephemeral --metadata-field "gc.run_target=$target" --metadata-field "gc.kind=workflow" --unassigned --exclude-type=epic --json --sort oldest --limit=20 2>/dev/null); r=$(printf "%s" "$legacy_candidates" | jq '\''[.[] | select((.metadata["gc.routed_to"] // "") == "")] | .[:1]'\'' 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; legacy_ephemeral_candidates=$(printf "[]"); r=$(printf "%s" "$legacy_ephemeral_candidates" | jq '\''.[0:1]'\'' 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; return 1; }; probe_pool_demand "$1"; probe_pool_demand "$2"; printf "[]"' -- rig/control-dispatcher rig/workflow-control
sh -c 'case "$GC_SESSION_ORIGIN" in ephemeral|"") ;; *) exit 0 ;; esac; probe_pool_demand() { target="$1"; [ -z "$target" ] && return 1; r=$(bd ready --include-ephemeral --metadata-field "gc.routed_to=$target" --unassigned --exclude-type=epic --json --sort hybrid --limit=20 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; legacy_candidates=$(bd ready --include-ephemeral --metadata-field "gc.run_target=$target" --metadata-field "gc.kind=workflow" --unassigned --exclude-type=epic --json --sort oldest --limit=20 2>/dev/null); r=$(printf "%s" "$legacy_candidates" | jq '\''[.[] | select((.metadata["gc.routed_to"] // "") == "")] | .[:1]'\'' 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; legacy_ephemeral_candidates=$(printf "[]"); r=$(printf "%s" "$legacy_ephemeral_candidates" | jq '\''.[0:1]'\'' 2>/dev/null); [ -n "$r" ] && [ "$r" != "[]" ] && printf "%s" "$r" && exit 0; return 1; }; probe_pool_demand "$1"; probe_pool_demand "$2"; printf "[]"' -- rig/control-dispatcher rig/workflow-control
Loading
Loading