From 24923362a7a129ba78773b83915d50a692f5f554 Mon Sep 17 00:00:00 2001 From: codex-server Date: Sat, 2 May 2026 00:10:03 -0300 Subject: [PATCH] auto-sync: tudo-para-ia-mais-humana 2026-05-02 00:10:03 --- ...ay-access-policy-central-write-status.json | 2 +- dados/mcp-gateway-access-policy.json | 10 +- ...publication-gate-central-write-status.json | 2 +- dados/mcp-publication-gate-mais-humana.json | 26 +- ...geted-sync-audit-central-write-status.json | 10 + dados/targeted-sync-audit.json | 118 ++++ ecossistema/MCP-GATEWAY-ACCESS-POLICY.md | 4 +- .../MCP-PUBLICATION-GATE-MAIS-HUMANA.md | 12 +- ecossistema/TARGETED-SYNC-AUDIT.md | 82 +++ matrizes/mcp-publication-gate-decisions.csv | 4 +- matrizes/targeted-sync-audit.csv | 4 + src/mais_humana/cli.py | 48 ++ src/mais_humana/targeted_sync_audit.py | 529 +++++++++++++++++ src/mais_humana/workspace_hygiene.py | 535 ++++++++++++++++++ tests/test_targeted_sync_audit.py | 156 +++++ tests/test_workspace_hygiene.py | 84 +++ 16 files changed, 1598 insertions(+), 28 deletions(-) create mode 100644 dados/targeted-sync-audit-central-write-status.json create mode 100644 dados/targeted-sync-audit.json create mode 100644 ecossistema/TARGETED-SYNC-AUDIT.md create mode 100644 matrizes/targeted-sync-audit.csv create mode 100644 src/mais_humana/targeted_sync_audit.py create mode 100644 src/mais_humana/workspace_hygiene.py create mode 100644 tests/test_targeted_sync_audit.py create mode 100644 tests/test_workspace_hygiene.py diff --git a/dados/mcp-gateway-access-policy-central-write-status.json b/dados/mcp-gateway-access-policy-central-write-status.json index 62e7c19..05fa342 100644 --- a/dados/mcp-gateway-access-policy-central-write-status.json +++ b/dados/mcp-gateway-access-policy-central-write-status.json @@ -8,7 +8,7 @@ "path": "G:\\_codex-git\\nucleo-gestao-operacional\\central-de-ordem-de-servico\\projects\\15_repo_tudo-para-ia-mais-humana-platform\\reports\\MCP-GATEWAY-ACCESS-POLICY__RODADA015.md" } ], - "generatedAt": "2026-05-02T02:38:41+00:00", + "generatedAt": "2026-05-02T03:09:23+00:00", "ok": false, "policy": "falha de escrita central nao aborta artefatos do projeto real" } \ No newline at end of file diff --git a/dados/mcp-gateway-access-policy.json b/dados/mcp-gateway-access-policy.json index 3493aa8..acecd2e 100644 --- a/dados/mcp-gateway-access-policy.json +++ b/dados/mcp-gateway-access-policy.json @@ -136,7 +136,7 @@ } ], "endpoint": "https://mcps-gateway.ami-app.workers.dev/v1/execute", - "generated_at": "2026-05-02T02:38:41+00:00", + "generated_at": "2026-05-02T03:09:23+00:00", "liveReady": true, "log_retention_days": 30, "policy_version": "mcp-gateway-access-policy.v1", @@ -150,7 +150,7 @@ "evidence_id": "evidence-a75a27e0669c49da1db8b615", "http_status": 200, "method": "POST", - "observed_at": "2026-05-02T02:38:40+00:00", + "observed_at": "2026-05-02T03:08:48+00:00", "ok": true, "request_hash": "3e1c8f057ac439f4b9b3eb7f8f5be9ac36323f08adc23db6fc7d51633076b79a", "response_excerpt": { @@ -186,7 +186,7 @@ "evidence_id": "evidence-af37a8d489b0038a7a6b5575", "http_status": 200, "method": "POST", - "observed_at": "2026-05-02T02:38:41+00:00", + "observed_at": "2026-05-02T03:08:48+00:00", "ok": true, "request_hash": "17e7d8039c8c34e3f570b6de8b386edc1cfd0c079084b0c7013016d2c76b388c", "response_excerpt": { @@ -222,7 +222,7 @@ "evidence_id": "evidence-3f0e3b9f829c7ff912b335d0", "http_status": 200, "method": "POST", - "observed_at": "2026-05-02T02:38:41+00:00", + "observed_at": "2026-05-02T03:08:48+00:00", "ok": true, "request_hash": "dae7d91a59e37901d50c027d3a0792f697902bd4289801edb2a508f3baf177fe", "response_excerpt": { @@ -251,7 +251,7 @@ } ], "rate_limit_per_minute": 30, - "report_id": "mcp-gateway-access-policy-15ac101b6174411e", + "report_id": "mcp-gateway-access-policy-4beabbcbe6c59074", "required_content_type": "application/json", "required_method": "POST", "required_user_agent": "Codex-Mais-Humana-MCP-Publication-Gate/1.0", diff --git a/dados/mcp-publication-gate-central-write-status.json b/dados/mcp-publication-gate-central-write-status.json index c2d184e..d29d49b 100644 --- a/dados/mcp-publication-gate-central-write-status.json +++ b/dados/mcp-publication-gate-central-write-status.json @@ -8,7 +8,7 @@ "path": "G:\\_codex-git\\nucleo-gestao-operacional\\central-de-ordem-de-servico\\projects\\15_repo_tudo-para-ia-mais-humana-platform\\reports\\executivos\\MCP-PUBLICATION-GATE-MAIS-HUMANA__RODADA015.md" } ], - "generatedAt": "2026-05-02T02:38:41+00:00", + "generatedAt": "2026-05-02T03:08:48+00:00", "ok": false, "policy": "falha de escrita central nao aborta artefatos do projeto real" } \ No newline at end of file diff --git a/dados/mcp-publication-gate-mais-humana.json b/dados/mcp-publication-gate-mais-humana.json index a4b61d1..d46b8c4 100644 --- a/dados/mcp-publication-gate-mais-humana.json +++ b/dados/mcp-publication-gate-mais-humana.json @@ -17,6 +17,7 @@ "repo_remote": "https://git.ami.app.br/admin/tudo-para-ia-mais-humana.git" }, "blockers": [ + "runner_node_esbuild_spawn_eperm", "wrangler_auth_not_confirmed", "canonical_name_requires_institutional_decision", "git_sync_blocked" @@ -52,7 +53,7 @@ ], "next_action": "corrigir credencial Git/Schannel e reconciliar ahead/behind sem reset destrutivo", "order_id": "0033_EXECUTIVA__sincronizar-git-mais-humana-mcps-central-com-credenciais", - "reason": "fetch/push bloqueado por SEC_E_NO_CREDENTIALS; fetch remoto falhou no ciclo seguro da rodada", + "reason": "sync report 20260501_235902: fetch/probe remote failed with SEC_E_NO_CREDENTIALS on Windows and FETCH_HEAD Permission denied in codex_vm; destructive sync blocked.", "status": "blocked" }, { @@ -111,7 +112,7 @@ "next_action": "homologar host que permita Node, esbuild/workerd e node --test sem spawn EPERM", "order_id": "0046_GERENCIAL__homologar-runner-oficial-wrangler-node-esbuild", "reason": "Wrangler autenticou quando executado diretamente, mas deploy dry-run nao ficou confirmado", - "status": "not_run" + "status": "blocked" }, { "evidence_refs": [ @@ -149,7 +150,7 @@ "mais_humana.mcp_transit.ledger" ] }, - "generated_at": "2026-05-02T02:38:41+00:00", + "generated_at": "2026-05-02T03:08:48+00:00", "liveReady": true, "live_probes": [ { @@ -158,7 +159,7 @@ "error_code": "", "evidence_id": "evidence-a75a27e0669c49da1db8b615", "http_status": 200, - "observed_at": "2026-05-02T02:38:40+00:00", + "observed_at": "2026-05-02T03:08:48+00:00", "ok": true, "response_excerpt": { "__truncated__": true, @@ -191,7 +192,7 @@ "error_code": "", "evidence_id": "evidence-af37a8d489b0038a7a6b5575", "http_status": 200, - "observed_at": "2026-05-02T02:38:41+00:00", + "observed_at": "2026-05-02T03:08:48+00:00", "ok": true, "response_excerpt": { "__truncated__": true, @@ -224,7 +225,7 @@ "error_code": "", "evidence_id": "evidence-3f0e3b9f829c7ff912b335d0", "http_status": 200, - "observed_at": "2026-05-02T02:38:41+00:00", + "observed_at": "2026-05-02T03:08:48+00:00", "ok": true, "response_excerpt": { "__truncated__": true, @@ -254,7 +255,7 @@ ], "localReady": true, "provider_id": "mais_humana", - "report_id": "mcp-publication-gate-2026-05-02t0238410000", + "report_id": "mcp-publication-gate-2026-05-02t0308480000", "status": "partial", "summary": [ "Provider local Mais Humana pronto: True.", @@ -266,18 +267,19 @@ "wrangler_runner": { "account_id": "", "account_name": "", - "attempted": false, + "attempted": true, "authenticated": false, "blockers": [ + "runner_node_esbuild_spawn_eperm", "wrangler_auth_not_confirmed" ], "command_status": { - "wrangler_deploy_dry_run": "not_confirmed", - "wrangler_version": "unknown", - "wrangler_whoami": "unknown" + "wrangler_deploy_dry_run": "blocked_spawn_eperm", + "wrangler_version": "blocked", + "wrangler_whoami": "blocked" }, "deploy_dry_run_ok": false, - "raw_summary": "", + "raw_summary": "wrangler direct attempted in round 015 follow-up; wrangler --version, whoami and deployments list all failed before execution with node child_process spawn EPERM on Windows runner; no deploy was attempted.", "version": "" } } \ No newline at end of file diff --git a/dados/targeted-sync-audit-central-write-status.json b/dados/targeted-sync-audit-central-write-status.json new file mode 100644 index 0000000..29c45b3 --- /dev/null +++ b/dados/targeted-sync-audit-central-write-status.json @@ -0,0 +1,10 @@ +{ + "failures": [ + { + "error": "PermissionError: [Errno 13] Permission denied: 'G:\\\\_codex-git\\\\nucleo-gestao-operacional\\\\central-de-ordem-de-servico\\\\projects\\\\15_repo_tudo-para-ia-mais-humana-platform\\\\reports\\\\EXECUTADO__targeted-sync-audit.md'", + "path": "G:\\_codex-git\\nucleo-gestao-operacional\\central-de-ordem-de-servico\\projects\\15_repo_tudo-para-ia-mais-humana-platform\\reports\\EXECUTADO__targeted-sync-audit.md" + } + ], + "generatedAt": "2026-05-02T03:09:48+00:00", + "ok": false +} \ No newline at end of file diff --git a/dados/targeted-sync-audit.json b/dados/targeted-sync-audit.json new file mode 100644 index 0000000..a5cbb5c --- /dev/null +++ b/dados/targeted-sync-audit.json @@ -0,0 +1,118 @@ +{ + "blockers": [ + "mais-humana:git_acl_or_lock_blocked", + "mcps-internos:git_acl_or_lock_blocked", + "nucleo-central:git_acl_or_lock_blocked" + ], + "fetch": true, + "generated_at": "2026-05-02T03:09:48+00:00", + "observations": [ + { + "ahead": 0, + "behind": 0, + "blockers": [ + "git_acl_or_lock_blocked" + ], + "branch": "main", + "decision": "corrigir ACL/locks de .git antes de qualquer merge/push", + "dirty": true, + "exists": true, + "fetch_attempted": true, + "fetch_exit": 255, + "fetch_output": "error: cannot open '.git/FETCH_HEAD': Permission denied", + "head": "6e230bb97983580d9a32093ab2ef21a377bfde2f", + "is_git": true, + "origin": "https://git.ami.app.br/admin/tudo-para-ia-mais-humana.git", + "short_head": "6e230bb97983", + "status": "acl_blocked", + "status_short": "## main\n M dados/mcp-gateway-access-policy-central-write-status.json\n M dados/mcp-gateway-access-policy.json\n M dados/mcp-publication-gate-central-write-status.json\n M dados/mcp-publication-gate-mais-humana.json\n M ecossistema/MCP-GATEWAY-ACCESS-POLICY.md\n M ecossistema/MCP-PUBLICATION-GATE-MAIS-HUMANA.md\n M matrizes/mcp-publication-gate-decisions.csv\n M src/mais_humana/cli.py\n?? src/mais_humana/targeted_sync_audit.py\n?? src/mais_humana/workspace_hygiene.py\n?? tests/test_targeted_sync_audit.py\n?? tests/test_workspace_hygiene.py", + "target": { + "expected_remote": "https://git.ami.app.br/admin/tudo-para-ia-mais-humana.git", + "path": "G:\\_codex-git\\tudo-para-ia-mais-humana", + "role": "projeto real da plataforma 15", + "target_id": "mais-humana" + } + }, + { + "ahead": 0, + "behind": 0, + "blockers": [ + "git_acl_or_lock_blocked" + ], + "branch": "main", + "decision": "corrigir ACL/locks de .git antes de qualquer merge/push", + "dirty": true, + "exists": true, + "fetch_attempted": true, + "fetch_exit": 255, + "fetch_output": "error: cannot open '.git/FETCH_HEAD': Permission denied", + "head": "02a0d7b16f528f18c2670c7431557103860fb488", + "is_git": true, + "origin": "https://git.ami.app.br/admin/tudo-para-ia-mcps-internos-plataform.git", + "short_head": "02a0d7b16f52", + "status": "acl_blocked", + "status_short": "## main...origin/main\n M apps/tudo-para-ia-mcps-central/src/registry/catalog.ts\n M deploy/mcps-gateway/src/managers/gpt-tooling-manager.ts\n M deploy/mcps-gateway/src/stj/tooling.ts\n M tests/support/docs-central-stub.ts\n?? apps/tudo-para-ia-mcps-central/src/registry/router007-transit.ts", + "target": { + "expected_remote": "https://git.ami.app.br/admin/tudo-para-ia-mcps-internos-plataform.git", + "path": "G:\\_codex-git\\tudo-para-ia-mcps-internos-plataform", + "role": "control-plane MCP que publica as tools Mais Humana", + "target_id": "mcps-internos" + } + }, + { + "ahead": 5, + "behind": 5, + "blockers": [ + "git_acl_or_lock_blocked" + ], + "branch": "main", + "decision": "corrigir ACL/locks de .git antes de qualquer merge/push", + "dirty": true, + "exists": true, + "fetch_attempted": true, + "fetch_exit": 255, + "fetch_output": "error: cannot open '.git/FETCH_HEAD': Permission denied", + "head": "e9b83aff598bc3172c29dde8c65045135d408c6d", + "is_git": true, + "origin": "https://git.ami.app.br/admin/nucleo-gestao-operacional.git", + "short_head": "e9b83aff598b", + "status": "acl_blocked", + "status_short": "## main...origin/main [ahead 5, behind 5]\n M central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/controle-semantico.sqlite\n M central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/current/current-project-state.md\n M central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/indexes/ordens-executivas-index.md\n M central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/indexes/ordens-gerenciais-index.md\n M central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/indexes/reports-index.md\n D central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executivas/0059_EXECUTIVA__executar-deploy-docs-central-em-host-com-esbuild-spawn-liberado.md\n D central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executivas/0060_EXECUTIVA__registrar-docs-ecosystem-workspace-inventory-no-mcps-internos.md\n D central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executivas/0061_EXECUTIVA__rodar-smoke-remoto-docs-ecosystem-workspace-inventory-pos-deploy.md\n D central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executivas/0062_EXECUTIVA__publicar-evidence-pack-workspace-inventory-docs.md\n D central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executivas/0063_EXECUTIVA__reconciliar-commit-push-docs-e-central-com-gitea-liberado.md\n D central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/gerenciais/0056_GERENCIAL__homologar-workspace-inventory-como-fonte-de-verdade-docs.md\n D central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/gerenciais/0057_GERENCIAL__formalizar-docs-only-inventory-sem-alterar-outras-plataformas.md\n D central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/gerenciais/0058_GERENCIAL__homologar-runner-wrangler-esbuild-e-remote-smoke-docs.md\n D central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/gerenciais/0059_GERENCIAL__governar-ciclo-de-registro-mcp-docs-ecosystem-tools.md\n D central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/gerenciais/0060_GERENCIAL__governar-divergencia-git-central-e-mudancas-concorrentes.md\n M central-de-ordem-de-servico/projects/05_repo_tudo-para-ia-finance-platform/controle-semantico.sqlite\n M central-de-ordem-de-servico/projects/05_repo_tudo-para-ia-finance-platform/indexes/reports-index.md\n M central-de-ordem-de-servico/projects/06_repo_tudo-para-ia-gettys-platform/controle-semantico.sqlite\n M central-de-ordem-de-servico/projects/07_repo_tudo-para-ia-identity-platform/controle-semantico.sqlite\n M central-de-ordem-de-servico/projects/07_repo_tudo-para-ia-identity-platform/indexes/reports-index.md\n M central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/controle-semantico.sqlite\n M central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/current/current-project-state.md\n M central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/indexes/ordens-executivas-index.md\n M central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/indexes/ordens-gerenciais-index.md\n D central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/executivas/0051_EXECUTIVA__executar-pages-deploy-com-wrangler-486-em-host-aprovado.md\n D central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/executivas/0052_EXECUTIVA__substituir-canonical-local-por-dominio-publico-e-verificar-522.md\n D central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/executivas/0053_EXECUTIVA__aplicar-registro-mcp-central-com-ui-consumer-readback.md\n D central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/executivas/0054_EXECUTIVA__reconciliar-manifesto-docs-peer-e-public-docs-sourcehash.md\n D central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/executivas/0055_EXECUTIVA__homologar-aceites-lead-handoff-com-business-compliance-customerops.md\n D central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/gerenciais/0046_GERENCIAL__homologar-runtime-pages-deploy-externo-com-slo-de-upload.md\n D central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/gerenciais/0047_GERENCIAL__decidir-dominio-publico-e-politica-pagesdev-rollback.md\n D central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/gerenciais/0048_GERENCIAL__pactuar-mutacao-mcp-central-e-consumo-ui-contract.md\n D central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/gerenciais/0049_GERENCIAL__pactuar-docs-platform-manifesto-peer-public-platform.md\n D central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/gerenciais/0050_GERENCIAL__aprovar-retencao-purge-suporte-leads-publicos.md\n M central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/controle-semantico.sqlite\n M central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/current/active-order-queue.md\n M central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/current/current-project-state.md\n M central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/indexes/ordens-executivas-index.md\n M central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/indexes/ordens-gerenciais-index.md\n M central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/indexes/pending-index.md\n M central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/indexes/reports-index.md\n D central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/executivas/0061_EXECUTIVA__publicar-mcp-gateway-live-aliases-round015.md\n D central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/executivas/0062_EXECUTIVA__executar-deploy-stj-workers-pos-mcp-central.md\n D central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/executivas/0063_EXECUTIVA__confirmar-kv-readback-byte-a-byte-round015.md\n D central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/executivas/0064_EXECUTIVA__rodar-suite-stj-completa-runner-node-esbuild.md\n D central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/executivas/0065_EXECUTIVA__sincronizar-repositorios-apos-credenciais-remotas.md\n D central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/gerenciais/0056_GERENCIAL__aprovar-release-live-mcp-gateway-round015.md\n D central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/gerenciais/0057_GERENCIAL__homologar-runner-cloudflare-sem-spawn-eperm.md\n D central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/gerenciais/0058_GERENCIAL__definir-politica-readback-byte-preserving-kv.md\n D central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/gerenciais/0059_GERENCIAL__pactuar-aceite-business-identity-docs-stj-mcp.md\n D central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/gerenciais/0060_GERENCIAL__tratar-limite-material-producao-codigo-stj.md\n M central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/controle-semantico.sqlite\n M central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/current/current-project-state.md\n M central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/indexes/audit-index.md\n M central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/indexes/ordens-executivas-index.md\n M central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/indexes/ordens-gerenciais-index.md\n M central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/indexes/pending-index.md\n M central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/indexes/reports-index.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executivas/0080_EXECUTIVA__publicar-mcp-transit-gateway-acceptance-no-gateway-docs-ci.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executivas/0081_EXECUTIVA__rodar-browser-validation-host-homologado-com-screenshots.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executivas/0082_EXECUTIVA__executar-rollback-pages-com-janela-aprovada.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executivas/0083_EXECUTIVA__conectar-resolver-credentialref-institucional-admin-ui.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executivas/0084_EXECUTIVA__sincronizar-git-ui-mcps-central-com-credenciais-e-loteamento.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executivas/0085_EXECUTIVA__corrigir-quatro-bloqueios-restantes-da-suite-mcps-internos.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/gerenciais/0075_GERENCIAL__aprovar-mcp-transit-gateway-acceptance-como-contrato.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/gerenciais/0076_GERENCIAL__homologar-runner-visual-browser-para-ui-platform.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/gerenciais/0077_GERENCIAL__aprovar-politica-rollback-pages-ui.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/gerenciais/0078_GERENCIAL__governar-resolver-credentialref-admin-ui-com-security.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/gerenciais/0079_GERENCIAL__governar-sincronizacao-git-com-credenciais-e-loteamento.md\n D central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/gerenciais/0080_GERENCIAL__homologar-runtime-ts-mcps-internos-e-dependencias-cruzadas.md\n M central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/controle-semantico.sqlite\n M central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/current/active-order-queue.md\n M central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/current/current-project-state.md\n M central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/indexes/ordens-gerenciais-index.md\n M central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/indexes/orders-index.md\n M central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/indexes/pending-index.md\n M central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/indexes/reports-index.md\n M central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/status/overview.md\n M central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/000_sincronizacao-dos-espelhos.md\n M central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/RESOLUCAO-DE-BLOQUEIOS-GIT-GITEA-WINDOWS-E-LINUX.md\n M central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/SINCRONIZACAO-MANUAL-DE-REPOSITORIO.md\n M central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/coletar-sincronizacao-espelhos.ps1\n M central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/sincronizar-repositorios-gitea-windows.ps1\n M roteador-de-ordens-de-servico/000-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n M roteador-de-ordens-de-servico/001-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n D roteador-de-ordens-de-servico/002-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n D roteador-de-ordens-de-servico/003-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n M roteador-de-ordens-de-servico/004-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n D roteador-de-ordens-de-servico/005-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n D roteador-de-ordens-de-servico/006-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n M roteador-de-ordens-de-servico/007-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n D roteador-de-ordens-de-servico/008-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n D roteador-de-ordens-de-servico/009-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n M roteador-de-ordens-de-servico/010-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n D roteador-de-ordens-de-servico/011-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n D roteador-de-ordens-de-servico/012-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n M roteador-de-ordens-de-servico/013-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n M roteador-de-ordens-de-servico/014-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n M roteador-de-ordens-de-servico/015-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO.MD\n?? central-de-ordem-de-servico/projects/01_repo_tudo-para-ia-business-platform/reports/RELATORIO-RODADA__2026-05-02__business-round009.md\n?? central-de-ordem-de-servico/projects/01_repo_tudo-para-ia-business-platform/reports/executivas/EXECUCAO-ORDENS-0066-A-0070__20260501_2045.md\n?? central-de-ordem-de-servico/projects/01_repo_tudo-para-ia-business-platform/reports/executivas/EXECUCAO-ORDENS-0066-A-0070__20260501_2232.md\n?? central-de-ordem-de-servico/projects/01_repo_tudo-para-ia-business-platform/status/STATUS-RODADA__2026-05-02__round009-2332.md\n?? central-de-ordem-de-servico/projects/01_repo_tudo-para-ia-business-platform/status/STATUS-RODADA__20260501_2045.md\n?? central-de-ordem-de-servico/projects/01_repo_tudo-para-ia-business-platform/status/STATUS-RODADA__20260501_2232.md\n?? central-de-ordem-de-servico/projects/02_repo_tudo-para-ia-compliance-platform/reports/RELATORIO-RODADA__2026-05-02__compliance-round009.md\n?? central-de-ordem-de-servico/projects/02_repo_tudo-para-ia-compliance-platform/reports/executivas/EXECUTADO-RODADA__2026-05-01__round007-2045.md\n?? central-de-ordem-de-servico/projects/02_repo_tudo-para-ia-compliance-platform/reports/executivas/EXECUTADO-RODADA__2026-05-01__round008-2232.md\n?? central-de-ordem-de-servico/projects/02_repo_tudo-para-ia-compliance-platform/status/STATUS-RODADA__2026-05-01__round007-2045.md\n?? central-de-ordem-de-servico/projects/02_repo_tudo-para-ia-compliance-platform/status/STATUS-RODADA__2026-05-01__round008-2232.md\n?? central-de-ordem-de-servico/projects/02_repo_tudo-para-ia-compliance-platform/status/STATUS-RODADA__2026-05-02__round009-2332.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/audit/ordens-executadas/AUDITORIA-GPT__20260502_control-plane-registry.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/audit/ordens-executadas/AUDITORIA-GPT__20260502_documentation-truth.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/executivas/0059_EXECUTIVA__executar-deploy-docs-central-em-host-com-esbuild-spawn-liberado.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/executivas/0060_EXECUTIVA__registrar-docs-ecosystem-workspace-inventory-no-mcps-internos.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/executivas/0061_EXECUTIVA__rodar-smoke-remoto-docs-ecosystem-workspace-inventory-pos-deploy.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/executivas/0062_EXECUTIVA__publicar-evidence-pack-workspace-inventory-docs.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/executivas/0063_EXECUTIVA__reconciliar-commit-push-docs-e-central-com-gitea-liberado.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/executivas/0064_EXECUTIVA__executar-deploy-docs-control-plane-registry-com-wrangler.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/executivas/0065_EXECUTIVA__registrar-docs-ecosystem-control-plane-registry-no-mcps-internos.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/executivas/0066_EXECUTIVA__rodar-smoke-remoto-control-plane-registry-pos-deploy-e-registro.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/executivas/0067_EXECUTIVA__publicar-evidence-pack-control-plane-registry-docs.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/executivas/0068_EXECUTIVA__reconciliar-push-docs-e-central-com-gitea-liberado.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/gerenciais/0056_GERENCIAL__homologar-workspace-inventory-como-fonte-de-verdade-docs.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/gerenciais/0057_GERENCIAL__formalizar-docs-only-inventory-sem-alterar-outras-plataformas.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/gerenciais/0058_GERENCIAL__homologar-runner-wrangler-esbuild-e-remote-smoke-docs.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/gerenciais/0059_GERENCIAL__governar-ciclo-de-registro-mcp-docs-ecosystem-tools.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/gerenciais/0060_GERENCIAL__governar-divergencia-git-central-e-mudancas-concorrentes.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/gerenciais/0061_GERENCIAL__homologar-control-plane-registry-como-fonte-de-verdade-mcp.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/gerenciais/0062_GERENCIAL__definir-owners-e-aceite-dos-status-pending-mcp-registration.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/gerenciais/0063_GERENCIAL__homologar-politica-docs-only-para-inventario-e-control-plane.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/gerenciais/0064_GERENCIAL__governar-runner-wrangler-esbuild-sem-spawn-eperm.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executadas/gerenciais/0065_GERENCIAL__governar-sync-central-divergente-com-staging-por-plataforma.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executivas/0069_EXECUTIVA__executar-deploy-docs-documentation-truth-com-wrangler.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executivas/0070_EXECUTIVA__registrar-docs-ecosystem-documentation-truth-no-mcps-internos.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executivas/0071_EXECUTIVA__rodar-smoke-remoto-documentation-truth-pos-deploy-e-registro.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executivas/0072_EXECUTIVA__publicar-evidence-pack-documentation-truth-docs.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/executivas/0073_EXECUTIVA__reconciliar-push-docs-e-central-apos-gitea-fix.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/gerenciais/0066_GERENCIAL__homologar-documentation-truth-como-fonte-de-verdade-docs.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/gerenciais/0067_GERENCIAL__governar-fila-needs-mcp-registration-documental.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/gerenciais/0068_GERENCIAL__formalizar-quality-gates-diataxis-mcp-owner-hash.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/gerenciais/0069_GERENCIAL__homologar-runner-wrangler-para-deploy-docs-sem-eperm.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/orders/gerenciais/0070_GERENCIAL__governar-sync-central-docs-com-generated-artifacts.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/reports/executivas/EXECUCAO-ORDENS-0059-A-0063__20260502_control-plane-registry.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/reports/executivas/EXECUCAO-ORDENS-0064-A-0068__20260502_documentation-truth.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/reports/executivas/EXECUCAO-RODADA__20260501_docs-customer-ops-mcps-reconciliacao.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/reports/executivas/PENDENCIAS-CODEX__20260502_control-plane-registry.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/reports/executivas/PENDENCIAS-CODEX__20260502_documentation-truth.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/reports/gerenciais/AVALIACAO-GERENCIAL-DA-PLATAFORMA__20260502_control-plane-registry.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/reports/gerenciais/AVALIACAO-GERENCIAL-DA-PLATAFORMA__20260502_documentation-truth.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/reports/gerenciais/EXECUCAO-GERENCIAL-CONSOLIDADA__20260502_control-plane-registry.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/reports/gerenciais/EXECUCAO-GERENCIAL-CONSOLIDADA__20260502_documentation-truth.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/status/STATUS-RODADA__20260501_docs-customer-ops-mcps-reconciliacao.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/status/STATUS-RODADA__20260502_control-plane-registry.md\n?? central-de-ordem-de-servico/projects/04_repo_tudo-para-ia-docs-plataform/status/STATUS-RODADA__20260502_documentation-truth.md\n?? central-de-ordem-de-servico/projects/05_repo_tudo-para-ia-finance-platform/current/STATUS-RODADA__2026-05-01_205530_FINANCE-52-MCP-CENTRAL.md\n?? central-de-ordem-de-servico/projects/05_repo_tudo-para-ia-finance-platform/current/STATUS-RODADA__2026-05-02_FINANCE-MCPS-LIVE-REVALIDACAO-2.md\n?? central-de-ordem-de-servico/projects/05_repo_tudo-para-ia-finance-platform/current/STATUS-RODADA__2026-05-02_FINANCE-MCPS-REMOTE-VALIDATION.md\n?? central-de-ordem-de-servico/projects/05_repo_tudo-para-ia-finance-platform/current/STATUS-RODADA__2026-05-02_ROUTER007-MCP-TRANSIT-ASSURANCE.md\n?? central-de-ordem-de-servico/projects/05_repo_tudo-para-ia-finance-platform/reports/executivas/EXECUCAO-RODADA__2026-05-02_ROUTER007-MCP-TRANSIT-ASSURANCE.md\n?? central-de-ordem-de-servico/projects/06_repo_tudo-para-ia-gettys-platform/current/STATUS-RODADA__2026-05-01_205530_GETTYS-61-MCP-CENTRAL.md\n?? central-de-ordem-de-servico/projects/06_repo_tudo-para-ia-gettys-platform/current/STATUS-RODADA__2026-05-02_GETTYS-MCP-CENTRAL-SAMESOURCE.md\n?? central-de-ordem-de-servico/projects/06_repo_tudo-para-ia-gettys-platform/current/STATUS-RODADA__2026-05-02_GETTYS-MCPS-LIVE-REVALIDACAO-2.md\n?? central-de-ordem-de-servico/projects/06_repo_tudo-para-ia-gettys-platform/current/STATUS-RODADA__2026-05-02_ROUTER007-MCP-TRANSIT-ASSURANCE.md\n?? central-de-ordem-de-servico/projects/06_repo_tudo-para-ia-gettys-platform/indexes/reports-index.md\n?? central-de-ordem-de-servico/projects/06_repo_tudo-para-ia-gettys-platform/reports/EXECUCAO-RODADA__2026-05-02_ROUTER007-MCP-TRANSIT-ASSURANCE.md\n?? central-de-ordem-de-servico/projects/07_repo_tudo-para-ia-identity-platform/current/STATUS-2026-05-01-IDENTITY-MCPS-WRANGLER.md\n?? central-de-ordem-de-servico/projects/07_repo_tudo-para-ia-identity-platform/current/STATUS-2026-05-02-IDENTITY-MCPS-LIVE-REVALIDACAO-2.md\n?? central-de-ordem-de-servico/projects/07_repo_tudo-para-ia-identity-platform/current/STATUS-2026-05-02-IDENTITY-MCPS-REMOTE-VALIDATION.md\n?? central-de-ordem-de-servico/projects/07_repo_tudo-para-ia-identity-platform/current/STATUS-RODADA__2026-05-02_ROUTER007-MCP-TRANSIT-ASSURANCE.md\n?? central-de-ordem-de-servico/projects/07_repo_tudo-para-ia-identity-platform/reports/EXECUCAO-RODADA__2026-05-02_ROUTER007-MCP-TRANSIT-ASSURANCE.md\n?? central-de-ordem-de-servico/projects/10_repo_tudo-para-ia-mcps-internos-plataform/current/STATUS-RODADA__2026-05-01_205530_FINANCE-GETTYS-CONTRATOS.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/current/CURRENT__2026-05-01__public-platform-router013.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/current/active-order-queue.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/indexes/INDEX__2026-05-02__public-platform-router013-readback.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/executivas/0056_EXECUTIVA__executar-pages-deploy-runner-oficial.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/executivas/0057_EXECUTIVA__confirmar-readback-canonical-live.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/executivas/0058_EXECUTIVA__registrar-contrato-mcp-central-public.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/executivas/0059_EXECUTIVA__sincronizar-docs-platform-sourcehash.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/executivas/0060_EXECUTIVA__homologar-lead-handoff-sem-pii.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/gerenciais/0051_GERENCIAL__homologar-runner-pages-deploy.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/gerenciais/0052_GERENCIAL__decidir-dominio-final-canonical.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/gerenciais/0053_GERENCIAL__governar-mcp-central-ui-public.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/gerenciais/0054_GERENCIAL__governar-docs-platform-peer-public.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/orders/gerenciais/0055_GERENCIAL__aprovar-retencao-purge-suporte-leads.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/EXECUCAO__2026-05-01__public-platform-router013.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/PENDENCIAS-CODEX__2026-05-01__public-platform-router013.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/executivas-executadas/0051_EXECUTIVA__executar-pages-deploy-com-wrangler-486-em-host-aprovado.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/executivas-executadas/0052_EXECUTIVA__substituir-canonical-local-por-dominio-publico-e-verificar-522.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/executivas-executadas/0053_EXECUTIVA__aplicar-registro-mcp-central-com-ui-consumer-readback.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/executivas-executadas/0054_EXECUTIVA__reconciliar-manifesto-docs-peer-e-public-docs-sourcehash.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/executivas-executadas/0055_EXECUTIVA__homologar-aceites-lead-handoff-com-business-compliance-customerops.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/executivas/\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/gerenciais-executadas/0046_GERENCIAL__homologar-runtime-pages-deploy-externo-com-slo-de-upload.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/gerenciais-executadas/0047_GERENCIAL__decidir-dominio-publico-e-politica-pagesdev-rollback.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/gerenciais-executadas/0048_GERENCIAL__pactuar-mutacao-mcp-central-e-consumo-ui-contract.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/gerenciais-executadas/0049_GERENCIAL__pactuar-docs-platform-manifesto-peer-public-platform.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/gerenciais-executadas/0050_GERENCIAL__aprovar-retencao-purge-suporte-leads-publicos.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/gerenciais/AVALIACAO-GERENCIAL-DA-PLATAFORMA__2026-05-01__public-platform-router013.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/reports/gerenciais/AVALIACAO-GERENCIAL-DA-PLATAFORMA__2026-05-02__public-platform-router013-readback.md\n?? central-de-ordem-de-servico/projects/12_repo_tudo-para-ia-public-platform/status/STATUS__2026-05-02__public-platform-router013-readback.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/executivas/0066_EXECUTIVA__publicar-mcp-gateway-aliases-round015.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/executivas/0067_EXECUTIVA__deploy-stj-workers-wrangler.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/executivas/0068_EXECUTIVA__consolidar-readback-byte-preserving.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/executivas/0069_EXECUTIVA__rodar-suite-stj-runner-liberado.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/executivas/0070_EXECUTIVA__sincronizar-repositorios-stj.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/gerenciais/0061_GERENCIAL__aprovar-release-mcp-gateway-round015.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/gerenciais/0062_GERENCIAL__homologar-runner-cloudflare-operacional.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/gerenciais/0063_GERENCIAL__formalizar-readback-byte-preserving.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/gerenciais/0064_GERENCIAL__pactuar-chave-mcp-gateway-e-aceites.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/orders/gerenciais/0065_GERENCIAL__governar-sync-git-remotos.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/reports/executivas-executadas/\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/reports/executivas/EXECUCAO-RODADA__2026-05-01__round017-router013.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/reports/executivas/EXECUCAO-RODADA__2026-05-01__router013-stj-live-readback.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/reports/executivas/EXECUCAO-RODADA__2026-05-02__router013-stj-transit-assurance.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/reports/executivas/PENDENCIAS-CODEX__2026-05-01__round017-router013.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/reports/gerenciais-executadas/\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/reports/gerenciais/AVALIACAO-GERENCIAL-DA-PLATAFORMA__2026-05-01__round017-router013.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/reports/gerenciais/AVALIACAO-GERENCIAL-DA-PLATAFORMA__2026-05-02__stj-transit-assurance.md\n?? central-de-ordem-de-servico/projects/13_repo_tudo-para-ia-stj-platform/status/STATUS-RODADA__2026-05-02__stj-transit-assurance.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0075_GERENCIAL__aprovar-mcp-transit-gateway-acceptance-como-contrato.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0076_GERENCIAL__homologar-runner-visual-browser-para-ui-platform.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0077_GERENCIAL__aprovar-politica-rollback-pages-ui.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0078_GERENCIAL__governar-resolver-credentialref-admin-ui-com-security.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0079_GERENCIAL__governar-sincronizacao-git-com-credenciais-e-loteamento.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0080_EXECUTIVA__publicar-mcp-transit-gateway-acceptance-no-gateway-docs-ci.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0080_GERENCIAL__homologar-runtime-ts-mcps-internos-e-dependencias-cruzadas.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0081_EXECUTIVA__rodar-browser-validation-host-homologado-com-screenshots.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0082_EXECUTIVA__executar-rollback-pages-com-janela-aprovada.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0083_EXECUTIVA__conectar-resolver-credentialref-institucional-admin-ui.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0084_EXECUTIVA__sincronizar-git-ui-mcps-central-com-credenciais-e-loteamento.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/0085_EXECUTIVA__corrigir-quatro-bloqueios-restantes-da-suite-mcps-internos.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/AUDITORIA-GPT__ROUND025__20260502_013957.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/audit/ordens-executadas/AUDITORIA-GPT__ROUND026__20260502_034800.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/indexes/INDEX__ROUND024__20260501_212632.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/indexes/INDEX__ROUND025__20260502_013957.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/indexes/INDEX__ROUND026__20260502_034800.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0080_EXECUTIVA__publicar-mcp-transit-gateway-acceptance-no-gateway-docs-ci.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0081_EXECUTIVA__rodar-browser-validation-host-homologado-com-screenshots.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0082_EXECUTIVA__executar-rollback-pages-com-janela-aprovada.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0083_EXECUTIVA__conectar-resolver-credentialref-institucional-admin-ui.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0084_EXECUTIVA__sincronizar-git-ui-mcps-central-com-credenciais-e-loteamento.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0085_EXECUTIVA__corrigir-quatro-bloqueios-restantes-da-suite-mcps-internos.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0086_EXECUTIVA__promover-gateway-acceptance-docs-ci-com-hash-e-artifacts.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0087_EXECUTIVA__executar-browser-validation-em-runner-homologado-sem-eperm.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0088_EXECUTIVA__ensaiar-rollback-pages-com-owner-e-health-readback.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0089_EXECUTIVA__ativar-resolver-credentialref-readonly-institucional.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0090_EXECUTIVA__reconciliar-git-fetch-head-acl-e-push-loteado.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/executivas/0091_EXECUTIVA__rodar-suite-mcps-internos-full-com-runtime-fixo.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0075_GERENCIAL__aprovar-mcp-transit-gateway-acceptance-como-contrato.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0076_GERENCIAL__homologar-runner-visual-browser-para-ui-platform.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0077_GERENCIAL__aprovar-politica-rollback-pages-ui.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0078_GERENCIAL__governar-resolver-credentialref-admin-ui-com-security.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0079_GERENCIAL__governar-sincronizacao-git-com-credenciais-e-loteamento.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0080_GERENCIAL__homologar-runtime-ts-mcps-internos-e-dependencias-cruzadas.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0081_GERENCIAL__aprovar-gateway-acceptance-docs-ci-como-gate.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0082_GERENCIAL__homologar-runner-browser-sem-eperm-para-ui.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0083_GERENCIAL__aprovar-janela-rollback-pages-com-retencao.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0084_GERENCIAL__governar-resolver-credentialref-institucional.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0085_GERENCIAL__governar-acl-fetch-head-e-sync-loteado.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executadas/gerenciais/0086_GERENCIAL__homologar-runtime-ts-fixo-mcps-internos.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executivas/0092_EXECUTIVA__promover-gateway-acceptance-docs-ci-com-artifact-externo.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executivas/0093_EXECUTIVA__executar-browser-validation-host-homologado-com-screenshots-reais.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executivas/0094_EXECUTIVA__ensaiar-rollback-pages-com-owner-e-readback-live.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executivas/0095_EXECUTIVA__ativar-resolver-credentialref-readonly-sem-segredo-bruto.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/executivas/0096_EXECUTIVA__reconciliar-git-fetch-head-schannel-acl-e-push-central.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/gerenciais/0087_GERENCIAL__aprovar-gateway-acceptance-docs-ci-com-retencao.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/gerenciais/0088_GERENCIAL__homologar-runner-browser-ui-sem-eperm.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/gerenciais/0089_GERENCIAL__aprovar-politica-rollback-pages-ui-com-owner.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/gerenciais/0090_GERENCIAL__governar-resolver-credentialref-readonly-sem-segredo.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/orders/gerenciais/0091_GERENCIAL__governar-sync-git-schannel-acl-e-central-divergente.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/reports/executivos/EXECUTADO__ROUND024__20260501_212632.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/reports/executivos/EXECUTADO__ROUND025__20260502_013957.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/reports/executivos/EXECUTADO__ROUND026__20260502_034800.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/reports/executivos/PENDENCIAS-CODEX__ROUND024__20260501_212632.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/reports/executivos/PENDENCIAS-CODEX__ROUND025__20260502_013957.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/reports/executivos/PENDENCIAS-CODEX__ROUND026__20260502_034800.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/reports/gerenciais/AVALIACAO-GERENCIAL-DA-PLATAFORMA__ROUND024__20260501_212632.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/reports/gerenciais/AVALIACAO-GERENCIAL-DA-PLATAFORMA__ROUND025__20260502_013957.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/reports/gerenciais/AVALIACAO-GERENCIAL-DA-PLATAFORMA__ROUND026__20260502_034800.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/status/STATUS-RODADA__ROUND024__20260501_212632.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/status/STATUS-RODADA__ROUND025__20260502_013957.md\n?? central-de-ordem-de-servico/projects/14_repo_tudo-para-ia-ui-platform/status/STATUS-RODADA__ROUND026__20260502_034800.md\n?? central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/audit/AUDITORIA-GPT__rodada-015-access-policy-mcp-live-2026-05-02.md\n?? central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/indexes/INDEX__RODADA015__20260502T0238Z.md\n?? central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/orders/executivas/0036_EXECUTIVA__normalizar-limpeza-test-tmp-e-acl-local.md\n?? central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/orders/gerenciais/0048_GERENCIAL__homologar-politica-acesso-gpt-mcp-como-gate-institucional.md\n?? central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/reports/EXECUTADO__rodada-015-access-policy-mcp-live-2026-05-02.md\n?? central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/reports/PENDENCIAS-CODEX__rodada-015-access-policy-mcp-live-2026-05-02.md\n?? central-de-ordem-de-servico/projects/15_repo_tudo-para-ia-mais-humana-platform/reports/gerenciais/AVALIACAO-GERENCIAL-DA-PLATAFORMA__20260502T0238Z.md\n?? central-de-ordem-de-servico/projects/deploy-plataformas/\n?? central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/reports/CODEX-CORRECAO-INTEGRAL-GIT-GITEA-LOCKS-DISCO-E-SINCRONIZACAO__EVIDENCIA__2026-05-01_163249.json\n?? central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/reports/CODEX-CORRECAO-INTEGRAL-GIT-GITEA-LOCKS-DISCO-E-SINCRONIZACAO__EXECUTADO__2026-05-01_163249.md\n?? central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/reports/CODEX-CORRECAO-INTEGRAL-GIT-GITEA-LOCKS-DISCO-E-SINCRONIZACAO__PENDENCIAS-CODEX__2026-05-01_163249.md\n?? central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/reports/CODEX-INTEGRACOES-CONSOLIDAR-UMA-PASTA-E-MAPEAR-REMOTE__EVIDENCIA__2026-05-01_181729.json\n?? central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/reports/CODEX-INTEGRACOES-CONSOLIDAR-UMA-PASTA-E-MAPEAR-REMOTE__EXECUTADO__2026-05-01_181729.md\n?? central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/reports/CODEX-INTEGRACOES-CONSOLIDAR-UMA-PASTA-E-MAPEAR-REMOTE__PENDENCIAS-CODEX__2026-05-01_181729.md\n?? central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/reports/sincronizacao-espelhos-20260501_235902.json\n?? central-de-ordem-de-servico/projects/sincronizacao-de-repositorios/reports/sincronizacao-espelhos-20260501_235902.md\n?? central-de-ordem-de-servico/reports/sync-audit/\n?? roteador-de-ordens-de-servico/outros/", + "target": { + "expected_remote": "https://git.ami.app.br/admin/nucleo-gestao-operacional.git", + "path": "G:\\_codex-git\\nucleo-gestao-operacional", + "role": "nucleo e central de ordem de servico", + "target_id": "nucleo-central" + } + } + ], + "report_id": "targeted-sync-audit-322089789211", + "status": "diverged", + "summary": [ + "Repositories observed: 3.", + "Fetch attempted: True.", + "Aligned: 0.", + "Blocked or divergent: 3.", + "No reset, restore, rebase, pull, merge, or push was executed by this audit." + ], + "targets": [ + { + "expected_remote": "https://git.ami.app.br/admin/tudo-para-ia-mais-humana.git", + "path": "G:\\_codex-git\\tudo-para-ia-mais-humana", + "role": "projeto real da plataforma 15", + "target_id": "mais-humana" + }, + { + "expected_remote": "https://git.ami.app.br/admin/tudo-para-ia-mcps-internos-plataform.git", + "path": "G:\\_codex-git\\tudo-para-ia-mcps-internos-plataform", + "role": "control-plane MCP que publica as tools Mais Humana", + "target_id": "mcps-internos" + }, + { + "expected_remote": "https://git.ami.app.br/admin/nucleo-gestao-operacional.git", + "path": "G:\\_codex-git\\nucleo-gestao-operacional", + "role": "nucleo e central de ordem de servico", + "target_id": "nucleo-central" + } + ] +} \ No newline at end of file diff --git a/ecossistema/MCP-GATEWAY-ACCESS-POLICY.md b/ecossistema/MCP-GATEWAY-ACCESS-POLICY.md index 6258105..bce7e25 100644 --- a/ecossistema/MCP-GATEWAY-ACCESS-POLICY.md +++ b/ecossistema/MCP-GATEWAY-ACCESS-POLICY.md @@ -1,7 +1,7 @@ # Politica de acesso GPT/MCP Gateway -- report_id: `mcp-gateway-access-policy-15ac101b6174411e` -- generated_at: `2026-05-02T02:38:41+00:00` +- report_id: `mcp-gateway-access-policy-4beabbcbe6c59074` +- generated_at: `2026-05-02T03:09:23+00:00` - policy_version: `mcp-gateway-access-policy.v1` - endpoint: `https://mcps-gateway.ami-app.workers.dev/v1/execute` - status: `passed` diff --git a/ecossistema/MCP-PUBLICATION-GATE-MAIS-HUMANA.md b/ecossistema/MCP-PUBLICATION-GATE-MAIS-HUMANA.md index e15e823..7282661 100644 --- a/ecossistema/MCP-PUBLICATION-GATE-MAIS-HUMANA.md +++ b/ecossistema/MCP-PUBLICATION-GATE-MAIS-HUMANA.md @@ -1,7 +1,7 @@ # Gate de publicacao MCP Mais Humana -- report_id: `mcp-publication-gate-2026-05-02t0238410000` -- generated_at: `2026-05-02T02:38:41+00:00` +- report_id: `mcp-publication-gate-2026-05-02t0308480000` +- generated_at: `2026-05-02T03:08:48+00:00` - provider_id: `mais_humana` - current_project_id: `tudo-para-ia-mais-humana` - canonical_project_id: `tudo-para-ia-mais-humana-platform` @@ -31,13 +31,14 @@ ## Wrangler -- attempted: `False` +- attempted: `True` - version: `nao_confirmada` - authenticated: `False` - account_name: `nao_confirmada` - account_id: `nao_confirmada` - deploy_dry_run_ok: `False` - blockers: + - `runner_node_esbuild_spawn_eperm` - `wrangler_auth_not_confirmed` ## Probes live @@ -87,7 +88,7 @@ ### 0033_EXECUTIVA__sincronizar-git-mais-humana-mcps-central-com-credenciais - status: `blocked` -- motivo: fetch/push bloqueado por SEC_E_NO_CREDENTIALS; fetch remoto falhou no ciclo seguro da rodada +- motivo: sync report 20260501_235902: fetch/probe remote failed with SEC_E_NO_CREDENTIALS on Windows and FETCH_HEAD Permission denied in codex_vm; destructive sync blocked. - evidencias: `git_sync_status` - proxima_acao: corrigir credencial Git/Schannel e reconciliar ahead/behind sem reset destrutivo @@ -128,7 +129,7 @@ ### 0046_GERENCIAL__homologar-runner-oficial-wrangler-node-esbuild -- status: `not_run` +- status: `blocked` - motivo: Wrangler autenticou quando executado diretamente, mas deploy dry-run nao ficou confirmado - evidencias: `wrangler_runner` - proxima_acao: homologar host que permita Node, esbuild/workerd e node --test sem spawn EPERM @@ -142,6 +143,7 @@ ## Blockers +- `runner_node_esbuild_spawn_eperm` - `wrangler_auth_not_confirmed` - `canonical_name_requires_institutional_decision` - `git_sync_blocked` diff --git a/ecossistema/TARGETED-SYNC-AUDIT.md b/ecossistema/TARGETED-SYNC-AUDIT.md new file mode 100644 index 0000000..28f0267 --- /dev/null +++ b/ecossistema/TARGETED-SYNC-AUDIT.md @@ -0,0 +1,82 @@ +# Targeted Git Sync Audit + +- report_id: `targeted-sync-audit-322089789211` +- generated_at: `2026-05-02T03:09:48+00:00` +- status: `diverged` +- fetch: `True` + +## Summary + +- Repositories observed: 3. +- Fetch attempted: True. +- Aligned: 0. +- Blocked or divergent: 3. +- No reset, restore, rebase, pull, merge, or push was executed by this audit. + +## Repositories + +### mais-humana + +- role: projeto real da plataforma 15 +- path: `G:\_codex-git\tudo-para-ia-mais-humana` +- exists: `True` +- git: `True` +- branch: `main` +- head: `6e230bb97983` +- ahead: `0` +- behind: `0` +- dirty: `True` +- origin: `https://git.ami.app.br/admin/tudo-para-ia-mais-humana.git` +- expected_origin: `https://git.ami.app.br/admin/tudo-para-ia-mais-humana.git` +- status: `acl_blocked` +- decision: corrigir ACL/locks de .git antes de qualquer merge/push +- fetch_exit: `255` +- fetch_output: `error: cannot open '.git/FETCH_HEAD': Permission denied` +- blockers: + - `git_acl_or_lock_blocked` + +### mcps-internos + +- role: control-plane MCP que publica as tools Mais Humana +- path: `G:\_codex-git\tudo-para-ia-mcps-internos-plataform` +- exists: `True` +- git: `True` +- branch: `main` +- head: `02a0d7b16f52` +- ahead: `0` +- behind: `0` +- dirty: `True` +- origin: `https://git.ami.app.br/admin/tudo-para-ia-mcps-internos-plataform.git` +- expected_origin: `https://git.ami.app.br/admin/tudo-para-ia-mcps-internos-plataform.git` +- status: `acl_blocked` +- decision: corrigir ACL/locks de .git antes de qualquer merge/push +- fetch_exit: `255` +- fetch_output: `error: cannot open '.git/FETCH_HEAD': Permission denied` +- blockers: + - `git_acl_or_lock_blocked` + +### nucleo-central + +- role: nucleo e central de ordem de servico +- path: `G:\_codex-git\nucleo-gestao-operacional` +- exists: `True` +- git: `True` +- branch: `main` +- head: `e9b83aff598b` +- ahead: `5` +- behind: `5` +- dirty: `True` +- origin: `https://git.ami.app.br/admin/nucleo-gestao-operacional.git` +- expected_origin: `https://git.ami.app.br/admin/nucleo-gestao-operacional.git` +- status: `acl_blocked` +- decision: corrigir ACL/locks de .git antes de qualquer merge/push +- fetch_exit: `255` +- fetch_output: `error: cannot open '.git/FETCH_HEAD': Permission denied` +- blockers: + - `git_acl_or_lock_blocked` + +## Blockers + +- `mais-humana:git_acl_or_lock_blocked` +- `mcps-internos:git_acl_or_lock_blocked` +- `nucleo-central:git_acl_or_lock_blocked` diff --git a/matrizes/mcp-publication-gate-decisions.csv b/matrizes/mcp-publication-gate-decisions.csv index ace566f..6dd26dd 100644 --- a/matrizes/mcp-publication-gate-decisions.csv +++ b/matrizes/mcp-publication-gate-decisions.csv @@ -1,11 +1,11 @@ order_id,status,reason,next_action,evidence_refs 0031_EXECUTIVA__publicar-provider-mais-humana-no-mcps-gateway-via-wrangler-homologado,partial,codigo local do provider existe; publicacao live depende de runner Wrangler sem spawn EPERM,homologar runner Node/esbuild/workerd e repetir wrangler deploy --dry-run antes do deploy real,6032d87c13f58ddb8ba217955c95baf1841bd1b8b8a98a090282bc562cafb6ff; wrangler_runner 0032_EXECUTIVA__validar-live-tools-mais-humana-v1-execute-com-evidencia,passed,endpoint live foi sondado sem persistir bearer bruto,retestar as tres tools apos deploy do mcps-gateway contendo o provider Mais Humana,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0 -0033_EXECUTIVA__sincronizar-git-mais-humana-mcps-central-com-credenciais,blocked,fetch/push bloqueado por SEC_E_NO_CREDENTIALS; fetch remoto falhou no ciclo seguro da rodada,corrigir credencial Git/Schannel e reconciliar ahead/behind sem reset destrutivo,git_sync_status +0033_EXECUTIVA__sincronizar-git-mais-humana-mcps-central-com-credenciais,blocked,sync report 20260501_235902: fetch/probe remote failed with SEC_E_NO_CREDENTIALS on Windows and FETCH_HEAD Permission denied in codex_vm; destructive sync blocked.,corrigir credencial Git/Schannel e reconciliar ahead/behind sem reset destrutivo,git_sync_status 0034_EXECUTIVA__corrigir-acl-escrita-central-e-sql-semantico-plataforma-15,partial,artefatos centrais foram testados pelo gerador de gate; falhas ficam registradas no projeto real,manter escrita automatica central e SQL semantico sob teste em toda rodada,central_write_status 0035_EXECUTIVA__reconciliar-nome-canonico-real-alias-platform,blocked,politica de alias foi materializada sem renome destrutivo,"aguardar decisao institucional antes de renomear remote, pasta central, ownerPlatformId ou referencias historicas",alias_policy 0043_GERENCIAL__aprovar-janela-publicacao-provider-mais-humana-com-rollback,partial,"janela pode ser planejada, mas deploy real ainda depende do runner homologado","definir owner, janela, version atual, rollback e criterio de sucesso antes de deploy real",wrangler_runner; 6032d87c13f58ddb8ba217955c95baf1841bd1b8b8a98a090282bc562cafb6ff 0044_GERENCIAL__institucionalizar-ledger-transito-mcp-como-gate-release,passed,ledger MCP existe como contrato local e deve ser criterio de release,aplicar requiredFields em toda publicacao interplataforma,mcp_transit_ledger; 6032d87c13f58ddb8ba217955c95baf1841bd1b8b8a98a090282bc562cafb6ff 0045_GERENCIAL__pactuar-politica-acesso-waf-gpt-mcp-gateway,partial,"probes usam User-Agent controlado, bearer redigido e response excerpt seguro","formalizar headers minimos, WAF, rate limit, logs e retencao de evidencias",evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0 -0046_GERENCIAL__homologar-runner-oficial-wrangler-node-esbuild,not_run,"Wrangler autenticou quando executado diretamente, mas deploy dry-run nao ficou confirmado","homologar host que permita Node, esbuild/workerd e node --test sem spawn EPERM",wrangler_runner +0046_GERENCIAL__homologar-runner-oficial-wrangler-node-esbuild,blocked,"Wrangler autenticou quando executado diretamente, mas deploy dry-run nao ficou confirmado","homologar host que permita Node, esbuild/workerd e node --test sem spawn EPERM",wrangler_runner 0047_GERENCIAL__decidir-nome-canonico-e-politica-alias-mais-humana,blocked,"nome atual, nome canonico recomendado e aliases estao documentados",registrar decisao formal: preservar alias ou executar migracao coordenada,alias_policy diff --git a/matrizes/targeted-sync-audit.csv b/matrizes/targeted-sync-audit.csv new file mode 100644 index 0000000..dfe7b59 --- /dev/null +++ b/matrizes/targeted-sync-audit.csv @@ -0,0 +1,4 @@ +target_id,path,branch,head,ahead,behind,dirty,status,origin,fetch_exit,decision,blockers +mais-humana,G:\_codex-git\tudo-para-ia-mais-humana,main,6e230bb97983,0,0,yes,acl_blocked,https://git.ami.app.br/admin/tudo-para-ia-mais-humana.git,255,corrigir ACL/locks de .git antes de qualquer merge/push,git_acl_or_lock_blocked +mcps-internos,G:\_codex-git\tudo-para-ia-mcps-internos-plataform,main,02a0d7b16f52,0,0,yes,acl_blocked,https://git.ami.app.br/admin/tudo-para-ia-mcps-internos-plataform.git,255,corrigir ACL/locks de .git antes de qualquer merge/push,git_acl_or_lock_blocked +nucleo-central,G:\_codex-git\nucleo-gestao-operacional,main,e9b83aff598b,5,5,yes,acl_blocked,https://git.ami.app.br/admin/nucleo-gestao-operacional.git,255,corrigir ACL/locks de .git antes de qualquer merge/push,git_acl_or_lock_blocked diff --git a/src/mais_humana/cli.py b/src/mais_humana/cli.py index c0c2899..e6182d3 100644 --- a/src/mais_humana/cli.py +++ b/src/mais_humana/cli.py @@ -36,6 +36,8 @@ from .repository_mesh_readiness import build_mesh_readiness_report, write_readin from .repository_mesh_gitea import build_gitea_mesh_plan, write_gitea_plan_artifacts from .scanner import environment_summary, scan_ecosystem from .storage import table_counts +from .targeted_sync_audit import run_targeted_sync_audit +from .workspace_hygiene import run_workspace_hygiene def build_parser() -> argparse.ArgumentParser: @@ -101,6 +103,16 @@ def build_parser() -> argparse.ArgumentParser: access_policy.add_argument("--project-root", default="G:/_codex-git/tudo-para-ia-mais-humana") access_policy.add_argument("--central-platform-folder", default="") access_policy.add_argument("--publication-gate-json", default="") + hygiene = sub.add_parser("workspace-hygiene", help="Inspect or clean approved local artifacts for closeout.") + hygiene.add_argument("--project-root", default="G:/_codex-git/tudo-para-ia-mais-humana") + hygiene.add_argument("--central-platform-folder", default="") + hygiene.add_argument("--apply", action="store_true") + sync_audit = sub.add_parser("targeted-sync-audit", help="Write safe Git synchronization audit for the active round repos.") + sync_audit.add_argument("--project-root", default="G:/_codex-git/tudo-para-ia-mais-humana") + sync_audit.add_argument("--mcp-repo-root", default="G:/_codex-git/tudo-para-ia-mcps-internos-plataform") + sync_audit.add_argument("--central-repo-root", default="G:/_codex-git/nucleo-gestao-operacional") + sync_audit.add_argument("--central-platform-folder", default="") + sync_audit.add_argument("--fetch", action="store_true") return parser @@ -413,6 +425,38 @@ def command_mcp_access_policy(args: argparse.Namespace) -> int: return 0 +def command_workspace_hygiene(args: argparse.Namespace) -> int: + central_platform_folder = Path(args.central_platform_folder) if args.central_platform_folder else None + report, records = run_workspace_hygiene( + project_root=Path(args.project_root), + central_platform_folder=central_platform_folder, + apply=bool(args.apply), + ) + payload = { + "report": report.to_dict(), + "generatedFiles": [record.path for record in records], + } + print(json.dumps(payload, ensure_ascii=False, indent=2)) + return 0 + + +def command_targeted_sync_audit(args: argparse.Namespace) -> int: + central_platform_folder = Path(args.central_platform_folder) if args.central_platform_folder else None + report, records = run_targeted_sync_audit( + project_root=Path(args.project_root), + mcp_repo_root=Path(args.mcp_repo_root), + central_repo_root=Path(args.central_repo_root), + central_platform_folder=central_platform_folder, + fetch=bool(args.fetch), + ) + payload = { + "report": report.to_dict(), + "generatedFiles": [record.path for record in records], + } + print(json.dumps(payload, ensure_ascii=False, indent=2)) + return 0 + + def main(argv: list[str] | None = None) -> int: parser = build_parser() args = parser.parse_args(argv) @@ -446,6 +490,10 @@ def main(argv: list[str] | None = None) -> int: return command_mcp_publication_gate(args) if args.command == "mcp-access-policy": return command_mcp_access_policy(args) + if args.command == "workspace-hygiene": + return command_workspace_hygiene(args) + if args.command == "targeted-sync-audit": + return command_targeted_sync_audit(args) parser.error(f"unknown command: {args.command}") return 2 diff --git a/src/mais_humana/targeted_sync_audit.py b/src/mais_humana/targeted_sync_audit.py new file mode 100644 index 0000000..e79f84c --- /dev/null +++ b/src/mais_humana/targeted_sync_audit.py @@ -0,0 +1,529 @@ +"""Targeted Git synchronization audit for the Mais Humana round. + +This module implements the safe portion of the manual repository sync +procedure for the specific repositories involved in the platform 15 work: +Mais Humana, MCPs Internos, and the operational nucleus/central. It never +resets, restores, rebases, pulls, merges, or pushes. It records status, +branch, origin, HEAD, ahead/behind, optional fetch errors, and a clear decision +about whether automatic synchronization is blocked. +""" + +from __future__ import annotations + +import csv +import io +import json +import os +import subprocess +from dataclasses import dataclass +from enum import Enum +from pathlib import Path +from typing import Any, Protocol, Sequence + +from .models import GeneratedFile, as_plain_data, merge_unique, utc_now +from .redaction import redact_sensitive_text + + +class SyncAuditStatus(str, Enum): + """Final status for one repo observation or the whole report.""" + + ALIGNED = "aligned" + AHEAD = "ahead" + BEHIND = "behind" + DIVERGED = "diverged" + DIRTY = "dirty" + CREDENTIAL_BLOCKED = "credential_blocked" + ACL_BLOCKED = "acl_blocked" + MISSING = "missing" + NOT_GIT = "not_git" + UNKNOWN = "unknown" + + +@dataclass(frozen=True, slots=True) +class GitCommandResult: + """Output from one git command.""" + + command: tuple[str, ...] + exit_code: int + output: str + + @property + def ok(self) -> bool: + return self.exit_code == 0 + + def to_dict(self) -> dict[str, Any]: + return as_plain_data(self) + + +@dataclass(frozen=True, slots=True) +class SyncAuditTarget: + """Repository that must be checked in this round.""" + + target_id: str + path: str + expected_remote: str + role: str + + def to_dict(self) -> dict[str, Any]: + return as_plain_data(self) + + +@dataclass(frozen=True, slots=True) +class RepoSyncObservation: + """Safe synchronization observation for one repository.""" + + target: SyncAuditTarget + exists: bool + is_git: bool + branch: str + head: str + short_head: str + origin: str + status_short: str + dirty: bool + ahead: int | None + behind: int | None + fetch_attempted: bool + fetch_exit: int | None + fetch_output: str + status: SyncAuditStatus + blockers: tuple[str, ...] + decision: str + + @property + def clean_for_auto_sync(self) -> bool: + return self.status in {SyncAuditStatus.ALIGNED, SyncAuditStatus.AHEAD, SyncAuditStatus.BEHIND} and not self.dirty + + def to_dict(self) -> dict[str, Any]: + return as_plain_data(self) + + +@dataclass(frozen=True, slots=True) +class TargetedSyncAuditReport: + """Full targeted sync audit report.""" + + report_id: str + generated_at: str + fetch: bool + targets: tuple[SyncAuditTarget, ...] + observations: tuple[RepoSyncObservation, ...] + summary: tuple[str, ...] + blockers: tuple[str, ...] + + @property + def status(self) -> SyncAuditStatus: + if any(item.status in {SyncAuditStatus.CREDENTIAL_BLOCKED, SyncAuditStatus.ACL_BLOCKED, SyncAuditStatus.DIVERGED} for item in self.observations): + return SyncAuditStatus.DIVERGED + if any(item.status == SyncAuditStatus.DIRTY for item in self.observations): + return SyncAuditStatus.DIRTY + if any(item.status in {SyncAuditStatus.MISSING, SyncAuditStatus.NOT_GIT, SyncAuditStatus.UNKNOWN} for item in self.observations): + return SyncAuditStatus.UNKNOWN + if all(item.status == SyncAuditStatus.ALIGNED for item in self.observations): + return SyncAuditStatus.ALIGNED + return SyncAuditStatus.UNKNOWN + + def to_dict(self) -> dict[str, Any]: + data = as_plain_data(self) + data["status"] = self.status.value + return data + + +class GitRunner(Protocol): + """Small protocol for testable git execution.""" + + def run(self, repo_path: Path, args: Sequence[str]) -> GitCommandResult: + """Run git args in repo_path.""" + + +class SubprocessGitRunner: + """Git runner using subprocess without shell interpolation.""" + + def run(self, repo_path: Path, args: Sequence[str]) -> GitCommandResult: + safe = repo_path.resolve(strict=False).as_posix() + command = ("git", "-c", f"safe.directory={safe}", "-C", str(repo_path), *args) + env = os.environ.copy() + env["GIT_TERMINAL_PROMPT"] = "0" + env["GIT_CEILING_DIRECTORIES"] = str(repo_path.resolve(strict=False).parent) + try: + completed = subprocess.run(command, cwd=str(repo_path), env=env, text=True, capture_output=True, timeout=120, check=False) + output = "\n".join(part for part in (completed.stdout, completed.stderr) if part).strip() + return GitCommandResult(tuple(args), int(completed.returncode), redact_sensitive_text(output)) + except (OSError, subprocess.TimeoutExpired) as exc: + return GitCommandResult(tuple(args), 1, redact_sensitive_text(f"{type(exc).__name__}: {exc}")) + + +def default_sync_targets( + *, + project_root: Path, + mcp_repo_root: Path, + central_repo_root: Path, +) -> tuple[SyncAuditTarget, ...]: + """Return the three repositories that matter for platform 15 closeout.""" + + return ( + SyncAuditTarget( + target_id="mais-humana", + path=str(project_root), + expected_remote="https://git.ami.app.br/admin/tudo-para-ia-mais-humana.git", + role="projeto real da plataforma 15", + ), + SyncAuditTarget( + target_id="mcps-internos", + path=str(mcp_repo_root), + expected_remote="https://git.ami.app.br/admin/tudo-para-ia-mcps-internos-plataform.git", + role="control-plane MCP que publica as tools Mais Humana", + ), + SyncAuditTarget( + target_id="nucleo-central", + path=str(central_repo_root), + expected_remote="https://git.ami.app.br/admin/nucleo-gestao-operacional.git", + role="nucleo e central de ordem de servico", + ), + ) + + +def _first_line(value: str) -> str: + return (value or "").splitlines()[0].strip() if value else "" + + +def _short(head: str) -> str: + cleaned = head.strip() + return cleaned[:12] if len(cleaned) >= 12 else cleaned + + +def _parse_ahead_behind(output: str) -> tuple[int | None, int | None]: + parts = [part for part in output.replace("\t", " ").split(" ") if part.strip()] + if len(parts) != 2: + return None, None + try: + behind = int(parts[0]) + ahead = int(parts[1]) + return ahead, behind + except ValueError: + return None, None + + +def classify_observation( + *, + exists: bool, + is_git: bool, + dirty: bool, + ahead: int | None, + behind: int | None, + fetch_output: str, + command_outputs: Sequence[str], +) -> tuple[SyncAuditStatus, tuple[str, ...], str]: + """Classify a repository without suggesting destructive reconciliation.""" + + combined = "\n".join([fetch_output, *command_outputs]) + lower = combined.lower() + if not exists: + return SyncAuditStatus.MISSING, ("path_missing",), "materializar repositorio ausente antes de sincronizar" + if not is_git: + return SyncAuditStatus.NOT_GIT, ("not_a_git_repository",), "confirmar caminho real do repositorio" + if "sec_e_no_credentials" in lower or "could not read username" in lower or "authentication" in lower: + return SyncAuditStatus.CREDENTIAL_BLOCKED, ("git_credentials_unavailable",), "corrigir credencial Git/Schannel e repetir fetch/push seguro" + if "permission denied" in lower or "fetch_head" in lower or "index.lock" in lower: + return SyncAuditStatus.ACL_BLOCKED, ("git_acl_or_lock_blocked",), "corrigir ACL/locks de .git antes de qualquer merge/push" + if dirty: + if behind and behind > 0: + return SyncAuditStatus.DIVERGED, ("dirty_worktree_remote_ahead",), "bloquear pull automatico para preservar alteracao valida mais recente" + return SyncAuditStatus.DIRTY, ("dirty_worktree",), "commit escopado ou revisar alteracoes antes da sincronizacao" + if ahead is None or behind is None: + return SyncAuditStatus.UNKNOWN, ("ahead_behind_unknown",), "repetir rev-list apos fetch funcional" + if ahead > 0 and behind > 0: + return SyncAuditStatus.DIVERGED, (f"ahead={ahead} behind={behind}",), "reconciliacao manual obrigatoria sem reset/rebase destrutivo" + if ahead > 0: + return SyncAuditStatus.AHEAD, (f"ahead={ahead}",), "push seguro apos credencial valida e verificacao de lease" + if behind > 0: + return SyncAuditStatus.BEHIND, (f"behind={behind}",), "merge --ff-only permitido apenas com worktree limpa e decisao de precedencia" + return SyncAuditStatus.ALIGNED, (), "nenhuma acao de sincronizacao necessaria no estado observado" + + +def observe_repo(target: SyncAuditTarget, *, runner: GitRunner | None = None, fetch: bool = False) -> RepoSyncObservation: + """Collect safe Git facts for one repository.""" + + git = runner or SubprocessGitRunner() + path = Path(target.path) + exists = path.exists() + is_git = exists and (path / ".git").exists() + fetch_result = GitCommandResult(("fetch", "--all", "--prune"), 127, "not_run") + branch = "" + head = "" + origin = "" + status_short = "" + dirty = False + ahead: int | None = None + behind: int | None = None + command_outputs: list[str] = [] + if is_git: + if fetch: + fetch_result = git.run(path, ("fetch", "--all", "--prune")) + branch_result = git.run(path, ("branch", "--show-current")) + head_result = git.run(path, ("rev-parse", "HEAD")) + origin_result = git.run(path, ("remote", "get-url", "origin")) + status_result = git.run(path, ("status", "--short", "--branch")) + porcelain_result = git.run(path, ("status", "--porcelain", "--untracked-files=all")) + branch = _first_line(branch_result.output) + head = _first_line(head_result.output) + origin = _first_line(origin_result.output) + status_short = status_result.output.strip() + dirty = bool(porcelain_result.output.strip()) + command_outputs.extend([branch_result.output, head_result.output, origin_result.output, status_result.output, porcelain_result.output]) + if any("not a git repository" in result.output.lower() for result in (branch_result, head_result, status_result)): + is_git = False + dirty = False + if branch: + counts_result = git.run(path, ("rev-list", "--left-right", "--count", f"origin/{branch}...{branch}")) + ahead, behind = _parse_ahead_behind(counts_result.output) + command_outputs.append(counts_result.output) + status, blockers, decision = classify_observation( + exists=exists, + is_git=is_git, + dirty=dirty, + ahead=ahead, + behind=behind, + fetch_output=fetch_result.output if fetch else "", + command_outputs=command_outputs, + ) + return RepoSyncObservation( + target=target, + exists=exists, + is_git=is_git, + branch=branch, + head=head, + short_head=_short(head), + origin=origin, + status_short=status_short, + dirty=dirty, + ahead=ahead, + behind=behind, + fetch_attempted=fetch, + fetch_exit=fetch_result.exit_code if fetch else None, + fetch_output=redact_sensitive_text(fetch_result.output if fetch else ""), + status=status, + blockers=blockers, + decision=decision, + ) + + +def build_targeted_sync_audit( + *, + targets: Sequence[SyncAuditTarget], + runner: GitRunner | None = None, + fetch: bool = False, +) -> TargetedSyncAuditReport: + """Build the targeted sync audit report.""" + + observations = tuple(observe_repo(target, runner=runner, fetch=fetch) for target in targets) + blockers = merge_unique( + f"{item.target.target_id}:{blocker}" + for item in observations + for blocker in item.blockers + ) + summary = ( + f"Repositories observed: {len(observations)}.", + f"Fetch attempted: {fetch}.", + f"Aligned: {sum(1 for item in observations if item.status == SyncAuditStatus.ALIGNED)}.", + f"Blocked or divergent: {sum(1 for item in observations if item.blockers)}.", + "No reset, restore, rebase, pull, merge, or push was executed by this audit.", + ) + report_id = "targeted-sync-audit-" + str(abs(hash(json.dumps([item.to_dict() for item in observations], sort_keys=True))))[:12] + return TargetedSyncAuditReport( + report_id=report_id, + generated_at=utc_now(), + fetch=fetch, + targets=tuple(targets), + observations=observations, + summary=summary, + blockers=blockers, + ) + + +def sync_audit_csv(report: TargetedSyncAuditReport) -> str: + """Render observations as CSV.""" + + rows = [["target_id", "path", "branch", "head", "ahead", "behind", "dirty", "status", "origin", "fetch_exit", "decision", "blockers"]] + for item in report.observations: + rows.append( + [ + item.target.target_id, + item.target.path, + item.branch, + item.short_head, + "" if item.ahead is None else str(item.ahead), + "" if item.behind is None else str(item.behind), + "yes" if item.dirty else "no", + item.status.value, + item.origin, + "" if item.fetch_exit is None else str(item.fetch_exit), + item.decision, + "; ".join(item.blockers), + ] + ) + buffer = io.StringIO() + writer = csv.writer(buffer, lineterminator="\n") + writer.writerows(rows) + return buffer.getvalue() + + +def sync_audit_markdown(report: TargetedSyncAuditReport) -> str: + """Render the targeted sync audit as Markdown.""" + + lines = [ + "# Targeted Git Sync Audit", + "", + f"- report_id: `{report.report_id}`", + f"- generated_at: `{report.generated_at}`", + f"- status: `{report.status.value}`", + f"- fetch: `{report.fetch}`", + "", + "## Summary", + "", + ] + lines.extend(f"- {item}" for item in report.summary) + lines.extend(["", "## Repositories", ""]) + for item in report.observations: + lines.extend( + [ + f"### {item.target.target_id}", + "", + f"- role: {item.target.role}", + f"- path: `{item.target.path}`", + f"- exists: `{item.exists}`", + f"- git: `{item.is_git}`", + f"- branch: `{item.branch}`", + f"- head: `{item.short_head}`", + f"- ahead: `{item.ahead}`", + f"- behind: `{item.behind}`", + f"- dirty: `{item.dirty}`", + f"- origin: `{item.origin}`", + f"- expected_origin: `{item.target.expected_remote}`", + f"- status: `{item.status.value}`", + f"- decision: {item.decision}", + ] + ) + if item.fetch_attempted: + lines.append(f"- fetch_exit: `{item.fetch_exit}`") + if item.fetch_output: + lines.append(f"- fetch_output: `{item.fetch_output[:500]}`") + if item.blockers: + lines.append("- blockers:") + lines.extend(f" - `{blocker}`" for blocker in item.blockers) + lines.append("") + lines.extend(["## Blockers", ""]) + if report.blockers: + lines.extend(f"- `{item}`" for item in report.blockers) + else: + lines.append("- Nenhum blocker de sincronizacao no escopo auditado.") + return "\n".join(lines).strip() + "\n" + + +def sync_audit_artifact_records(project_root: Path, central_platform_folder: Path | None = None) -> tuple[GeneratedFile, ...]: + """Return semantic records for sync audit artifacts.""" + + records = [ + GeneratedFile( + path=str(project_root / "dados" / "targeted-sync-audit.json"), + description="Auditoria Git segura dos repositorios da rodada Mais Humana.", + function="targeted git sync audit", + file_type="json", + changed_by="mais_humana.targeted_sync_audit", + change_summary="Registrado status Git, fetch, ahead/behind, bloqueios de credencial/ACL e decisao segura.", + relation_to_order="0033_EXECUTIVA__sincronizar-git-mais-humana-mcps-central-com-credenciais", + ), + GeneratedFile( + path=str(project_root / "matrizes" / "targeted-sync-audit.csv"), + description="Matriz de sincronizacao Git escopada.", + function="targeted git sync matrix", + file_type="csv", + changed_by="mais_humana.targeted_sync_audit", + change_summary="Criada matriz de repos, hashes, divergencias e bloqueios.", + relation_to_order="0033_EXECUTIVA__sincronizar-git-mais-humana-mcps-central-com-credenciais", + ), + GeneratedFile( + path=str(project_root / "ecossistema" / "TARGETED-SYNC-AUDIT.md"), + description="Relatorio humano da sincronizacao Git escopada.", + function="targeted git sync report", + file_type="markdown", + changed_by="mais_humana.targeted_sync_audit", + change_summary="Criado relatorio de sincronizacao sem operacao destrutiva.", + relation_to_order="0033_EXECUTIVA__sincronizar-git-mais-humana-mcps-central-com-credenciais", + ), + ] + if central_platform_folder is not None: + records.append( + GeneratedFile( + path=str(central_platform_folder / "reports" / "EXECUTADO__targeted-sync-audit.md"), + description="Copia central da auditoria Git escopada.", + function="targeted git sync central report", + file_type="markdown", + changed_by="mais_humana.targeted_sync_audit", + change_summary="Registrado estado Git da rodada na pasta central.", + relation_to_order="0033_EXECUTIVA__sincronizar-git-mais-humana-mcps-central-com-credenciais", + ) + ) + return tuple(records) + + +def write_sync_audit_artifacts( + report: TargetedSyncAuditReport, + project_root: Path, + *, + central_platform_folder: Path | None = None, +) -> tuple[GeneratedFile, ...]: + """Write project and optional central sync audit artifacts.""" + + targets: list[tuple[Path, str]] = [ + (project_root / "dados" / "targeted-sync-audit.json", json.dumps(report.to_dict(), ensure_ascii=False, indent=2, sort_keys=True)), + (project_root / "matrizes" / "targeted-sync-audit.csv", sync_audit_csv(report)), + (project_root / "ecossistema" / "TARGETED-SYNC-AUDIT.md", sync_audit_markdown(report)), + ] + records = list(sync_audit_artifact_records(project_root, central_platform_folder)) + central_failures: list[dict[str, str]] = [] + if central_platform_folder is not None: + targets.append((central_platform_folder / "reports" / "EXECUTADO__targeted-sync-audit.md", sync_audit_markdown(report))) + for path, content in targets: + try: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + except OSError as exc: + if central_platform_folder is not None and central_platform_folder in path.parents: + central_failures.append({"path": str(path), "error": f"{type(exc).__name__}: {exc}"}) + continue + raise + if central_failures: + status_path = project_root / "dados" / "targeted-sync-audit-central-write-status.json" + status_path.write_text( + json.dumps({"generatedAt": utc_now(), "ok": False, "failures": central_failures}, ensure_ascii=False, indent=2, sort_keys=True), + encoding="utf-8", + ) + records.append( + GeneratedFile( + path=str(status_path), + description="Status de escrita central da auditoria Git escopada.", + function="targeted git sync central write status", + file_type="json", + changed_by="mais_humana.targeted_sync_audit", + change_summary="Registrada falha de escrita central sem abortar artefatos do projeto real.", + relation_to_order="0034_EXECUTIVA__corrigir-acl-escrita-central-e-sql-semantico-plataforma-15", + ) + ) + return tuple(records) + + +def run_targeted_sync_audit( + *, + project_root: Path, + mcp_repo_root: Path, + central_repo_root: Path, + central_platform_folder: Path | None = None, + fetch: bool = False, + runner: GitRunner | None = None, +) -> tuple[TargetedSyncAuditReport, tuple[GeneratedFile, ...]]: + """Run the safe targeted sync audit and write artifacts.""" + + targets = default_sync_targets(project_root=project_root, mcp_repo_root=mcp_repo_root, central_repo_root=central_repo_root) + report = build_targeted_sync_audit(targets=targets, runner=runner, fetch=fetch) + records = write_sync_audit_artifacts(report, project_root, central_platform_folder=central_platform_folder) + return report, records diff --git a/src/mais_humana/workspace_hygiene.py b/src/mais_humana/workspace_hygiene.py new file mode 100644 index 0000000..ba09a99 --- /dev/null +++ b/src/mais_humana/workspace_hygiene.py @@ -0,0 +1,535 @@ +"""Local workspace hygiene checks for service-order closeout. + +The Mais Humana rounds generate Python test scratch folders and may touch +JavaScript/Cloudflare workspaces while validating MCP publication. This module +turns cleanup into an auditable operation instead of an informal shell step: +it verifies target paths, deletes only approved local artifacts when requested, +and writes redacted project/central reports that explain any ACL retention. +""" + +from __future__ import annotations + +import csv +import io +import json +import os +import shutil +from dataclasses import dataclass +from enum import Enum +from pathlib import Path +from typing import Any, Sequence + +from .models import GeneratedFile, as_plain_data, merge_unique, utc_now + + +DEFAULT_LOCAL_ARTIFACTS = ( + ".test-tmp", + "node_modules", +) + + +class HygieneStatus(str, Enum): + """Result for a cleanup target or whole report.""" + + PASSED = "passed" + PARTIAL = "partial" + BLOCKED = "blocked" + NOT_FOUND = "not_found" + NOT_RUN = "not_run" + + +class HygieneActionKind(str, Enum): + """Action planned or executed for one local artifact.""" + + DELETE_DIRECTORY = "delete_directory" + DELETE_FILE = "delete_file" + VERIFY_ABSENT = "verify_absent" + BLOCK_UNSAFE_PATH = "block_unsafe_path" + + +@dataclass(frozen=True, slots=True) +class HygieneTarget: + """Approved local cleanup target.""" + + target_id: str + relative_path: str + reason: str + required_absent: bool = True + delete_when_apply: bool = True + + def to_dict(self) -> dict[str, Any]: + return as_plain_data(self) + + +@dataclass(frozen=True, slots=True) +class PathFootprint: + """Best-effort path size and child count.""" + + exists: bool + is_dir: bool + is_file: bool + child_count: int + byte_count: int + errors: tuple[str, ...] + + def to_dict(self) -> dict[str, Any]: + return as_plain_data(self) + + +@dataclass(frozen=True, slots=True) +class HygieneAction: + """Observed cleanup action for one target.""" + + target_id: str + path: str + action: HygieneActionKind + status: HygieneStatus + applied: bool + deleted: bool + footprint_before: PathFootprint + footprint_after: PathFootprint + error: str = "" + note: str = "" + + @property + def clean(self) -> bool: + return self.status in {HygieneStatus.PASSED, HygieneStatus.NOT_FOUND} and not self.footprint_after.exists + + def to_dict(self) -> dict[str, Any]: + return as_plain_data(self) + + +@dataclass(frozen=True, slots=True) +class WorkspaceHygieneReport: + """Full hygiene report for a platform workspace.""" + + report_id: str + generated_at: str + project_root: str + central_platform_folder: str + apply: bool + targets: tuple[HygieneTarget, ...] + actions: tuple[HygieneAction, ...] + summary: tuple[str, ...] + blockers: tuple[str, ...] + + @property + def status(self) -> HygieneStatus: + if any(action.status == HygieneStatus.BLOCKED for action in self.actions): + return HygieneStatus.BLOCKED + if any(action.status in {HygieneStatus.PARTIAL, HygieneStatus.NOT_RUN} for action in self.actions): + return HygieneStatus.PARTIAL + return HygieneStatus.PASSED + + @property + def clean(self) -> bool: + return all(action.clean for action in self.actions) + + def to_dict(self) -> dict[str, Any]: + data = as_plain_data(self) + data["status"] = self.status.value + data["clean"] = self.clean + return data + + +def default_hygiene_targets() -> tuple[HygieneTarget, ...]: + """Return local artifact targets allowed for automated cleanup.""" + + return ( + HygieneTarget( + target_id="python-test-temp", + relative_path=".test-tmp", + reason="scratch directory created by Python unit tests; must not survive closeout", + ), + HygieneTarget( + target_id="node-dependencies", + relative_path="node_modules", + reason="local Node dependency directory; must not be versioned or retained after local tests", + ), + ) + + +def _norm(path: Path) -> str: + return os.path.normcase(os.path.abspath(str(path))) + + +def safe_child_path(root: Path, relative_path: str) -> Path: + """Resolve a target and reject paths outside the project root.""" + + if Path(relative_path).is_absolute(): + raise ValueError(f"absolute cleanup target is not allowed: {relative_path}") + root_resolved = root.resolve(strict=False) + target = (root_resolved / relative_path).resolve(strict=False) + try: + common = os.path.commonpath([_norm(root_resolved), _norm(target)]) + except ValueError as exc: + raise ValueError(f"cleanup target crosses drive boundary: {relative_path}") from exc + if common != _norm(root_resolved): + raise ValueError(f"cleanup target escapes project root: {relative_path}") + return target + + +def _footprint(path: Path, *, max_errors: int = 8) -> PathFootprint: + if not path.exists(): + return PathFootprint(False, False, False, 0, 0, ()) + if path.is_file(): + try: + size = path.stat().st_size + return PathFootprint(True, False, True, 1, int(size), ()) + except OSError as exc: + return PathFootprint(True, False, True, 1, 0, (f"{type(exc).__name__}: {exc}",)) + + child_count = 0 + byte_count = 0 + errors: list[str] = [] + for current_root, dirnames, filenames in os.walk(path, topdown=True, onerror=lambda exc: errors.append(f"{type(exc).__name__}: {exc}")): + child_count += len(dirnames) + len(filenames) + for filename in filenames: + try: + byte_count += int((Path(current_root) / filename).stat().st_size) + except OSError as exc: + if len(errors) < max_errors: + errors.append(f"{type(exc).__name__}: {exc}") + if len(errors) >= max_errors: + errors.append("error_limit_reached") + break + return PathFootprint(True, True, False, child_count, byte_count, tuple(errors[:max_errors])) + + +def _delete_path(path: Path) -> tuple[bool, str]: + try: + if not path.exists(): + return False, "" + if path.is_dir(): + shutil.rmtree(path) + return True, "" + path.unlink() + return True, "" + except OSError as exc: + return False, f"{type(exc).__name__}: {exc}" + + +def run_hygiene_actions( + project_root: Path, + *, + apply: bool = False, + targets: Sequence[HygieneTarget] | None = None, +) -> tuple[HygieneAction, ...]: + """Inspect and optionally remove approved local artifacts.""" + + action_rows: list[HygieneAction] = [] + for target in tuple(targets or default_hygiene_targets()): + try: + path = safe_child_path(project_root, target.relative_path) + except ValueError as exc: + empty = PathFootprint(False, False, False, 0, 0, ()) + action_rows.append( + HygieneAction( + target_id=target.target_id, + path=str(project_root / target.relative_path), + action=HygieneActionKind.BLOCK_UNSAFE_PATH, + status=HygieneStatus.BLOCKED, + applied=False, + deleted=False, + footprint_before=empty, + footprint_after=empty, + error=str(exc), + note="unsafe path blocked before filesystem write", + ) + ) + continue + + before = _footprint(path) + if not before.exists: + action_rows.append( + HygieneAction( + target_id=target.target_id, + path=str(path), + action=HygieneActionKind.VERIFY_ABSENT, + status=HygieneStatus.NOT_FOUND, + applied=False, + deleted=False, + footprint_before=before, + footprint_after=before, + note="target already absent", + ) + ) + continue + + kind = HygieneActionKind.DELETE_DIRECTORY if before.is_dir else HygieneActionKind.DELETE_FILE + if not apply or not target.delete_when_apply: + action_rows.append( + HygieneAction( + target_id=target.target_id, + path=str(path), + action=kind, + status=HygieneStatus.NOT_RUN, + applied=False, + deleted=False, + footprint_before=before, + footprint_after=before, + note="dry run; use --apply to remove approved artifact", + ) + ) + continue + + deleted, error = _delete_path(path) + after = _footprint(path) + status = HygieneStatus.PASSED if deleted and not after.exists else HygieneStatus.BLOCKED + note = "removed approved local artifact" if status == HygieneStatus.PASSED else "artifact retained by ACL or filesystem lock" + action_rows.append( + HygieneAction( + target_id=target.target_id, + path=str(path), + action=kind, + status=status, + applied=True, + deleted=deleted, + footprint_before=before, + footprint_after=after, + error=error, + note=note, + ) + ) + return tuple(action_rows) + + +def build_workspace_hygiene_report( + project_root: Path, + *, + central_platform_folder: Path | None = None, + apply: bool = False, + targets: Sequence[HygieneTarget] | None = None, +) -> WorkspaceHygieneReport: + """Build a hygiene report for project closeout.""" + + target_set = tuple(targets or default_hygiene_targets()) + actions = run_hygiene_actions(project_root, apply=apply, targets=target_set) + blockers = merge_unique( + f"{action.target_id}:{action.error or action.note}" + for action in actions + if action.status == HygieneStatus.BLOCKED + ) + removed = sum(1 for action in actions if action.deleted) + already_absent = sum(1 for action in actions if action.status == HygieneStatus.NOT_FOUND) + retained = sum(1 for action in actions if action.footprint_after.exists) + summary = ( + f"Targets evaluated: {len(actions)}.", + f"Apply mode: {apply}.", + f"Removed artifacts: {removed}.", + f"Already absent: {already_absent}.", + f"Artifacts still present: {retained}.", + "Only approved project-local artifacts are eligible for deletion.", + ) + seed = json.dumps( + { + "projectRoot": str(project_root), + "actions": [action.to_dict() for action in actions], + "generatedAt": utc_now(), + }, + ensure_ascii=False, + sort_keys=True, + ) + report_id = "workspace-hygiene-" + str(abs(hash(seed)))[:12] + return WorkspaceHygieneReport( + report_id=report_id, + generated_at=utc_now(), + project_root=str(project_root), + central_platform_folder=str(central_platform_folder or ""), + apply=apply, + targets=target_set, + actions=actions, + summary=summary, + blockers=blockers, + ) + + +def hygiene_csv(report: WorkspaceHygieneReport) -> str: + """Render hygiene target status as CSV.""" + + rows = [["target_id", "path", "action", "status", "applied", "deleted", "exists_after", "children_before", "bytes_before", "error", "note"]] + for action in report.actions: + rows.append( + [ + action.target_id, + action.path, + action.action.value, + action.status.value, + "yes" if action.applied else "no", + "yes" if action.deleted else "no", + "yes" if action.footprint_after.exists else "no", + str(action.footprint_before.child_count), + str(action.footprint_before.byte_count), + action.error, + action.note, + ] + ) + buffer = io.StringIO() + writer = csv.writer(buffer, lineterminator="\n") + writer.writerows(rows) + return buffer.getvalue() + + +def hygiene_markdown(report: WorkspaceHygieneReport) -> str: + """Render human-readable hygiene evidence.""" + + lines = [ + "# Workspace Hygiene Report", + "", + f"- report_id: `{report.report_id}`", + f"- generated_at: `{report.generated_at}`", + f"- project_root: `{report.project_root}`", + f"- central_platform_folder: `{report.central_platform_folder}`", + f"- status: `{report.status.value}`", + f"- clean: `{report.clean}`", + f"- apply: `{report.apply}`", + "", + "## Summary", + "", + ] + lines.extend(f"- {item}" for item in report.summary) + lines.extend(["", "## Targets", ""]) + for action in report.actions: + lines.extend( + [ + f"### {action.target_id}", + "", + f"- path: `{action.path}`", + f"- action: `{action.action.value}`", + f"- status: `{action.status.value}`", + f"- applied: `{action.applied}`", + f"- deleted: `{action.deleted}`", + f"- exists_after: `{action.footprint_after.exists}`", + f"- children_before: `{action.footprint_before.child_count}`", + f"- bytes_before: `{action.footprint_before.byte_count}`", + f"- note: {action.note}", + ] + ) + if action.error: + lines.append(f"- error: `{action.error}`") + if action.footprint_before.errors: + lines.append("- footprint_errors:") + lines.extend(f" - `{item}`" for item in action.footprint_before.errors) + lines.append("") + lines.extend(["## Blockers", ""]) + if report.blockers: + lines.extend(f"- `{item}`" for item in report.blockers) + else: + lines.append("- Nenhum blocker de higiene local.") + return "\n".join(lines).strip() + "\n" + + +def hygiene_artifact_records(project_root: Path, central_platform_folder: Path | None = None) -> tuple[GeneratedFile, ...]: + """Return semantic records for hygiene artifacts.""" + + records = [ + GeneratedFile( + path=str(project_root / "dados" / "workspace-hygiene-report.json"), + description="Relatorio estruturado de limpeza operacional local.", + function="workspace hygiene report", + file_type="json", + changed_by="mais_humana.workspace_hygiene", + change_summary="Registrada limpeza de .test-tmp e node_modules com bloqueios ACL quando houver.", + relation_to_order="0036_EXECUTIVA__normalizar-limpeza-test-tmp-e-acl-local", + ), + GeneratedFile( + path=str(project_root / "matrizes" / "workspace-hygiene-targets.csv"), + description="Matriz de alvos de higiene local e estado final.", + function="workspace hygiene matrix", + file_type="csv", + changed_by="mais_humana.workspace_hygiene", + change_summary="Criada matriz auditavel de artefatos locais removidos, ausentes ou retidos.", + relation_to_order="0036_EXECUTIVA__normalizar-limpeza-test-tmp-e-acl-local", + ), + GeneratedFile( + path=str(project_root / "ecossistema" / "WORKSPACE-HYGIENE-REPORT.md"), + description="Relatorio humano de higiene local da rodada.", + function="workspace hygiene human report", + file_type="markdown", + changed_by="mais_humana.workspace_hygiene", + change_summary="Criado relatorio de fechamento de limpeza operacional.", + relation_to_order="0036_EXECUTIVA__normalizar-limpeza-test-tmp-e-acl-local", + ), + ] + if central_platform_folder is not None: + records.append( + GeneratedFile( + path=str(central_platform_folder / "reports" / "EXECUTADO__workspace-hygiene.md"), + description="Copia central da higiene local da plataforma Mais Humana.", + function="workspace hygiene central report", + file_type="markdown", + changed_by="mais_humana.workspace_hygiene", + change_summary="Registrado estado de .test-tmp e node_modules na pasta central.", + relation_to_order="0036_EXECUTIVA__normalizar-limpeza-test-tmp-e-acl-local", + ) + ) + return tuple(records) + + +def write_hygiene_artifacts( + report: WorkspaceHygieneReport, + project_root: Path, + *, + central_platform_folder: Path | None = None, +) -> tuple[GeneratedFile, ...]: + """Write project and optional central hygiene artifacts.""" + + targets: list[tuple[Path, str]] = [ + (project_root / "dados" / "workspace-hygiene-report.json", json.dumps(report.to_dict(), ensure_ascii=False, indent=2, sort_keys=True)), + (project_root / "matrizes" / "workspace-hygiene-targets.csv", hygiene_csv(report)), + (project_root / "ecossistema" / "WORKSPACE-HYGIENE-REPORT.md", hygiene_markdown(report)), + ] + records = list(hygiene_artifact_records(project_root, central_platform_folder)) + central_failures: list[dict[str, str]] = [] + if central_platform_folder is not None: + targets.append((central_platform_folder / "reports" / "EXECUTADO__workspace-hygiene.md", hygiene_markdown(report))) + for path, content in targets: + try: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + except OSError as exc: + if central_platform_folder is not None and central_platform_folder in path.parents: + central_failures.append({"path": str(path), "error": f"{type(exc).__name__}: {exc}"}) + continue + raise + if central_failures: + status_path = project_root / "dados" / "workspace-hygiene-central-write-status.json" + status_path.write_text( + json.dumps( + { + "generatedAt": utc_now(), + "centralPlatformFolder": str(central_platform_folder), + "ok": False, + "failures": central_failures, + }, + ensure_ascii=False, + indent=2, + sort_keys=True, + ), + encoding="utf-8", + ) + records.append( + GeneratedFile( + path=str(status_path), + description="Status de escrita central do relatorio de higiene local.", + function="workspace hygiene central write status", + file_type="json", + changed_by="mais_humana.workspace_hygiene", + change_summary="Registrada falha de escrita central sem abortar artefatos do projeto real.", + relation_to_order="0034_EXECUTIVA__corrigir-acl-escrita-central-e-sql-semantico-plataforma-15", + ) + ) + return tuple(records) + + +def run_workspace_hygiene( + *, + project_root: Path, + central_platform_folder: Path | None = None, + apply: bool = False, +) -> tuple[WorkspaceHygieneReport, tuple[GeneratedFile, ...]]: + """Execute the hygiene gate and write artifacts.""" + + report = build_workspace_hygiene_report(project_root, central_platform_folder=central_platform_folder, apply=apply) + records = write_hygiene_artifacts(report, project_root, central_platform_folder=central_platform_folder) + return report, records diff --git a/tests/test_targeted_sync_audit.py b/tests/test_targeted_sync_audit.py new file mode 100644 index 0000000..a366e51 --- /dev/null +++ b/tests/test_targeted_sync_audit.py @@ -0,0 +1,156 @@ +from __future__ import annotations + +import json +import unittest +from pathlib import Path +from typing import Sequence + +from mais_humana.cli import main +from mais_humana.targeted_sync_audit import ( + GitCommandResult, + SyncAuditStatus, + SyncAuditTarget, + TargetedSyncAuditReport, + build_targeted_sync_audit, + classify_observation, + observe_repo, + run_targeted_sync_audit, + sync_audit_csv, + sync_audit_markdown, +) +from tests.helpers import make_tmp + + +class FakeGitRunner: + def __init__(self) -> None: + self.results: dict[tuple[str, str], GitCommandResult] = {} + + def set_result(self, repo: Path, args: Sequence[str], output: str, exit_code: int = 0) -> None: + self.results[(str(repo), " ".join(args))] = GitCommandResult(tuple(args), exit_code, output) + + def run(self, repo_path: Path, args: Sequence[str]) -> GitCommandResult: + return self.results.get((str(repo_path), " ".join(args)), GitCommandResult(tuple(args), 0, "")) + + +def make_git_repo(root: Path, name: str) -> Path: + repo = root / name + (repo / ".git").mkdir(parents=True) + return repo + + +def target(path: Path, target_id: str = "repo") -> SyncAuditTarget: + return SyncAuditTarget(target_id, str(path), "https://git.ami.app.br/admin/repo.git", "unit test repo") + + +def configure_clean_runner(runner: FakeGitRunner, repo: Path, *, ahead_behind: str = "0 0") -> None: + runner.set_result(repo, ("branch", "--show-current"), "main\n") + runner.set_result(repo, ("rev-parse", "HEAD"), "a" * 40 + "\n") + runner.set_result(repo, ("remote", "get-url", "origin"), "https://git.ami.app.br/admin/repo.git\n") + runner.set_result(repo, ("status", "--short", "--branch"), "## main...origin/main\n") + runner.set_result(repo, ("status", "--porcelain", "--untracked-files=all"), "") + runner.set_result(repo, ("rev-list", "--left-right", "--count", "origin/main...main"), ahead_behind) + + +class TargetedSyncAuditTests(unittest.TestCase): + def test_classify_missing_and_not_git(self) -> None: + status, blockers, decision = classify_observation( + exists=False, + is_git=False, + dirty=False, + ahead=None, + behind=None, + fetch_output="", + command_outputs=(), + ) + self.assertEqual(status, SyncAuditStatus.MISSING) + self.assertIn("path_missing", blockers) + self.assertIn("materializar", decision) + + def test_observe_clean_repo_aligned(self) -> None: + root = make_tmp() + repo = make_git_repo(root, "repo") + runner = FakeGitRunner() + configure_clean_runner(runner, repo) + observation = observe_repo(target(repo), runner=runner) + self.assertEqual(observation.status, SyncAuditStatus.ALIGNED) + self.assertEqual(observation.branch, "main") + self.assertEqual(observation.short_head, "a" * 12) + self.assertTrue(observation.clean_for_auto_sync) + + def test_fetch_credential_error_blocks_sync(self) -> None: + root = make_tmp() + repo = make_git_repo(root, "repo") + runner = FakeGitRunner() + configure_clean_runner(runner, repo) + runner.set_result(repo, ("fetch", "--all", "--prune"), "fatal: schannel SEC_E_NO_CREDENTIALS", 128) + observation = observe_repo(target(repo), runner=runner, fetch=True) + self.assertEqual(observation.status, SyncAuditStatus.CREDENTIAL_BLOCKED) + self.assertIn("git_credentials_unavailable", observation.blockers) + + def test_dirty_and_remote_ahead_is_diverged(self) -> None: + root = make_tmp() + repo = make_git_repo(root, "repo") + runner = FakeGitRunner() + configure_clean_runner(runner, repo, ahead_behind="2 0") + runner.set_result(repo, ("status", "--porcelain", "--untracked-files=all"), " M README.md\n") + observation = observe_repo(target(repo), runner=runner) + self.assertEqual(observation.status, SyncAuditStatus.DIVERGED) + self.assertIn("dirty_worktree_remote_ahead", observation.blockers) + + def test_build_report_and_render_outputs(self) -> None: + root = make_tmp() + repo = make_git_repo(root, "repo") + runner = FakeGitRunner() + configure_clean_runner(runner, repo) + report = build_targeted_sync_audit(targets=(target(repo),), runner=runner) + self.assertIsInstance(report, TargetedSyncAuditReport) + self.assertEqual(report.status, SyncAuditStatus.ALIGNED) + self.assertIn("Targeted Git Sync Audit", sync_audit_markdown(report)) + self.assertIn("target_id,path,branch", sync_audit_csv(report)) + + def test_run_targeted_sync_audit_writes_project_and_central_artifacts(self) -> None: + root = make_tmp() + project = make_git_repo(root, "tudo-para-ia-mais-humana") + mcp = make_git_repo(root, "tudo-para-ia-mcps-internos-plataform") + central_repo = make_git_repo(root, "nucleo-gestao-operacional") + central = root / "central" / "15_repo_tudo-para-ia-mais-humana-platform" + runner = FakeGitRunner() + for repo in (project, mcp, central_repo): + configure_clean_runner(runner, repo) + report, records = run_targeted_sync_audit( + project_root=project, + mcp_repo_root=mcp, + central_repo_root=central_repo, + central_platform_folder=central, + runner=runner, + ) + self.assertEqual(report.status, SyncAuditStatus.ALIGNED) + self.assertTrue((project / "dados" / "targeted-sync-audit.json").exists()) + self.assertTrue((project / "matrizes" / "targeted-sync-audit.csv").exists()) + self.assertTrue((project / "ecossistema" / "TARGETED-SYNC-AUDIT.md").exists()) + self.assertTrue((central / "reports" / "EXECUTADO__targeted-sync-audit.md").exists()) + self.assertGreaterEqual(len(records), 4) + + def test_cli_targeted_sync_audit_writes_payload(self) -> None: + root = make_tmp() + project = make_git_repo(root, "project") + mcp = make_git_repo(root, "mcp") + central = make_git_repo(root, "central") + code = main( + [ + "targeted-sync-audit", + "--project-root", + str(project), + "--mcp-repo-root", + str(mcp), + "--central-repo-root", + str(central), + ] + ) + self.assertEqual(code, 0) + payload = json.loads((project / "dados" / "targeted-sync-audit.json").read_text(encoding="utf-8")) + self.assertEqual(len(payload["observations"]), 3) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_workspace_hygiene.py b/tests/test_workspace_hygiene.py new file mode 100644 index 0000000..6c8fe5c --- /dev/null +++ b/tests/test_workspace_hygiene.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +import json +import unittest +from pathlib import Path + +from mais_humana.cli import main +from mais_humana.workspace_hygiene import ( + HygieneStatus, + HygieneTarget, + build_workspace_hygiene_report, + hygiene_csv, + hygiene_markdown, + run_workspace_hygiene, + safe_child_path, +) +from tests.helpers import make_tmp + + +class WorkspaceHygieneTests(unittest.TestCase): + def make_project_with_artifacts(self) -> Path: + project = make_tmp() + scratch = project / ".test-tmp" / "case" + deps = project / "node_modules" / "pkg" + scratch.mkdir(parents=True) + deps.mkdir(parents=True) + (scratch / "evidence.tmp").write_text("temporary evidence", encoding="utf-8") + (deps / "package.json").write_text("{}", encoding="utf-8") + return project + + def test_safe_child_path_rejects_escape(self) -> None: + project = make_tmp() + with self.assertRaises(ValueError): + safe_child_path(project, "..\\outside") + + def test_dry_run_reports_present_artifacts_without_deleting(self) -> None: + project = self.make_project_with_artifacts() + report = build_workspace_hygiene_report(project, apply=False) + self.assertEqual(report.status, HygieneStatus.PARTIAL) + self.assertFalse(report.clean) + self.assertTrue((project / ".test-tmp").exists()) + self.assertTrue((project / "node_modules").exists()) + self.assertIn("dry run", hygiene_markdown(report)) + self.assertIn("target_id,path,action,status", hygiene_csv(report)) + + def test_apply_removes_approved_artifacts(self) -> None: + project = self.make_project_with_artifacts() + report = build_workspace_hygiene_report(project, apply=True) + self.assertEqual(report.status, HygieneStatus.PASSED) + self.assertTrue(report.clean) + self.assertFalse((project / ".test-tmp").exists()) + self.assertFalse((project / "node_modules").exists()) + self.assertTrue(all(action.deleted for action in report.actions)) + + def test_custom_unsafe_target_is_blocked_before_delete(self) -> None: + project = make_tmp() + target = HygieneTarget("unsafe", "..\\outside", "unit test") + report = build_workspace_hygiene_report(project, apply=True, targets=(target,)) + self.assertEqual(report.status, HygieneStatus.BLOCKED) + self.assertTrue(report.blockers) + self.assertIn("escapes project root", report.actions[0].error) + + def test_run_workspace_hygiene_writes_project_and_central_artifacts(self) -> None: + project = self.make_project_with_artifacts() + central = make_tmp() / "central" / "15_repo_tudo-para-ia-mais-humana-platform" + report, records = run_workspace_hygiene(project_root=project, central_platform_folder=central, apply=True) + self.assertEqual(report.status, HygieneStatus.PASSED) + self.assertTrue((project / "dados" / "workspace-hygiene-report.json").exists()) + self.assertTrue((project / "matrizes" / "workspace-hygiene-targets.csv").exists()) + self.assertTrue((project / "ecossistema" / "WORKSPACE-HYGIENE-REPORT.md").exists()) + self.assertTrue((central / "reports" / "EXECUTADO__workspace-hygiene.md").exists()) + self.assertGreaterEqual(len(records), 4) + + def test_cli_workspace_hygiene_writes_json_payload(self) -> None: + project = self.make_project_with_artifacts() + code = main(["workspace-hygiene", "--project-root", str(project), "--apply"]) + self.assertEqual(code, 0) + payload = json.loads((project / "dados" / "workspace-hygiene-report.json").read_text(encoding="utf-8")) + self.assertEqual(payload["status"], "passed") + self.assertEqual(payload["clean"], True) + + +if __name__ == "__main__": + unittest.main()