235 lines
9.2 KiB
Python
235 lines
9.2 KiB
Python
"""Compile governance findings into service-order continuity."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Iterable, Sequence
|
|
|
|
from .governance_models import EcosystemGovernancePortfolio, GovernanceOrderCandidate
|
|
from .models import OrderStatus, OrderType, ServiceOrder, incrementing_id, merge_unique, slugify
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class CompiledOrderSet:
|
|
"""Service-order set produced from recommendations and governance checks."""
|
|
|
|
service_orders: tuple[ServiceOrder, ...]
|
|
source_candidates: tuple[GovernanceOrderCandidate, ...]
|
|
executive_count: int
|
|
managerial_count: int
|
|
notes: tuple[str, ...]
|
|
|
|
def to_dict(self) -> dict[str, object]:
|
|
return {
|
|
"service_orders": [order.to_dict() for order in self.service_orders],
|
|
"source_candidates": [candidate.to_dict() for candidate in self.source_candidates],
|
|
"executive_count": self.executive_count,
|
|
"managerial_count": self.managerial_count,
|
|
"notes": self.notes,
|
|
}
|
|
|
|
|
|
def priority_rank(value: str) -> int:
|
|
lowered = value.lower()
|
|
if lowered in {"critica", "critico", "critical"}:
|
|
return 4
|
|
if lowered in {"alta", "high"}:
|
|
return 3
|
|
if lowered in {"media", "medium"}:
|
|
return 2
|
|
if lowered in {"baixa", "low"}:
|
|
return 1
|
|
return 0
|
|
|
|
|
|
def candidate_sort_key(candidate: GovernanceOrderCandidate) -> tuple[int, str, str]:
|
|
return (-priority_rank(candidate.priority), candidate.platform_id, candidate.title)
|
|
|
|
|
|
def candidate_to_service_order(candidate: GovernanceOrderCandidate, index: int, project_id: str = "tudo-para-ia-mais-humana") -> ServiceOrder:
|
|
prefix = "EXECUTIVA" if candidate.order_type == OrderType.EXECUTIVE else "GERENCIAL"
|
|
return ServiceOrder(
|
|
order_id=incrementing_id(prefix, index, candidate.title),
|
|
order_type=candidate.order_type,
|
|
project_id=project_id,
|
|
title=candidate.title,
|
|
purpose=candidate.purpose,
|
|
object_scope=(
|
|
f"Plataforma relacionada: {candidate.platform_id}. "
|
|
"Checks de origem: " + ", ".join(candidate.source_check_ids)
|
|
),
|
|
reason=candidate.reason,
|
|
expected_result=candidate.expected_result,
|
|
affected_paths=candidate.affected_paths,
|
|
validations=candidate.validations,
|
|
ready_criteria=(
|
|
"check de governanca reavaliado",
|
|
"evidencia registrada",
|
|
"validacao executada ou pendencia real declarada",
|
|
"SQL semantico atualizado",
|
|
),
|
|
status=OrderStatus.PLANNED,
|
|
priority=candidate.priority,
|
|
)
|
|
|
|
|
|
def dedupe_service_orders(orders: Iterable[ServiceOrder]) -> tuple[ServiceOrder, ...]:
|
|
seen: set[tuple[str, str, str]] = set()
|
|
output: list[ServiceOrder] = []
|
|
for order in orders:
|
|
key = (order.order_type.value, slugify(order.title), order.object_scope[:80])
|
|
if key in seen:
|
|
continue
|
|
seen.add(key)
|
|
output.append(order)
|
|
return tuple(output)
|
|
|
|
|
|
def select_candidates(candidates: Sequence[GovernanceOrderCandidate], order_type: OrderType, limit: int) -> tuple[GovernanceOrderCandidate, ...]:
|
|
typed = [candidate for candidate in candidates if candidate.order_type == order_type]
|
|
typed.sort(key=candidate_sort_key)
|
|
return tuple(typed[:limit])
|
|
|
|
|
|
def compile_governance_orders(
|
|
portfolio: EcosystemGovernancePortfolio,
|
|
min_executive: int = 5,
|
|
min_managerial: int = 5,
|
|
project_id: str = "tudo-para-ia-mais-humana",
|
|
) -> CompiledOrderSet:
|
|
executive_candidates = list(select_candidates(portfolio.order_candidates, OrderType.EXECUTIVE, min_executive))
|
|
managerial_candidates = list(select_candidates(portfolio.order_candidates, OrderType.MANAGERIAL, min_managerial))
|
|
notes: list[str] = []
|
|
if len(executive_candidates) < min_executive:
|
|
notes.append(
|
|
f"Somente {len(executive_candidates)} candidatas executivas reais foram encontradas; "
|
|
"nao foram criadas ordens artificiais."
|
|
)
|
|
if len(managerial_candidates) < min_managerial:
|
|
notes.append(
|
|
f"Somente {len(managerial_candidates)} candidatas gerenciais reais foram encontradas; "
|
|
"nao foram criadas ordens artificiais."
|
|
)
|
|
orders: list[ServiceOrder] = []
|
|
for index, candidate in enumerate(executive_candidates, start=1):
|
|
orders.append(candidate_to_service_order(candidate, index, project_id))
|
|
for index, candidate in enumerate(managerial_candidates, start=1):
|
|
orders.append(candidate_to_service_order(candidate, index, project_id))
|
|
service_orders = dedupe_service_orders(orders)
|
|
return CompiledOrderSet(
|
|
service_orders=service_orders,
|
|
source_candidates=tuple(executive_candidates + managerial_candidates),
|
|
executive_count=sum(1 for order in service_orders if order.order_type == OrderType.EXECUTIVE),
|
|
managerial_count=sum(1 for order in service_orders if order.order_type == OrderType.MANAGERIAL),
|
|
notes=tuple(notes),
|
|
)
|
|
|
|
|
|
def merge_order_sets(primary: Sequence[ServiceOrder], governance: Sequence[ServiceOrder], min_executive: int = 5, min_managerial: int = 5) -> tuple[ServiceOrder, ...]:
|
|
merged: list[ServiceOrder] = list(primary)
|
|
executive_count = sum(1 for order in merged if order.order_type == OrderType.EXECUTIVE)
|
|
managerial_count = sum(1 for order in merged if order.order_type == OrderType.MANAGERIAL)
|
|
for order in governance:
|
|
if order.order_type == OrderType.EXECUTIVE and executive_count >= min_executive:
|
|
continue
|
|
if order.order_type == OrderType.MANAGERIAL and managerial_count >= min_managerial:
|
|
continue
|
|
merged.append(order)
|
|
if order.order_type == OrderType.EXECUTIVE:
|
|
executive_count += 1
|
|
else:
|
|
managerial_count += 1
|
|
return dedupe_service_orders(merged)
|
|
|
|
|
|
def compiled_orders_markdown(compiled: CompiledOrderSet) -> str:
|
|
lines = [
|
|
"# Ordens compiladas por governanca",
|
|
"",
|
|
f"- executivas: `{compiled.executive_count}`",
|
|
f"- gerenciais: `{compiled.managerial_count}`",
|
|
f"- candidatas de origem: `{len(compiled.source_candidates)}`",
|
|
"",
|
|
]
|
|
if compiled.notes:
|
|
lines.append("## Observacoes")
|
|
lines.append("")
|
|
lines.extend(f"- {note}" for note in compiled.notes)
|
|
lines.append("")
|
|
lines.append("## Ordens")
|
|
lines.append("")
|
|
for order in compiled.service_orders:
|
|
lines.append(f"### {order.order_id}")
|
|
lines.append("")
|
|
lines.append(f"- tipo: `{order.order_type.value}`")
|
|
lines.append(f"- prioridade: `{order.priority}`")
|
|
lines.append(f"- titulo: {order.title}")
|
|
lines.append(f"- motivo: {order.reason}")
|
|
lines.append(f"- resultado: {order.expected_result}")
|
|
lines.append("- validacoes:")
|
|
for validation in order.validations:
|
|
lines.append(f" - {validation}")
|
|
lines.append("")
|
|
return "\n".join(lines).strip() + "\n"
|
|
|
|
|
|
def order_coverage_rows(compiled: CompiledOrderSet) -> list[list[str]]:
|
|
rows = [["order_id", "type", "priority", "title", "paths", "validations"]]
|
|
for order in compiled.service_orders:
|
|
rows.append(
|
|
[
|
|
order.order_id,
|
|
order.order_type.value,
|
|
order.priority,
|
|
order.title,
|
|
" | ".join(order.affected_paths),
|
|
" | ".join(order.validations),
|
|
]
|
|
)
|
|
return rows
|
|
|
|
|
|
def source_candidate_rows(compiled: CompiledOrderSet) -> list[list[str]]:
|
|
rows = [["candidate_id", "platform", "type", "priority", "title", "source_checks"]]
|
|
for candidate in compiled.source_candidates:
|
|
rows.append(
|
|
[
|
|
candidate.candidate_id,
|
|
candidate.platform_id,
|
|
candidate.order_type.value,
|
|
candidate.priority,
|
|
candidate.title,
|
|
" | ".join(candidate.source_check_ids),
|
|
]
|
|
)
|
|
return rows
|
|
|
|
|
|
def active_queue_from_orders(orders: Sequence[ServiceOrder]) -> tuple[str, ...]:
|
|
return tuple(order.order_id for order in orders if order.status == OrderStatus.PLANNED)
|
|
|
|
|
|
def explain_order_gap(compiled: CompiledOrderSet, order_type: OrderType, minimum: int = 5) -> str:
|
|
actual = compiled.executive_count if order_type == OrderType.EXECUTIVE else compiled.managerial_count
|
|
label = "executivas" if order_type == OrderType.EXECUTIVE else "gerenciais"
|
|
if actual >= minimum:
|
|
return f"Minimo de ordens {label} cumprido: {actual}/{minimum}."
|
|
return f"Minimo de ordens {label} parcial: {actual}/{minimum}; faltam checks reais suficientes."
|
|
|
|
|
|
def order_set_summary(compiled: CompiledOrderSet) -> tuple[str, ...]:
|
|
return (
|
|
explain_order_gap(compiled, OrderType.EXECUTIVE),
|
|
explain_order_gap(compiled, OrderType.MANAGERIAL),
|
|
f"Candidatas usadas: {len(compiled.source_candidates)}.",
|
|
f"Fila ativa compilada: {len(active_queue_from_orders(compiled.service_orders))}.",
|
|
)
|
|
|
|
|
|
def combine_order_notes(*sets: CompiledOrderSet) -> tuple[str, ...]:
|
|
notes: list[str] = []
|
|
for item in sets:
|
|
notes.extend(item.notes)
|
|
notes.extend(order_set_summary(item))
|
|
return merge_unique(notes)
|