350 lines
12 KiB
Python
350 lines
12 KiB
Python
"""Helpers for company work-item projection identity metadata."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Mapping
|
|
|
|
|
|
WORK_ITEM_PROJECTION_ID_KEY = "work_item_projection_id"
|
|
WORK_ITEM_TURN_TYPE_KEY = "work_item_turn_type"
|
|
GATE_REWORK_PROJECTION_ID_KEY = "rework_projection_id"
|
|
GATE_TARGET_PROJECTION_ID_KEY = "target_projection_id"
|
|
GATE_TARGET_PROJECTION_IDS_KEY = "target_projection_ids"
|
|
|
|
CANONICAL_WORK_ITEM_TURN_TYPES: frozenset[str] = frozenset(
|
|
{
|
|
"intake",
|
|
"dispatch",
|
|
"plan",
|
|
"setup",
|
|
"execute",
|
|
"review",
|
|
"report",
|
|
"followup",
|
|
"monitor",
|
|
"aggregate",
|
|
"deliver",
|
|
"self_evolution",
|
|
}
|
|
)
|
|
|
|
_TURN_TYPE_ALIASES: dict[str, str] = {
|
|
"delegate": "dispatch",
|
|
"delegation": "dispatch",
|
|
"delivery": "deliver",
|
|
"follow-up": "followup",
|
|
"follow_up": "followup",
|
|
"synthesis": "aggregate",
|
|
"synthesize": "aggregate",
|
|
"self-evolution": "self_evolution",
|
|
"self evolution": "self_evolution",
|
|
}
|
|
|
|
|
|
def _clean(value: Any) -> str:
|
|
return str(value or "").strip()
|
|
|
|
|
|
def normalize_work_item_turn_type(value: Any, *, fallback: str = "") -> str:
|
|
"""Normalize runtime/work-item turn-kind aliases to canonical names."""
|
|
normalized = _clean(value).lower() or _clean(fallback).lower()
|
|
return _TURN_TYPE_ALIASES.get(normalized, normalized)
|
|
|
|
|
|
def canonical_work_item_turn_type_for_kind(value: Any, *, fallback: str = "execute") -> str:
|
|
"""Map a WorkItem/runtime business kind to the canonical runtime turn type."""
|
|
normalized = normalize_work_item_turn_type(value, fallback="")
|
|
if normalized in CANONICAL_WORK_ITEM_TURN_TYPES:
|
|
return normalized
|
|
fallback_normalized = normalize_work_item_turn_type(fallback, fallback="")
|
|
if fallback_normalized in CANONICAL_WORK_ITEM_TURN_TYPES:
|
|
return fallback_normalized
|
|
return ""
|
|
|
|
|
|
def work_item_projection_id_from_metadata(
|
|
metadata: Mapping[str, Any] | None,
|
|
*,
|
|
fallback: str = "",
|
|
) -> str:
|
|
"""Read the canonical projected work-item task identity."""
|
|
if not metadata:
|
|
return _clean(fallback)
|
|
value = _clean(metadata.get(WORK_ITEM_PROJECTION_ID_KEY))
|
|
if value:
|
|
return value
|
|
return _clean(fallback)
|
|
|
|
|
|
def work_item_turn_type_from_metadata(
|
|
metadata: Mapping[str, Any] | None,
|
|
*,
|
|
fallback: str = "execute",
|
|
) -> str:
|
|
"""Read the canonical company work-item turn type."""
|
|
if not metadata:
|
|
return _clean(fallback).lower()
|
|
for key in (
|
|
WORK_ITEM_TURN_TYPE_KEY,
|
|
"work_kind",
|
|
"delegation_turn_kind",
|
|
):
|
|
value = normalize_work_item_turn_type(metadata.get(key))
|
|
if value:
|
|
return value
|
|
return normalize_work_item_turn_type(fallback)
|
|
|
|
|
|
def projection_id_for_task(task: Any) -> str:
|
|
"""Return the work-item projection identity for a projected Task."""
|
|
metadata = dict(getattr(task, "metadata", {}) or {})
|
|
return work_item_projection_id_from_metadata(
|
|
metadata,
|
|
fallback=_clean(getattr(task, "id", "")),
|
|
)
|
|
|
|
|
|
def turn_type_for_task(task: Any, *, fallback: str = "execute") -> str:
|
|
"""Return the work-item turn type for a projected Task."""
|
|
metadata = dict(getattr(task, "metadata", {}) or {})
|
|
return work_item_turn_type_from_metadata(metadata, fallback=fallback)
|
|
|
|
|
|
def projection_id_for_work_item(item: Any) -> str:
|
|
"""Return the projection identity for a DelegationWorkItem-like object."""
|
|
explicit_projection = _clean(getattr(item, "projection_id", ""))
|
|
if explicit_projection:
|
|
return explicit_projection
|
|
metadata = dict(getattr(item, "metadata", {}) or {})
|
|
return work_item_projection_id_from_metadata(
|
|
metadata,
|
|
fallback=(
|
|
_clean(getattr(item, "projection_id", ""))
|
|
or _clean(getattr(item, "work_item_id", ""))
|
|
),
|
|
)
|
|
|
|
|
|
def turn_type_for_work_item(item: Any, *, fallback: str = "execute") -> str:
|
|
"""Return the turn type for a DelegationWorkItem-like object."""
|
|
metadata = dict(getattr(item, "metadata", {}) or {})
|
|
return work_item_turn_type_from_metadata(
|
|
metadata,
|
|
fallback=_clean(getattr(item, "kind", "")) or fallback,
|
|
)
|
|
|
|
|
|
def canonical_turn_type_for_work_item(item: Any, *, fallback: str = "execute") -> str:
|
|
"""Return a canonical turn type for a WorkItem-like object or metadata."""
|
|
if isinstance(item, Mapping):
|
|
return work_item_turn_type_from_metadata(item, fallback=fallback)
|
|
return turn_type_for_work_item(item, fallback=fallback)
|
|
|
|
|
|
def _turn_type_for_value(value: Any, *, fallback: str = "") -> str:
|
|
if isinstance(value, Mapping):
|
|
return work_item_turn_type_from_metadata(value, fallback=fallback)
|
|
if hasattr(value, "metadata"):
|
|
return canonical_turn_type_for_work_item(value, fallback=fallback or "execute")
|
|
return canonical_work_item_turn_type_for_kind(value, fallback=fallback)
|
|
|
|
|
|
def is_delivery_turn(value_or_metadata: Any) -> bool:
|
|
"""Return True for final delivery turns, including legacy ``delivery`` alias."""
|
|
return _turn_type_for_value(value_or_metadata, fallback="") == "deliver"
|
|
|
|
|
|
def is_manager_reviewable_turn(value_or_metadata: Any) -> bool:
|
|
"""Return the turn type's default manager-review policy.
|
|
|
|
Dispatch/intake/plan are normally board-producing turns and therefore
|
|
exempt. The executor handles the one dynamic exception — a current turn
|
|
that produced no board mutation — before it writes the authoritative
|
|
WorkItem phase. Downstream review plumbing follows that phase directly.
|
|
"""
|
|
turn_type = _turn_type_for_value(value_or_metadata, fallback="")
|
|
if not turn_type:
|
|
return False
|
|
return turn_type not in {"intake", "plan", "dispatch", "aggregate", "deliver", "self_evolution"}
|
|
|
|
|
|
def mark_work_item_projection(
|
|
metadata: Mapping[str, Any] | None = None,
|
|
*,
|
|
projection_id: str = "",
|
|
turn_type: str = "",
|
|
) -> dict[str, Any]:
|
|
"""Return metadata with canonical work-item projection keys only."""
|
|
result = dict(metadata or {})
|
|
projection = _clean(projection_id) or work_item_projection_id_from_metadata(result)
|
|
turn = normalize_work_item_turn_type(turn_type) or work_item_turn_type_from_metadata(result)
|
|
if projection:
|
|
result[WORK_ITEM_PROJECTION_ID_KEY] = projection
|
|
if turn:
|
|
result[WORK_ITEM_TURN_TYPE_KEY] = turn
|
|
return result
|
|
|
|
|
|
def mark_projected_work_item_task(
|
|
metadata: Mapping[str, Any] | None = None,
|
|
*,
|
|
projection_id: str = "",
|
|
turn_type: str = "",
|
|
) -> dict[str, Any]:
|
|
"""Return projected task/work-item metadata with canonical identity keys."""
|
|
return mark_work_item_projection(
|
|
metadata,
|
|
projection_id=projection_id,
|
|
turn_type=turn_type,
|
|
)
|
|
|
|
|
|
def work_item_identity_payload(
|
|
*,
|
|
projection_id: str = "",
|
|
turn_type: str = "",
|
|
source: Mapping[str, Any] | None = None,
|
|
include_empty: bool = False,
|
|
) -> dict[str, str]:
|
|
"""Build a canonical event/checkpoint/ws payload identity fragment."""
|
|
source_meta = dict(source or {})
|
|
projection = _clean(projection_id) or work_item_projection_id_from_metadata(source_meta, fallback="")
|
|
turn = normalize_work_item_turn_type(turn_type) or work_item_turn_type_from_metadata(source_meta, fallback="")
|
|
payload: dict[str, str] = {}
|
|
if projection or include_empty:
|
|
payload[WORK_ITEM_PROJECTION_ID_KEY] = projection
|
|
if turn or include_empty:
|
|
payload[WORK_ITEM_TURN_TYPE_KEY] = turn
|
|
return payload
|
|
|
|
|
|
def work_item_identity_payload_from_metadata(
|
|
metadata: Mapping[str, Any] | None,
|
|
*,
|
|
projection_id_fallback: str = "",
|
|
turn_type_fallback: str = "",
|
|
include_empty: bool = False,
|
|
) -> dict[str, str]:
|
|
"""Build a canonical payload identity fragment from metadata."""
|
|
source_meta = dict(metadata or {})
|
|
return work_item_identity_payload(
|
|
projection_id=work_item_projection_id_from_metadata(
|
|
source_meta,
|
|
fallback=projection_id_fallback,
|
|
),
|
|
turn_type=work_item_turn_type_from_metadata(
|
|
source_meta,
|
|
fallback=turn_type_fallback,
|
|
),
|
|
include_empty=include_empty,
|
|
)
|
|
|
|
|
|
def work_item_identity_payload_for_task(
|
|
task: Any,
|
|
*,
|
|
fallback_turn_type: str = "",
|
|
include_empty: bool = False,
|
|
) -> dict[str, str]:
|
|
"""Build a canonical payload identity fragment for a Task-like object."""
|
|
if task is None:
|
|
return work_item_identity_payload(
|
|
turn_type=fallback_turn_type,
|
|
include_empty=include_empty,
|
|
)
|
|
return work_item_identity_payload(
|
|
projection_id=projection_id_for_task(task),
|
|
turn_type=turn_type_for_task(task, fallback=fallback_turn_type),
|
|
include_empty=include_empty,
|
|
)
|
|
|
|
|
|
def migrate_work_item_projection_metadata(
|
|
metadata: Mapping[str, Any] | None,
|
|
*,
|
|
projection_id_fallback: str = "",
|
|
turn_type_fallback: str = "",
|
|
) -> tuple[dict[str, Any], bool]:
|
|
"""Normalize canonical projection metadata from canonical inputs only."""
|
|
before = dict(metadata or {})
|
|
result = dict(before)
|
|
projection = work_item_projection_id_from_metadata(
|
|
result,
|
|
fallback=projection_id_fallback,
|
|
)
|
|
turn = work_item_turn_type_from_metadata(
|
|
result,
|
|
fallback=turn_type_fallback or "execute",
|
|
)
|
|
if projection and not _clean(result.get(WORK_ITEM_PROJECTION_ID_KEY)):
|
|
result[WORK_ITEM_PROJECTION_ID_KEY] = projection
|
|
if turn and not _clean(result.get(WORK_ITEM_TURN_TYPE_KEY)):
|
|
result[WORK_ITEM_TURN_TYPE_KEY] = turn
|
|
return result, result != before
|
|
|
|
|
|
def rework_projection_id_for_gate(gate: Any, *, fallback: str = "") -> str:
|
|
"""Return the gate rework target as a work-item projection identity."""
|
|
metadata = dict(getattr(gate, "metadata", {}) or {})
|
|
return _clean(
|
|
metadata.get(GATE_REWORK_PROJECTION_ID_KEY)
|
|
or getattr(gate, "rework_projection_id", "")
|
|
or fallback
|
|
)
|
|
|
|
|
|
def mark_gate_rework_projection(gate: Any, projection_id: str) -> Any:
|
|
"""Attach projection-only gate rework identity."""
|
|
projection = _clean(projection_id)
|
|
metadata = dict(getattr(gate, "metadata", {}) or {})
|
|
if projection:
|
|
metadata[GATE_REWORK_PROJECTION_ID_KEY] = projection
|
|
setattr(gate, "metadata", metadata)
|
|
if hasattr(gate, "rework_projection_id"):
|
|
setattr(gate, "rework_projection_id", projection or None)
|
|
return gate
|
|
|
|
|
|
def target_projection_id_for_decision(decision: Any, *, fallback: str = "") -> str:
|
|
"""Return a gate-harness target as a work-item projection identity."""
|
|
return _clean(
|
|
getattr(decision, GATE_TARGET_PROJECTION_ID_KEY, "")
|
|
or fallback
|
|
)
|
|
|
|
|
|
def target_projection_ids_for_decision(decision: Any) -> list[str]:
|
|
"""Return all gate-harness targets as work-item projection identities."""
|
|
raw_ids = list(getattr(decision, GATE_TARGET_PROJECTION_IDS_KEY, []) or [])
|
|
if not raw_ids:
|
|
single = target_projection_id_for_decision(decision)
|
|
raw_ids = [single] if single else []
|
|
result: list[str] = []
|
|
seen: set[str] = set()
|
|
for item in raw_ids:
|
|
value = _clean(item)
|
|
if value and value not in seen:
|
|
seen.add(value)
|
|
result.append(value)
|
|
return result
|
|
|
|
|
|
def gate_rework_payload(
|
|
*,
|
|
rework_projection_id: str = "",
|
|
target_projection_id: str = "",
|
|
review_projection_id: str = "",
|
|
) -> dict[str, Any]:
|
|
"""Build projection-only gate/rework payload metadata."""
|
|
rework = _clean(rework_projection_id)
|
|
target = _clean(target_projection_id)
|
|
review = _clean(review_projection_id)
|
|
payload: dict[str, Any] = {}
|
|
if rework:
|
|
payload[GATE_REWORK_PROJECTION_ID_KEY] = rework
|
|
if target:
|
|
payload[GATE_TARGET_PROJECTION_ID_KEY] = target
|
|
if review:
|
|
payload["review_projection_id"] = review
|
|
return payload
|