fix(ui): enforce durable org identity for runtime followups

This commit is contained in:
cgycorey
2026-08-02 17:20:34 +01:00
parent 734a2d5969
commit 15ab07cba2
9 changed files with 943 additions and 22 deletions
+76 -15
View File
@@ -37,6 +37,7 @@ from opc.core.config import (
company_org_path,
get_opc_home,
get_project_workplace,
validate_organization_id,
)
from opc.core.events import EventBus
from opc.core.models import (
@@ -3563,6 +3564,13 @@ class OPCEngine:
return False
return bool(dict(getattr(task, "metadata", {}) or {}).get("shared_role_session", False))
@staticmethod
def _normalize_durable_org_id(value: Any) -> str:
try:
return validate_organization_id(value)
except ValueError:
return ""
@staticmethod
def _runtime_org_id_for_identity(
decision: RouterDecision | None,
@@ -3583,7 +3591,6 @@ class OPCEngine:
getattr(decision, "org_id", None),
task_metadata.get("org_id"),
task_metadata.get("organization_id"),
getattr(org_config, "organization_id", None),
):
normalized = str(candidate or "").strip()
if normalized:
@@ -3628,6 +3635,12 @@ class OPCEngine:
root_session: bool = False,
) -> Task:
assert self.store and self.memory
runtime_company_profile = str(
getattr(decision, "company_profile", "")
or (work_item.metadata or {}).get("company_profile", "")
or getattr(getattr(self.config, "org", None), "company_profile", "")
or ""
).strip().lower()
runtime_org_id = self._runtime_org_id_for_identity(
decision,
getattr(work_item, "metadata", None),
@@ -3685,7 +3698,39 @@ class OPCEngine:
set_linked_work_item_id(existing, work_item.work_item_id)
existing.session_id = session_id
existing.metadata = dict(existing.metadata or {})
if runtime_org_id:
if runtime_company_profile == "custom":
persisted_org_id = self._normalize_durable_org_id(getattr(existing, "org_id", None))
incoming_org_id = self._normalize_durable_org_id(runtime_org_id)
if persisted_org_id and incoming_org_id and persisted_org_id != incoming_org_id:
from opc.plugins.office_ui.services.models import ServiceError
raise ServiceError(
"org_id_conflict",
"org_id_conflict",
{
"project_id": self.project_id or "default",
"task_id": str(getattr(work_item, "work_item_id", "") or ""),
"persisted_org_id": persisted_org_id,
"incoming_org_id": incoming_org_id,
"reason": "custom_company_run_org_id_conflict",
},
)
resolved_org_id = persisted_org_id or incoming_org_id
if not resolved_org_id:
from opc.plugins.office_ui.services.models import ServiceError
raise ServiceError(
"org_id_required",
"org_id_required",
{
"project_id": self.project_id or "default",
"task_id": str(getattr(work_item, "work_item_id", "") or ""),
"reason": "custom_company_run_requires_durable_org_id",
},
)
runtime_org_id = resolved_org_id
existing.org_id = resolved_org_id
existing.metadata["org_id"] = resolved_org_id
existing.metadata["organization_id"] = resolved_org_id
elif runtime_org_id:
existing.org_id = runtime_org_id
existing.metadata["org_id"] = runtime_org_id
existing.metadata["organization_id"] = runtime_org_id
@@ -3730,6 +3775,17 @@ class OPCEngine:
)
await self.store.save_task(existing)
return existing
if runtime_company_profile == "custom" and not runtime_org_id:
from opc.plugins.office_ui.services.models import ServiceError
raise ServiceError(
"org_id_required",
"org_id_required",
{
"project_id": self.project_id or "default",
"task_id": str(getattr(work_item, "work_item_id", "") or ""),
"reason": "custom_company_run_requires_durable_org_id",
},
)
employee_assignment = dict(topology_seat.get("employee_assignment", {}) or {})
if not employee_assignment and self.org_engine and role_id:
preferred_employee_id = str(topology_seat.get("employee_id", "") or "").strip() or None
@@ -3780,12 +3836,6 @@ class OPCEngine:
owner_execution_copy = build_work_item_owner_execution_copy(work_item)
owner_execution_copy.setdefault("delegation_role_session_id", role_session_id)
owner_execution_copy["work_kind"] = work_item_turn_type
runtime_company_profile = str(
getattr(decision, "company_profile", "")
or (work_item.metadata or {}).get("company_profile", "")
or getattr(getattr(self.config, "org", None), "company_profile", "")
or ""
).strip().lower()
runtime_identity_metadata = (
{
"org_id": runtime_org_id or "",
@@ -12704,7 +12754,12 @@ class OPCEngine:
seen_employee_ids.add(employee_id)
history = ""
if self.memory:
organization_id = str(getattr(getattr(self.config, "org", None), "organization_id", "") or "").strip()
organization_id = str(
getattr(delivery_task, "org_id", "")
or (delivery_task.metadata or {}).get("org_id")
or (delivery_task.metadata or {}).get("organization_id")
or ""
).strip()
history = self.memory.employee_evolution.build_employee_delta_context(
employee_id,
project_id=task.project_id,
@@ -13246,13 +13301,19 @@ class OPCEngine:
await self._mark_company_runtime_checkpoint_status(checkpoint, status="invalid")
return "Could not run self-evolution because the runtime task set could not be restored."
from opc.plugins.office_ui.execution_identity import resolve_delivery_task_org_identity
organization_id, identity_error = resolve_delivery_task_org_identity(
waiting_task,
payload=payload,
active_org_id=getattr(getattr(self.config, "org", None), "organization_id", ""),
default_org_id=DEFAULT_ORGANIZATION_ID,
)
if identity_error:
await self._mark_company_runtime_checkpoint_status(checkpoint, status="invalid")
return f"Could not run self-evolution because {identity_error}."
plan = deserialize_company_work_item_runtime_plan(payload.get("company_work_item_plan") or payload.get("plan", {}))
organization_id = str(
getattr(waiting_task, "org_id", "")
or payload.get("organization_id")
or getattr(getattr(self.config, "org", None), "organization_id", "")
or DEFAULT_ORGANIZATION_ID
).strip() or DEFAULT_ORGANIZATION_ID
root_role_id = str(
getattr(plan, "final_decider_role_id", "")
or plan.metadata.get("final_decider_role_id", "")
+31 -3
View File
@@ -22,7 +22,11 @@ from opc.core.active_task_runs import (
ActiveTaskRunAdmissionClosed,
ActiveTaskRunRegistry,
)
from opc.core.config import DEFAULT_EXTERNAL_AGENT_STARTUP_TIMEOUT_SECONDS, DEFAULT_ORGANIZATION_ID
from opc.core.config import (
DEFAULT_EXTERNAL_AGENT_STARTUP_TIMEOUT_SECONDS,
DEFAULT_ORGANIZATION_ID,
validate_organization_id,
)
from opc.core.models import (
AdaptiveRoleProfile,
AdaptiveSignalSpec,
@@ -1326,6 +1330,26 @@ class CompanyRuntimeSpecBuilder(CompanyRuntimeWorkItemHelper):
or "corporate"
).strip() or "corporate"
org_config = getattr(self.org_engine.config, "org", None)
selected_org_id = ""
if profile == "custom":
try:
selected_org_id = validate_organization_id(getattr(decision, "org_id", None))
except ValueError:
selected_org_id = ""
if not selected_org_id:
# A custom-organization run must carry a durable org_id on the
# decision. Never derive it from the process-wide active
# config; fail closed before any work items are created.
from opc.plugins.office_ui.services.models import ServiceError
raise ServiceError(
"org_id_required",
"org_id_required",
{
"company_profile": profile,
"reason": "custom_company_run_requires_durable_org_id",
},
)
decision.org_id = selected_org_id
metadata: dict[str, Any] = {
"source": "work_item_runtime",
"execution_mode": "company_mode",
@@ -1333,7 +1357,11 @@ class CompanyRuntimeSpecBuilder(CompanyRuntimeWorkItemHelper):
"runtime_model": "multi_team_org",
"work_item_driven": True,
"company_profile": profile,
"organization_id": str(getattr(org_config, "organization_id", "") or "").strip(),
"organization_id": (
selected_org_id
if profile == "custom"
else str(getattr(org_config, "organization_id", "") or "").strip()
),
"organization_name": str(getattr(org_config, "organization_name", "") or "").strip(),
"organization_config_file": str(getattr(org_config, "organization_config_file", "") or "").strip(),
"original_request": original_message,
@@ -1341,7 +1369,7 @@ class CompanyRuntimeSpecBuilder(CompanyRuntimeWorkItemHelper):
"domains": list(getattr(decision, "domains", []) or []),
"preferred_agent": getattr(decision, "preferred_agent", None),
"requested_sub_tasks": list(getattr(decision, "sub_tasks", []) or []),
"org_id": getattr(decision, "org_id", None),
"org_id": selected_org_id if profile == "custom" else getattr(decision, "org_id", None),
}
return CompanyRuntimeSpec(
profile=profile,
+15 -1
View File
@@ -64,8 +64,22 @@ class CustomRuntimeRunner:
) -> str:
from opc.engine import OPCEngine
from opc.layer2_organization.phase_hooks import unregister_dispatcher_wake
from opc.plugins.office_ui.services.models import ServiceError
org_config, resolved_org_id = self._build_org_config(org_id)
normalized_org_id = str(org_id or "").strip()
if not normalized_org_id:
# Isolated org mode must carry a durable org_id; resolving the
# active index here would silently route the run to whichever
# organization is currently loaded.
raise ServiceError(
"org_id_required",
"org_id_required",
{
"project_id": project_id or self.parent.project_id or "default",
"reason": "custom_company_run_requires_durable_org_id",
},
)
org_config, resolved_org_id = self._build_org_config(normalized_org_id)
normalized_project_id = str(project_id or self.parent.project_id or "default").strip() or "default"
shared_store = getattr(self.parent, "store", None)
runtime = OPCEngine(
+44 -1
View File
@@ -14,7 +14,7 @@ for that identity:
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from typing import Any, Mapping
from opc.core.config import validate_organization_id
from opc.layer2_organization.company_runtime_identity import is_company_runtime_task
@@ -198,3 +198,46 @@ def execution_identity_from_task(
default_preferred_agent=default_preferred_agent,
explicit_exec_mode=explicit,
)
def resolve_delivery_task_org_identity(
task: Any | None,
*,
payload: Mapping[str, Any] | None = None,
active_org_id: Any = "",
default_org_id: Any = "",
) -> tuple[str, str]:
"""Validate the org identity of a delivery self-evolution task.
Returns ``(organization_id, error)`` with at most one non-empty. Prefers
``Task.org_id``, then task metadata org fields; conflicting sources are
rejected. Checkpoint-payload org fields are a last-resort legacy fallback
and never override task/metadata identity. The active configuration org
is only consulted for a confirmed corporate task; custom-org deliveries
without a durable org id fail closed.
"""
metadata = task_metadata(task)
candidates: list[str] = []
for value in (
getattr(task, "org_id", None),
metadata.get("org_id"),
metadata.get("organization_id"),
):
normalized = normalize_org_id(value)
if normalized and normalized not in candidates:
candidates.append(normalized)
if len(candidates) > 1:
return "", "the delivery task org identity conflicts across task and metadata sources"
task_org_id = candidates[0] if candidates else ""
if task_org_id:
return task_org_id, ""
payload_org_id = normalize_org_id(
(payload or {}).get("org_id")
or (payload or {}).get("organization_id")
)
if payload_org_id:
return payload_org_id, ""
identity = execution_identity_from_task(task)
if identity.is_company:
return normalize_org_id(active_org_id) or normalize_org_id(default_org_id), ""
return "", "the custom-organization delivery task has no durable org identity"
+10
View File
@@ -7854,6 +7854,16 @@ class WSHandler:
parent_task = await run_engine.store.get_task(parent_task_id)
except Exception:
logger.opt(exception=True).debug("failed to load parent task for delivery feedback reply")
if parent_task is None:
raise ServiceError(
"org_id_required",
"org_id_required",
{
"project_id": pid,
"task_id": parent_task_id,
"reason": "delivery_feedback_requires_durable_parent_task",
},
)
session_exec_mode = self._normalize_session_exec_mode(self._exec_mode)
session_company_profile = self._normalize_session_company_profile(self._company_profile)
session_org_id = ""