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

108 lines
19 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.
"""Add current C43/C44 evidence without replacing historical audit sections."""
import json
import re
from pathlib import Path
root = Path(__file__).resolve().parent.parent
docs = root / 'docs/investmoz/v2/auditoria-portal'
private = root / 'storage/app/private/investmoz-v2/portal-audit'
runtime = json.loads((private / 'investor-path-qa-runtime.json').read_text())
projection = json.loads((private / 'pedidos-abertos-projection.json').read_text())
marker = 'qa-dashboard-20261010'
def readable(body):
# Preserve exact identifiers/URLs while spacing numerical evidence and prose.
tokens = []
pattern = r'`[^`]+`|https?://[^\s;),]+|[0-9a-f]{64}|[\w./-]+\.(?:json|php|xml|tsx|ts|md)|AUD-[A-Z]+-\d+|C\d+|\bI[0-3]\b|\bP[0-2]\b|realEstatePatch|Opportunity[A-Za-z]+'
def keep(match):
tokens.append(match.group())
return '\x00'+str(len(tokens)-1)+'\x00'
body = re.sub(pattern, keep, body)
body = re.sub(r'(?<=[A-Za-zÀ-ÿ])(?=\d)|(?<=\d)(?=[A-Za-zÀ-ÿ])', ' ', body)
body = re.sub(r'([,;:])(?=[A-Za-zÀ-ÿ\d])', r'\1 ', body)
body = re.sub(r'([,;:])(?=\x00|\()', r'\1 ', body)
body = re.sub(r'(?<=[A-Za-zÀ-ÿ])(?=\x00)', ' ', body)
body = re.sub(r'\.([A-ZÀ-Ÿ])', r'. \1', body)
for old, new in {'QA e': 'QA e', 'QAflag': 'QA flag', 'QA/backend': 'QA/backend', 'sótrue': 'só true', 'porformulário': 'por formulário', 'empreparação': 'em preparação', 'schemaíntegro': 'schema íntegro', 'àgestão': 'à gestão', 'daQA': 'da QA', 'noativo': 'no ativo', 'doativo': 'do ativo', 'semduplicar': 'sem duplicar', 'seativo': 'se ativo', 'MFA em': 'MFA em', 'flagfalse': 'flag false', 'codeQA': 'código QA', 'workflow completo': 'workflow completo', 'statusarchived': 'status archived', 'volta adraft': 'volta a draft', 'labelCriar': 'label Criar', 'dossiersprivados': 'dossiers privados', 'tipos/enums': 'tipos/enums', 'sem publicação': 'sem publicação', 'no management_draft': 'no management_draft', 'MFAprévia': 'MFA: prévia', 'antes deaceitação': 'antes de aceitação', 'provas porversão/perfil': 'provas por versão/perfil', 'Dow nsomente': 'Down somente', 'Downsomente': 'Down somente', 'Não há hotfile/cacheconfig': 'Não há hotfile/cache de configuração', 'capturas sanitizadas': 'capturas sanitizadas'}.items():
body = body.replace(old, new)
for old, new in {'transaçãoSQL': 'transação SQL', 'GestoresQA': 'Gestores QA', 'InvestidoresQA': 'Investidores QA', 'emailverificado': 'email verificado', 'possuiMFA': 'possui MFA', 'títuloGestão': 'título Gestão', 'antigaCriar': 'antiga Criar', 'menuPainel': 'menu Painel', 'nofim': 'no fim', 'comoCriar': 'como Criar', 'rótuloNova': 'rótulo Nova', 'emportal.managers': 'em portal.managers', 'CorreçãoQA': 'Correção QA', 'atalhosGestão': 'atalhos Gestão', 'açãoarchive': 'ação archive', 'emstatus': 'em status', 'usaflagsfalse': 'usa flags false', 'usaassets': 'usa assets', 'versãoInertia': 'versão Inertia', 'dessemanifesto': 'desse manifesto', 'bootHTTP': 'boot HTTP', 'filtroarchived': 'filtro archived', 'OportunidadeQA': 'Oportunidade QA', 'oportunidadeQA': 'oportunidade QA', 'IDestável': 'ID estável', 'draftexistente': 'draft existente', 'patchmerge': 'patch merge', 'nomeadosDashboard': 'nomeados Dashboard', 'buildQA': 'build QA', 'ePHPStan': 'e PHPStan', 'novoPDF': 'novo PDF', 'ProvaClamD': 'Prova ClamD', 'porID': 'por ID', 'apenasAPI': 'apenas API', 'eativação': 'e ativação', 'tarefasQA': 'tarefas QA', 'antes de': 'antes de', 'code/assets': 'código/assets', 'no/dashboard': 'no /dashboard', 'apontava/investidor': 'apontava /investidor', 'emportal': 'em portal', 'Lista integral legível': 'Lista integral legível', 'gestorautenticado': 'gestor autenticado', 'configuração ativa': 'configuração ativa', 'somente se': 'somente se', 'PORTAL': 'PORTAL', 'code_hash': 'code_hash'}.items():
body = body.replace(old, new)
return re.sub(r'\x00(\d+)\x00', lambda m: tokens[int(m[1])], body)
def insert(path, body):
text = path.read_text(encoding='utf-8-sig')
text = re.sub(r'\n<!-- '+marker+r':begin -->.*?<!-- '+marker+r':end -->\n', '\n', text, flags=re.S)
headline, rest = text.split('\n', 1)
block = '\n<!-- '+marker+':begin -->\n'+readable(body.strip())+'\n\n**Histórico preservado:** os blocos anteriores a C43/C44 abaixo conservam as suas fontes e provas. Os seus hashes/ready/contagens não certificam a revisão atual; a primeira adaptação imobiliária não equivale ao schema integral nem ao workflow.\n<!-- '+marker+':end -->\n'
path.write_text(headline+'\n'+block+'\n'+rest.lstrip('\n'), encoding='utf-8')
facts = '''QA exclusiva:http://127.0.0.1:18097, alvo real `desk_restore_20261009_174726_test:55441`. Ativo consultado por transaçãoSQL READ ONLY;0escritas/instalações/publicações ativas. Cinco fases/19etapas,5dossiers/95etapas e393geometrias QA preservados. C37 e aceitação visual permanecem abertos.
GestoresQA14/17 têm emailverificado+`manage-portal`; gestor17 possuiMFA normal. InvestidoresQA13/18 não têm gestão. No ativo, a leitura confirmou contas2/13 autorizadas,020000instalada e030000ausente; o dashboard ativo contém títuloGestão de Oportunidades e ação antigaCriar oportunidade. Não há hotfile/cacheconfig/cache de rotas a explicar a ausência. URL configurado ativo:http://portal-investidor.test; **URL/conta da sessão reportada ainda desconhecidos**, sem atribuição especulativa de causa a essa conta.'''
evidence = '''- `dashboard-active-readonly.json`:configuração/contas elegíveis/instalação/manifesto ativo, sem bootHTTP/escrita de sessão no ativo.
- `dashboard-opportunities-http-qa.json`:links obtidos do dashboard→gestão→create→201→GET→logout/nova sessão→GET→PUT→archive→filtroarchived→restore→GET. OportunidadeQA13,IDestável/quatro eventos,12originais e relações/documentos/dossiers preservados;6publicadas mantidas;outra conta403.
- `dashboard-manager-mfa-http-qa.json`:gestor17,MFA em duas sessões→dashboard→gestão→recuperação/reload→logout;0alterações de registos. `dashboard-navigation-catalogue-qa.json`:menuPainel da gestão→/dashboard,dossiers privados→/investidor,atalhos únicos e ausência de gestão para investidor.
- `real-estate-draft-http-qa.json`:outra oportunidadeQA14,rascunho imobiliário parcial no draftexistente→nova sessão→patchmerge→cinco422sem mutação→outsider403;schema normativo SHA9ce0acfa5df1f81a3357dee9e5a9a1c4e77e4eefc8bce294497d18f4caa8e5c0.
- `dashboard-real-estate-qa.xml`:casos nomeadosDashboardOpportunityAccessTest/OpportunityManagementTest/OpportunityRealEstateDraftTest,8ensaios/201asserções. Typecheck,buildQA ePHPStan dirigidos passaram; contagem não substitui os critérios visuais.
- `resource-originals-preservation-http-qa.json`:cinco binários anteriores preservados e novoPDF válido recuperado/parseado,0novos recursos. ProvaClamD real anterior mantida; não afirma novo scan das derivadas nem renderização.
- `dashboard-matrix-reconciliation-qa.json` e `pedidos-abertos-projection.json`:fontes/trechos/IDs/versões preservados,3354requisitos/linhas e5830ocorrências;3349abertos apresentados uma vez cada. EstadoAUD-OP-04 passa de não implementado a parcial; nenhum requisito global encerrado.'''
causes = '''**C43 — causas encontradas no código/compilação:**(1)AppSidebar mostrava só o primeiro filho de cada grupo, descartando oportunidades;(2)menuPainel apontava/investidor mesmo para gestor;(3)dashboard de gestão colocava criação nofim comoCriar oportunidade, sem rótuloNova oportunidade. A secção de gestão só é devolvida pelo backend a contas verificadas emportal.managers; o seu ocultamento para investidor é autorização esperada, não motivo para conceder perfil administrativo.
CorreçãoQA:atalhosGestão de Oportunidades/Nova oportunidade no início do dashboard,sidebar/menu agrupado;Painel da gestão→/dashboard,dossiers→/investidor. Nova açãoarchive conserva o rascunho emstatusarchived/deleted_at=null;delete/exclusão lógica mantém o contrato anterior. Restauro volta adraft,ID/histórico intactos,sem publicação. Código usaflagsfalse por omissão; QA usaassets `public/build-qa-opportunities`, versãoInertia dessemanifesto. **`public/build` ativo manteve SHA75352185c2a85c34ab726613db864a598e301a5b342ebbc80ac8e678eed17a94.** Recursos030000não são requisito para navegar/criar rascunho básico.
**C44 — progresso específico:**primeiro adaptador imobiliário aceita campos fornecidos nas24propriedadesrealEstatePatch,validando tipos/enums/limites/UUID e recusando campos desconhecidos/de resposta. Guarda/merge privadamente no management_draft atual. Ainda faltam formulário especializado,vínculos canónicos,condições finais/Create/Response,DUAT/transação e workflow. Nenhuma coleção/tabela paralela,renumeração ou decisão externa criada. O.source.json conserva o retrato histórico da extração, não certifica o estado runtime atual.'''
groups = '''| Grupo de trabalho dos abertos | Requisitos | O que falta / próxima ação |
| --- | ---: | --- |
| Não implementados |145|Workflow integral segregado;rascunhos incompletos procura/capacidade e jornadas educativas ainda por fazer;demais critérios específicos não implementados no relatório porID. Implementar workflow sobre draft/auditoria após contratos/gates;educação não começa enquanto prioridades abertas.|
| Parciais |3183|Contrato imobiliário apenasAPI;DUAT/transações/campos/regras finais e vínculos;cartografia31distritos/157postos/mapas por consumidor;relações/citações;acervo/PDFs/partilhas/derivadas;parâmetros fiscais;negócios/direitos/mandatos;reconciliação documental/UX eativação. Inclui4decisões com estado original,sem bloquear tarefasQA independentes.|
| Preparados emQA |19|Escopos concretos de rascunhos/recursos/maturidade,países/origem/estatísticas,seletor provincial,Balcão/percurso/CRM/orientação/simulador/parceria/fundiário/importação privada com provasQA. Completar critérios restantes na interface e operações/tipos ainda abertos;ativação permanece separada. Não são19requisitos globais concluídos.|
| Instalados com falha de acesso |2|AUD-DASH-01(C43) eAUD-UI-01(C37/inspeção). Código/backendQA corrigidos nos escopos descritos;identificar sessão reportada e demonstrar dashboard/cliques e loginA/B completos. Confirmar visualmente sem conceder gestão ao investidor.|
**Lista integral legível:**http://127.0.0.1:18097/qa-auditoria/pedidos-abertos,gestorQA14/17.3349cartões,um porID,com pedido,lacuna,próxima ação,critério,fontes/versões/evidências e filtros de grupo/módulo. Vista derivada da [matriz única](matriz-requisitos.csv),sem edição nem estados paralelos;investidor403. Os grupos são editoriais,distintos dos estados canónicos:3199parciais,145não implementados,4decisões,1implementado não ativado,5concluídos de âmbito restrito.
Decisões humanas preservadas:pares exatos das6oportunidades com âncoras/clusters;identidade/termos/contactos do operador;URLs/serviços/responsáveis institucionais;modelo/indicadores/baseline de sucesso. Não reabrir aceitação das fontes oficiais;não inventar pares,parâmetros ou score.'''
insert(docs / 'relatorio-executivo.md', '## Acesso à Gestão de Oportunidades — loteC43/C44,10/10/2026\n\n'+facts+'\n\n'+causes+'\n\n'+evidence+'\n\n'+groups+'\n\nVisual pendente:[roteiro curto](demonstracao-dashboard-oportunidades.md). API/persistência/assets são provas separadas de interface;nenhum clique automatizado/cenárioA/B visual foi alegado.')
insert(docs / 'backlog.md', '## Prioridade corrente:Gestão de OportunidadesC43 —10/10/2026\n\n'+groups+'''
Ordem executável restante:1)incorporar ensaio visualC43 e corrigir reprodução;2)formulário/bindings/condições finais imobiliárias;3)adaptadoresDUAT/transação;4)gates e workflow segregado,sem autoaprovação;5)continuar correspondências/cadastros/mapas,países/origem porformulário e operações documentais independentes. C37 continua pendente,sem repetir login do investidor neste lote;não iniciar jornadas educativas novas. Detalhes/ações por cadaID estão na vista integral.
AceitaçãoC43:gestor17/MFA parte de/dashboard→cliques→rascunho→guarda→outra sessão→recupera→edita→arquiva→restaura;feedback/ID/filtro/histórico visíveis;outra conta403;dossier privado e público intactos. CritériosAPI satisfeitos não encerram o critério de interface.''')
insert(docs / 'casos-reproducao.md', '## Casos adicionaisC43/C44 —10/10/2026\n\n'+causes+'''
C43,reprodução de código/assets:seguirPainel do catálogo com gestor→/investidor;na sidebar,grupoGestão→primeiro filho/interests apenas;no/dashboard a criação está nofim e tem labelCriar oportunidade. Esperado:gestor chega ao seu dashboard e encontra Gestão/Nova sem URL decorado;investidor conserva área privada. Observado:links omitidos/destino partilhado/nome diferente. Evidência do utilizador ainda sem URL/conta;não se afirma que o seu perfil é o motivo. Também havia somenteExcluir rascunho no rascunho inicial,com delete→deleted_at em vez dearchive→statusarchived;corrigido separadamente sem alterardelete.
C44,reprodução anterior por inspeção:categoriareal_estate disponível,mas payloadreal_estate não fazia parte dos campos validados/persistidos. Esperado:guardar dados parciais e recuperar privadamente. Correção limitada:adaptador24propriedadesPatch;cinco negativos HTTP reais422sem mutação. Não se inventou ensaioHTTP pré-correção nem se declarou o contrato integral concluído.
'''+evidence)
plan = f'''## Sequência adicionalC43/C44 —10/10/2026
Preparação apenas;nenhuma ativação autorizada/executada. Fingerprints correntes:percurso`{runtime['code_hash']}`,recursos`{runtime['resource_code_hash']}`,cartografia`{runtime['geometry_code_hash']}`. Provasready anteriores ficam históricas;nenhuma candidata final.
1. ConcluirC43/visuaisC37/A-B e consumidores;registar reprodução/correção,fixar revisão+manifestos. Renovar backupDB/ficheiros/chaves/originais e restauro numa novaQA guardada,conferindoIDs/relações/hashes/schema. Não forçar contagens históricas288tabelas/5ficheiros.
2. Disponibilizar código eassets ativos dessa revisão aprovada,configuração reconciliada e cache conferida. Atalhos/arquivo usam`PORTAL_OPPORTUNITY_DASHBOARD_ACCESS_ENABLED`;estáfalse no ativo e sótrue naQA. **Nenhuma migration nova paraC43 ou primeiro draft imobiliário.**020000já instalada:não repetir. Antes de habilitar,conferir gestor(emailverificado+allowlist),rotas e manifesto realmente servido. Rollback:flagfalse e código/assets compatíveis;preservar drafts/estadoarchived/auditoria.
3. Recursos:gestorautenticado GET/POST`/management/opportunity-resources-install`somente se030000ausente.3tabelas de associação+1coluna documents+função/3triggers;0recursos/originais criados automaticamente. ClamD/GD exigidos pelas operações binárias afetadas,sem bloquear rascunho/metadados. Downsomente vazio;após uso retirar disponibilidade sem eliminar originais/dados.
4. Percurso:GET/POST`/management/balcao-install`somente para migrationspendentes190000;2colunas+1definição imutável,0conversões/dossiers/etapas. Disponibilização`INVESTOR_PATH_ENABLED`separada,depois deaceitação/instalação;reversão porflagpreserva19etapas/5fases,IDs/resultados/documentos/consentimentos.
5. Cartografia:gestor/MFAprévia/crosswalk/hash→aplicar níveis1→2→3 semduplicar. Seativo continuar0 ecorrespondênciasiguais,previsão393limitesinternos=11províncias+128distritos+254postos;0territórios novos,31/157pendentes. Publicação dascamadasseparada. Reversão3→2→1somente novas intactas/não usadas,nem publicadas;guardar originais/hash/crosswalk/receipts e relações.
6. Contratos especializados:`PORTAL_OPPORTUNITY_SPECIALIZED_DRAFTS_ENABLED`ficafalse no ativo. **Não habilitar com este loteAPI parcial.**Completar formulário/bindings/condições finais/DUAT/transação/workflow e provas porversão/perfil;depois planopróprio na mesma auditoria. Desligarflag conservaJSON privado;rollback de código deve manter chave/payloads sem descartá-los. Instalar recursos ou importarcartografia não valida/submete/aprova/publica contrato nem ativa cálculo fiscal.
Plano detalhado anterior conservado abaixo;aplicação documental ativa autenticada,scan próprio dasderivadas e operação permanenteClamD continuam dependências específicas.
'''
insert(docs / 'plano-ativacao.md', plan)
insert(docs / 'cobertura-percursos-i0-i3.md', '## Cobertura adicional:dashboard e draft imobiliário —10/10/2026\n\n'+evidence+'\n\nGestão desde/dashboard:API/destinos reais/gravação/novasessão/recuperação/arquivo/restauro demonstrados;interfacepending. Formulário especializado imobiliário ausente;24campos dePatch são adaptaçãoAPI parcial. Nenhuma cobertura cartográfica/países/origem/documental anterior promovida por esses ensaios. Gestor17/MFA distinto do investidor18;C37 eA/B visuais permanecem abertos.')
insert(docs / 'execucao-percurso-i1-i3.md', '## Continuação independenteC43/C44 —10/10/2026\n\n'+facts+'\n\n'+evidence+'\n\nRevisão atual não candidata;nenhuma aceitação integralI1–I3 por contagem de testes. Cadastro básico de oportunidades não é dossier privado;operaçãoQA13 não criou dossier/etapa nem alterou as6oportunidades publicadas. Rascunho imobiliárioQA14 não é decisão externa nem contrato completo.')
insert(root / 'docs/investmoz/v2/gestao-oportunidades-dashboard.md', '## Estado corrente:acesso ao dashboardC43 —10/10/2026\n\n'+causes+'\n\n'+facts+'\n\n[Ensaio desde o dashboard](auditoria-portal/demonstracao-dashboard-oportunidades.md),[matriz única](auditoria-portal/matriz-requisitos.csv),[pedidos abertos/backlog](auditoria-portal/backlog.md),[evidências](auditoria-portal/relatorio-executivo.md). API/persistência/assetsQA demonstrados;visual eativação pendentes.393geometrias e schema110defs não encerram o cadastro funcional.')
path = private / 'investor-path-evidence.json'
evidence_json = json.loads(path.read_text())
evidence_json['code_hash'] = runtime['code_hash']
evidence_json['resource_code_hash'] = runtime['resource_code_hash']
evidence_json['geometry_code_hash'] = runtime['geometry_code_hash']
evidence_json['dashboard_increment'] = {'cases': ['C43', 'C44'], 'qa_proofs': ['dashboard-opportunities-http-qa.json', 'dashboard-manager-mfa-http-qa.json', 'dashboard-navigation-catalogue-qa.json', 'real-estate-draft-http-qa.json', 'dashboard-real-estate-qa.xml'], 'visual_passed': False, 'active_enabled': False, 'canonical_matrix_requirements': 3354, 'open_requirements': 3349}
for key in ['integrated_ui_ab_passed', 'candidate_revision_fixed', 'activation_ready', 'active_activation_authorized', 'c37_browser_acceptance_passed']:
evidence_json[key] = False
evidence_json['current_active_backup_compatibility_renewal_required'] = True
path.write_text(json.dumps(evidence_json, indent=2, ensure_ascii=False), encoding='utf-8')
print(json.dumps({'canonical_matrix_preserved': True, 'current_reports_updated': 7, 'open_requirements': projection['open_requirements'], 'active_writes': 0}))