"""Fix 5 PR3 tests — per-role serial queue semantics. Covers: - Schema + model roundtrip for ``pending_work_item_ids``. - Atomic enqueue/dequeue helpers (FIFO, idempotent, busy check). - ``enqueue_session_work_on_runnable_hook`` firing only when the feature flag is on AND the session is focused on a different work item. - ``clear_session_focus_on_terminal_hook`` dequeuing the next pending work item and clearing its ``queued_behind_session`` stamp. - ``is_dispatchable`` returns False for items stamped with ``queued_behind_session``. The flag defaults to ON. Compatibility tests can still flip ``store.role_serial_queue_enabled = False`` before acting. """ from __future__ import annotations import tempfile import textwrap import unittest from pathlib import Path from opc.core.config import OPCConfig from opc.core.models import ( DelegationRoleSession, DelegationWorkItem, Phase, SeatState, Task, TaskStatus, ) from opc.database.store import OPCStore from opc.layer2_organization import phase_hooks # noqa: F401 (registers hooks) from opc.layer2_organization.phase import is_dispatchable from opc.layer2_organization.phase_hooks import reconcile_role_serial_queues class _StoreFixture(unittest.IsolatedAsyncioTestCase): async def asyncSetUp(self) -> None: self._tmpdir = tempfile.TemporaryDirectory() self.store = OPCStore(db_path=Path(self._tmpdir.name) / "store.db") await self.store.initialize() async def asyncTearDown(self) -> None: await self.store.close() self._tmpdir.cleanup() # ── Schema + model roundtrip ───────────────────────────────────────────── class SchemaRoundtripTests(_StoreFixture): async def test_pending_work_item_ids_persists(self) -> None: session = DelegationRoleSession( role_session_id="role-runtime::r::cto", run_id="r", role_id="cto", pending_work_item_ids=["wi-1", "wi-2", "wi-3"], ) await self.store.save_delegation_role_session(session) loaded = await self.store.get_delegation_role_session("role-runtime::r::cto") self.assertIsNotNone(loaded) self.assertEqual(loaded.pending_work_item_ids, ["wi-1", "wi-2", "wi-3"]) async def test_default_pending_is_empty_list(self) -> None: session = DelegationRoleSession( role_session_id="role-runtime::r::cto", run_id="r", role_id="cto", ) await self.store.save_delegation_role_session(session) loaded = await self.store.get_delegation_role_session("role-runtime::r::cto") self.assertEqual(loaded.pending_work_item_ids, []) async def test_legacy_role_statuses_normalize_to_three_states(self) -> None: cases = [ ("cold", "", "idle", ""), ("reserved", "wi-1", "running", "wi-1"), ("running", "", "idle", ""), ("idle", "wi-stale", "idle", ""), ("dead", "", "blocked", ""), ("handoff_pending", "wi-2", "blocked", "wi-2"), ] for index, (status, focus, expected_status, expected_focus) in enumerate(cases): sid = f"role-runtime::r::legacy-{index}" await self.store.save_delegation_role_session( DelegationRoleSession( role_session_id=sid, run_id="r", role_id=f"legacy-{index}", status=status, focused_work_item_id=focus, ) ) loaded = await self.store.get_delegation_role_session(sid) self.assertEqual(loaded.status, expected_status) self.assertEqual(loaded.focused_work_item_id, expected_focus) async def test_seat_status_and_resident_status_normalize_together(self) -> None: seat = SeatState( seat_state_id="seat-state::r::cto", team_instance_id="team-instance::r::cto", run_id="r", team_id="team::cto", seat_id="seat::cto", role_id="cto", status="reserved", resident_status="cold", current_work_item_id="wi-1", ) await self.store.save_seat_state(seat) loaded = await self.store.get_seat_state(seat.seat_state_id) self.assertEqual(loaded.status, "running") self.assertEqual(loaded.resident_status, "running") # ── Atomic enqueue/dequeue + busy check ───────────────────────────────── class QueueHelperTests(_StoreFixture): async def _seed_session(self, *, focused: str = "") -> str: sid = "role-runtime::r::cto" session = DelegationRoleSession( role_session_id=sid, run_id="r", role_id="cto", focused_work_item_id=focused, status="running" if focused else "idle", ) await self.store.save_delegation_role_session(session) return sid async def test_enqueue_appends_in_order(self) -> None: sid = await self._seed_session() self.assertTrue(await self.store.enqueue_pending_work_item(sid, "wi-1")) self.assertTrue(await self.store.enqueue_pending_work_item(sid, "wi-2")) self.assertTrue(await self.store.enqueue_pending_work_item(sid, "wi-3")) loaded = await self.store.get_delegation_role_session(sid) self.assertEqual(loaded.pending_work_item_ids, ["wi-1", "wi-2", "wi-3"]) async def test_enqueue_duplicate_is_noop(self) -> None: sid = await self._seed_session() self.assertTrue(await self.store.enqueue_pending_work_item(sid, "wi-1")) # Second enqueue returns False and leaves the queue intact. self.assertFalse(await self.store.enqueue_pending_work_item(sid, "wi-1")) loaded = await self.store.get_delegation_role_session(sid) self.assertEqual(loaded.pending_work_item_ids, ["wi-1"]) async def test_enqueue_unknown_session_returns_false(self) -> None: self.assertFalse( await self.store.enqueue_pending_work_item("no::such::session", "wi-1") ) async def test_dequeue_pops_fifo_head(self) -> None: sid = await self._seed_session() for wid in ("wi-1", "wi-2", "wi-3"): await self.store.enqueue_pending_work_item(sid, wid) self.assertEqual(await self.store.dequeue_pending_work_item(sid), "wi-1") self.assertEqual(await self.store.dequeue_pending_work_item(sid), "wi-2") loaded = await self.store.get_delegation_role_session(sid) self.assertEqual(loaded.pending_work_item_ids, ["wi-3"]) async def test_dequeue_empty_queue_returns_none(self) -> None: sid = await self._seed_session() self.assertIsNone(await self.store.dequeue_pending_work_item(sid)) async def test_role_session_is_busy_reflects_focus(self) -> None: sid = await self._seed_session(focused="wi-current") self.assertTrue(await self.store.role_session_is_busy(sid)) other = await self._seed_other_session() self.assertFalse(await self.store.role_session_is_busy(other)) async def _seed_other_session(self) -> str: sid = "role-runtime::r::cmo" session = DelegationRoleSession( role_session_id=sid, run_id="r", role_id="cmo", ) await self.store.save_delegation_role_session(session) return sid # ── is_dispatchable honors queued stamp ────────────────────────────────── class IsDispatchableQueueFilterTests(unittest.TestCase): def test_returns_false_when_queued_behind_session_stamp_present(self) -> None: item = DelegationWorkItem( work_item_id="wi-queued", run_id="r", cell_id="c", role_id="cto", seat_id="seat", manager_role_id="", manager_seat_id="", title="t", phase=Phase.READY, metadata={"queued_behind_session": "role-runtime::r::cto"}, ) self.assertFalse(is_dispatchable(item)) def test_returns_true_for_runnable_without_stamp(self) -> None: item = DelegationWorkItem( work_item_id="wi-fresh", run_id="r", cell_id="c", role_id="cto", seat_id="seat", manager_role_id="", manager_seat_id="", title="t", phase=Phase.READY, ) self.assertTrue(is_dispatchable(item)) def test_empty_stamp_is_treated_as_not_queued(self) -> None: item = DelegationWorkItem( work_item_id="wi-empty", run_id="r", cell_id="c", role_id="cto", seat_id="seat", manager_role_id="", manager_seat_id="", title="t", phase=Phase.READY, metadata={"queued_behind_session": ""}, ) self.assertTrue(is_dispatchable(item)) def test_returns_false_when_company_runtime_dispatch_hold_present(self) -> None: item = DelegationWorkItem( work_item_id="wi-suspended", run_id="r", cell_id="c", role_id="cto", seat_id="seat", manager_role_id="", manager_seat_id="", title="t", phase=Phase.RUNNING, metadata={"dispatch_hold": "company_runtime_suspended"}, ) self.assertFalse(is_dispatchable(item)) def test_passive_review_parent_without_claim_is_not_dispatchable(self) -> None: for phase in (Phase.AWAITING_MANAGER_REVIEW, Phase.AWAITING_HUMAN): with self.subTest(phase=phase): item = DelegationWorkItem( work_item_id=f"wi-{phase.value}", run_id="r", cell_id="c", role_id="cto", seat_id="seat", manager_role_id="ceo", manager_seat_id="seat::ceo", title="t", phase=phase, ) self.assertFalse(is_dispatchable(item)) # ── enqueue_session_work_on_runnable_hook ──────────────────────────────── class EnqueueHookTests(_StoreFixture): async def _seed_session(self, *, focused: str = "") -> str: sid = "role-runtime::r::cto" session = DelegationRoleSession( role_session_id=sid, run_id="r", role_id="cto", focused_work_item_id=focused, status="running" if focused else "idle", ) await self.store.save_delegation_role_session(session) return sid async def _save_runnable_item( self, *, wid: str, sid: str ) -> DelegationWorkItem: item = DelegationWorkItem( work_item_id=wid, run_id="r", cell_id="c", role_id="cto", seat_id="seat", role_runtime_session_id=sid, manager_role_id="ceo", manager_seat_id="seat::ceo", title="t", phase=Phase.READY, ) await self.store.save_delegation_work_item(item) return item async def test_flag_off_is_noop(self) -> None: # Flag defaults to False — enqueueing a runnable work item for a # busy session must NOT touch the session queue or stamp metadata. sid = await self._seed_session(focused="wi-current") self.store.role_serial_queue_enabled = False await self._save_runnable_item(wid="wi-new", sid=sid) session = await self.store.get_delegation_role_session(sid) self.assertEqual(session.pending_work_item_ids, []) item = await self.store.get_delegation_work_item("wi-new") self.assertNotIn("queued_behind_session", item.metadata) async def test_flag_on_busy_session_enqueues(self) -> None: sid = await self._seed_session(focused="wi-current") self.store.role_serial_queue_enabled = True await self._save_runnable_item(wid="wi-new", sid=sid) session = await self.store.get_delegation_role_session(sid) self.assertEqual(session.pending_work_item_ids, ["wi-new"]) item = await self.store.get_delegation_work_item("wi-new") self.assertEqual(item.metadata.get("queued_behind_session"), sid) # Stamped item is no longer dispatchable — the claim filter skips it. self.assertFalse(is_dispatchable(item)) async def test_flag_on_idle_session_does_not_enqueue(self) -> None: # An idle session (no focus) should let the work item proceed # through the normal claim path — not get queued. sid = await self._seed_session(focused="") self.store.role_serial_queue_enabled = True await self._save_runnable_item(wid="wi-new", sid=sid) session = await self.store.get_delegation_role_session(sid) self.assertEqual(session.pending_work_item_ids, []) item = await self.store.get_delegation_work_item("wi-new") self.assertNotIn("queued_behind_session", item.metadata) async def test_same_item_as_focus_not_queued(self) -> None: # If the session's focus IS the work item whose phase is moving # (e.g. a re-READY cycle after rework), we must NOT enqueue # against itself — the session is actively handling it. sid = await self._seed_session(focused="wi-same") self.store.role_serial_queue_enabled = True await self._save_runnable_item(wid="wi-same", sid=sid) session = await self.store.get_delegation_role_session(sid) self.assertEqual(session.pending_work_item_ids, []) # ── clear_session_focus_on_terminal_hook — dequeue path ───────────────── class DequeueOnTerminalTests(_StoreFixture): async def test_flag_on_terminal_dequeues_and_clears_stamp(self) -> None: sid = "role-runtime::r::cto" session = DelegationRoleSession( role_session_id=sid, run_id="r", role_id="cto", focused_work_item_id="wi-active", status="running", pending_work_item_ids=["wi-next", "wi-later"], ) await self.store.save_delegation_role_session(session) self.store.role_serial_queue_enabled = True # Queued item has the stamp from when it was enqueued. queued = DelegationWorkItem( work_item_id="wi-next", run_id="r", cell_id="c", role_id="cto", seat_id="s", manager_role_id="ceo", manager_seat_id="seat::ceo", role_runtime_session_id=sid, title="t", phase=Phase.READY, metadata={"queued_behind_session": sid}, ) await self.store.save_delegation_work_item(queued) later = DelegationWorkItem( work_item_id="wi-later", run_id="r", cell_id="c", role_id="cto", seat_id="s", manager_role_id="ceo", manager_seat_id="seat::ceo", role_runtime_session_id=sid, title="t", phase=Phase.READY, metadata={"queued_behind_session": sid}, ) await self.store.save_delegation_work_item(later) # The active work item transitions to APPROVED — terminal. Seed # a linked task so the task.status sync hook also gets its input. task = Task( id="task-active", title="t", description="", assigned_to="cto", status=TaskStatus.RUNNING, project_id="p", session_id="s", ) await self.store.save_task(task) active = DelegationWorkItem( work_item_id="wi-active", run_id="r", cell_id="c", role_id="cto", seat_id="s", manager_role_id="ceo", manager_seat_id="seat::ceo", role_runtime_session_id=sid, title="t", phase=Phase.RUNNING, ) await self.store.save_delegation_work_item(active) await self.store.link_work_item_runtime_task(active.work_item_id, task.id) await self.store.update_delegation_work_item( "wi-active", phase=Phase.APPROVED ) # Head of queue ("wi-next") has been dequeued; stamp removed. session_after = await self.store.get_delegation_role_session(sid) self.assertEqual(session_after.pending_work_item_ids, ["wi-later"]) queued_after = await self.store.get_delegation_work_item("wi-next") self.assertNotIn("queued_behind_session", queued_after.metadata) self.assertTrue(is_dispatchable(queued_after)) async def test_flag_off_terminal_does_not_dequeue(self) -> None: sid = "role-runtime::r::cto" session = DelegationRoleSession( role_session_id=sid, run_id="r", role_id="cto", focused_work_item_id="wi-active", status="running", pending_work_item_ids=["wi-next"], ) await self.store.save_delegation_role_session(session) self.store.role_serial_queue_enabled = False # explicit active = DelegationWorkItem( work_item_id="wi-active", run_id="r", cell_id="c", role_id="cto", seat_id="s", manager_role_id="ceo", manager_seat_id="seat::ceo", role_runtime_session_id=sid, title="t", phase=Phase.RUNNING, ) await self.store.save_delegation_work_item(active) await self.store.update_delegation_work_item( "wi-active", phase=Phase.APPROVED ) # Queue untouched when flag is off. session_after = await self.store.get_delegation_role_session(sid) self.assertEqual(session_after.pending_work_item_ids, ["wi-next"]) # ── serial queue reconciler ────────────────────────────────────────────── class SerialQueueReconcilerTests(_StoreFixture): async def _seed_session( self, *, sid: str = "role-runtime::r::cto", focused: str = "", pending: list[str] | None = None, status: str | None = None, ) -> str: session = DelegationRoleSession( role_session_id=sid, run_id="r", role_id=sid.rsplit("::", 1)[-1], focused_work_item_id=focused, status=status or ("running" if focused else "idle"), pending_work_item_ids=list(pending or []), ) await self.store.save_delegation_role_session(session) return sid async def _save_item( self, *, wid: str, sid: str, phase: Phase = Phase.READY, marker: bool = False, ) -> DelegationWorkItem: item = DelegationWorkItem( work_item_id=wid, run_id="r", cell_id="c", role_id=sid.rsplit("::", 1)[-1], seat_id="seat", manager_role_id="ceo", manager_seat_id="seat::ceo", role_runtime_session_id=sid, title="t", phase=phase, metadata={"queued_behind_session": sid} if marker else {}, ) await self.store.save_delegation_work_item(item) return item async def test_reconcile_clears_stale_marker_for_idle_empty_queue(self) -> None: self.store.role_serial_queue_enabled = True sid = await self._seed_session() await self._save_item(wid="wi-ready", sid=sid, marker=True) result = await reconcile_role_serial_queues(self.store, "r") self.assertIn("wi-ready", result["cleared_markers"]) item = await self.store.get_delegation_work_item("wi-ready") self.assertNotIn("queued_behind_session", item.metadata) self.assertTrue(is_dispatchable(item)) async def test_reconcile_preserves_valid_marker_for_busy_session(self) -> None: self.store.role_serial_queue_enabled = True sid = await self._seed_session(focused="wi-active", pending=["wi-next"]) active = await self._save_item(wid="wi-active", sid=sid, phase=Phase.RUNNING) active.claimed_by_role_runtime_session_id = sid active.claimed_by_seat_id = "seat" await self.store.save_delegation_work_item(active) await self._save_item(wid="wi-next", sid=sid, marker=True) result = await reconcile_role_serial_queues(self.store, "r") self.assertEqual(result["cleared_markers"], []) session = await self.store.get_delegation_role_session(sid) self.assertEqual(session.pending_work_item_ids, ["wi-next"]) item = await self.store.get_delegation_work_item("wi-next") self.assertEqual(item.metadata.get("queued_behind_session"), sid) self.assertFalse(is_dispatchable(item)) async def test_reconcile_promotes_aux_behind_unclaimed_review_focus(self) -> None: self.store.role_serial_queue_enabled = True sid = await self._seed_session( focused="wi-parent", pending=["wi-report"], status="running", ) await self._save_item( wid="wi-parent", sid=sid, phase=Phase.AWAITING_MANAGER_REVIEW, ) report = await self._save_item(wid="wi-report", sid=sid, marker=True) report.metadata.update({ "report_execution_work_item": True, "report_target_work_item_id": "wi-parent", }) await self.store.save_delegation_work_item(report) result = await reconcile_role_serial_queues(self.store, "r") self.assertIn(sid, result["cleared_focus_session_ids"]) self.assertIn("wi-report", result["promoted_work_item_ids"]) session = await self.store.get_delegation_role_session(sid) self.assertEqual(session.focused_work_item_id, "") self.assertEqual(session.pending_work_item_ids, []) report_after = await self.store.get_delegation_work_item("wi-report") self.assertNotIn("queued_behind_session", report_after.metadata) self.assertTrue(is_dispatchable(report_after)) async def test_reconcile_preserves_live_claimed_review_focus(self) -> None: self.store.role_serial_queue_enabled = True sid = await self._seed_session( focused="wi-parent", pending=["wi-report"], status="running", ) parent = await self._save_item( wid="wi-parent", sid=sid, phase=Phase.AWAITING_MANAGER_REVIEW, ) parent.claimed_by_role_runtime_session_id = sid parent.claimed_by_seat_id = "seat" await self.store.save_delegation_work_item(parent) await self._save_item(wid="wi-report", sid=sid, marker=True) result = await reconcile_role_serial_queues(self.store, "r") self.assertEqual(result["cleared_focus_session_ids"], []) self.assertEqual(result["promoted_work_item_ids"], []) session = await self.store.get_delegation_role_session(sid) self.assertEqual(session.focused_work_item_id, "wi-parent") self.assertEqual(session.pending_work_item_ids, ["wi-report"]) report = await self.store.get_delegation_work_item("wi-report") self.assertEqual(report.metadata.get("queued_behind_session"), sid) self.assertFalse(is_dispatchable(report)) async def test_reconcile_prunes_dead_entries_and_promotes_one_head(self) -> None: self.store.role_serial_queue_enabled = True sid = "role-runtime::r::cto" await self._save_item(wid="wi-done", sid=sid, phase=Phase.APPROVED, marker=True) await self._save_item(wid="wi-next", sid=sid, marker=True) await self._save_item(wid="wi-later", sid=sid, marker=True) await self._seed_session( sid=sid, pending=["wi-missing", "wi-done", "wi-next", "wi-later"], ) result = await reconcile_role_serial_queues(self.store, "r") self.assertIn("wi-missing", result["pruned_pending_ids"]) self.assertIn("wi-done", result["pruned_pending_ids"]) self.assertIn("wi-next", result["promoted_work_item_ids"]) session = await self.store.get_delegation_role_session(sid) self.assertEqual(session.pending_work_item_ids, ["wi-later"]) promoted = await self.store.get_delegation_work_item("wi-next") later = await self.store.get_delegation_work_item("wi-later") self.assertNotIn("queued_behind_session", promoted.metadata) self.assertEqual(later.metadata.get("queued_behind_session"), sid) second = await reconcile_role_serial_queues(self.store, "r") self.assertNotIn("wi-later", second["promoted_work_item_ids"]) later_after = await self.store.get_delegation_work_item("wi-later") self.assertEqual(later_after.metadata.get("queued_behind_session"), sid) async def test_terminal_transition_reconciles_even_when_focus_already_empty(self) -> None: self.store.role_serial_queue_enabled = True sid = await self._seed_session(pending=["wi-next"]) await self._save_item(wid="wi-next", sid=sid, marker=True) active = await self._save_item(wid="wi-active", sid=sid, phase=Phase.RUNNING) await self.store.update_delegation_work_item( active.work_item_id, phase=Phase.APPROVED, ) session = await self.store.get_delegation_role_session(sid) self.assertEqual(session.pending_work_item_ids, []) next_item = await self.store.get_delegation_work_item("wi-next") self.assertNotIn("queued_behind_session", next_item.metadata) self.assertTrue(is_dispatchable(next_item)) async def test_idempotent_work_item_save_repairs_linked_task_status(self) -> None: task = Task( id="task-drift", title="t", description="", assigned_to="cto", status=TaskStatus.AWAITING_MANAGER_REVIEW, project_id="p", session_id="s", metadata={}, ) await self.store.save_task(task) item = DelegationWorkItem( work_item_id="wi-approved", run_id="r", cell_id="c", role_id="cto", seat_id="seat", manager_role_id="ceo", manager_seat_id="seat::ceo", title="t", phase=Phase.APPROVED, ) await self.store.save_delegation_work_item(item) await self.store.link_work_item_runtime_task(item.work_item_id, task.id) task.status = TaskStatus.AWAITING_MANAGER_REVIEW await self.store.save_task(task) await self.store.save_delegation_work_item(item) repaired = await self.store.get_task(task.id) self.assertEqual(repaired.status, TaskStatus.DONE) class StartupClaimSweepTests(_StoreFixture): async def test_restart_clears_dead_running_focus_so_auxiliary_can_resume(self) -> None: sid = "role-runtime::r::cto" report_id = "report::wi-parent::v1" await self.store.save_delegation_role_session( DelegationRoleSession( role_session_id=sid, run_id="r", role_id="cto", focused_work_item_id=report_id, status="running", ) ) await self.store.save_delegation_work_item( DelegationWorkItem( work_item_id=report_id, run_id="r", cell_id="c", role_id="cto", seat_id="seat", role_runtime_session_id=sid, manager_role_id="ceo", manager_seat_id="seat::ceo", title="report", kind="report", phase=Phase.RUNNING, claimed_by_role_runtime_session_id=sid, claimed_by_seat_id="seat", metadata={ "report_execution_work_item": True, "report_target_work_item_id": "wi-parent", "claimed_by_role_session_id": sid, "claimed_task_id": "task-report", }, ) ) db_path = self.store.db_path await self.store.close() self.store = OPCStore(db_path=db_path) await self.store.initialize() self.store.role_serial_queue_enabled = True report = await self.store.get_delegation_work_item(report_id) session_before = await self.store.get_delegation_role_session(sid) self.assertEqual(report.claimed_by_role_runtime_session_id, "") self.assertTrue(is_dispatchable(report)) self.assertEqual(session_before.focused_work_item_id, report_id) self.assertEqual(session_before.status, "running") result = await reconcile_role_serial_queues(self.store, "r") session_after = await self.store.get_delegation_role_session(sid) self.assertIn(sid, result["cleared_focus_session_ids"]) self.assertEqual(session_after.focused_work_item_id, "") self.assertEqual(session_after.status, "idle") self.assertTrue(is_dispatchable(await self.store.get_delegation_work_item(report_id))) async def test_restart_releases_review_claim_without_dispatching_parent(self) -> None: parent = DelegationWorkItem( work_item_id="wi-parent", run_id="r", cell_id="c", role_id="cto", seat_id="seat", manager_role_id="ceo", manager_seat_id="seat::ceo", title="parent", phase=Phase.AWAITING_MANAGER_REVIEW, claimed_by_role_runtime_session_id="dead-role-session", claimed_by_seat_id="seat", metadata={ "claimed_by_role_session_id": "dead-role-session", "claimed_task_id": "task-parent", }, ) report = DelegationWorkItem( work_item_id="wi-report", run_id="r", cell_id="c", role_id="cto", seat_id="seat", manager_role_id="ceo", manager_seat_id="seat::ceo", title="report", phase=Phase.READY, metadata={ "report_execution_work_item": True, "report_target_work_item_id": "wi-parent", }, ) await self.store.save_delegation_work_item(parent) await self.store.save_delegation_work_item(report) db_path = self.store.db_path await self.store.close() self.store = OPCStore(db_path=db_path) await self.store.initialize() parent_after = await self.store.get_delegation_work_item("wi-parent") report_after = await self.store.get_delegation_work_item("wi-report") self.assertEqual(parent_after.claimed_by_role_runtime_session_id, "") self.assertEqual(parent_after.claimed_by_seat_id, "") self.assertEqual(parent_after.metadata.get("claimed_by_role_session_id"), "") self.assertEqual(parent_after.metadata.get("claimed_task_id"), "") self.assertTrue(parent_after.metadata.get("claim_swept_at")) self.assertFalse(is_dispatchable(parent_after)) self.assertTrue(is_dispatchable(report_after)) # ── Config loader picks up the feature flag ────────────────────────────── class ConfigLoaderFlagTests(unittest.TestCase): """OPCConfig.load must pass ``role_serial_queue_enabled`` through from the org YAML. The engine mirrors this onto the store during init so phase hooks can consult it without an upward dependency.""" def test_flag_on_in_yaml_reaches_org_config(self) -> None: with tempfile.TemporaryDirectory() as tmp: config_dir = Path(tmp) (config_dir / "org_config.yaml").write_text( textwrap.dedent( """\ role_serial_queue_enabled: true """ ), encoding="utf-8", ) config = OPCConfig.load(config_dir=config_dir) self.assertTrue(config.org.role_serial_queue_enabled) def test_flag_default_true_when_key_absent(self) -> None: with tempfile.TemporaryDirectory() as tmp: config_dir = Path(tmp) # An empty org_config.yaml — flag should stay at its default. (config_dir / "org_config.yaml").write_text( "team_runtime:\n default_team_id: ''\n", encoding="utf-8", ) config = OPCConfig.load(config_dir=config_dir) self.assertTrue(config.org.role_serial_queue_enabled) if __name__ == "__main__": unittest.main()