feat: fundar plataforma mais humana
This commit is contained in:
189
src/mais_humana/portfolio_queries.py
Normal file
189
src/mais_humana/portfolio_queries.py
Normal file
@@ -0,0 +1,189 @@
|
||||
"""Human-readable query helpers over the governance portfolio."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterable, Sequence
|
||||
|
||||
from .governance_models import EcosystemGovernancePortfolio, GovernanceDomain, GovernanceStatus, PlatformGovernanceCard
|
||||
from .models import as_plain_data, merge_unique
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class PortfolioQuestion:
|
||||
question_id: str
|
||||
question: str
|
||||
answer: str
|
||||
evidence: tuple[str, ...]
|
||||
next_action: str
|
||||
|
||||
def to_dict(self) -> dict[str, object]:
|
||||
return as_plain_data(self)
|
||||
|
||||
|
||||
def card_or_none(portfolio: EcosystemGovernancePortfolio, platform_id: str) -> PlatformGovernanceCard | None:
|
||||
return portfolio.card_for(platform_id)
|
||||
|
||||
|
||||
def summarize_card(card: PlatformGovernanceCard) -> str:
|
||||
blockers = ", ".join(check.title for check in card.blockers[:3]) or "sem blocker principal"
|
||||
action = card.next_actions[0] if card.next_actions else "manter regressao"
|
||||
return (
|
||||
f"{card.platform_id} esta em status {card.status_label}, score {card.governance_score}, "
|
||||
f"maturidade {card.maturity.value}. Blockers: {blockers}. Proxima acao: {action}."
|
||||
)
|
||||
|
||||
|
||||
def strongest_platforms(portfolio: EcosystemGovernancePortfolio, limit: int = 5) -> tuple[PlatformGovernanceCard, ...]:
|
||||
return tuple(sorted(portfolio.cards, key=lambda item: (-item.governance_score, item.platform_id))[:limit])
|
||||
|
||||
|
||||
def weakest_platforms(portfolio: EcosystemGovernancePortfolio, limit: int = 5) -> tuple[PlatformGovernanceCard, ...]:
|
||||
return tuple(sorted(portfolio.cards, key=lambda item: (item.governance_score, item.platform_id))[:limit])
|
||||
|
||||
|
||||
def platforms_by_domain_gap(portfolio: EcosystemGovernancePortfolio, domain: GovernanceDomain) -> tuple[PlatformGovernanceCard, ...]:
|
||||
cards: list[PlatformGovernanceCard] = []
|
||||
for card in portfolio.cards:
|
||||
if any(check.domain == domain and check.status in {GovernanceStatus.ATTENTION, GovernanceStatus.FAIL, GovernanceStatus.BLOCKED} for check in card.checks):
|
||||
cards.append(card)
|
||||
cards.sort(key=lambda item: (item.governance_score, item.platform_id))
|
||||
return tuple(cards)
|
||||
|
||||
|
||||
def blockers_for_domain(portfolio: EcosystemGovernancePortfolio, domain: GovernanceDomain) -> tuple[str, ...]:
|
||||
items: list[str] = []
|
||||
for card in portfolio.cards:
|
||||
for check in card.blockers:
|
||||
if check.domain == domain:
|
||||
items.append(f"{card.platform_id}: {check.title} - {check.next_action}")
|
||||
return merge_unique(items)
|
||||
|
||||
|
||||
def build_operational_questions(portfolio: EcosystemGovernancePortfolio) -> tuple[PortfolioQuestion, ...]:
|
||||
questions: list[PortfolioQuestion] = []
|
||||
questions.append(
|
||||
PortfolioQuestion(
|
||||
question_id="estado-geral-governanca",
|
||||
question="Qual e o estado geral de governanca humana do ecossistema?",
|
||||
answer=(
|
||||
f"O score medio de governanca e {portfolio.average_governance_score}. "
|
||||
f"Plataformas bloqueadas: {len(portfolio.blocked_platforms)}. "
|
||||
f"Plataformas controladas: {len(portfolio.controlled_platforms)}."
|
||||
),
|
||||
evidence=portfolio.executive_summary,
|
||||
next_action="atuar primeiro nos blockers de dominio com maior impacto humano",
|
||||
)
|
||||
)
|
||||
weak = weakest_platforms(portfolio)
|
||||
questions.append(
|
||||
PortfolioQuestion(
|
||||
question_id="plataformas-mais-fracas",
|
||||
question="Quais plataformas mais precisam de continuidade?",
|
||||
answer="As plataformas com menor score sao: " + ", ".join(f"{card.platform_id} ({card.governance_score})" for card in weak),
|
||||
evidence=tuple(summarize_card(card) for card in weak),
|
||||
next_action="executar as OS vinculadas aos checks dessas plataformas",
|
||||
)
|
||||
)
|
||||
strong = strongest_platforms(portfolio)
|
||||
questions.append(
|
||||
PortfolioQuestion(
|
||||
question_id="plataformas-mais-fortes",
|
||||
question="Quais plataformas estao mais maduras para leitura humana?",
|
||||
answer="As plataformas mais fortes sao: " + ", ".join(f"{card.platform_id} ({card.governance_score})" for card in strong),
|
||||
evidence=tuple(summarize_card(card) for card in strong),
|
||||
next_action="usar essas plataformas como referencia de padrao e regressao",
|
||||
)
|
||||
)
|
||||
for domain in (
|
||||
GovernanceDomain.DOCS,
|
||||
GovernanceDomain.INTEGRATIONS,
|
||||
GovernanceDomain.IDENTITY,
|
||||
GovernanceDomain.BUSINESS,
|
||||
GovernanceDomain.MCP,
|
||||
GovernanceDomain.CLOUD,
|
||||
GovernanceDomain.OBSERVABILITY,
|
||||
):
|
||||
blockers = blockers_for_domain(portfolio, domain)
|
||||
impacted = platforms_by_domain_gap(portfolio, domain)
|
||||
answer = (
|
||||
f"Dominio {domain.value} tem {len(blockers)} blockers e "
|
||||
f"{len(impacted)} plataformas com gap/atencao."
|
||||
)
|
||||
if blockers:
|
||||
answer += " Principais: " + " | ".join(blockers[:3])
|
||||
questions.append(
|
||||
PortfolioQuestion(
|
||||
question_id=f"dominio-{domain.value}",
|
||||
question=f"O que bloqueia ou exige atencao no dominio {domain.value}?",
|
||||
answer=answer,
|
||||
evidence=blockers[:8] or tuple(summarize_card(card) for card in impacted[:5]),
|
||||
next_action=(
|
||||
f"priorizar checks do dominio {domain.value} e validar owner "
|
||||
"institucional antes da proxima promocao"
|
||||
),
|
||||
)
|
||||
)
|
||||
questions.append(
|
||||
PortfolioQuestion(
|
||||
question_id="ordens-saida-justificadas",
|
||||
question="As ordens de saida estao justificadas por checks reais?",
|
||||
answer=(
|
||||
f"Ha {len(portfolio.order_candidates)} candidatas de OS derivadas de checks de governanca. "
|
||||
"Cada candidata guarda source_check_ids e validacoes."
|
||||
),
|
||||
evidence=tuple(f"{candidate.candidate_id}: {', '.join(candidate.source_check_ids)}" for candidate in portfolio.order_candidates[:12]),
|
||||
next_action="manter ativas apenas ordens ligadas a pendencias reais ou continuidade impossivel nesta rodada",
|
||||
)
|
||||
)
|
||||
return tuple(questions)
|
||||
|
||||
|
||||
def questions_markdown(questions: Sequence[PortfolioQuestion]) -> str:
|
||||
lines = ["# Perguntas operacionais sobre governanca", ""]
|
||||
for question in questions:
|
||||
lines.append(f"## {question.question}")
|
||||
lines.append("")
|
||||
lines.append(question.answer)
|
||||
lines.append("")
|
||||
lines.append(f"Proxima acao: {question.next_action}")
|
||||
if question.evidence:
|
||||
lines.append("")
|
||||
lines.append("Evidencias:")
|
||||
for item in question.evidence[:10]:
|
||||
lines.append(f"- {item}")
|
||||
lines.append("")
|
||||
return "\n".join(lines).strip() + "\n"
|
||||
|
||||
|
||||
def questions_rows(questions: Sequence[PortfolioQuestion]) -> list[list[str]]:
|
||||
rows = [["question_id", "question", "answer", "next_action", "evidence_count"]]
|
||||
for question in questions:
|
||||
rows.append([question.question_id, question.question, question.answer, question.next_action, str(len(question.evidence))])
|
||||
return rows
|
||||
|
||||
|
||||
def query_by_keyword(questions: Sequence[PortfolioQuestion], keyword: str) -> tuple[PortfolioQuestion, ...]:
|
||||
lowered = keyword.lower()
|
||||
return tuple(
|
||||
question
|
||||
for question in questions
|
||||
if lowered in question.question.lower() or lowered in question.answer.lower() or any(lowered in evidence.lower() for evidence in question.evidence)
|
||||
)
|
||||
|
||||
|
||||
def unresolved_question_ids(questions: Sequence[PortfolioQuestion]) -> tuple[str, ...]:
|
||||
ids: list[str] = []
|
||||
for question in questions:
|
||||
text = f"{question.answer} {question.next_action}".lower()
|
||||
if "blocker" in text or "gap" in text or "priorizar" in text:
|
||||
ids.append(question.question_id)
|
||||
return tuple(ids)
|
||||
|
||||
|
||||
def compact_question_payload(questions: Sequence[PortfolioQuestion]) -> dict[str, object]:
|
||||
return {
|
||||
"count": len(questions),
|
||||
"unresolved": unresolved_question_ids(questions),
|
||||
"questions": [question.to_dict() for question in questions],
|
||||
}
|
||||
Reference in New Issue
Block a user