Files
OpenOPC/opc/layer2_organization/work_item_runtime_invariants.py
2026-07-01 17:56:31 +08:00

530 lines
21 KiB
Python

"""Diagnostics for company WorkItem runtime Task projections."""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Iterable, Mapping
from opc.core.models import DelegationWorkItem, Phase, Task
from opc.layer2_organization.phase import (
DONE_PHASES,
is_report_execution_work_item_metadata,
is_review_execution_work_item_metadata,
should_hide_work_item_from_company_kanban,
)
from opc.layer2_organization.metadata_ownership import validate_metadata_ownership
from opc.layer2_organization.work_item_identity import (
WORK_ITEM_TURN_TYPE_KEY,
canonical_work_item_turn_type_for_kind,
normalize_work_item_turn_type,
projection_id_for_work_item,
work_item_projection_id_from_metadata,
)
from opc.layer2_organization.work_item_links import linked_work_item_id_for_task
from opc.layer2_organization.work_item_runtime import is_work_item_runtime_metadata
WORK_ITEM_RUNTIME_INVARIANT_EVENT_TYPE = "work_item_runtime_invariant_violation"
_RUNTIME_MODELS = {"multi_team_org"}
_AUXILIARY_TURN_KINDS = {"review", "report", "followup", "follow_up", "delivery", "deliver"}
_HIDDEN_RUNNABLE_TURN_KINDS = _AUXILIARY_TURN_KINDS | {"aggregate", "synthesize"}
@dataclass(frozen=True)
class WorkItemRuntimeInvariantIssue:
code: str
severity: str
run_id: str = ""
work_item_id: str = ""
runtime_task_id: str = ""
projection_id: str = ""
message: str = ""
details: dict[str, Any] = field(default_factory=dict)
def fingerprint(self) -> tuple[str, str, str, str]:
return (
str(self.code or "").strip(),
str(self.work_item_id or "").strip(),
str(self.runtime_task_id or "").strip(),
str(self.projection_id or "").strip(),
)
def to_event_payload(self) -> dict[str, Any]:
payload = {
"code": self.code,
"severity": self.severity,
"run_id": self.run_id,
"work_item_id": self.work_item_id,
"runtime_task_id": self.runtime_task_id,
"projection_id": self.projection_id,
"message": self.message,
}
if self.details:
payload["details"] = dict(self.details)
return payload
def _clean(value: Any) -> str:
return str(value or "").strip()
def _lower(value: Any) -> str:
return _clean(value).lower()
def _phase_value(value: Any) -> str:
if isinstance(value, Phase):
return value.value
return _lower(value)
def _is_done_phase(value: Any) -> bool:
if isinstance(value, Phase):
return value in DONE_PHASES
normalized = _lower(value)
return normalized in {phase.value for phase in DONE_PHASES}
def _runtime_model(metadata: Mapping[str, Any]) -> str:
return _lower(metadata.get("runtime_model") or metadata.get("execution_model"))
def _turn_kind(metadata: Mapping[str, Any], *, fallback: str = "") -> str:
turn = normalize_work_item_turn_type(metadata.get(WORK_ITEM_TURN_TYPE_KEY), fallback="")
if turn:
return turn
for key in ("work_kind", "delegation_turn_kind"):
owner_kind = canonical_work_item_turn_type_for_kind(metadata.get(key), fallback="")
if owner_kind:
return owner_kind
return canonical_work_item_turn_type_for_kind(fallback, fallback="")
def _task_projection_id(task: Task | None) -> str:
if task is None:
return ""
return work_item_projection_id_from_metadata(dict(task.metadata or {}), fallback=_clean(getattr(task, "id", "")))
def _issue(
code: str,
severity: str,
*,
task: Task | None = None,
work_item: DelegationWorkItem | None = None,
work_item_id: str = "",
projection_id: str = "",
message: str,
details: Mapping[str, Any] | None = None,
) -> WorkItemRuntimeInvariantIssue:
task_metadata = dict(getattr(task, "metadata", {}) or {})
item_metadata = dict(getattr(work_item, "metadata", {}) or {})
wid = (
_clean(work_item_id)
or _clean(getattr(work_item, "work_item_id", ""))
or linked_work_item_id_for_task(task)
)
projection = _clean(projection_id) or _task_projection_id(task)
if not projection and work_item is not None:
projection = projection_id_for_work_item(work_item)
return WorkItemRuntimeInvariantIssue(
code=code,
severity=severity,
run_id=(
_clean(getattr(work_item, "run_id", ""))
or _clean(item_metadata.get("delegation_run_id"))
or _clean(task_metadata.get("delegation_run_id"))
),
work_item_id=wid,
runtime_task_id=_clean(getattr(task, "id", "")),
projection_id=projection,
message=message,
details=dict(details or {}),
)
def is_company_runtime_projection_task(task: Task | None) -> bool:
"""Return true for company WorkItem runtime projection Tasks.
The predicate intentionally does not read legacy owner metadata. A task is
a projection only when it carries the canonical runtime marker and the
canonical projection identity.
"""
if task is None:
return False
metadata = dict(getattr(task, "metadata", {}) or {})
if not is_work_item_runtime_metadata(metadata):
return False
if bool(metadata.get("synthetic_inbox_turn") or metadata.get("synthetic_company_inbox")):
return False
runtime_model = _runtime_model(metadata)
if runtime_model and runtime_model not in _RUNTIME_MODELS:
return False
return bool(work_item_projection_id_from_metadata(metadata, fallback=""))
def _expected_work_kind(work_item: DelegationWorkItem | None) -> str:
if work_item is None:
return ""
metadata = dict(work_item.metadata or {})
return _turn_kind(metadata, fallback=_clean(getattr(work_item, "kind", "")) or "execute") or "execute"
def _expected_role_id(work_item: DelegationWorkItem | None) -> str:
return _clean(getattr(work_item, "role_id", "")) if work_item is not None else ""
def _expected_seat_id(work_item: DelegationWorkItem | None) -> str:
if work_item is None:
return ""
return _clean(getattr(work_item, "seat_id", "")) or _clean(dict(work_item.metadata or {}).get("seat_id"))
def _expected_turn_mode(work_item: DelegationWorkItem | None) -> str:
if work_item is None:
return ""
return _clean(dict(work_item.metadata or {}).get("current_turn_mode"))
def validate_work_item_runtime_projection(
task: Task,
work_item: DelegationWorkItem | None,
*,
work_item_by_id: Mapping[str, DelegationWorkItem] | None = None,
) -> list[WorkItemRuntimeInvariantIssue]:
"""Validate that a projected runtime Task is backed by a WorkItem link.
This function is read-only. It reports mismatches; it never repairs links
and never uses legacy Task metadata as an owner source.
"""
if not is_company_runtime_projection_task(task):
return []
task_metadata = dict(getattr(task, "metadata", {}) or {})
item_metadata = dict(getattr(work_item, "metadata", {}) or {}) if work_item is not None else {}
linked_work_item_id = linked_work_item_id_for_task(task)
projection_id = _task_projection_id(task)
issues: list[WorkItemRuntimeInvariantIssue] = []
if not linked_work_item_id:
issues.append(
_issue(
"missing_link",
"error",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Company runtime projection task is not hydrated from work_item_runtime_links.",
)
)
if work_item is None:
issues.append(
_issue(
"missing_work_item",
"error",
task=task,
work_item_id=linked_work_item_id,
projection_id=projection_id,
message="Company runtime projection task link does not resolve to a WorkItem.",
)
)
return issues
expected_work_item_id = _clean(getattr(work_item, "work_item_id", ""))
if linked_work_item_id and expected_work_item_id and linked_work_item_id != expected_work_item_id:
issues.append(
_issue(
"link_work_item_mismatch",
"error",
task=task,
work_item=work_item,
work_item_id=linked_work_item_id,
projection_id=projection_id,
message="Runtime task link points at a different WorkItem than the supplied WorkItem.",
details={"expected_work_item_id": expected_work_item_id, "linked_work_item_id": linked_work_item_id},
)
)
expected_projection_id = projection_id_for_work_item(work_item)
if projection_id and expected_projection_id and projection_id != expected_projection_id:
issues.append(
_issue(
"projection_mismatch",
"warning",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Runtime task projection id differs from the WorkItem projection id.",
details={"expected_projection_id": expected_projection_id, "task_projection_id": projection_id},
)
)
expected_kind = _expected_work_kind(work_item)
task_kind = _turn_kind(task_metadata, fallback=_lower(task_metadata.get("work_kind")) or expected_kind)
if expected_kind and task_kind and task_kind != expected_kind:
issues.append(
_issue(
"work_kind_mismatch",
"error",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Runtime task turn kind differs from the WorkItem turn kind.",
details={"expected_work_kind": expected_kind, "task_work_kind": task_kind},
)
)
expected_role_id = _expected_role_id(work_item)
task_role_id = _clean(getattr(task, "assigned_to", "")) or _clean(task_metadata.get("work_item_role_id"))
if expected_role_id and task_role_id and task_role_id != expected_role_id:
issues.append(
_issue(
"owner_role_mismatch",
"error",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Runtime task owner role differs from the WorkItem role.",
details={"expected_role_id": expected_role_id, "task_role_id": task_role_id},
)
)
expected_seat_id = _expected_seat_id(work_item)
task_seat_id = _clean(task_metadata.get("delegation_seat_id") or task_metadata.get("seat_id"))
if expected_seat_id and task_seat_id and task_seat_id != expected_seat_id:
issues.append(
_issue(
"owner_seat_mismatch",
"error",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Runtime task owner seat differs from the WorkItem seat.",
details={"expected_seat_id": expected_seat_id, "task_seat_id": task_seat_id},
)
)
expected_turn_mode = _expected_turn_mode(work_item)
task_turn_mode = _clean(task_metadata.get("current_turn_mode"))
if expected_turn_mode:
if task_turn_mode and task_turn_mode != expected_turn_mode:
issues.append(
_issue(
"turn_mode_mismatch",
"error",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Runtime task current_turn_mode differs from the WorkItem mode.",
details={"expected_turn_mode": expected_turn_mode, "task_turn_mode": task_turn_mode},
)
)
elif not task_turn_mode and expected_kind in _AUXILIARY_TURN_KINDS:
issues.append(
_issue(
"turn_mode_missing",
"warning",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Auxiliary runtime task is missing the WorkItem current_turn_mode execution copy.",
details={"expected_turn_mode": expected_turn_mode, "work_kind": expected_kind},
)
)
has_work_item_context = work_item_by_id is not None
work_item_by_id = dict(work_item_by_id or {})
if is_review_execution_work_item_metadata(item_metadata):
target_id = _clean(item_metadata.get("review_target_work_item_id"))
target = work_item_by_id.get(target_id) if target_id else None
if not target_id:
issues.append(
_issue(
"review_target_missing",
"error",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Review runtime WorkItem is missing review_target_work_item_id.",
)
)
elif has_work_item_context and target is None:
issues.append(
_issue(
"review_target_unresolved",
"error",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Review runtime WorkItem target does not exist in the active WorkItem set.",
details={"review_target_work_item_id": target_id},
)
)
elif target is not None:
target_metadata = dict(target.metadata or {})
expected_review_role = (
_clean(target_metadata.get("review_owner_role_id"))
or _clean(getattr(target, "manager_role_id", ""))
)
expected_review_seat = (
_clean(target_metadata.get("review_owner_seat_id"))
or _clean(getattr(target, "manager_seat_id", ""))
)
if expected_review_role and expected_review_role != expected_role_id:
issues.append(
_issue(
"review_owner_mismatch",
"error",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Review WorkItem owner role does not match the target WorkItem review owner.",
details={"expected_review_role_id": expected_review_role, "review_work_item_role_id": expected_role_id},
)
)
if expected_review_seat and expected_review_seat != expected_seat_id:
issues.append(
_issue(
"review_owner_mismatch",
"error",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Review WorkItem owner seat does not match the target WorkItem review owner.",
details={"expected_review_seat_id": expected_review_seat, "review_work_item_seat_id": expected_seat_id},
)
)
review_meta_role = _clean(item_metadata.get("review_owner_role_id"))
review_meta_seat = _clean(item_metadata.get("review_owner_seat_id"))
if expected_review_role and review_meta_role and review_meta_role != expected_review_role:
issues.append(
_issue(
"review_owner_metadata_mismatch",
"warning",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Review WorkItem metadata owner role differs from the target review owner.",
details={"expected_review_role_id": expected_review_role, "metadata_review_owner_role_id": review_meta_role},
)
)
if expected_review_seat and review_meta_seat and review_meta_seat != expected_review_seat:
issues.append(
_issue(
"review_owner_metadata_mismatch",
"warning",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Review WorkItem metadata owner seat differs from the target review owner.",
details={"expected_review_seat_id": expected_review_seat, "metadata_review_owner_seat_id": review_meta_seat},
)
)
if is_report_execution_work_item_metadata(item_metadata):
target_id = _clean(item_metadata.get("report_target_work_item_id"))
if not target_id:
issues.append(
_issue(
"report_target_missing",
"error",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Report runtime WorkItem is missing report_target_work_item_id.",
)
)
elif has_work_item_context and target_id not in work_item_by_id:
issues.append(
_issue(
"report_target_unresolved",
"error",
task=task,
work_item=work_item,
projection_id=projection_id,
message="Report runtime WorkItem target does not exist in the active WorkItem set.",
details={"report_target_work_item_id": target_id},
)
)
for ownership_issue in validate_metadata_ownership(work_item, task):
issues.append(
_issue(
ownership_issue.code,
ownership_issue.severity,
task=task,
work_item=work_item,
projection_id=projection_id,
message=ownership_issue.message,
details={
"metadata_key": ownership_issue.key,
"owner": ownership_issue.owner,
**dict(ownership_issue.details or {}),
},
)
)
return issues
def _work_item_expects_runtime_projection(work_item: DelegationWorkItem) -> bool:
metadata = dict(work_item.metadata or {})
if not is_work_item_runtime_metadata(metadata):
return False
runtime_model = _runtime_model(metadata)
if runtime_model and runtime_model not in _RUNTIME_MODELS:
return False
if _is_done_phase(getattr(work_item, "phase", "")):
return False
kind = _expected_work_kind(work_item)
if should_hide_work_item_from_company_kanban(metadata) and kind not in _HIDDEN_RUNNABLE_TURN_KINDS:
return False
return bool(projection_id_for_work_item(work_item))
def diagnose_work_item_runtime_projections(
tasks: Iterable[Task],
work_items: Iterable[DelegationWorkItem],
) -> list[WorkItemRuntimeInvariantIssue]:
"""Return projection invariant issues without mutating Tasks or the DB."""
task_list = list(tasks or [])
work_item_list = list(work_items or [])
work_item_by_id = {
_clean(getattr(item, "work_item_id", "")): item
for item in work_item_list
if _clean(getattr(item, "work_item_id", ""))
}
issues: list[WorkItemRuntimeInvariantIssue] = []
linked_work_item_ids: set[str] = set()
for task in task_list:
if not is_company_runtime_projection_task(task):
continue
linked_work_item_id = linked_work_item_id_for_task(task)
if linked_work_item_id:
linked_work_item_ids.add(linked_work_item_id)
issues.extend(
validate_work_item_runtime_projection(
task,
work_item_by_id.get(linked_work_item_id) if linked_work_item_id else None,
work_item_by_id=work_item_by_id,
)
)
for work_item in work_item_list:
wid = _clean(getattr(work_item, "work_item_id", ""))
if not wid or wid in linked_work_item_ids:
continue
if not _work_item_expects_runtime_projection(work_item):
continue
issues.append(
_issue(
"work_item_missing_runtime_task",
"error",
work_item=work_item,
projection_id=projection_id_for_work_item(work_item),
message="Non-terminal company WorkItem has no linked runtime Task projection after materialization.",
details={"phase": _phase_value(getattr(work_item, "phase", "")), "work_kind": _expected_work_kind(work_item)},
)
)
return issues