Files
Investidor-V2/tools/portal-audit-profiles-docs.py
nala 01405cbf8a
tests / ci (push) Canceled after 0s
oportunidades 5
2026-10-10 14:15:28 +02:00

223 lines
29 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Current executive evidence and readable projections of the sole requirement matrix."""
import csv
import json
import re
import sys
import xml.etree.ElementTree as ET
from pathlib import Path
sys.stdout.reconfigure(encoding='utf-8')
csv.field_size_limit(16 * 1024 * 1024)
ROOT = Path(__file__).resolve().parent.parent
DOCS = ROOT / 'docs/investmoz/v2/auditoria-portal'
PRIVATE = ROOT / 'storage/app/private/investmoz-v2/portal-audit'
counts = json.loads((PRIVATE / 'contagens-requisitos.json').read_text(encoding='utf-8'))
projection = json.loads((PRIVATE / 'pedidos-abertos-projection.json').read_text(encoding='utf-8'))
current = json.loads((PRIVATE / 'profiles-v1-current-version-qa.json').read_text(encoding='utf-8'))
preservation = json.loads((PRIVATE / 'profiles-v1-preservation-qa.json').read_text(encoding='utf-8'))
rows = list(csv.DictReader((DOCS / 'matriz-requisitos.csv').open(encoding='utf-8-sig')))
profiles = [r for r in rows if r['ID'].startswith('AUD-PROFILE-')]
test_suite = ET.parse(PRIVATE / 'profiles-v1-final-qa.xml').getroot().find('testsuite')
assert test_suite is not None and test_suite.get('failures') == '0' and test_suite.get('errors') == '0'
assert len(profiles) == 32 and current['browser_visual_observed'] is False
def update(name, body):
path = DOCS / name
text = path.read_text(encoding='utf-8-sig')
start, end = '<!-- qa-profiles-v1-20261010:begin -->', '<!-- qa-profiles-v1-20261010:end -->'
block = start + '\n' + body.strip() + '\n\n' + end
if start in text:
text = re.sub(re.escape(start) + '.*?' + re.escape(end), lambda _: block, text, flags=re.S)
else:
heading, rest = text.split('\n', 1)
text = heading + '\n\n' + block + '\n\n> Registos anteriores preservados como histórico. Os estados correntes são os da matriz e do bloco mais recente acima; uma entrega posterior não altera retroativamente a evidência anterior.\n' + rest
path.write_text(text, encoding='utf-8')
status_table = '\n'.join(f"| {name} | {data['requisitos']} | {data['linhas_origem']} |" for name,data in counts['por_estado'].items())
groups_table = '\n'.join(f'| {name} | {total} |' for name,total in projection['group_counts'].items())
details = '\n\n'.join(f"**{r['ID']} — {r['Pedido/trecho']}** ({r['Estado']}).\n\nImplementação: {r['Implementação encontrada']}\n\nProva: {r['API']}\n\nLacuna/próxima ação: {r['Lacuna']}\n\nAceitação: {r['Critério de aceitação']}" for r in profiles)
clean_executive = f"""## Perfis v1: resultado do lote em QA — 10/10/2026
A v1 foi lida integralmente: 530 parágrafos, confrontados com os 471 do exemplar anterior, AGENTS, auditoria, código, schema PostgreSQL e configuração. Fortify, contas, documentos, relações, IDs, classificações, histórico, cinco fases e 19 etapas foram preservados. Keycloak foi avaliado como recomendação; não há necessidade de SSO/federação demonstrada para substituir Fortify neste lote. A aceitação das fontes oficiais permanece intacta.
**A mesma matriz contém 3.386 requisitos/linhas e 6.838 ocorrências de origem.** Os 3.354 requisitos e 5.830 referências anteriores foram conservados. Acrescentaram-se 32 requisitos verificáveis, os 1.001 parágrafos dos dois exemplares e sete referências diretas da reconciliação. Parágrafos de estrutura e tabelas são referências, não pedidos independentes. Inventário: 591 exemplares, versões e anexos; 202 ficheiros acessíveis nesta varredura, incluindo 12 marcadores de bloqueio Office preservados por bytes/hash.
| Estado canónico | Requisitos | Ocorrências |
| --- | ---: | ---: |
{status_table}
O sexto concluído é apenas **AUD-PROFILE-27**, a avaliação arquitetural de Keycloak. Não encerra autenticação visual nem uma integração externa. **AUD-OP-03 passa a parcial**, pelas regras e transições novas; o workflow integral continua aberto.
QA: **http://127.0.0.1:18097**, destino efetivamente verificado `desk_restore_20261009_174726_test:55441`, com guarda antes de escrita. Foram preparadas 12 contas sintéticas, com MFA configurado e confirmado normalmente por Fortify, duas organizações e quatro representações. O ensaio comprovou:
- Dashboard do Promotor → links devolvidos pela interface → criação do rascunho 15 → gravação idempotente → nova sessão MFA → recuperação → edição pelo outro Promotor autorizado da mesma organização. Autor e ID permanecem; outra organização, tipo não autorizado e transferência de organização recebem 403.
- Quatro pedidos de Promotor, comprovativos privados com ClamD real e hash recuperado, acompanhamento noutra sessão e aprovação independente. Rejeição pode registar conferências falsas sem inventar validação. Auditor com outro papel continua sem escrita operacional.
- Revogação do Validador 24: sessão antiga recebe 401; nova sessão MFA autentica, mas o papel já não autoriza. Inicialização da dupla 27/28 pelo terceiro aprovador 29; substituição atómica 28→30; dupla atual 27/30, terceiro negado, replay negado e sessão anterior invalidada.
- Recuperação do titular 30 por código Fortify noutra sessão, sem desativar MFA; código consumido não autentica. Desativação de MFA, eliminação e mudança de email do titular são recusadas. Auditor recupera e exporta metadados filtrados, sem snapshots privados.
- Consumidores territoriais do Promotor corrigidos para rotas autorizadas: 11 províncias, **Cabo Delgado** selecionada, guardada e recuperada com o mesmo ID/nome; uma área geométrica devolvida pela API. O desenho no navegador continua por demonstrar.
**Continuam abertos:** C37, cenários A/B e C43 na interface; contratos especializados completos e vínculos canónicos; submissão/aprovação/publicação positivas, agendamento e versão pública; filas dos coordenadores, pareceres, incidentes de suporte, decisões de recurso, SLA e governança; âmbito provincial de autorização; tokens/dispositivos; privacidade e todas as operações documentais por tipo/perfil. A submissão real do rascunho 15 responde 422 controlado por contrato Create incompleto. Revisão/correção positiva foi ensaiada com uma fixture explicitamente submetida, não com uma submissão real.
API e persistência estão demonstradas nos escopos acima. Interface preparada e compilada; nenhum navegador automatizável foi inventariado, portanto não há aceitação visual. TypeScript, build QA e PHPStan passaram; {test_suite.get('tests')} testes específicos, com {test_suite.get('assertions')} asserções, passaram. A contagem não substitui a prova por requisito.
Manifesto QA demonstrado: `{current['qa_manifest_sha256']}`. Manifesto ativo preservado: `75352185c2a85c34ab726613db864a598e301a5b342ebbc80ac8e678eed17a94`. Não há revisão candidata fixada enquanto faltar a aceitação visual.
Acumulação com a permissão administrativa antiga foi reconciliada antes da alteração: uma conta com atribuição v1 não usa a criação legada para contornar organização/tipo; a revogação não restaura automaticamente privilégio antigo mais amplo. Auditor com permissão legada continua sem escrita administrativa. Testes de compatibilidade comprovam as negações; gestores sem atribuições v1 conservam as funções anteriores. Caso C49 adicionado, sem alteração de privilégios ativos.
Preservação por ID/colunas originais comprovada em 18 tabelas, incluindo conta 18, documentos e auditoria; manifesto ativo inalterado. Ativo consultado exclusivamente em transação READ ONLY (`investemoz:5432`): perfis 040000 ausentes e flag desativada; 020000 instalada, 030000/percurso ausentes, zero geometrias. **Nenhuma escrita ou alteração de privilégios ativos.** QA mantém 393 geometrias privadas; faltam 31 distritos e 157 postos, já nomeados. Publicação de camadas é separada.
Evidências sanitizadas: `profiles-v1-http-qa.json`, `profiles-v1-mfa-enrollment-qa.json`, `profiles-v1-recovery-audit-qa.json`, `profiles-v1-current-version-qa.json`, `profiles-v1-preservation-qa.json`, `profiles-v1-reconciliation-proof.json`, `profiles-v1-final-qa.xml` e `profiles-v1-build-qa.log`, em `storage/app/private/investmoz-v2/portal-audit/`. Credenciais, cookies, segredos e códigos não constam dos relatórios.
[Correspondência por requisito](perfis-v1-reconciliacao.md), [roteiro manual](roteiro-manual-perfis-v1.md), [backlog](backlog.md), [ativação e reversão](plano-ativacao.md). Relatório e backlog também disponíveis no servidor QA, com autenticação, em `/qa-auditoria/relatorio-executivo` e `/qa-auditoria/backlog`.
"""
update('relatorio-executivo.md', clean_executive)
update('perfis-v1-reconciliacao.md', clean_executive + '\n\n### Correspondência derivada da mesma matriz\n\nEsta projeção não é outro inventário editável. Fontes e versões integrais permanecem no CSV.\n\n' + details)
clean_backlog = f"""## Próximo lote: prioridade e critérios de fecho — 10/10/2026
A matriz única tem 3.386 requisitos/linhas, 6.838 ocorrências e 3.380 requisitos abertos. As contagens abaixo agrupam o trabalho; mantêm o estado canónico de cada requisito. “Preparado em QA” identifica um escopo demonstrado, sem declarar todo o requisito concluído.
| Grupo dos abertos | Requisitos |
| --- | ---: |
{groups_table}
Lista integral pesquisável, derivada do mesmo CSV: **http://127.0.0.1:18097/qa-auditoria/pedidos-abertos**. Acesso do gestor QA 17, Auditor 26 ou Superutilizador 27/30 com MFA. Não há permissões administrativas automáticas para o investidor.
| Prioridade / requisitos | Próxima correção ou ensaio | Critério concreto |
| --- | --- | --- |
| P0 — AUD-UI-01; PROFILE-16/17/24 | Incorporar prova visual do login, atualização, logout, nova sessão e revogação; continuar diagnóstico sanitizado de C37. | Sessão recuperável e isolada; revogação efetiva; falha controlada sem autenticação indevida. |
| P1 — PROFILE-05/06/07/25/30/32; AUD-DASH-01 | Executar o roteiro do dashboard, criação, recuperação, coedição, pedido/decisão e acessos negados; corrigir reproduções. | Resultado visível e persistente; mesmo ID/autor; autorização no servidor. |
| P1 — AUD-OP-04; PROFILE-07/28 | Completar contratos Create/Patch/Response, formulário e adaptadores para entidades existentes. | Campos, regras, documentos e vínculos canónicos completos por categoria; o primeiro draft imobiliário de 24 campos não encerra o contrato. |
| P1 — AUD-OP-03; PROFILE-08/09/11/12/19/20/21/22 | Submissão real, atribuição independente, pareceres/correções, aprovação/publicação, versão pública, incidentes e recurso. | Ciclo integral com atores distintos e contrato íntegro; nenhuma fixture de estado contada como submissão. |
| P1 — AUD-GEO-02/03; AUD-FIELD-*; PROFILE-01/06 | Resolver os 31 distritos e 157 postos nomeados; verificar todos os seletores/mapas e âmbito provincial de autorização. | Cadastro, geometria e apresentação distinguidos por consumidor; selecionar → guardar → reabrir → mapa visível. |
| P1 — AUD-COUNTRY-*; AUD-STATS-01 | Completar país/origem, recuperação, filtros e estatísticas por formulário. | Origem persistida e contabilizada; residência, país fiscal e origem dos fundos não substituem origem declarada. |
| P1 — AUD-OP-02; AUD-LIB-01/02; AUD-SCAN-01 | Completar operações documentais, PDFs, partilhas e derivadas por tipo/perfil. | Scan próprio, permissões, revogação e recuperação por hash; original preservado. ClamD real já demonstrado não encerra operações restantes. |
| P1 — PROFILE-13/14/15/18/23/26/31 | Completar operações críticas, concorrência da dupla, elevação, revalidação, privacidade, governança e instalação autenticada 040000. | Prévia, autorização, aplicação sem duplicação, recuperação e reversão verificadas; instalação separada da disponibilização. |
**Decisões concretas para futura ativação:** PROFILE-29 — quais funções dos gestores ativos correspondem a Validador, Publicador, Auditor ou administração controlada; quem serão os dois titulares reais e o terceiro aprovador do bootstrap? PROFILE-22 — quais valores, versões e vigência dos SLA, tolerâncias e ciclos por tipo? PROFILE-16 — qual instância fará a recuperação de emergência se ambos perderem todos os meios? As cinco decisões canónicas incluem ainda as quatro pendências anteriores, preservadas por ID. Estas perguntas não impedem desenvolvimento QA independente.
A edição por outros Promotores autorizados da mesma organização já foi decidida e aplicada em QA. Novas jornadas educativas não foram iniciadas. Workflow e contratos especializados continuam no backlog. [Correspondência e evidência](perfis-v1-reconciliacao.md), [roteiro](roteiro-manual-perfis-v1.md), [ativação](plano-ativacao.md).
"""
update('backlog.md', clean_backlog)
clean_activation = f"""## Sequência consolidada: instalações, disponibilização e reversão — 10/10/2026
Preparação exclusivamente em QA. Nenhuma ativação autorizada e nenhuma revisão candidata fixada. As provas `ready` anteriores são históricas: os fingerprints incluem agora as regras de perfis, portanto não comprovam esta revisão nem instalação funcional.
1. Incorporar os ensaios visuais C37/C43/A/B, perfis e consumidores; corrigir falhas; fixar revisão, manifestos e configuração. Reconciliar permissões legadas e titulares reais. Completar os contratos antes de disponibilizar submissão/aprovação/publicação.
2. Renovar backup da base, originais, ficheiros e configuração/chaves após fixar a revisão. Restaurar numa nova QA guardada e comparar IDs, relações, hashes, schema, compatibilidade e reversão. Usar as contagens reais do momento. A cópia de 09/10 não é apresentada como backup renovado desta candidata.
3. **Gestão 020000:** já instalada no ativo; não repetir. Atalhos C43 e primeiro rascunho imobiliário não exigem essa instalação. Disponibilização dos atalhos por `PORTAL_OPPORTUNITY_DASHBOARD_ACCESS_ENABLED`, separada do schema; preservar gestores verificados e funções legadas reconciliadas.
4. **Recursos 030000:** se ausente, prévia e aplicação autenticadas por GET/POST `/management/opportunity-resources-install`, com provas atuais. Esperado: três tabelas de associação, uma coluna em documents, uma função e três triggers; zero originais/recursos criados automaticamente. ClamD/GD/WebP são dependências das operações binárias afetadas. Instalação não confirma scans, divulgação ou publicação.
5. **Perfis 040000:** falta concluir o mecanismo autenticado de instalação e o bootstrap ativo em QA. A migration guardada está preparada, sem autorização para execução ativa indiscriminada. Esperado: quatro tabelas de autorização ligadas às entidades existentes; uma coluna em users e três em opportunities; uma função e dois triggers. **Zero contas, atribuições ou titulares reais criados automaticamente.** Depende da gestão 020000; recursos 030000 são necessários para os respetivos consumidores. A cerimónia designa dois titulares reais com MFA e terceiro aprovador independente, sem converter a allowlist antiga. `PORTAL_PROFILE_ACCESS_ENABLED` é disponibilização separada. QA já instalada: não repetir migration ou bootstrap; dupla sintética atual 27/30.
6. **Balcão e percurso:** instalar apenas dependências ausentes pelo mecanismo autenticado existente; 190000 prepara o percurso e múltiplos investimentos. Preservar cinco fases e 19 etapas. Instalação não disponibiliza nem conclui I1–I3; flags, assets, rotas e cenários A/B visuais têm provas próprias. Não depende de CRM externo.
7. **Importação cartográfica:** prévia, correspondências, hash e aplicação autenticada privada/idempotente/auditável, usando territórios existentes. QA: 393 de 581 geometrias esperadas — províncias 11/11, distritos 128/159, postos 254/411; pendentes 0/31/157, com os 188 nomes em correspondencias-cartograficas.md. A prévia ativa calcula a interseção inequívoca do alvo, sem copiar contagens QA cegamente. Publicação das camadas é outra ação. Importação não ativa cálculos fiscais; fonte oficial aceite não requer nova validação de credibilidade.
8. Somente após futura autorização ativa, verificar código/compilação/cache/cookies/guards, contagens antes/depois, auditoria, originais, versão pública e recuperação dos percursos no alvo aprovado.
**Reversão:** desativar flags específicas e interromper novas operações, mantendo código de autorização compatível com os privados. Não regressar a código que os exponha. 040000 recusa `down` se há dados/pedidos/dupla/histórico; depois de uso, preservar tabelas ou reconciliar restauro numa janela autorizada. Revogações e substituições permanecem rastreáveis. Não restaurar um backup antigo apagando dados posteriores. 030000 só reverte antes de uso; percurso e importação usam as reversões existentes, preservando relações/originais. Reversão da publicação de camadas é independente da importação.
Fingerprints preparados, sem fixação de candidata:
{chr(10).join('- '+name+': `'+digest+'`' for name,digest in preservation['fingerprints'].items())}
Manifesto QA `{current['qa_manifest_sha256']}`; manifesto ativo `75352185c2a85c34ab726613db864a598e301a5b342ebbc80ac8e678eed17a94` preservado. Provas específicas precisam corresponder à revisão final e ao alvo real.
"""
update('plano-ativacao.md', clean_activation)
clean_manual = """# Ensaio manual de perfis v1 — QA exclusiva
**Endereço inicial: http://127.0.0.1:18097/dashboard.** Não usar portal-investidor.test nem outra porta. O servidor verifica `desk_restore_20261009_174726_test:55441` antes de escritas. Em Network, confirmar o header `X-Investmoz-QA-Target` de uma resposta de página/API. Capturas devem omitir Cookie, X-XSRF-TOKEN, Authorization, credenciais, segredos e corpos de login/MFA.
Credenciais e material MFA ficam apenas no ficheiro local privado `storage/app/private/investmoz-v2/portal-audit/profiles-v1-actors-private.json`. Consulte no editor e no autenticador local; não os copie para a conversa. Todas as contas sintéticas foram configuradas normalmente por Fortify sob a chave QA estável. Não gerar outra chave nem desativar MFA.
## Contas e estado atual
| Conta QA | Estado após os ensaios |
| --- | --- |
| 20 | Público, sem criação de oportunidades |
| 21 | Promotor da organização A; autor do rascunho 15 |
| 22 | Outro Promotor autorizado da organização A; coedição |
| 23 | Promotor da organização B; acesso à oportunidade 15 negado |
| 24 | Validador revogado; conta e login MFA preservados |
| 25 | Publicador; sem edição técnica ou aprovação de rascunho |
| 26 | Auditor; leitura e exportação de metadados |
| 27 e 30 | Os dois Superutilizadores atuais |
| 28 | Titular substituído; conta preservada, administração negada |
| 29 | Terceiro aprovador do bootstrap QA; não é Superutilizador |
| 31 | Promotor + Validador + Auditor; restrição de leitura prevalece |
## Primeiro ensaio: Promotor, recuperação e coedição
1. Numa sessão QA isolada, entrar como 21: login → MFA → dashboard. Esperado: “Minhas oportunidades” e “Nova oportunidade”. Atualizar a página mantém a sessão; registar se volta ao login.
2. Clicar “Minhas oportunidades” → abrir 15 → editar. Esperado: mesmo ID, organização e rascunho; título editado por 22 e Cabo Delgado recuperados. O dossier privado não se transforma em oportunidade publicada.
3. Selecionar província/distrito disponíveis e conferir o mapa/estado de cobertura. Guardar com fundamento. Esperado: mensagem de gravação; mudar o pai limpa filhos. Limite administrativo não representa perímetro do terreno.
4. Logout → nova sessão/login MFA 21 → dashboard → Minhas → 15. Esperado: campo, nome, ID, versão e mapa recuperados. Separar prova do desenho, API e persistência.
5. Noutra sessão, 22 → dashboard → Minhas → 15 → editar/guardar. Esperado: autorizado; autor 21 preservado e editor 22 registado. Nova sessão 21 recupera a edição.
6. Como 23, abrir o URL da oportunidade 15. Esperado: 403 controlado sem conteúdo da organização A. Como 31, leitura permitida e gravação negada; os dados não mudam. Como 20, criação não aparece e acesso direto é negado.
7. Como 21, solicitar arquivo com razão. Esperado: pedido persistido, estado draft mantido. Promotor não ganha exclusão/restauro. Submissão e publicação completas continuam indisponíveis pelo contrato; não interpretar isso como falha MFA/C37.
## Pedido de Promotor e decisão independente
1. Como 20: dashboard → “Solicitar perfil de Promotor” → `/perfil/promotor`. Esperado: somente pedidos e comprovativos próprios. Se necessário, preparar um anexo sintético privado no dossier do Balcão; aguardar scan clean real.
2. Escolher representação, organização existente autorizada quando aplicável, tipos, comprovativo e fundamento. Submeter. Esperado: ID e estado pending; nenhuma criação autorizada antes da decisão.
3. Logout/nova sessão 20 → acompanhamento. Esperado: mesmo pedido recuperado. Antes de repetir por erro de interface, conferir o acompanhamento; a mesma chave não duplica o pedido.
4. Noutra sessão, 27 ou 30 → Gestão de perfis → consultar comprovativo → conferir identidade, representação e documentos → escolher tipos → decidir com razão. Declarar apenas conferências efetivamente realizadas. Rejeição pode manter conferências falsas e não concede perfil. Aprovação própria é negada.
5. Nova sessão 20 após aprovação → dashboard. Esperado: Minhas/Nova para o âmbito e tipos aprovados; outro tipo/organização continua negado. Documentos e decisão original permanecem.
## Revisão, auditoria e operações críticas
1. Como 25, consultar 15. Esperado: sem edição técnica, aprovação ou publicação de draft. A publicação positiva integral ainda depende do contrato completo; não fabricar estados para encerrar o teste.
2. Como 26 → Auditoria → filtrar `superuser_replaced` → exportar JSON. Esperado: metadados da substituição 28→30, sem segredos ou snapshots privados; exportação auditada. Escrita operacional continua negada com outros papéis.
3. Como 27/30 → Gestão de perfis. Esperado: dupla 27/30, alertas, pedidos, atribuições e formulários. Como 28, administração negada; como 24, login MFA válido mas papel revogado.
4. Para ensaio positivo do Validador, atribuir explicitamente 24 pelo 27/30, com tipos e fundamento. Preservar a revogação anterior. Filas e completude ainda pendentes. Ao terminar, revogar a nova atribuição: sessão antiga perde acesso; nova sessão conserva autenticação, sem o papel.
5. Para uma substituição adicional, usar candidato sintético QA com MFA. Preparar → outro titular aprova → aplicar. Esperado: sempre dois titulares, terceiro isolado negado, replay negado e acesso anterior revogado. Não escolher titulares reais nem repetir bootstrap para regressar a 28.
6. Elevação exige outro titular, ação/objeto exatos, papel operacional e MFA recente. Não remove impedimentos de autoria/Auditor. Após 15 minutos, decisão administrativa exige novo MFA por logout/login QA; não desativar MFA.
7. Recuperação do titular usa código Fortify local, sem captura. Código consumido não autentica. Emergência quando ambos perdem todos os meios permanece uma decisão/procedimento institucional.
## Registar os resultados na mesma matriz
Por ação: conta QA, URL, hora UTC, ID, esperado, observado, mensagem visível, status API e campo após nova sessão. Omitir segredos. Associar ao AUD-PROFILE correspondente; falhas adicionais entram nos casos de reprodução. C37 e A/B não são fechados por este roteiro.
Os cenários A/B mantêm as cinco fases e 19 etapas do roteiro existente: criação → gravação → nova sessão → recuperação → aplicabilidade → ferramenta → resultado no dossier → Balcão → acompanhamento, incluindo tarefa independente em paralelo e ausência de mistura/acesso indevido.
Relatório e backlog autenticados: http://127.0.0.1:18097/qa-auditoria/relatorio-executivo e http://127.0.0.1:18097/qa-auditoria/backlog. Lista da matriz: `/qa-auditoria/pedidos-abertos`. Acesso do gestor QA 17, Auditor 26 ou Super 27/30 com MFA; Público e Promotor isolado não recebem acesso administrativo.
"""
(DOCS / 'roteiro-manual-perfis-v1.md').write_text(clean_manual, encoding='utf-8')
clean_cases = """## Reproduções adicionais de perfis — 10/10/2026
C37 permanece pendente; não houve nova tentativa da conta 18 nem fecho visual. C43/C44 preservados.
| Caso / requisito | Reprodução | Esperado | Observado e causa | Correção/prova | Pendente |
| --- | --- | --- | --- | --- | --- |
| C45 — PROFILE-05/06/25, AUD-GEO-03 | Promotor 21: dashboard → Nova → seletor/mapa; comparar chamadas territoriais. | Perfil autorizado consulta, grava e recupera território/geometria. | Consumidor chamava rotas management reservadas a manage-portal. Inspeção de código/rotas; nenhuma captura visual anterior. | Alias autorizados reutilizam serviços: 11 províncias, Cabo Delgado guardada/recuperada, uma área API. profiles-v1-current-version-qa.json. | Desenho/cliques por perfil e restantes consumidores. |
| C46 — PROFILE-06/07/10/29 | Gestor sem perfil: API administrativa de contexto da oportunidade privada; território, prévia de origem e subjects. | Allowlist legada não revela/edita o privado v1. | Rotas auxiliares tinham apenas can:manage-portal, sem política do registo. Lacuna identificada em código, sem realizar escrita indevida. | Middleware cobre aliases/payload; subjects/dashboard/catalog usam âmbito. Testes 403/lista vazia. | Outras relações/filas e âmbito provincial. |
| C47 — PROFILE-04 | Rejeitar pedido com approved_types=[] e conferências false. | Rejeição fundamentada sem inventar conferência. | Ensaio respondeu 422: approved_types required rejeitava array vazio. | present|array; não-vazio só na aprovação; accepted_if só approved. Teste rejeita sem conceder e preserva conferência false; decisão própria 403. | Decisão na interface. |
| C48 — PROFILE-15/16/24/26 | Titular 30: DELETE MFA, DELETE conta, PATCH email. | Manter MFA obrigatório, dupla e histórico. | Regra específica da identidade privilegiada v1 não existia. Lacuna identificada em código; nunca se desativou MFA para ensaio. | ProtectPrivilegedIdentity, 403 e auditoria; recovery Fortify noutra sessão/reuse negado; trigger DELETE testado. | Visual e recuperação institucional de emergência. |
| C49 — PROFILE-10/29 | Conta sintética com papéis v1 e allowlist legada: abrir Nova legada, POST draft legado; depois escrita administrativa com Auditor. | Não contornar organização/tipo nem a restrição do Auditor pela acumulação. | Exceção legada podia autorizar escrita mais ampla. Identificada em código, sem usar conta ativa ou criar dados fora do âmbito. | Decisão documentada antes da correção; legacyWriteAllowed usa histórico; 403 na criação e escrita, atalho legado ausente nas props. Gestor sem atribuição v1 preservado. | Interface, conciliação dos gestores reais e consumidores restantes. |
Submissão real do rascunho 15 → 422 por contrato Create ausente é lacuna funcional mantida, não falha de MFA/autenticação. A fixture de revisão não demonstra submissão integral. Evidências por critério em profiles-v1-final-qa.xml, http-qa, recovery-audit, current-version e preservation; JSON/HTML não substitui interface.
"""
update('casos-reproducao.md', clean_cases)
clean_coverage = """## Cobertura após perfis v1 — 10/10/2026
I0–I3 permanecem em QA. Cinco fases e 19 etapas preservadas, sem renumeração. C37, A/B e C43 visuais continuam pendentes. A autorização organizacional reutiliza OpportunityManagement, Resources, Fortify e entidades existentes; nenhuma jornada educativa nova foi iniciada.
- Interface: preparada e compilada, sem observação no navegador. Roteiro manual de perfis inclui acessos permitidos/negados; A/B preservam o roteiro existente.
- API: links descobertos no dashboard, rascunho 15 recuperado noutra sessão, coedição 22 e negações por tipo/organização/múltiplos papéis. Seletores autorizados e geometria do Promotor funcionam; submissão integral permanece bloqueada por contrato incompleto.
- Persistência: autor, ID, versão e histórico preservados; Cabo Delgado recuperada com o mesmo ID/nome. Pedido de Promotor, comprovativos, auditoria, revogação e dupla demonstrados nos escopos descritos.
- Documentos: quatro comprovativos sintéticos com ClamD real e hash recuperável; não generalizar às operações restantes. Originais anteriores preservados em 18 tabelas.
- Ativo: exclusivamente READ ONLY, sem instalação/flag de perfis. 020000 instalada; recursos/percurso ainda ausentes. Mesma matriz: 3.386 requisitos, 6.838 ocorrências.
Coordenadores, pareceristas, suporte e recurso estão explicitamente mapeados na reconciliação. Filas, decisões, SLA e incidentes funcionais continuam parciais ou não implementados no backlog. 393 geometrias privadas QA não encerram a integração visual; permanecem 31 distritos/157 postos nomeados.
"""
update('cobertura-percursos-i0-i3.md', clean_coverage)
update('execucao-percurso-i1-i3.md', clean_coverage)
print(json.dumps({'updated_documents': 8, 'profile_requirements': len(profiles), 'canonical_requirements': counts['requisitos'], 'active_writes': 0, 'visual_acceptance_pending': True}))
# The dated extraction report is historical once the canonical workflow increment exists.
if (PRIVATE / 'opportunity-workflow-http-qa.json').exists():
import runpy
runpy.run_path(str(ROOT / 'tools/portal-audit-workflow-docs.py'), run_name='__main__')