What to build
Split the transactional pipelines/multi-key operations in registry.py and the trace-writing path (trace_writer.py/span_recorder.py) that mix keys belonging to different logical entities — these can't share a Cluster hash tag and would throw CROSSSLOT under Cluster mode. Two known patterns:
Mode A — worker admin-state writes that also update the global admin-workers index set (ADMIN_WORKERS) in the same pipeline. Split into two independent, non-transactional writes; treat the index as best-effort/eventually-consistent, with the per-worker worker_admin(id) key as source of truth for reads.
Mode B — trace writes that mix the trace group (meta + spans, same entity, stays atomic once tagged in Phase 2a) with session/worker/agent_type index writes (different entities) in the same pipeline today — up to 5 different entity keys in one pipeline. Split into: (1) an atomic pipeline for trace_meta + trace_spans + their TTL, and (2) independent best-effort writes for each index key (trace_index_session/trace_index_worker/trace_index_agent), each individually try/caught and logged on failure without failing the parent trace write. This preserves the existing "trace writing is best-effort, never fails task execution" design principle in TraceWriteClient/SpanRecorder — it just narrows what's atomic.
Note: the two keys written together by deny_worker_for_type (agent_type_members + agent_type_denied) are explicitly NOT part of this split — they already share a hash tag from Phase 2a and keep their existing atomic write.
Acceptance criteria
Blocked by
#43
What to build
Split the transactional pipelines/multi-key operations in
registry.pyand the trace-writing path (trace_writer.py/span_recorder.py) that mix keys belonging to different logical entities — these can't share a Cluster hash tag and would throw CROSSSLOT under Cluster mode. Two known patterns:Mode A — worker admin-state writes that also update the global admin-workers index set (
ADMIN_WORKERS) in the same pipeline. Split into two independent, non-transactional writes; treat the index as best-effort/eventually-consistent, with the per-workerworker_admin(id)key as source of truth for reads.Mode B — trace writes that mix the trace group (meta + spans, same entity, stays atomic once tagged in Phase 2a) with session/worker/agent_type index writes (different entities) in the same pipeline today — up to 5 different entity keys in one pipeline. Split into: (1) an atomic pipeline for
trace_meta+trace_spans+ their TTL, and (2) independent best-effort writes for each index key (trace_index_session/trace_index_worker/trace_index_agent), each individually try/caught and logged on failure without failing the parent trace write. This preserves the existing "trace writing is best-effort, never fails task execution" design principle inTraceWriteClient/SpanRecorder— it just narrows what's atomic.Note: the two keys written together by
deny_worker_for_type(agent_type_members+agent_type_denied) are explicitly NOT part of this split — they already share a hash tag from Phase 2a and keep their existing atomic write.Acceptance criteria
ADMIN_WORKERSset update split into two independent calls; reads accept brief inconsistency of the indextrace_meta+trace_spans+expire pipeline and (b) per-index independent best-effort writes (session/worker/agent_type), each wrapped so failure doesn't propagate to the callertrace_meta/trace_spansfrom being read back correctly bytrace_iddeny_worker_for_typepath explicitly left untouched (still one atomic write, now sharing a tag from Phase 2a)Blocked by
#43