hold-label-routed-to check and cache-reconcile fight over gc.routed_to on hold:<role> beads: --fix writes the bare value, the cache re-stamps the bound identity within seconds, warning never clears #23
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Filed by gastown.deacon during a patrol on 2026-09-07.
The defect
gc doctor --fixand the cache-reconcile write path disagree on the value ofgc.routed_tofor beads carryinghold:<role>labels, so thehold-label-routed-towarning can never stay clear and the two planes flap against each other.The check (cmd/gc/doctor_hold_label_routed_to.go) wants the BARE hold value:
hold:mayorrequiresgc.routed_to == "mayor". Its Fix writes that bare value through the raw store (store.SetMetadata).But a write of the bare value through
gc bd update --set-metadata gc.routed_to=mayoris normalized on the way in: reads through the CachingStore showgastown.mayor(the bound agent identity). And the cache-reconcile actor then re-stamps the bound identity back onto the raw store.Measured evidence (2026-09-07 22:55Z-23:15Z)
hold:mayorwithgc.routed_to="gastown.mayor"and no bare-value form anywhere.gc doctor --fix(second run, to completion) reported1 fixedand a greenhold-label-routed-to (fixed)in-process.gc bd update ce-0fmi --set-metadata gc.routed_to=mayorreturns success. A read 8s later showsmayor. A read 24s later showsgastown.mayoragain.cache-reconcileemits ce-0fmi withgc.routed_to:"mayor"(my write)cache-reconcileemits ce-0fmi withgc.routed_to:"gastown.mayor"(4 seconds later)gc doctorwarned again, count 55 (was 58). The population shifts between runs.Why it matters
The doctor warning is a standing false alarm AND a standing real one, depending on which plane you believe. The raw store holds the check's desired value for seconds at a time. The read plane agents actually consume holds the bound identity. Every patrol that sees the warning will re-run the fix, which re-flaps the write, which re-emits events for 55+ beads. That is a permanent treadmill under a check that looks like it converged.
The route-recovery lane already has vocabulary for this exact shape (route_recovery_lane.go: "a sibling lane is clearing gc.routed_to behind us... a faster treadmill is not a fix") but that lane only restores EMPTY routes, so it is not the reverter here; the cache-reconcile re-stamp is.
What the deacon did
gc doctor --fixtwice (second run to completion, reported1 fixed).gc.routed_to=mayoron the affected beads once viagc bd update(normalized away).gastown.mayor).Suggested direction (for the owner to decide)
The two components need one contract for what a
hold:<value>label implies forgc.routed_to:<value>through the same binding the CLI write path uses, and compare against the resolved form.gc.routed_tofor hold-labeled beads, and cache-reconcile must not re-stamp a value it did not observe a change for.Option 1 looks smaller: the check already has the city config in scope, and the CLI normalization is established behavior that other consumers may depend on.
Also worth a look in the same area:
cache-reconcilere-emitting a full bead snapshot 4s after an unrelated write makes every metadata diff on the city unreadable from events.jsonl, which is how this defect hid for a while (the event stream shows both values as writes from the same actor).