Merge pull request #27 from cgycorey/fix/org-id-required-fallback
fix(ui): durable custom-org identity for role tasks, replies, approvals, and followups
This commit is contained in:
@@ -2072,6 +2072,7 @@ class CompanyRecruiterFlowTests(unittest.IsolatedAsyncioTestCase):
|
||||
decision = RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
company_profile="custom",
|
||||
org_id="test-org",
|
||||
domains=[],
|
||||
)
|
||||
runtime_spec = engine.company_runtime_spec_builder.build_spec(
|
||||
@@ -2140,6 +2141,7 @@ class CompanyRecruiterFlowTests(unittest.IsolatedAsyncioTestCase):
|
||||
decision = RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
company_profile="custom",
|
||||
org_id="test-org",
|
||||
domains=[],
|
||||
)
|
||||
runtime_spec = engine.company_runtime_spec_builder.build_spec(
|
||||
@@ -2199,6 +2201,7 @@ class CompanyRecruiterFlowTests(unittest.IsolatedAsyncioTestCase):
|
||||
decision = RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
company_profile="custom",
|
||||
org_id="test-org",
|
||||
domains=[],
|
||||
)
|
||||
runtime_spec = engine.company_runtime_spec_builder.build_spec(
|
||||
@@ -2312,6 +2315,7 @@ class CompanyRecruiterFlowTests(unittest.IsolatedAsyncioTestCase):
|
||||
decision = RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
company_profile="custom",
|
||||
org_id="test-org",
|
||||
domains=[],
|
||||
)
|
||||
runtime_spec = engine.company_runtime_spec_builder.build_spec(
|
||||
|
||||
@@ -260,6 +260,212 @@ def test_work_item_chat_resume_uses_canonical_ui_anchor_as_engine_origin() -> No
|
||||
asyncio.run(scenario())
|
||||
|
||||
|
||||
def test_company_suspend_reply_routes_selected_org_to_engine() -> None:
|
||||
async def scenario() -> None:
|
||||
_tasks, checkpoint = _runtime_records()
|
||||
handler = WSHandler.__new__(WSHandler)
|
||||
handler._exec_mode = "task"
|
||||
handler._company_profile = "corporate"
|
||||
handler._shutting_down = False
|
||||
handler._active_runtime_children = {}
|
||||
handler._session_to_task = {}
|
||||
handler._task_bg_context = {}
|
||||
handler._company_suspend_reply_locks = {"runtime-session": asyncio.Lock()}
|
||||
handler.chat_store = None
|
||||
handler._set_company_runtime_control = AsyncMock()
|
||||
handler._normalize_session_exec_mode = MagicMock(return_value="task")
|
||||
handler._normalize_session_company_profile = MagicMock(return_value="corporate")
|
||||
handler._resolve_task_session_config = MagicMock(return_value=("org", "custom"))
|
||||
handler._resolve_task_org_id = MagicMock(return_value="selected-org")
|
||||
handler._extract_checkpoint_metadata = AsyncMock(return_value=None)
|
||||
handler._sync_task_transcript_messages = AsyncMock()
|
||||
handler.on_kanban_changed = AsyncMock()
|
||||
handler._flush_progress = AsyncMock()
|
||||
run_engine = SimpleNamespace(
|
||||
project_id="project-a",
|
||||
process_message=AsyncMock(return_value="resumed"),
|
||||
)
|
||||
target = {
|
||||
"ui_anchor_task_id": "ui-anchor",
|
||||
"config_task": SimpleNamespace(
|
||||
metadata={"exec_mode": "org", "company_profile": "custom"},
|
||||
org_id="selected-org",
|
||||
),
|
||||
}
|
||||
|
||||
await handler._process_company_suspend_reply(
|
||||
ui_task_id="final-decider",
|
||||
runtime_session_id="runtime-session",
|
||||
content="continue",
|
||||
attachment_refs=None,
|
||||
message_metadata={"ui_force_resume": True},
|
||||
user_message_id=None,
|
||||
user_message_created_at=None,
|
||||
run_engine=run_engine,
|
||||
run_project_id="project-a",
|
||||
target=target,
|
||||
checkpoint=checkpoint,
|
||||
lock=handler._company_suspend_reply_locks["runtime-session"],
|
||||
)
|
||||
|
||||
call = run_engine.process_message.await_args
|
||||
assert call.kwargs["org_id"] == "selected-org"
|
||||
|
||||
asyncio.run(scenario())
|
||||
|
||||
|
||||
def test_delivery_feedback_reply_fails_closed_without_durable_parent_task() -> None:
|
||||
async def scenario() -> None:
|
||||
handler = WSHandler.__new__(WSHandler)
|
||||
handler._exec_mode = "task"
|
||||
handler._company_profile = "corporate"
|
||||
handler._shutting_down = False
|
||||
handler._active_runtime_children = {}
|
||||
handler._session_to_task = {}
|
||||
handler._task_bg_context = {}
|
||||
handler._company_delivery_feedback_reply_locks = {}
|
||||
handler.chat_store = None
|
||||
handler._store_is_ready = MagicMock(return_value=True)
|
||||
handler._normalize_session_exec_mode = MagicMock(return_value="task")
|
||||
handler._normalize_session_company_profile = MagicMock(return_value="corporate")
|
||||
handler._resolve_task_session_config = MagicMock(return_value=("org", "custom"))
|
||||
handler._resolve_task_org_id = MagicMock(return_value="")
|
||||
handler._chat_store_is_ready = MagicMock(return_value=False)
|
||||
handler._flush_progress = AsyncMock()
|
||||
run_engine = SimpleNamespace(
|
||||
project_id="project-a",
|
||||
store=SimpleNamespace(get_task=AsyncMock(return_value=None)),
|
||||
run_company_delivery_self_evolution_checkpoint=AsyncMock(return_value="ran"),
|
||||
)
|
||||
|
||||
await handler._process_company_delivery_feedback_reply(
|
||||
parent_task_id="delivery-task",
|
||||
parent_session_id="delivery-session",
|
||||
reply_channel_id="session:delivery-task",
|
||||
content="approved",
|
||||
attachment_refs=None,
|
||||
message_metadata=None,
|
||||
user_message_id=None,
|
||||
user_message_created_at=None,
|
||||
run_engine=run_engine,
|
||||
run_project_id="project-a",
|
||||
checkpoint=SimpleNamespace(checkpoint_id="cp-delivery", payload={}),
|
||||
waiting_task_id="delivery-task",
|
||||
lock=asyncio.Lock(),
|
||||
)
|
||||
|
||||
run_engine.run_company_delivery_self_evolution_checkpoint.assert_not_awaited()
|
||||
handler._resolve_task_org_id.assert_not_called()
|
||||
|
||||
asyncio.run(scenario())
|
||||
|
||||
|
||||
def test_delivery_feedback_reply_proceeds_with_durable_parent_task() -> None:
|
||||
async def scenario() -> None:
|
||||
handler = WSHandler.__new__(WSHandler)
|
||||
handler._exec_mode = "task"
|
||||
handler._company_profile = "corporate"
|
||||
handler._shutting_down = False
|
||||
handler._active_runtime_children = {}
|
||||
handler._session_to_task = {}
|
||||
handler._task_bg_context = {}
|
||||
handler._company_delivery_feedback_reply_locks = {}
|
||||
handler.chat_store = None
|
||||
handler._store_is_ready = MagicMock(return_value=True)
|
||||
handler._normalize_session_exec_mode = MagicMock(return_value="task")
|
||||
handler._normalize_session_company_profile = MagicMock(return_value="corporate")
|
||||
handler._resolve_task_session_config = MagicMock(return_value=("org", "custom"))
|
||||
handler._resolve_task_org_id = MagicMock(return_value="selected-org")
|
||||
handler._chat_store_is_ready = MagicMock(return_value=False)
|
||||
handler._flush_progress = AsyncMock()
|
||||
parent_task = SimpleNamespace(id="delivery-task")
|
||||
run_engine = SimpleNamespace(
|
||||
project_id="project-a",
|
||||
store=SimpleNamespace(get_task=AsyncMock(return_value=parent_task)),
|
||||
run_company_delivery_self_evolution_checkpoint=AsyncMock(return_value="ran"),
|
||||
)
|
||||
|
||||
await handler._process_company_delivery_feedback_reply(
|
||||
parent_task_id="delivery-task",
|
||||
parent_session_id="delivery-session",
|
||||
reply_channel_id="session:delivery-task",
|
||||
content="approved",
|
||||
attachment_refs=None,
|
||||
message_metadata=None,
|
||||
user_message_id=None,
|
||||
user_message_created_at=None,
|
||||
run_engine=run_engine,
|
||||
run_project_id="project-a",
|
||||
checkpoint=SimpleNamespace(checkpoint_id="cp-delivery", payload={}),
|
||||
waiting_task_id="delivery-task",
|
||||
lock=asyncio.Lock(),
|
||||
)
|
||||
|
||||
call = run_engine.run_company_delivery_self_evolution_checkpoint.await_args
|
||||
assert call is not None
|
||||
assert call.kwargs["action"] == "approve"
|
||||
handler._resolve_task_org_id.assert_called_once_with(parent_task)
|
||||
|
||||
asyncio.run(scenario())
|
||||
|
||||
|
||||
def test_suspend_reply_missing_custom_org_id_fails_closed_before_engine_call() -> None:
|
||||
async def scenario() -> None:
|
||||
_tasks, checkpoint = _runtime_records()
|
||||
handler = WSHandler.__new__(WSHandler)
|
||||
handler._exec_mode = "task"
|
||||
handler._company_profile = "corporate"
|
||||
handler._shutting_down = False
|
||||
handler.chat_store = None
|
||||
handler._company_suspend_reply_locks = {
|
||||
"runtime-session": asyncio.Lock(),
|
||||
}
|
||||
handler._task_bg_context = {}
|
||||
handler._active_runtime_children = {}
|
||||
handler._session_to_task = {}
|
||||
handler._set_company_runtime_control = AsyncMock()
|
||||
handler._normalize_session_exec_mode = MagicMock(return_value="task")
|
||||
handler._normalize_session_company_profile = MagicMock(return_value="corporate")
|
||||
handler._resolve_task_session_config = MagicMock(return_value=("org", "custom"))
|
||||
handler._resolve_task_org_id = MagicMock(return_value="")
|
||||
handler._extract_checkpoint_metadata = AsyncMock(return_value=None)
|
||||
handler._sync_task_transcript_messages = AsyncMock()
|
||||
handler.on_kanban_changed = AsyncMock()
|
||||
handler._flush_progress = AsyncMock()
|
||||
run_engine = SimpleNamespace(
|
||||
project_id="project-a",
|
||||
process_message=AsyncMock(),
|
||||
)
|
||||
config_task = SimpleNamespace(
|
||||
metadata={"exec_mode": "org", "company_profile": "custom"},
|
||||
org_id=None,
|
||||
)
|
||||
target = {
|
||||
"ui_anchor_task_id": "ui-anchor",
|
||||
"config_task": config_task,
|
||||
}
|
||||
|
||||
await handler._process_company_suspend_reply(
|
||||
ui_task_id="final-decider",
|
||||
runtime_session_id="runtime-session",
|
||||
content="continue",
|
||||
attachment_refs=None,
|
||||
message_metadata=None,
|
||||
user_message_id=None,
|
||||
user_message_created_at=None,
|
||||
run_engine=run_engine,
|
||||
run_project_id="project-a",
|
||||
target=target,
|
||||
checkpoint=checkpoint,
|
||||
lock=handler._company_suspend_reply_locks["runtime-session"],
|
||||
)
|
||||
|
||||
run_engine.process_message.assert_not_awaited()
|
||||
handler._set_company_runtime_control.assert_not_awaited()
|
||||
|
||||
asyncio.run(scenario())
|
||||
|
||||
|
||||
def test_delivery_feedback_rejects_missing_canonical_identity_without_first_task_fallback() -> None:
|
||||
async def scenario() -> None:
|
||||
tasks, checkpoint = _runtime_records()
|
||||
|
||||
@@ -49,11 +49,20 @@ class _EngineStub:
|
||||
return self.reply
|
||||
|
||||
|
||||
def _pending_checkpoint(checkpoint_id: str, checkpoint_type: str = "task_user_input") -> Any:
|
||||
def _pending_checkpoint(
|
||||
checkpoint_id: str,
|
||||
checkpoint_type: str = "task_user_input",
|
||||
*,
|
||||
task_id: str = "chat-task",
|
||||
session_id: str = "session-1",
|
||||
) -> Any:
|
||||
return SimpleNamespace(
|
||||
checkpoint_id=checkpoint_id,
|
||||
checkpoint_type=checkpoint_type,
|
||||
status="pending",
|
||||
task_id=task_id,
|
||||
session_id=session_id,
|
||||
payload={"task_ids": [task_id], "waiting_task_id": task_id, "session_id": session_id},
|
||||
)
|
||||
|
||||
|
||||
@@ -189,6 +198,30 @@ class LockFreeCheckpointAnswerTests(unittest.IsolatedAsyncioTestCase):
|
||||
holder.release_event.set() # type: ignore[attr-defined]
|
||||
await holder
|
||||
|
||||
async def test_lock_free_requires_exact_checkpoint_type_and_owner(self) -> None:
|
||||
engine = _EngineStub(
|
||||
_StoreStub([
|
||||
_pending_checkpoint(
|
||||
"ckpt-park",
|
||||
"company_work_item_gate",
|
||||
task_id="other-task",
|
||||
session_id="other-session",
|
||||
)
|
||||
])
|
||||
)
|
||||
handler = _make_handler(engine)
|
||||
holder = await self._hold_lock(handler, "chat-task")
|
||||
try:
|
||||
handled = await handler._try_lock_free_parked_checkpoint_answer(
|
||||
engine=engine,
|
||||
**_answer_kwargs(),
|
||||
)
|
||||
self.assertFalse(handled)
|
||||
self.assertEqual(engine.calls, [])
|
||||
finally:
|
||||
holder.release_event.set() # type: ignore[attr-defined]
|
||||
await holder
|
||||
|
||||
async def test_engine_failure_surfaces_error_without_queueing(self) -> None:
|
||||
engine = _EngineStub(
|
||||
_StoreStub([_pending_checkpoint("ckpt-park")]),
|
||||
|
||||
@@ -112,6 +112,21 @@ def test_task_org_id_field_is_org_identity_fallback() -> None:
|
||||
assert identity.org_id == "quantum_harbor"
|
||||
|
||||
|
||||
def test_durable_task_org_id_wins_over_stale_metadata_org_id() -> None:
|
||||
task = SimpleNamespace(
|
||||
metadata={
|
||||
"exec_mode": "org",
|
||||
"company_profile": "custom",
|
||||
"organization_id": "active-org",
|
||||
},
|
||||
org_id="selected-org",
|
||||
)
|
||||
|
||||
identity = execution_identity_from_task(task)
|
||||
|
||||
assert identity.org_id == "selected-org"
|
||||
|
||||
|
||||
def test_default_org_id_applies_only_when_task_has_no_persisted_identity() -> None:
|
||||
task = SimpleNamespace(metadata={}, org_id=None)
|
||||
|
||||
@@ -146,3 +161,42 @@ def test_explicit_company_identity_ignores_default_org_id() -> None:
|
||||
assert identity.exec_mode == "company"
|
||||
assert identity.company_profile == "corporate"
|
||||
assert identity.org_id == ""
|
||||
|
||||
|
||||
def test_company_mode_marker_without_profile_is_company_identity() -> None:
|
||||
task = SimpleNamespace(
|
||||
metadata={"mode": "company"},
|
||||
org_id=None,
|
||||
)
|
||||
|
||||
identity = execution_identity_from_task(task)
|
||||
|
||||
assert identity.exec_mode == "company"
|
||||
assert identity.company_profile == "corporate"
|
||||
assert identity.org_id == ""
|
||||
|
||||
|
||||
def test_work_item_runtime_marker_without_profile_is_company_identity() -> None:
|
||||
task = SimpleNamespace(
|
||||
metadata={"work_item_runtime": True},
|
||||
org_id=None,
|
||||
)
|
||||
|
||||
identity = execution_identity_from_task(task)
|
||||
|
||||
assert identity.exec_mode == "company"
|
||||
assert identity.company_profile == "corporate"
|
||||
assert identity.org_id == ""
|
||||
|
||||
|
||||
def test_company_runtime_marker_with_custom_profile_is_org_identity() -> None:
|
||||
task = SimpleNamespace(
|
||||
metadata={"mode": "company", "work_item_runtime": True, "company_profile": "custom"},
|
||||
org_id=None,
|
||||
)
|
||||
|
||||
identity = execution_identity_from_task(task)
|
||||
|
||||
assert identity.exec_mode == "org"
|
||||
assert identity.company_profile == "custom"
|
||||
assert identity.org_id == ""
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from types import SimpleNamespace
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from opc.plugins.office_ui.services.context import OfficeServiceContext
|
||||
from opc.plugins.office_ui.services.models import ServiceError
|
||||
from opc.plugins.office_ui.services.session import SessionService
|
||||
|
||||
|
||||
class _Store:
|
||||
def __init__(self) -> None:
|
||||
self.saved: list[Any] = []
|
||||
|
||||
async def save_task(self, task: Any) -> None:
|
||||
self.saved.append(task)
|
||||
|
||||
|
||||
def _task(**overrides: Any) -> SimpleNamespace:
|
||||
task = SimpleNamespace(
|
||||
id="task-role-1",
|
||||
session_id="sess-1",
|
||||
project_id="demo",
|
||||
title="Role task",
|
||||
parent_session_id=None,
|
||||
metadata={},
|
||||
org_id=None,
|
||||
)
|
||||
for key, value in overrides.items():
|
||||
setattr(task, key, value)
|
||||
return task
|
||||
|
||||
|
||||
def _context(*, hook: Any | None = None) -> OfficeServiceContext:
|
||||
engine = SimpleNamespace(project_id="demo", store=_Store(), memory=None)
|
||||
context = OfficeServiceContext(engine=engine, agent_store=None, chat_store=None, event_adapter=None)
|
||||
if hook is not None:
|
||||
context.get_active_saved_org_name = hook
|
||||
return context
|
||||
|
||||
|
||||
class TestPersistSessionConfigOrgIdentity(unittest.IsolatedAsyncioTestCase):
|
||||
async def _persist(
|
||||
self,
|
||||
context: OfficeServiceContext,
|
||||
task: Any,
|
||||
*,
|
||||
exec_mode: str = "org",
|
||||
company_profile: str = "custom",
|
||||
org_id: str = "",
|
||||
) -> None:
|
||||
await SessionService(context).persist_session_config(
|
||||
task,
|
||||
exec_mode=exec_mode,
|
||||
company_profile=company_profile,
|
||||
preferred_agent="native",
|
||||
org_id=org_id,
|
||||
)
|
||||
|
||||
async def test_rejects_missing_org_id_without_active_org_fallback(self) -> None:
|
||||
active_org = AsyncMock(return_value="vc-investment-firm")
|
||||
context = _context(hook=active_org)
|
||||
task = _task()
|
||||
|
||||
with self.assertRaises(ServiceError) as ctx:
|
||||
await self._persist(context, task)
|
||||
|
||||
assert ctx.exception.code == "org_id_required"
|
||||
active_org.assert_not_awaited()
|
||||
assert context.engine.store.saved == []
|
||||
|
||||
async def test_explicit_org_id_still_used_when_present(self) -> None:
|
||||
active_org = AsyncMock(return_value="other-org")
|
||||
context = _context(hook=active_org)
|
||||
task = _task()
|
||||
|
||||
await self._persist(context, task, org_id="vc-investment-firm")
|
||||
|
||||
assert task.metadata["org_id"] == "vc-investment-firm"
|
||||
assert task.org_id == "vc-investment-firm"
|
||||
active_org.assert_not_awaited()
|
||||
|
||||
async def test_raises_when_no_active_org_available(self) -> None:
|
||||
empty_org = AsyncMock(return_value="")
|
||||
context = _context(hook=empty_org)
|
||||
task = _task()
|
||||
|
||||
with self.assertRaises(ServiceError) as ctx:
|
||||
await self._persist(context, task)
|
||||
assert ctx.exception.code == "org_id_required"
|
||||
empty_org.assert_not_awaited()
|
||||
|
||||
async def test_raises_when_hook_unset(self) -> None:
|
||||
context = _context()
|
||||
task = _task()
|
||||
|
||||
with self.assertRaises(ServiceError) as ctx:
|
||||
await self._persist(context, task)
|
||||
assert ctx.exception.code == "org_id_required"
|
||||
|
||||
async def test_raises_when_hook_fails(self) -> None:
|
||||
broken = AsyncMock(side_effect=RuntimeError("org index unreadable"))
|
||||
context = _context(hook=broken)
|
||||
task = _task()
|
||||
|
||||
with self.assertRaises(ServiceError) as ctx:
|
||||
await self._persist(context, task)
|
||||
assert ctx.exception.code == "org_id_required"
|
||||
broken.assert_not_awaited()
|
||||
|
||||
async def test_company_mode_clears_org_fields_without_fallback(self) -> None:
|
||||
fallback_called = False
|
||||
|
||||
async def active_org() -> str:
|
||||
nonlocal fallback_called
|
||||
fallback_called = True
|
||||
return "vc-investment-firm"
|
||||
|
||||
context = _context(hook=active_org)
|
||||
task = _task(metadata={"org_id": "stale-org"})
|
||||
|
||||
await self._persist(
|
||||
context,
|
||||
task,
|
||||
exec_mode="company",
|
||||
company_profile="corporate",
|
||||
)
|
||||
|
||||
assert not fallback_called
|
||||
assert "org_id" not in task.metadata
|
||||
assert "organization_id" not in task.metadata
|
||||
assert task.org_id is None
|
||||
|
||||
async def test_task_mode_ignores_org_entirely(self) -> None:
|
||||
fallback_called = False
|
||||
|
||||
async def active_org() -> str:
|
||||
nonlocal fallback_called
|
||||
fallback_called = True
|
||||
return "vc-investment-firm"
|
||||
|
||||
context = _context(hook=active_org)
|
||||
task = _task()
|
||||
|
||||
await self._persist(
|
||||
context,
|
||||
task,
|
||||
exec_mode="task",
|
||||
company_profile="corporate",
|
||||
)
|
||||
|
||||
assert not fallback_called
|
||||
assert task.metadata["execution_mode"] == "task_mode"
|
||||
assert "org_id" not in task.metadata
|
||||
assert task.org_id is None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -13,6 +13,7 @@ from opc.core.org_config import (
|
||||
)
|
||||
from opc.engine import OPCEngine
|
||||
from opc.layer2_organization.custom_runtime import CustomRuntimeRunner
|
||||
from opc.plugins.office_ui.services.models import ServiceError
|
||||
|
||||
|
||||
def test_requested_mode_normalization_keeps_core_company_router_main_compatible() -> None:
|
||||
@@ -61,6 +62,34 @@ def test_custom_runtime_runner_loads_org_storage_without_mutating_parent_config(
|
||||
assert (config_dir / "company_orgs" / "org_lab_config.yaml").exists()
|
||||
|
||||
|
||||
def test_process_message_rejects_org_mode_without_org_id() -> None:
|
||||
engine = OPCEngine.__new__(OPCEngine)
|
||||
engine.opc_home = None
|
||||
engine.config = OPCConfig()
|
||||
runner = CustomRuntimeRunner(engine)
|
||||
caught: ServiceError | None = None
|
||||
|
||||
async def _run() -> None:
|
||||
await runner.process_message(
|
||||
"run org",
|
||||
project_id="default",
|
||||
session_id="session-1",
|
||||
org_id=None,
|
||||
preferred_agent=None,
|
||||
domains=None,
|
||||
origin_task_id=None,
|
||||
attachment_refs=None,
|
||||
message_metadata=None,
|
||||
)
|
||||
|
||||
try:
|
||||
asyncio.run(_run())
|
||||
except ServiceError as exc:
|
||||
caught = exc
|
||||
assert caught is not None
|
||||
assert caught.code == "org_id_required"
|
||||
|
||||
|
||||
def test_process_message_routes_org_mode_to_custom_runner(monkeypatch) -> None:
|
||||
engine = OPCEngine.__new__(OPCEngine)
|
||||
engine._initialized = True
|
||||
|
||||
@@ -11,9 +11,15 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
||||
import yaml
|
||||
from pydantic import ValidationError
|
||||
|
||||
from opc.core.config import AgentsConfig, ExternalAgentConfig, OPCConfig
|
||||
from opc.core.config import (
|
||||
AgentsConfig,
|
||||
DEFAULT_ORGANIZATION_ID,
|
||||
ExternalAgentConfig,
|
||||
OPCConfig,
|
||||
)
|
||||
from opc.core.models import (
|
||||
DelegationWorkItem,
|
||||
ExecutionCheckpoint,
|
||||
ExecutionMode,
|
||||
RouterDecision,
|
||||
SessionMessageRecord,
|
||||
@@ -24,7 +30,8 @@ from opc.core.models import (
|
||||
WorkItemExecutionStrategy,
|
||||
)
|
||||
from opc.engine import OPCEngine
|
||||
from opc.layer2_organization.company_mode import CompanyWorkItemExecutor
|
||||
from opc.layer2_organization.company_mode import CompanyRuntimeSpecBuilder, CompanyWorkItemExecutor
|
||||
from opc.plugins.office_ui.services.models import ServiceError
|
||||
from opc.layer3_agent.adapters.claude_code import ClaudeCodeAdapter
|
||||
from opc.layer3_agent.adapters.codex_adapter import CodexAdapter
|
||||
from opc.layer3_agent.adapters.cursor_adapter import CursorAdapter
|
||||
@@ -323,6 +330,650 @@ class RuntimeConfigEnforcementTests(unittest.IsolatedAsyncioTestCase):
|
||||
self.assertEqual(task.metadata["preferred_external_agent"], "opencode")
|
||||
self.assertEqual(task.metadata["work_item_execution_strategy"], WorkItemExecutionStrategy.EXTERNAL.value)
|
||||
|
||||
async def test_company_root_task_persists_decision_org_over_active_config(self) -> None:
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
engine.config.org.company_profile = "custom"
|
||||
engine.config.org.organization_id = "active-org"
|
||||
engine.store = SimpleNamespace(
|
||||
get_runtime_task_for_work_item=AsyncMock(return_value=None),
|
||||
save_delegation_work_item=AsyncMock(),
|
||||
save_task=AsyncMock(),
|
||||
link_work_item_runtime_task=AsyncMock(return_value=True),
|
||||
)
|
||||
engine.memory = SimpleNamespace(ensure_session=AsyncMock())
|
||||
engine.org_engine = SimpleNamespace(
|
||||
current_org_version=MagicMock(return_value=1),
|
||||
current_runtime_topology_version=MagicMock(return_value=1),
|
||||
)
|
||||
engine._requests_explicit_project_knowledge = MagicMock(return_value=False)
|
||||
work_item = DelegationWorkItem(
|
||||
work_item_id="wi-selected-org",
|
||||
run_id="run-selected-org",
|
||||
cell_id="team::engineering",
|
||||
team_instance_id="team-instance-1",
|
||||
role_id="engineer",
|
||||
seat_id="seat-engineer",
|
||||
title="Engineering execution",
|
||||
summary="Implement the requested change.",
|
||||
kind="execute",
|
||||
projection_id="engineering-execute",
|
||||
metadata={"seat_id": "seat-engineer", "team_id": "team::engineering"},
|
||||
)
|
||||
|
||||
task = await engine._ensure_runtime_work_item_task(
|
||||
work_item=work_item,
|
||||
parent_session_id="sess-company",
|
||||
original_message="Build the thing.",
|
||||
decision=RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
domains=[],
|
||||
company_profile="custom",
|
||||
org_id="selected-org",
|
||||
),
|
||||
runtime_topology={
|
||||
"final_decider_role_id": "lead",
|
||||
"seats": [
|
||||
{
|
||||
"seat_id": "seat-engineer",
|
||||
"team_id": "team::engineering",
|
||||
"role_id": "engineer",
|
||||
"employee_assignment": {"employee_id": "eng-1", "name": "Engineer"},
|
||||
"metadata": {"role_name": "Engineer"},
|
||||
}
|
||||
],
|
||||
},
|
||||
delegation_playbook={},
|
||||
secretary_context="",
|
||||
target_output_dir=None,
|
||||
origin_channel="cli",
|
||||
origin_chat_id="",
|
||||
origin_thread_id="",
|
||||
origin_task_id=None,
|
||||
attachment_refs=[],
|
||||
attachment_context="",
|
||||
force_native_execution=False,
|
||||
)
|
||||
|
||||
self.assertEqual(task.org_id, "selected-org")
|
||||
self.assertEqual(task.metadata["org_id"], "selected-org")
|
||||
self.assertEqual(task.metadata["organization_id"], "selected-org")
|
||||
|
||||
def test_build_spec_rejects_custom_run_without_durable_org_id(self) -> None:
|
||||
builder = CompanyRuntimeSpecBuilder(
|
||||
org_engine=SimpleNamespace(
|
||||
get_company_profile=lambda: "custom",
|
||||
config=SimpleNamespace(
|
||||
org=SimpleNamespace(
|
||||
organization_id="active-org",
|
||||
organization_name="Active Org",
|
||||
organization_config_file="org_active-org_config.yaml",
|
||||
company_profile="custom",
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
with self.assertRaises(ServiceError) as ctx:
|
||||
builder.build_spec(
|
||||
RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
company_profile="custom",
|
||||
org_id=None,
|
||||
),
|
||||
original_message="Run the company.",
|
||||
)
|
||||
assert ctx.exception.code == "org_id_required"
|
||||
|
||||
def test_build_spec_serializes_selected_org_not_active_config(self) -> None:
|
||||
builder = CompanyRuntimeSpecBuilder(
|
||||
org_engine=SimpleNamespace(
|
||||
get_company_profile=lambda: "custom",
|
||||
config=SimpleNamespace(
|
||||
org=SimpleNamespace(
|
||||
organization_id="active-org",
|
||||
organization_name="Active Org",
|
||||
organization_config_file="org_active-org_config.yaml",
|
||||
company_profile="custom",
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
decision = RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
company_profile="custom",
|
||||
org_id="selected-org",
|
||||
)
|
||||
spec = builder.build_spec(decision, original_message="Run the company.")
|
||||
assert spec.metadata["org_id"] == "selected-org"
|
||||
assert spec.metadata["organization_id"] == "selected-org"
|
||||
|
||||
def test_runtime_org_id_for_identity_never_derives_from_active_config(self) -> None:
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
engine.config.org.company_profile = "custom"
|
||||
engine.config.org.organization_id = "active-org"
|
||||
decision = RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
company_profile="custom",
|
||||
org_id=None,
|
||||
)
|
||||
resolved = OPCEngine._runtime_org_id_for_identity(
|
||||
decision,
|
||||
{},
|
||||
engine.config.org,
|
||||
)
|
||||
assert resolved is None
|
||||
|
||||
async def test_ensure_runtime_work_item_task_rejects_custom_without_durable_org(self) -> None:
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
engine.config.org.company_profile = "custom"
|
||||
engine.config.org.organization_id = "active-org"
|
||||
engine.store = SimpleNamespace(
|
||||
get_runtime_task_for_work_item=AsyncMock(return_value=None),
|
||||
save_delegation_work_item=AsyncMock(),
|
||||
save_task=AsyncMock(),
|
||||
link_work_item_runtime_task=AsyncMock(return_value=True),
|
||||
)
|
||||
engine.memory = SimpleNamespace(ensure_session=AsyncMock())
|
||||
engine.org_engine = SimpleNamespace(
|
||||
current_org_version=MagicMock(return_value=1),
|
||||
current_runtime_topology_version=MagicMock(return_value=1),
|
||||
)
|
||||
engine._requests_explicit_project_knowledge = MagicMock(return_value=False)
|
||||
work_item = DelegationWorkItem(
|
||||
work_item_id="wi-no-durable-org",
|
||||
run_id="run-no-durable-org",
|
||||
cell_id="team::engineering",
|
||||
team_instance_id="team-instance-1",
|
||||
role_id="engineer",
|
||||
seat_id="seat-engineer",
|
||||
title="Engineering execution",
|
||||
summary="Implement the requested change.",
|
||||
kind="execute",
|
||||
projection_id="engineering-execute",
|
||||
metadata={"seat_id": "seat-engineer", "team_id": "team::engineering"},
|
||||
)
|
||||
with self.assertRaises(ServiceError) as ctx:
|
||||
await engine._ensure_runtime_work_item_task(
|
||||
work_item=work_item,
|
||||
parent_session_id="sess-company",
|
||||
original_message="Build the thing.",
|
||||
decision=RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
company_profile="custom",
|
||||
org_id=None,
|
||||
),
|
||||
runtime_topology={
|
||||
"final_decider_role_id": "lead",
|
||||
"seats": [
|
||||
{
|
||||
"seat_id": "seat-engineer",
|
||||
"team_id": "team::engineering",
|
||||
"role_id": "engineer",
|
||||
"employee_assignment": {"employee_id": "eng-1", "name": "Engineer"},
|
||||
"metadata": {"role_name": "Engineer"},
|
||||
}
|
||||
],
|
||||
},
|
||||
delegation_playbook={},
|
||||
secretary_context="",
|
||||
target_output_dir=None,
|
||||
origin_channel="cli",
|
||||
origin_chat_id="",
|
||||
origin_thread_id="",
|
||||
origin_task_id=None,
|
||||
attachment_refs=[],
|
||||
attachment_context="",
|
||||
force_native_execution=False,
|
||||
)
|
||||
assert ctx.exception.code == "org_id_required"
|
||||
engine.store.save_task.assert_not_awaited()
|
||||
|
||||
async def test_ensure_runtime_work_item_task_rejects_existing_custom_task_without_durable_org(self) -> None:
|
||||
existing = Task(
|
||||
id="existing-no-org",
|
||||
title="Engineering execution",
|
||||
project_id="proj1",
|
||||
session_id="sess-company:wi-existing-no-org",
|
||||
assigned_to="engineer",
|
||||
metadata={
|
||||
"execution_mode": "company_mode",
|
||||
"runtime_model": "multi_team_org",
|
||||
"work_item_runtime": True,
|
||||
"work_item_projection_id": "engineering-execute",
|
||||
"work_item_turn_type": "execute",
|
||||
"company_profile": "custom",
|
||||
"delegation_seat_id": "seat-engineer",
|
||||
},
|
||||
)
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
engine.config.org.company_profile = "custom"
|
||||
engine.config.org.organization_id = "active-org"
|
||||
engine.store = SimpleNamespace(
|
||||
get_runtime_task_for_work_item=AsyncMock(return_value=existing),
|
||||
save_delegation_work_item=AsyncMock(),
|
||||
save_task=AsyncMock(),
|
||||
link_work_item_runtime_task=AsyncMock(return_value=True),
|
||||
)
|
||||
engine.memory = SimpleNamespace(ensure_session=AsyncMock())
|
||||
work_item = DelegationWorkItem(
|
||||
work_item_id="wi-existing-no-org",
|
||||
run_id="run-existing-no-org",
|
||||
cell_id="team::engineering",
|
||||
team_instance_id="team-instance-1",
|
||||
role_id="engineer",
|
||||
seat_id="seat-engineer",
|
||||
title="Engineering execution",
|
||||
summary="Implement the requested change.",
|
||||
kind="execute",
|
||||
projection_id="engineering-execute",
|
||||
metadata={"seat_id": "seat-engineer", "team_id": "team::engineering"},
|
||||
)
|
||||
with self.assertRaises(ServiceError) as ctx:
|
||||
await engine._ensure_runtime_work_item_task(
|
||||
work_item=work_item,
|
||||
parent_session_id="sess-company",
|
||||
original_message="Build the thing.",
|
||||
decision=RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
company_profile="custom",
|
||||
org_id=None,
|
||||
),
|
||||
runtime_topology={
|
||||
"final_decider_role_id": "lead",
|
||||
"seats": [
|
||||
{
|
||||
"seat_id": "seat-engineer",
|
||||
"team_id": "team::engineering",
|
||||
"role_id": "engineer",
|
||||
"employee_assignment": {"employee_id": "eng-1", "name": "Engineer"},
|
||||
"metadata": {"role_name": "Engineer"},
|
||||
}
|
||||
],
|
||||
},
|
||||
delegation_playbook={},
|
||||
secretary_context="",
|
||||
target_output_dir=None,
|
||||
origin_channel="cli",
|
||||
origin_chat_id="",
|
||||
origin_thread_id="",
|
||||
origin_task_id=None,
|
||||
attachment_refs=[],
|
||||
attachment_context="",
|
||||
force_native_execution=False,
|
||||
)
|
||||
assert ctx.exception.code == "org_id_required"
|
||||
engine.store.save_task.assert_not_awaited()
|
||||
|
||||
async def test_ensure_runtime_work_item_task_rejects_conflicting_org_ids(self) -> None:
|
||||
existing = Task(
|
||||
id="existing-conflict-org",
|
||||
title="Engineering execution",
|
||||
project_id="proj1",
|
||||
session_id="sess-company:wi-existing-conflict-org",
|
||||
assigned_to="engineer",
|
||||
org_id="persisted-org",
|
||||
metadata={
|
||||
"execution_mode": "company_mode",
|
||||
"runtime_model": "multi_team_org",
|
||||
"work_item_runtime": True,
|
||||
"work_item_projection_id": "engineering-execute",
|
||||
"work_item_turn_type": "execute",
|
||||
"company_profile": "custom",
|
||||
"organization_id": "persisted-org",
|
||||
"delegation_seat_id": "seat-engineer",
|
||||
},
|
||||
)
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
engine.config.org.company_profile = "custom"
|
||||
engine.config.org.organization_id = "active-org"
|
||||
engine.store = SimpleNamespace(
|
||||
get_runtime_task_for_work_item=AsyncMock(return_value=existing),
|
||||
save_delegation_work_item=AsyncMock(),
|
||||
save_task=AsyncMock(),
|
||||
link_work_item_runtime_task=AsyncMock(return_value=True),
|
||||
)
|
||||
engine.memory = SimpleNamespace(ensure_session=AsyncMock())
|
||||
work_item = DelegationWorkItem(
|
||||
work_item_id="wi-existing-conflict-org",
|
||||
run_id="run-existing-conflict-org",
|
||||
cell_id="team::engineering",
|
||||
team_instance_id="team-instance-1",
|
||||
role_id="engineer",
|
||||
seat_id="seat-engineer",
|
||||
title="Engineering execution",
|
||||
summary="Implement the requested change.",
|
||||
kind="execute",
|
||||
projection_id="engineering-execute",
|
||||
metadata={"seat_id": "seat-engineer", "team_id": "team::engineering"},
|
||||
)
|
||||
with self.assertRaises(ServiceError) as ctx:
|
||||
await engine._ensure_runtime_work_item_task(
|
||||
work_item=work_item,
|
||||
parent_session_id="sess-company",
|
||||
original_message="Build the thing.",
|
||||
decision=RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
company_profile="custom",
|
||||
org_id="selected-org",
|
||||
),
|
||||
runtime_topology={
|
||||
"final_decider_role_id": "lead",
|
||||
"seats": [
|
||||
{
|
||||
"seat_id": "seat-engineer",
|
||||
"team_id": "team::engineering",
|
||||
"role_id": "engineer",
|
||||
"employee_assignment": {"employee_id": "eng-1", "name": "Engineer"},
|
||||
"metadata": {"role_name": "Engineer"},
|
||||
}
|
||||
],
|
||||
},
|
||||
delegation_playbook={},
|
||||
secretary_context="",
|
||||
target_output_dir=None,
|
||||
origin_channel="cli",
|
||||
origin_chat_id="",
|
||||
origin_thread_id="",
|
||||
origin_task_id=None,
|
||||
attachment_refs=[],
|
||||
attachment_context="",
|
||||
force_native_execution=False,
|
||||
)
|
||||
assert ctx.exception.code == "org_id_conflict"
|
||||
engine.store.save_task.assert_not_awaited()
|
||||
|
||||
async def test_ensure_runtime_work_item_task_repairs_existing_custom_task_from_persisted_durable_org(self) -> None:
|
||||
existing = Task(
|
||||
id="existing-durable-org",
|
||||
title="Engineering execution",
|
||||
project_id="proj1",
|
||||
session_id="sess-company:wi-existing-durable-org",
|
||||
assigned_to="engineer",
|
||||
org_id="persisted-org",
|
||||
metadata={
|
||||
"execution_mode": "company_mode",
|
||||
"runtime_model": "multi_team_org",
|
||||
"work_item_runtime": True,
|
||||
"work_item_projection_id": "engineering-execute",
|
||||
"work_item_turn_type": "execute",
|
||||
"company_profile": "custom",
|
||||
"organization_id": "stale-org",
|
||||
"delegation_seat_id": "seat-engineer",
|
||||
},
|
||||
)
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
engine.config.org.company_profile = "custom"
|
||||
engine.config.org.organization_id = "active-org"
|
||||
engine.store = SimpleNamespace(
|
||||
get_runtime_task_for_work_item=AsyncMock(return_value=existing),
|
||||
save_delegation_work_item=AsyncMock(),
|
||||
save_task=AsyncMock(),
|
||||
link_work_item_runtime_task=AsyncMock(return_value=True),
|
||||
)
|
||||
engine.memory = SimpleNamespace(ensure_session=AsyncMock())
|
||||
work_item = DelegationWorkItem(
|
||||
work_item_id="wi-existing-durable-org",
|
||||
run_id="run-existing-durable-org",
|
||||
cell_id="team::engineering",
|
||||
team_instance_id="team-instance-1",
|
||||
role_id="engineer",
|
||||
seat_id="seat-engineer",
|
||||
title="Engineering execution",
|
||||
summary="Implement the requested change.",
|
||||
kind="execute",
|
||||
projection_id="engineering-execute",
|
||||
metadata={"seat_id": "seat-engineer", "team_id": "team::engineering"},
|
||||
)
|
||||
repaired = await engine._ensure_runtime_work_item_task(
|
||||
work_item=work_item,
|
||||
parent_session_id="sess-company",
|
||||
original_message="Build the thing.",
|
||||
decision=RouterDecision(
|
||||
mode=ExecutionMode.COMPANY_MODE,
|
||||
company_profile="custom",
|
||||
org_id=None,
|
||||
),
|
||||
runtime_topology={
|
||||
"final_decider_role_id": "lead",
|
||||
"seats": [
|
||||
{
|
||||
"seat_id": "seat-engineer",
|
||||
"team_id": "team::engineering",
|
||||
"role_id": "engineer",
|
||||
"employee_assignment": {"employee_id": "eng-1", "name": "Engineer"},
|
||||
"metadata": {"role_name": "Engineer"},
|
||||
}
|
||||
],
|
||||
},
|
||||
delegation_playbook={},
|
||||
secretary_context="",
|
||||
target_output_dir=None,
|
||||
origin_channel="cli",
|
||||
origin_chat_id="",
|
||||
origin_thread_id="",
|
||||
origin_task_id=None,
|
||||
attachment_refs=[],
|
||||
attachment_context="",
|
||||
force_native_execution=False,
|
||||
)
|
||||
self.assertEqual(repaired.id, "existing-durable-org")
|
||||
self.assertEqual(repaired.org_id, "persisted-org")
|
||||
self.assertEqual(repaired.metadata["org_id"], "persisted-org")
|
||||
self.assertEqual(repaired.metadata["organization_id"], "persisted-org")
|
||||
engine.store.save_task.assert_awaited_with(existing)
|
||||
|
||||
async def test_delivery_self_evolution_custom_without_durable_org_fails_closed(self) -> None:
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
engine.config.org.company_profile = "custom"
|
||||
engine.config.org.organization_id = "active-org"
|
||||
waiting_task = Task(
|
||||
id="waiting-custom",
|
||||
project_id="proj1",
|
||||
session_id="sess-delivery",
|
||||
metadata={
|
||||
"execution_mode": "company_mode",
|
||||
"company_profile": "custom",
|
||||
"work_item_runtime": True,
|
||||
"work_item_projection_id": "delivery",
|
||||
"work_item_turn_type": "deliver",
|
||||
},
|
||||
)
|
||||
engine.store = SimpleNamespace(get_task=AsyncMock(return_value=waiting_task))
|
||||
engine._mark_company_runtime_checkpoint_status = AsyncMock()
|
||||
engine._create_company_self_evolution_root_work_item = AsyncMock()
|
||||
checkpoint = ExecutionCheckpoint(
|
||||
checkpoint_id="cp-delivery",
|
||||
project_id="proj1",
|
||||
session_id="sess-delivery",
|
||||
task_id="waiting-custom",
|
||||
checkpoint_type="company_delivery_feedback",
|
||||
payload={"waiting_task_id": "waiting-custom", "task_ids": ["waiting-custom"]},
|
||||
)
|
||||
result = await engine._run_company_delivery_self_evolution_consumed(
|
||||
checkpoint,
|
||||
action="approve",
|
||||
)
|
||||
assert "durable org identity" in result
|
||||
engine._mark_company_runtime_checkpoint_status.assert_awaited_once_with(
|
||||
checkpoint,
|
||||
status="invalid",
|
||||
)
|
||||
engine._create_company_self_evolution_root_work_item.assert_not_awaited()
|
||||
|
||||
async def test_delivery_self_evolution_custom_uses_durable_org_over_payload_and_config(self) -> None:
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
engine.config.org.company_profile = "custom"
|
||||
engine.config.org.organization_id = "active-org"
|
||||
waiting_task = Task(
|
||||
id="waiting-custom-2",
|
||||
project_id="proj1",
|
||||
session_id="sess-delivery",
|
||||
org_id="selected-org",
|
||||
metadata={
|
||||
"execution_mode": "company_mode",
|
||||
"company_profile": "custom",
|
||||
"work_item_runtime": True,
|
||||
"work_item_projection_id": "delivery",
|
||||
"work_item_turn_type": "deliver",
|
||||
},
|
||||
)
|
||||
engine.store = SimpleNamespace(get_task=AsyncMock(return_value=waiting_task))
|
||||
engine._mark_company_runtime_checkpoint_status = AsyncMock()
|
||||
engine.org_engine = None
|
||||
engine._company_followup_target_task = MagicMock(
|
||||
return_value=SimpleNamespace(assigned_to="lead", metadata={}),
|
||||
)
|
||||
engine.company_executor = SimpleNamespace()
|
||||
engine._self_evolution_assignments_by_role = MagicMock(return_value={})
|
||||
engine._create_company_self_evolution_root_work_item = AsyncMock(return_value=None)
|
||||
checkpoint = ExecutionCheckpoint(
|
||||
checkpoint_id="cp-delivery-2",
|
||||
project_id="proj1",
|
||||
session_id="sess-delivery",
|
||||
task_id="waiting-custom-2",
|
||||
checkpoint_type="company_delivery_feedback",
|
||||
payload={
|
||||
"waiting_task_id": "waiting-custom-2",
|
||||
"task_ids": ["waiting-custom-2"],
|
||||
"organization_id": "stale-org",
|
||||
},
|
||||
)
|
||||
await engine._run_company_delivery_self_evolution_consumed(
|
||||
checkpoint,
|
||||
action="approve",
|
||||
)
|
||||
call = engine._create_company_self_evolution_root_work_item.await_args
|
||||
assert call is not None
|
||||
assert call.kwargs["organization_id"] == "selected-org"
|
||||
|
||||
async def test_delivery_self_evolution_corporate_still_uses_config_default(self) -> None:
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
waiting_task = Task(
|
||||
id="waiting-corporate",
|
||||
project_id="proj1",
|
||||
session_id="sess-delivery",
|
||||
metadata={
|
||||
"execution_mode": "company_mode",
|
||||
"company_profile": "corporate",
|
||||
"work_item_runtime": True,
|
||||
"work_item_projection_id": "delivery",
|
||||
"work_item_turn_type": "deliver",
|
||||
},
|
||||
)
|
||||
engine.store = SimpleNamespace(get_task=AsyncMock(return_value=waiting_task))
|
||||
engine._mark_company_runtime_checkpoint_status = AsyncMock()
|
||||
engine.org_engine = None
|
||||
engine._company_followup_target_task = MagicMock(
|
||||
return_value=SimpleNamespace(assigned_to="lead", metadata={}),
|
||||
)
|
||||
engine.company_executor = SimpleNamespace()
|
||||
engine._self_evolution_assignments_by_role = MagicMock(return_value={})
|
||||
engine._create_company_self_evolution_root_work_item = AsyncMock(return_value=None)
|
||||
checkpoint = ExecutionCheckpoint(
|
||||
checkpoint_id="cp-delivery-corp",
|
||||
project_id="proj1",
|
||||
session_id="sess-delivery",
|
||||
task_id="waiting-corporate",
|
||||
checkpoint_type="company_delivery_feedback",
|
||||
payload={"waiting_task_id": "waiting-corporate", "task_ids": ["waiting-corporate"]},
|
||||
)
|
||||
await engine._run_company_delivery_self_evolution_consumed(
|
||||
checkpoint,
|
||||
action="approve",
|
||||
)
|
||||
call = engine._create_company_self_evolution_root_work_item.await_args
|
||||
assert call is not None
|
||||
assert call.kwargs["organization_id"] == DEFAULT_ORGANIZATION_ID
|
||||
|
||||
async def test_delivery_self_evolution_metadata_only_legacy_custom_uses_metadata_org(self) -> None:
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
engine.config.org.company_profile = "custom"
|
||||
engine.config.org.organization_id = "active-org"
|
||||
waiting_task = Task(
|
||||
id="waiting-legacy-metadata",
|
||||
project_id="proj1",
|
||||
session_id="sess-delivery",
|
||||
metadata={
|
||||
"work_item_runtime": True,
|
||||
"work_item_projection_id": "delivery",
|
||||
"work_item_turn_type": "deliver",
|
||||
"org_id": "selected-org",
|
||||
},
|
||||
)
|
||||
engine.store = SimpleNamespace(get_task=AsyncMock(return_value=waiting_task))
|
||||
engine._mark_company_runtime_checkpoint_status = AsyncMock()
|
||||
engine.org_engine = None
|
||||
engine._company_followup_target_task = MagicMock(
|
||||
return_value=SimpleNamespace(assigned_to="lead", metadata={}),
|
||||
)
|
||||
engine.company_executor = SimpleNamespace()
|
||||
engine._self_evolution_assignments_by_role = MagicMock(return_value={})
|
||||
engine._create_company_self_evolution_root_work_item = AsyncMock(return_value=None)
|
||||
checkpoint = ExecutionCheckpoint(
|
||||
checkpoint_id="cp-delivery-legacy",
|
||||
project_id="proj1",
|
||||
session_id="sess-delivery",
|
||||
task_id="waiting-legacy-metadata",
|
||||
checkpoint_type="company_delivery_feedback",
|
||||
payload={
|
||||
"waiting_task_id": "waiting-legacy-metadata",
|
||||
"task_ids": ["waiting-legacy-metadata"],
|
||||
},
|
||||
)
|
||||
await engine._run_company_delivery_self_evolution_consumed(
|
||||
checkpoint,
|
||||
action="approve",
|
||||
)
|
||||
call = engine._create_company_self_evolution_root_work_item.await_args
|
||||
assert call is not None
|
||||
assert call.kwargs["organization_id"] == "selected-org"
|
||||
|
||||
async def test_delivery_self_evolution_conflicting_org_ids_fail_closed(self) -> None:
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
engine.config.org.company_profile = "custom"
|
||||
engine.config.org.organization_id = "active-org"
|
||||
waiting_task = Task(
|
||||
id="waiting-conflict",
|
||||
project_id="proj1",
|
||||
session_id="sess-delivery",
|
||||
org_id="selected-org",
|
||||
metadata={
|
||||
"work_item_runtime": True,
|
||||
"work_item_projection_id": "delivery",
|
||||
"work_item_turn_type": "deliver",
|
||||
"org_id": "other-org",
|
||||
},
|
||||
)
|
||||
engine.store = SimpleNamespace(get_task=AsyncMock(return_value=waiting_task))
|
||||
engine._mark_company_runtime_checkpoint_status = AsyncMock()
|
||||
engine.org_engine = None
|
||||
engine._company_followup_target_task = MagicMock(
|
||||
return_value=SimpleNamespace(assigned_to="lead", metadata={}),
|
||||
)
|
||||
engine.company_executor = SimpleNamespace()
|
||||
engine._self_evolution_assignments_by_role = MagicMock(return_value={})
|
||||
engine._create_company_self_evolution_root_work_item = AsyncMock(return_value=None)
|
||||
checkpoint = ExecutionCheckpoint(
|
||||
checkpoint_id="cp-delivery-conflict",
|
||||
project_id="proj1",
|
||||
session_id="sess-delivery",
|
||||
task_id="waiting-conflict",
|
||||
checkpoint_type="company_delivery_feedback",
|
||||
payload={
|
||||
"waiting_task_id": "waiting-conflict",
|
||||
"task_ids": ["waiting-conflict"],
|
||||
},
|
||||
)
|
||||
result = await engine._run_company_delivery_self_evolution_consumed(
|
||||
checkpoint,
|
||||
action="approve",
|
||||
)
|
||||
assert "org identity" in result
|
||||
engine._mark_company_runtime_checkpoint_status.assert_awaited_once_with(
|
||||
checkpoint,
|
||||
status="invalid",
|
||||
)
|
||||
engine._create_company_self_evolution_root_work_item.assert_not_awaited()
|
||||
|
||||
async def test_company_materialized_work_item_uses_selected_agent_over_template_preference(self) -> None:
|
||||
saved_tasks: list[Task] = []
|
||||
|
||||
@@ -389,6 +1040,132 @@ class RuntimeConfigEnforcementTests(unittest.IsolatedAsyncioTestCase):
|
||||
self.assertEqual(created.metadata["work_item_execution_strategy"], WorkItemExecutionStrategy.EXTERNAL.value)
|
||||
self.assertEqual(saved_tasks[0].assigned_external_agent, "cursor")
|
||||
|
||||
async def test_company_materialization_persists_durable_org_on_new_role_task(self) -> None:
|
||||
executor = CompanyWorkItemExecutor(
|
||||
org_engine=SimpleNamespace(),
|
||||
communication=SimpleNamespace(),
|
||||
approval_engine=SimpleNamespace(),
|
||||
memory=SimpleNamespace(ensure_session=AsyncMock()),
|
||||
execute_task=AsyncMock(),
|
||||
save_task=AsyncMock(),
|
||||
)
|
||||
executor.store = SimpleNamespace(
|
||||
get_runtime_task_for_work_item=AsyncMock(return_value=None),
|
||||
save_delegation_work_item=AsyncMock(),
|
||||
save_task=AsyncMock(),
|
||||
link_work_item_runtime_task=AsyncMock(return_value=True),
|
||||
)
|
||||
root_task = Task(
|
||||
id="root-custom-org",
|
||||
title="Root",
|
||||
project_id="proj1",
|
||||
session_id="sess-company",
|
||||
org_id="selected-org",
|
||||
metadata={
|
||||
"execution_mode": "company_mode",
|
||||
"runtime_model": "multi_team_org",
|
||||
"company_profile": "custom",
|
||||
"organization_id": "active-org",
|
||||
"runtime_topology": {
|
||||
"seats": [
|
||||
{
|
||||
"seat_id": "seat-engineer",
|
||||
"team_id": "team::engineering",
|
||||
"role_id": "engineer",
|
||||
"metadata": {"role_name": "Engineer"},
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
)
|
||||
work_item = DelegationWorkItem(
|
||||
work_item_id="wi-new-custom-org",
|
||||
run_id="run-custom-org",
|
||||
cell_id="team::engineering",
|
||||
team_instance_id="team-instance-1",
|
||||
role_id="engineer",
|
||||
seat_id="seat-engineer",
|
||||
title="Engineering execution",
|
||||
summary="Implement the requested change.",
|
||||
kind="execute",
|
||||
projection_id="engineering-execute",
|
||||
metadata={"seat_id": "seat-engineer", "team_id": "team::engineering"},
|
||||
)
|
||||
|
||||
tasks = await executor._materialize_work_item_tasks([root_task], [work_item])
|
||||
created = next(task for task in tasks if task.id != root_task.id)
|
||||
|
||||
self.assertEqual(created.org_id, "selected-org")
|
||||
self.assertEqual(created.metadata["org_id"], "selected-org")
|
||||
self.assertEqual(created.metadata["organization_id"], "selected-org")
|
||||
|
||||
async def test_company_materialization_repairs_existing_role_task_org_identity(self) -> None:
|
||||
existing = Task(
|
||||
id="existing-custom-role",
|
||||
title="Engineering execution",
|
||||
project_id="proj1",
|
||||
session_id="sess-company:wi-existing-custom-org",
|
||||
assigned_to="engineer",
|
||||
org_id="active-org",
|
||||
metadata={
|
||||
"execution_mode": "company_mode",
|
||||
"runtime_model": "multi_team_org",
|
||||
"work_item_runtime": True,
|
||||
"work_item_projection_id": "engineering-execute",
|
||||
"work_item_turn_type": "execute",
|
||||
"company_profile": "custom",
|
||||
"organization_id": "active-org",
|
||||
"delegation_seat_id": "seat-engineer",
|
||||
},
|
||||
)
|
||||
executor = CompanyWorkItemExecutor(
|
||||
org_engine=SimpleNamespace(),
|
||||
communication=SimpleNamespace(),
|
||||
approval_engine=SimpleNamespace(),
|
||||
memory=SimpleNamespace(ensure_session=AsyncMock()),
|
||||
execute_task=AsyncMock(),
|
||||
save_task=AsyncMock(),
|
||||
)
|
||||
executor.store = SimpleNamespace(
|
||||
get_runtime_task_for_work_item=AsyncMock(return_value=existing),
|
||||
save_delegation_work_item=AsyncMock(),
|
||||
save_task=AsyncMock(),
|
||||
)
|
||||
root_task = Task(
|
||||
id="root-custom-org-existing",
|
||||
title="Root",
|
||||
project_id="proj1",
|
||||
session_id="sess-company",
|
||||
org_id="selected-org",
|
||||
metadata={
|
||||
"execution_mode": "company_mode",
|
||||
"runtime_model": "multi_team_org",
|
||||
"company_profile": "custom",
|
||||
"organization_id": "active-org",
|
||||
},
|
||||
)
|
||||
work_item = DelegationWorkItem(
|
||||
work_item_id="wi-existing-custom-org",
|
||||
run_id="run-custom-org",
|
||||
cell_id="team::engineering",
|
||||
team_instance_id="team-instance-1",
|
||||
role_id="engineer",
|
||||
seat_id="seat-engineer",
|
||||
title="Engineering execution",
|
||||
summary="Implement the requested change.",
|
||||
kind="execute",
|
||||
projection_id="engineering-execute",
|
||||
metadata={"seat_id": "seat-engineer", "team_id": "team::engineering"},
|
||||
)
|
||||
|
||||
tasks = await executor._materialize_work_item_tasks([root_task], [work_item])
|
||||
repaired = next(task for task in tasks if task.id == existing.id)
|
||||
|
||||
self.assertEqual(repaired.org_id, "selected-org")
|
||||
self.assertEqual(repaired.metadata["org_id"], "selected-org")
|
||||
self.assertEqual(repaired.metadata["organization_id"], "selected-org")
|
||||
executor.store.save_task.assert_any_await(existing)
|
||||
|
||||
async def test_task_mode_external_followup_reuses_primary_session_external_agent_session(self) -> None:
|
||||
engine = OPCEngine(config=OPCConfig(), project_id="proj1")
|
||||
engine.store = SimpleNamespace(
|
||||
|
||||
@@ -1998,6 +1998,192 @@ class TestWSHandlerSessionSend(unittest.IsolatedAsyncioTestCase):
|
||||
self.assertIn("company_session_reopened_at", refreshed.metadata)
|
||||
self.engine.process_message.assert_called_once()
|
||||
|
||||
async def test_process_session_message_uses_durable_org_for_role_task(self) -> None:
|
||||
runtime_session_id = "runtime-org-session"
|
||||
anchor = await self.store.get_task(self.task_id)
|
||||
assert anchor is not None
|
||||
anchor.session_id = runtime_session_id
|
||||
anchor.metadata = {
|
||||
"exec_mode": "org",
|
||||
"mode": "company",
|
||||
"company_profile": "custom",
|
||||
"org_id": "wrong-active-org",
|
||||
"organization_id": "wrong-active-org",
|
||||
}
|
||||
anchor.org_id = "vc-investment-firm"
|
||||
await self.store.save_task(anchor)
|
||||
|
||||
role_task = Task(
|
||||
id="role-task-without-org-id",
|
||||
title="Sector Analyst",
|
||||
project_id="test-project",
|
||||
session_id=f"{runtime_session_id}:role:sector-analyst",
|
||||
parent_session_id=runtime_session_id,
|
||||
org_id="vc-investment-firm",
|
||||
metadata={
|
||||
"exec_mode": "org",
|
||||
"mode": "company",
|
||||
"company_profile": "custom",
|
||||
"org_id": "wrong-active-org",
|
||||
"organization_id": "wrong-active-org",
|
||||
"shared_role_session": True,
|
||||
"shared_role_id": "sector_analyst",
|
||||
"company_runtime_root_session_id": runtime_session_id,
|
||||
},
|
||||
)
|
||||
await self.store.save_task(role_task)
|
||||
self.handler.services_context.get_active_saved_org_name = AsyncMock(
|
||||
return_value="wrong-active-org"
|
||||
)
|
||||
|
||||
await self.handler._process_session_message(
|
||||
role_task.id,
|
||||
"approve",
|
||||
session_id=role_task.session_id,
|
||||
)
|
||||
|
||||
self.engine.process_message.assert_called_once()
|
||||
call_kwargs = self.engine.process_message.call_args.kwargs
|
||||
self.assertEqual(call_kwargs["mode"], "org")
|
||||
self.assertEqual(call_kwargs["company_profile"], "custom")
|
||||
self.assertEqual(call_kwargs["org_id"], "vc-investment-firm")
|
||||
|
||||
async def test_process_session_message_fails_closed_when_runtime_identity_is_missing(self) -> None:
|
||||
task = await self.store.get_task(self.task_id)
|
||||
assert task is not None
|
||||
task.metadata = {
|
||||
"mode": "company",
|
||||
"company_profile": "custom",
|
||||
}
|
||||
await self.store.save_task(task)
|
||||
self.handler._resolve_company_runtime_target = AsyncMock(return_value=None)
|
||||
self.handler.services_context.get_active_saved_org_name = AsyncMock(
|
||||
return_value="wrong-active-org"
|
||||
)
|
||||
|
||||
with self.assertRaises(ServiceError) as context:
|
||||
await self.handler._process_session_message(
|
||||
self.task_id,
|
||||
"approve",
|
||||
session_id=self.session_id,
|
||||
)
|
||||
|
||||
self.engine.process_message.assert_not_called()
|
||||
self.handler.services_context.get_active_saved_org_name.assert_not_awaited()
|
||||
self.assertEqual(context.exception.code, "company_runtime_identity_mismatch")
|
||||
|
||||
async def test_process_session_message_rejects_runtime_org_without_durable_org_id(self) -> None:
|
||||
runtime_session_id = "runtime-org-missing-id-session"
|
||||
anchor = await self.store.get_task(self.task_id)
|
||||
assert anchor is not None
|
||||
anchor.session_id = runtime_session_id
|
||||
anchor.metadata = {
|
||||
"exec_mode": "org",
|
||||
"mode": "company",
|
||||
"company_profile": "custom",
|
||||
}
|
||||
await self.store.save_task(anchor)
|
||||
|
||||
role_task = Task(
|
||||
id="role-task-missing-org-id",
|
||||
title="Sector Analyst",
|
||||
project_id="test-project",
|
||||
session_id=f"{runtime_session_id}:role:sector-analyst",
|
||||
parent_session_id=runtime_session_id,
|
||||
metadata={
|
||||
"exec_mode": "org",
|
||||
"mode": "company",
|
||||
"company_profile": "custom",
|
||||
"shared_role_session": True,
|
||||
"shared_role_id": "sector_analyst",
|
||||
"company_runtime_root_session_id": runtime_session_id,
|
||||
},
|
||||
)
|
||||
await self.store.save_task(role_task)
|
||||
self.handler.services_context.get_active_saved_org_name = AsyncMock(
|
||||
return_value="wrong-active-org"
|
||||
)
|
||||
|
||||
with self.assertRaises(ServiceError) as context:
|
||||
await self.handler._process_session_message(
|
||||
role_task.id,
|
||||
"approve",
|
||||
session_id=role_task.session_id,
|
||||
)
|
||||
|
||||
self.engine.process_message.assert_not_called()
|
||||
self.handler.services_context.get_active_saved_org_name.assert_not_awaited()
|
||||
self.assertEqual(context.exception.code, "org_id_required")
|
||||
|
||||
async def test_lock_free_process_session_message_uses_durable_org_for_role_task(self) -> None:
|
||||
runtime_session_id = "runtime-org-lock-free-session"
|
||||
anchor = await self.store.get_task(self.task_id)
|
||||
assert anchor is not None
|
||||
anchor.session_id = runtime_session_id
|
||||
anchor.metadata = {
|
||||
"exec_mode": "org",
|
||||
"mode": "company",
|
||||
"company_profile": "custom",
|
||||
"org_id": "vc-investment-firm",
|
||||
}
|
||||
await self.store.save_task(anchor)
|
||||
|
||||
role_task = Task(
|
||||
id="role-task-lock-free-without-org-id",
|
||||
title="Sector Analyst",
|
||||
project_id="test-project",
|
||||
session_id=f"{runtime_session_id}:role:sector-analyst",
|
||||
parent_session_id=runtime_session_id,
|
||||
metadata={
|
||||
"exec_mode": "org",
|
||||
"mode": "company",
|
||||
"company_profile": "custom",
|
||||
"shared_role_session": True,
|
||||
"shared_role_id": "sector_analyst",
|
||||
"company_runtime_root_session_id": runtime_session_id,
|
||||
},
|
||||
)
|
||||
await self.store.save_task(role_task)
|
||||
checkpoint = ExecutionCheckpoint(
|
||||
checkpoint_id="org-lock-free-gate",
|
||||
project_id="test-project",
|
||||
session_id=role_task.session_id,
|
||||
checkpoint_type="company_work_item_gate",
|
||||
status="pending",
|
||||
task_id=role_task.id,
|
||||
payload={
|
||||
"waiting_task_id": role_task.id,
|
||||
"task_ids": [role_task.id],
|
||||
"session_id": role_task.session_id,
|
||||
},
|
||||
)
|
||||
await self.store.save_execution_checkpoint(checkpoint)
|
||||
self.engine._load_execution_checkpoint_by_id = AsyncMock(return_value=checkpoint)
|
||||
self.handler.services_context.get_active_saved_org_name = AsyncMock(
|
||||
return_value="wrong-active-org"
|
||||
)
|
||||
|
||||
lock = self.handler._get_task_lock(role_task.id)
|
||||
await lock.acquire()
|
||||
try:
|
||||
await self.handler._process_session_message(
|
||||
role_task.id,
|
||||
"approve",
|
||||
session_id=role_task.session_id,
|
||||
message_metadata={
|
||||
"response_to_checkpoint_id": checkpoint.checkpoint_id,
|
||||
"response_to_checkpoint_type": checkpoint.checkpoint_type,
|
||||
},
|
||||
)
|
||||
finally:
|
||||
lock.release()
|
||||
|
||||
self.engine.process_message.assert_called_once()
|
||||
call_kwargs = self.engine.process_message.call_args.kwargs
|
||||
self.assertEqual(call_kwargs["mode"], "org")
|
||||
self.assertEqual(call_kwargs["company_profile"], "custom")
|
||||
self.assertEqual(call_kwargs["org_id"], "vc-investment-firm")
|
||||
|
||||
async def test_session_send_reuses_task_session_without_is_ready_flag(self) -> None:
|
||||
"""Session replies should reuse the task session even for simple stub stores."""
|
||||
ws = MagicMock()
|
||||
@@ -5296,6 +5482,41 @@ class TestOfficeServiceExecutionIdentity(unittest.IsolatedAsyncioTestCase):
|
||||
assert persisted is not None
|
||||
self.assertEqual(persisted.status, TaskStatus.RUNNING)
|
||||
|
||||
async def test_continue_rejects_runtime_custom_org_without_durable_org_id(self) -> None:
|
||||
task = Task(
|
||||
id="service-continue-org-missing-id",
|
||||
title="Broken custom runtime",
|
||||
session_id="service-continue-org-runtime",
|
||||
project_id="test-project",
|
||||
metadata={"exec_mode": "org", "company_profile": "custom"},
|
||||
)
|
||||
checkpoint = ExecutionCheckpoint(
|
||||
checkpoint_id="service-continue-org-checkpoint",
|
||||
project_id="test-project",
|
||||
session_id=task.session_id,
|
||||
checkpoint_type="company_runtime_suspended",
|
||||
status="pending",
|
||||
task_id=task.id,
|
||||
)
|
||||
await self.store.save_task(task)
|
||||
self.session_service._resolve_company_runtime_target = AsyncMock(return_value={
|
||||
"runtime_session_id": task.session_id,
|
||||
"ui_anchor_task_id": task.id,
|
||||
"config_task": task,
|
||||
"checkpoint": checkpoint,
|
||||
"affected_task_ids": [task.id],
|
||||
})
|
||||
|
||||
with self.assertRaises(ServiceError) as raised:
|
||||
await self.session_service.continue_run(
|
||||
project_id="test-project",
|
||||
task_id=task.id,
|
||||
content="continue",
|
||||
)
|
||||
|
||||
self.assertEqual(raised.exception.code, "org_id_required")
|
||||
self.engine.process_message.assert_not_called()
|
||||
|
||||
async def test_session_send_from_work_item_uses_runtime_checkpoint_identity(self) -> None:
|
||||
anchor = Task(
|
||||
id="service-send-anchor",
|
||||
@@ -5726,6 +5947,32 @@ class TestWSHandlerRunTask(unittest.IsolatedAsyncioTestCase):
|
||||
self.assertEqual(call_kwargs["company_profile"], "custom")
|
||||
self.assertEqual(call_kwargs["org_id"], "quantum_harbor")
|
||||
|
||||
async def test_run_task_fails_closed_for_custom_identity_without_org_id(self) -> None:
|
||||
task_id = str(uuid.uuid4())
|
||||
session_id = str(uuid.uuid4())
|
||||
task = Task(
|
||||
id=task_id,
|
||||
title="Missing Org Runtime",
|
||||
session_id=session_id,
|
||||
project_id="test-project",
|
||||
metadata={"exec_mode": "org", "company_profile": "custom"},
|
||||
)
|
||||
await self.store.save_task(task)
|
||||
self.handler.services_context.get_active_saved_org_name = AsyncMock(
|
||||
return_value="wrong-active-org"
|
||||
)
|
||||
|
||||
await self.handler._run_task(
|
||||
"Missing Org Runtime",
|
||||
"Description",
|
||||
"org",
|
||||
"custom",
|
||||
task_id,
|
||||
)
|
||||
|
||||
self.engine.process_message.assert_not_called()
|
||||
self.handler.services_context.get_active_saved_org_name.assert_not_awaited()
|
||||
|
||||
async def test_run_task_explicit_company_clears_stale_custom_fields(self) -> None:
|
||||
task_id = str(uuid.uuid4())
|
||||
session_id = str(uuid.uuid4())
|
||||
|
||||
Reference in New Issue
Block a user