270 lines
33 KiB
Python
270 lines
33 KiB
Python
"""Prepare targeted edits and reconcile existing reports from completed QA receipts, no database access."""
|
||
import collections
|
||
import csv
|
||
import hashlib
|
||
import json
|
||
import re
|
||
from datetime import datetime, timezone
|
||
from pathlib import Path
|
||
|
||
csv.field_size_limit(16000000)
|
||
ROOT = Path(__file__).resolve().parent.parent
|
||
DOC = ROOT / 'docs/investmoz/v2/auditoria-portal'
|
||
PRIVATE = ROOT / 'storage/app/private/investmoz-v2/portal-audit'
|
||
OUT = PRIVATE / 'legacy-sectors-finalize-20261010'
|
||
OUT.mkdir(exist_ok=True)
|
||
def read(name):
|
||
return json.loads((PRIVATE / name).read_text(encoding='utf-8'))
|
||
http = read('legacy-sectors-http-qa.json')
|
||
browser = read('legacy-sectors-browser-qa.json')
|
||
persistence = read('legacy-sectors-persistence-qa.json')
|
||
imported = read('legacy-sectors-apply-qa.json')
|
||
replay = read('legacy-sectors-replay-qa.json')
|
||
backup = read('profile-installation-backup-qa.json')
|
||
copy = json.loads((PRIVATE.parent / 'portal-qa-recovery/20261010_154445/damaged-copy-proof.json').read_text())
|
||
origin = read('legacy-financial-origin-20261010/proof.json')
|
||
assert http['result'] == browser['result'] == 'passed'
|
||
assert backup['restore_verified'] and backup['files_restore_verified'] and backup['target'] == imported['target']
|
||
assert copy['all_names_sizes_hashes_equal'] and len(persistence['cases']) == 8
|
||
assert datetime.fromisoformat(backup['verified_at']) >= datetime.fromisoformat(browser['completed_at'].replace('Z', '+00:00'))
|
||
assert origin['html_http_status'] == origin['inertia_http_status'] == 200 and origin['initial_origin_content_length'] == origin['inertia_origin_content_length'] == 0
|
||
assert imported['before']['opportunities'] == imported['after']['opportunities'] == 49
|
||
assert replay['before'] == replay['after'] and len(imported['resources']) == 22
|
||
stamp = datetime.now(timezone.utc).isoformat()
|
||
tag = '[Setores QA após C71 10/10/2026] '
|
||
rows = list(csv.reader((DOC / 'matriz-requisitos.csv').open(encoding='utf-8-sig', newline='')))
|
||
headers = rows[0]
|
||
canonical = {r[0]: dict(zip(headers, r)) for r in rows[1:]}
|
||
assert len(canonical) == len(rows) - 1 == 3393
|
||
backup_tables = len(backup['tables'])
|
||
backup_files = len(backup.get('files', []))
|
||
assert backup_tables == 295 and backup_files == 103
|
||
evidence = ('22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos/recursos/auditoria/scans. '
|
||
'Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia200. '
|
||
'Chromium desktop:16 artigos, pesquisa/imagens, Energia e Mineração distintas, C72 título preservado; QA21 criou4 dossiers, retorno, logout/novaMFA/F5/replay; QA23 negado403 e anónimo sem contexto. '
|
||
'Persistência READ ONLY:8 dossiers HTTP/Chromium, uma referência/evento cada,22 hashes únicos,0 relações geográficas automáticas. '
|
||
'legacy-sectors-{apply,replay,http,browser,persistence}-qa.json; legacy-financial-origin-20261010/proof.json. C37/QA18,A/B,móvel/acessibilidade/cobertura integral não encerrados.')
|
||
ops_evidence = (f'C71 corrigido somenteQA: novo cluster íntegro em diretório estável, mesma porta55441/base;295 tabelas/34.902 linhas byte-a-byte e31sequências preservadas. '
|
||
f'Schema/owners/ACL/triggers comparados semanticamente;2 constraints varchar/text e slots de coluna normalizados, sem afirmar DDL byte-a-byte. '
|
||
f'Cluster danificado original e cópia retidos:{copy["files"]} ficheiros, todos nomes/bytes/hashes iguais. '
|
||
f'Backup/restauro posterior ao lote:{backup["verified_at"]},295tabelas/103ficheiros,restauro em{backup["restored_target"]["database"]}:55441. '
|
||
'APP_KEY/MFA/conta18 preservados. Históricos QA preservados fisicamente, não todos restaurados no novo runtime. Provas portal-qa-recovery/20261010_154445 e profile-installation-backup-qa.json. Candidata global não fixada.')
|
||
updates = {}
|
||
for requirement in ['AUD-OPS-01'] + [f'AUD-LEG-{i:02d}' for i in range(1, 8)]:
|
||
old = canonical[requirement]
|
||
update = {}
|
||
update['Evidência funcional'] = old['Evidência funcional'] + ' | ' + tag + (ops_evidence if requirement == 'AUD-OPS-01' else evidence)
|
||
update['Consolidação'] = old['Consolidação'] + ' | ' + tag + 'Mesmo ID/referências/versões. Subcritérios deste lote demonstrados emQA; decisões e aceitações independentes mantidas.'
|
||
variants = json.loads(old['Critérios e versões por origem (JSON)'])
|
||
for variant in variants:
|
||
variant['incremento_setores_qa_20261010'] = {'atualizado_em': stamp, 'ambito': 'QA18097;base55441isolada',
|
||
'evidencia': ops_evidence if requirement == 'AUD-OPS-01' else evidence,
|
||
'estado_requisito_atual': 'parcial' if requirement == 'AUD-OPS-01' else old['Estado'],
|
||
'exclusoes': ['ativação', 'C37/QA18', 'A/B', 'móvel', 'acessibilidade', 'cobertura integral']}
|
||
update['Critérios e versões por origem (JSON)'] = json.dumps(variants, ensure_ascii=False, separators=(',', ':'))
|
||
if requirement == 'AUD-OPS-01':
|
||
update['Estado'] = 'parcial'
|
||
update['Lacuna'] = ('C71 técnico resolvido emQA; falta aceitação global C37/QA18,A/B,demais consumidores e revisão candidata. '
|
||
'Futura ativação exige snapshot/backup/restauro próprios do ativo e ações autenticadas;CLI--actor é apenas atribuiçãoQA. '
|
||
'Não repetir030/040/09-190naQA. | Histórico da falha e lacunas anteriores: ' + old['Lacuna'])
|
||
update['Critério de aceitação'] = ('Revisão/destino atual, backup/restauro integral correspondente, guarda/compatibilidade/reversão e ativação autenticada única; '
|
||
'QA atual295tabelas/103ficheiros demonstrada. Não substitui prova ativa. | Critério de versão anterior preservado: ' + old['Critério de aceitação'])
|
||
update['Gravação'] = old['Gravação'] + ' | ' + tag + 'Recuperação em destino vazio isolado; comparações e backup/restauro verificados,0escritasativas.'
|
||
update['Recuperação'] = old['Recuperação'] + ' | ' + tag + ops_evidence
|
||
update['API'] = old['API'] + ' | ' + tag + 'QA18097/login200 após retirada da manutenção; alvo real55441confirmado.'
|
||
update['Resultado apresentado'] = old['Resultado apresentado'] + ' | ' + tag + 'Manutenção retirada; percursos setoriais recuperados. Aceitação QA18 permanece independente.'
|
||
else:
|
||
for field in ['Interface', 'API', 'Gravação', 'Recuperação', 'Resultado apresentado']:
|
||
update[field] = old[field] + ' | ' + tag + evidence
|
||
pending = {
|
||
'AUD-LEG-01': '18/50 versões observadas cadastradas:17comtexto consultáveis e1vazia privada;32versões ainda não importadas, sitemap/paginação/cobertura histórica eC68pendentes.',
|
||
'AUD-LEG-02': 'Identidade aplicada e desktop dos novos setores observado; acessibilidade sistemática/móvel e restantes conteúdos pendentes. Editor Assunto opcional C74 sem ensaio visual próprio.',
|
||
'AUD-LEG-03': 'Quatro percursos setoriais com retorno e nova sessão demonstrados; relações territoriais concretas, ferramenta/Balcão/acompanhamento deA/B e demais perfis continuam independentes.',
|
||
'AUD-LEG-04': 'Consulta pública/proteção privada dos setores demonstradas. Disponibilização ativa,C37/QA18,A/B e aceitações manuais adicionais permanecem separadas.',
|
||
'AUD-LEG-05': 'Mesma biblioteca/versão/imagem reutilizada. Turismo editorial sem geometrias inferidas; relações territoriais e por etapa ainda exigem fundamento concreto.',
|
||
'AUD-LEG-06': '17caminhos comtexto preservados incluindo agronegócio e4novos retornos; restante mapaURL/aliases/acervo ainda incompleto. C37/QA18 eA/B não encerrados.',
|
||
'AUD-LEG-07': '22originais/5imagens/hashes/scans/replay e16novos artigos públicos testados;32versões restantes, anexos/links externos/C68,móvel/acessibilidade e perfis adicionais por testar.'}
|
||
update['Lacuna'] = pending[requirement] + ' | Histórico anterior: ' + old['Lacuna']
|
||
updates[requirement] = update
|
||
canonical[requirement].update(update)
|
||
|
||
packet = {'captured_at': stamp, 'files': []}
|
||
def table(name):
|
||
raw = (DOC / name).read_bytes()
|
||
return list(csv.reader(raw.decode('utf-8-sig').splitlines(keepends=True))), hashlib.sha256(raw).hexdigest()
|
||
def add(name, data, digest, patches, allowed, appended=None, source_hash_updates=None):
|
||
packet['files'].append({'filename': name, 'input_sha256': digest, 'rows': data, 'patches': patches,
|
||
'allowed_columns': allowed, 'append': appended or [], 'source_hash_updates': source_hash_updates or []})
|
||
data, digest = table('matriz-requisitos.csv')
|
||
add('matriz-requisitos.csv', data, digest, [{'row': i, 'values': updates[r[0]]} for i, r in enumerate(data) if i and r[0] in updates],
|
||
list(set(k for value in updates.values() for k in value)))
|
||
states = collections.Counter(r['Estado'] for r in canonical.values())
|
||
assert sum(states.values()) == 3393 and states['concluído e demonstrado'] == 7 and states['com falha'] == 0
|
||
|
||
data, digest = table('backlog-priorizado.csv')
|
||
bh = data[0]; patches = []; known = set()
|
||
for i, values in enumerate(data[1:], 1):
|
||
old = dict(zip(bh, values)); item = canonical[old['ID']]; known.add(old['ID'])
|
||
new = {'Prioridade': item['Prioridade'], 'Estado': item['Estado'], 'Pendência': item['Lacuna'],
|
||
'Dependência/pergunta': item['Dependência'], 'Aceitação': item['Critério de aceitação']}
|
||
if old['ID'] in updates:
|
||
new['Correção/componentes'] = 'Biblioteca/importador/LegacyContent/portal/legacy/percurso existentes; QA cluster/backup quandoOPS01; ver relatório atual.'
|
||
new['Ordem do próximo lote'] = 'C37/A-B e aceitações independentes; continuar expansão/documentos/países/cartografia sem reabrir fontes oficiais.'
|
||
changed = {k: v for k, v in new.items() if old[k] != v}
|
||
if changed: patches.append({'row': i, 'values': changed})
|
||
appended = []
|
||
for requirement, item in canonical.items():
|
||
if requirement not in known:
|
||
new = {'Prioridade': item['Prioridade'], 'ID': requirement, 'Estado': item['Estado'], 'Pendência': item['Lacuna'],
|
||
'Correção/componentes': item['Implementação encontrada'], 'Dependência/pergunta': item['Dependência'],
|
||
'Aceitação': item['Critério de aceitação'], 'Ordem do próximo lote': 'Critério individual; consultar backlog atual e matriz única'}
|
||
appended.append([new[h] for h in bh])
|
||
assert len(data) - 1 + len(appended) == 3393
|
||
add('backlog-priorizado.csv', data, digest, patches, [h for h in bh if h != 'ID'], appended)
|
||
manifest = json.loads((ROOT / 'storage/app/private/document-import-staging/legacy-setores-20261010/manifest.json').read_text(encoding='utf-8'))
|
||
resources = {r['external_id']: r for r in imported['resources']}
|
||
by_url = {r['source_url'].rstrip('/'): resources[r['external_id']] for r in manifest['documents']}
|
||
for filename in ['legado-inventario.csv', 'legado-conteudos-reconciliados.csv']:
|
||
data, digest = table(filename); h = data[0]; patches = []
|
||
for i, values in enumerate(data[1:], 1):
|
||
item = dict(zip(h, values)); row = None
|
||
if filename == 'legado-inventario.csv': row = by_url.get(item['URL'].rstrip('/'))
|
||
else:
|
||
row = next((r for r in resources.values() if r['external_id'].startswith('legacy-tempo-post-' + item['ID legado'] + '-')), None)
|
||
if row:
|
||
empty = row['external_id'].startswith('legacy-tempo-post-171994-')
|
||
status = (f'RecursoQA{row["id"]}; original/hash/ClamD/replay demonstrados. ' +
|
||
('Corpo vazio na origemHTML/Inertia200;privado,sem página publicada.' if empty else 'DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.'))
|
||
changes = {'Situação': status}
|
||
if filename == 'legado-inventario.csv': changes['Destino proposto'] = f'biblioteca existente recursoQA{row["id"]};URLs/versão originais preservados'
|
||
else: changes['Recurso QA'] = str(row['id'])
|
||
patches.append({'row': i, 'values': changes})
|
||
add(filename, data, digest, patches, ['Situação', 'Destino proposto', 'Recurso QA'])
|
||
|
||
block = f'''<!-- qa-c71-sectors-result-20261010:begin -->
|
||
## Resultado atual — {stamp}
|
||
|
||
**QA18097 recuperada; nenhuma alteração na base ativa.** C71 técnico corrigido: faltavam26 ficheiros de catálogos partilhados, incluindo `global/2964`, necessários ao `pg_dump`. O agente/processo que os removeu continua desconhecido. O cluster danificado foi preservado e substituído por cluster novo em diretório estável, apenas no alvoQA55441. As295tabelas/34.902linhas e31sequências iniciais conferiram; schema/owners/ACL/triggers equivalentes após normalização explícita de2constraints varchar/text e slots de colunas removidas. A cópia física retida confere em{copy['files']}ficheiros por nomes, tamanhos ehashes; isso não afirma restauro lógico de todos os bancos históricosQA.
|
||
|
||
**Backup/restauro posterior ao lote:** {backup['verified_at']},295tabelas e103ficheiros privados conferidos em `{backup['restored_target']['database']}:55441`. APP_KEY, MFA e contas preservados. Não é prova de backup da base ativa nem fixa candidata global. QA/login voltou aHTTP200; manutenção arquivada. 2FAS Auth continua compatível com TOTP; a rejeição manualQA18 registada foi de palavra-passe antes do MFA, sem justificar troca de aplicação.
|
||
|
||
| Requisito / caso | Evidência deste lote | Lacuna concreta |
|
||
| --- | --- | --- |
|
||
| AUD-OPS-01 / C71 | Cluster saudável, dados/sequências/permissões preservados, backup/restauro renovado,0escritasativas. Estado global passa de com falha para parcial. | C37/QA18,A/B e outros consumidores; candidata e backup ativo/autorização própria. |
|
||
| AUD-LEG-01/05/07 |22ficheiros (17artigos+5imagens) importados privadamente, hashes recuperados,22scans ClamD reais; replay sem duplicações/eventos/scans novos. |32das50versões observadas continuam não importadas; sitemap misto/paginação/links externos/C68 e cobertura integral. |
|
||
| AUD-LEG-02/03/06 / C72 |16artigos novos comtexto públicos, título deInfraestruturas preservado. Chromium desktop: imagens/pesquisa/artigos→MFA21→4dossiers→retorno→logout→nova sessão→F5/replay. HTTP e persistência separados,8dossiers no total. | Móvel/acessibilidade/mais perfis e percursosA/B completos não encerrados. |
|
||
| AUD-LEG-04 |Leitura pública; guardar requer login. Anónimo/QA23 sem contexto privado; QA23recebe403 ao dossier alheio. Estado de consulta/proteçãoQA mantido concluído no âmbito demonstrado. | Disponibilização ativa e demais aceitações são independentes. |
|
||
| Mercado Financeiro |OrigemHTML e respostaInertiaHTTP200 contêm corpo vazio; exemplar22 no lote fica privado na biblioteca (recurso23). `/mercado-financeiro` e respetiva exploração404,sem página vazia apresentada como entrega. | Obter conteúdo real/versão comtexto; não usar Fintech nem inventar corpo. |
|
||
| C74 |Imagens semAssunto eram recusadas porPUT422. QA aceita tema vazio sem inferir setor; interface tornaAssunto opcional. Cinco metadados vazios guardados/recuperados; teste dedicado1/11. | Editor administrativo sem ensaio visual próprio; alteração protegida pela guardaQA. |
|
||
|
||
**Contagens canónicas:**3393requisitos/3393linhas,6845ocorrências de origem; {states['parcial']}parciais,145não implementados,5dependentes de decisão,1implementado mas não ativado,7concluídos e demonstrados,0com falha. Casos adicionais e aceitações abertas continuam visíveis dentro dos requisitos parciais;0com falha global não significa portal sem erros. BacklogCSV é projeção reconciliada dos mesmos3393IDs, incluindo39 anteriormente omitidos, não outra matriz.
|
||
|
||
**RotasQA:** `/explorar/energia-mineracao` → `/energia-mineracao`, `/energia`, `/mineracao`; `/explorar/turismo` → `/turismo` e11artigos territoriais; `/explorar/infraestruturas` → `/infraestruturas`. Agronegócio preservado. Energia/Mineração são fontes distintas; Turismo mantém texto editorial e0associações territoriais automáticas. Todos os dados de fonte/autoria/datas/hash/URLs/versões originais são conservados. Os artigos não criaram oportunidades (49antes/depois), geometrias ou perfis. Divulgação foi uma ação autenticada do gestorQA14 pelo mecanismo existente, separada da importaçãoCLIQA (atribuição `--actor`, não autenticação ativa); nenhum desafioMFA foi observado nessa conta. QA21/QA23 usaramMFA normalmente.
|
||
|
||
**Próximo trabalho executável:** restantes32versões/acervo eC68 por ficheiro; Response/§27/validações, PDFs/derivadas epaíses/origem/estatísticas por consumidor;173correspondências territoriais ainda abertas comMandie/Guroambíguo. Não acrescentar jornadas educativas para contornar essas pendências. Perfis modulares eSLA conservam decisões próprias. C37/QA18,A/B,móvel/acessibilidade permanecem abertos; este lote não demonstraCRUD/workflow de oportunidades nem os encerra.
|
||
|
||
**Ativação futura:** revisão/hashes/flags e aceitação global→leitura/backup/restauro do ativo correspondente→código/build compatíveis com flags desligadas→030000→040000→09/190000 somente se ausentes→importação privada de conteúdo/cartografia com prévia e scan→divulgação separada→disponibilização incremental. QA já tem as3instalações;não as repetir. Previsão desta extensão:22originais (reutilizar hashes existentes),21potencialmente divulgáveis e1exemplar vazio privado;0contas/dossiers/opportunities/geometrias transferidos. O CLIrecusa aplicação ativa: falta preparar/demonstrar uma ação autenticada emlote que preserve exatamente as identidades/versionamento existentes; upload unitário não foi provado equivalente. Cartografia:408candidatas/173pendentes no retratoQA anterior, não importadas por esta frente. `ready=true` continua preparação, não instalação/disponibilização.
|
||
|
||
**Reversão:** retirar divulgação em ações auditadas e ocultar consumidores/flag, preservando originais, versões, consentimentos/referências eeventos. Restauro técnico usa o novo dump íntegro e chave estável numa QA distinta,comparação antes de corte;não voltar ao cluster danificado. Nunca drop de tabelas utilizadas nem copiar fixturesQA para o ativo. Provas: `legacy-sectors-{{apply,replay,http,browser,persistence}}-qa.json`, `legacy-financial-origin-20261010/proof.json`, `portal-qa-recovery/20261010_154445/*-proof.json` e `profile-installation-backup-qa.json` (privadas,sem credenciais/cookies/códigos nas capturas).
|
||
|
||
**Versões históricas preservadas abaixo:** frases sobreC71aberto,22ficheiros apenas preparados ou rotas apenas deagronegócio descrevem os incrementos anteriores e são substituídas, para o estado atual, pelas provas desta secção.
|
||
<!-- qa-c71-sectors-result-20261010:end -->
|
||
'''
|
||
def legible(value):
|
||
value = re.sub(r'\b(as|As|de|e|os|em|por)(?=\d)', r'\1 ', value)
|
||
value = re.sub(r'(\d+)(tabelas|linhas|ficheiros|sequências|constraints|instalações|artigos|imagens|itens|originais|versões|referências|eventos|scans|dossiers|requisitos|ocorrências|parciais|correspondências|nomes|exemplar|contas|pendentes|candidatas|não|dependentes|implementado|concluídos|com|das|novos|potencialmente)', r'\1 \2', value)
|
||
for old, new in {'comtexto': 'com texto', 'semtexto': 'sem texto', 'sem página': 'sem página', 'original/hash/ClamD': 'original / hash / ClamD',
|
||
'semcontorno': 'sem contorno', 'semcontas': 'sem contas', 'apósguarda': 'após guarda', 'porficheiro': 'por ficheiro',
|
||
'preservedos': 'preservados', 'privadas,sem': 'privadas, sem', 'ativos,sem': 'ativos, sem',
|
||
'21divulgados': '21 divulgados', '1artigo': '1 artigo', 'comQA21': 'com QA21',
|
||
'QA23negado403': 'QA23 negado 403', 'das50': 'das 50', 'eC68imagem404': 'e C68 (imagem 404)',
|
||
'19etapas': '19 etapas', '3393IDs': '3393 IDs', '39estavam': '39 estavam',
|
||
':22': ': 22', ':3393': ': 3393', ',6845': ', 6845', ';3235': '; 3235', ',145': ', 145',
|
||
',5 dependentes': ', 5 dependentes', ',1 implementado': ', 1 implementado', ',7 concluídos': ', 7 concluídos',
|
||
',0 com falha': ', 0 com falha', 'CLI--actor': 'CLI `--actor`',
|
||
'sequência030→040→09/190': 'sequência 030000 → 040000 → 09/190000'}.items():
|
||
value = value.replace(old, new)
|
||
return value
|
||
block = legible(block)
|
||
backlog_block = f'''<!-- qa-c71-sectors-result-20261010:begin -->
|
||
## Prioridades atuais após C71 — {stamp}
|
||
|
||
**QA recuperada e lote setorial demonstrado; base ativa fora do âmbito.** C71 técnico corrigido, com backup/restauro final de295tabelas/103ficheiros. AUD-OPS-01 volta a parcial, porque aceitação global e ativação continuam pendentes. Biblioteca:22novos originais importados/scaneados;21divulgados por ação separada e1artigo vazio privado. Chromium desktop comQA21:4dossiers criados, retorno, logout/novaMFA/F5/replay; QA23negado403. Ver relatório executivo e provas individuais.
|
||
|
||
| Prioridade / requisito | Falta e próxima ação | Critério concreto |
|
||
| --- | --- | --- |
|
||
| P0 / AUD-UI-01,C37/QA18 | Incorporar tentativa manual sanitizada; primeira rejeição atual foi de palavra-passe, antes do MFA. 2FAS continua compatível; sem nova aplicação ou reset de segredo. | MFA→`/investimentos`→F5→logout→novo login na sessão problemática; não usar QA21 como substituto. |
|
||
| P1 / AUD-LEG-01/06/07 |32das50versões ainda não importadas, sitemap/paginação/acervo eC68imagem404. Reconciliar próximo lote por identidade/hash/citação. | Prévia, armazenamento privado, scan real, replay/recuperação e divulgação separada; não inventar corpo de Mercado Financeiro. |
|
||
| P1 / AUD-LEG-02/03/07 | Móvel/acessibilidade/mais perfis e editor administrativo C74 sem ensaio visual próprio; restantes ligações/consumidores. | Prova de cada ação visível e permissão; preservar confirmação manual limitada do piloto e diferenças entre versões. |
|
||
| P1 / percurso,I0–I3,A/B | Cenários completos com ferramenta→resultado→Balcão→acompanhamento, e ações do dashboard/workflow continuam independentes. | Cinco fases/19etapas, nova sessão, preparação paralela, isolamento/permissões, retorno ao dossier. |
|
||
| P1 / países e cartografia | Completar países/origem/filtros/estatísticas por formulário e173correspondências territoriais; Mandie/Guro permanece ambíguo. | UI→API→gravação→recuperação→resultado por consumidor; território≠geometria≠mapa. |
|
||
| P1 / documentos,Response/§27 | Completar condições semânticas, PDFs/exportações/derivadas por consumidor. | Scan próprio, originais/hash preservados, permissões e resultados recuperáveis. |
|
||
| P1/P2 / decisões e ativação | Perfis modulares/SLA, calendário/nomeações reais e candidata permanecem separados. Preparar ação autenticada de importação em lote preservando identidade:CLI--actor sóQA. | Decisão concreta por regra; backup/restauro da base ativa da candidata e sequência030→040→09/190 sem repetições. |
|
||
|
||
**Mesma matriz:**3393requisitos/linhas,6845ocorrências;3235parciais,145não implementados,5dependentes de decisão,1implementado mas não ativado,7concluídos e demonstrados,0com falha global. O backlogCSV agora projeta todos os3393IDs;39estavam omitidos. Casos/aceitações dentro dos parciais continuam abertos. As secções abaixo são histórico anterior à recuperação/importação, não o estado atual.
|
||
<!-- qa-c71-sectors-result-20261010:end -->
|
||
'''
|
||
activation_block = f'''<!-- qa-c71-sectors-result-20261010:begin -->
|
||
## Preparação atual após recuperação e lote setorial — {stamp}
|
||
|
||
C71 corrigido emQA: comparação integral e backup/restauro renovado {backup['verified_at']} ({backup_tables}tabelas/{backup_files}ficheiros), em `{backup['restored_target']['database']}:55441`. Esta prova não é backup do ativo nem fixa candidata. C37/QA18,A/B,móvel/acessibilidade/outros consumidores e decisões próprias permanecem pendentes.
|
||
|
||
1. Concluir as aceitações da revisão; fixar código/manifesto/configuração e hashes. A guarda atual do legado continua restrita aQA; código preparado não é habilitação ativa.
|
||
2. Conferir o alvo ativo por leitura e provar backup/restauro próprio dessa revisão, incluindo ficheiros e chave estável. O último retrato ativo anterior continua histórico.
|
||
3. Disponibilizar código/build compatíveis com flags desligadas; preservarURLs,IDs,roteiros/consentimentos. Não copiar contas ou dossiers sintéticos.
|
||
4. Prévia e aplicação autenticadas030000→040000→**2026_10_09_190000_prepare_investor_path**, apenas se ausentes e coerentes. QA já tem as3: não repetir. O Balcão07/190 não substitui a extensão09/190; dependências/efeitos e bootstrap separado estão na tabela histórica abaixo.
|
||
5. Conteúdo: prévia/hash/identidade/versão, armazenamento privado eClamD. **22candidatos do lote (17artigos+5imagens)**;17artigos comtexto no total incluindo piloto anterior,1exemplar vazio privado. Reutilizarbytes/identidades já existentes; qualquer conflito fica pendente. A CLI com--actor é apenas ensaioQA, não instalação autenticada ativa. Ainda falta preparar/demonstrar um ponto autenticado de importação emlote com as mesmas identidades; upload unitário não foi demonstrado equivalente.
|
||
6. Cartografia emlote distinto, por pais e correspondências inequívocas; retratoQA408candidatas/173pendentes, Mandie/Guroambíguo.0geometrias importadas nesta frente; medir novamente no alvo. Publicação das camadas separada.
|
||
7. Divulgar os conteúdos autorizados em ação própria: previsão21recursos deste lote; Mercado Financeiro permanece privado/vazio e nunca apresentado como página concluída. QA demonstrou divulgação autenticada do gestor14, sem presumir MFA não observado. Aprovação/consulta/cálculo/decisão externa são estados independentes.
|
||
8. Disponibilizar consumidores/percurso incrementalmente após provas;0fixturesQA transferidos. `ready=true` não instala, não publica e não fecha requisitos.
|
||
|
||
**Reversão:** retirar divulgação e ocultar consumidores/flags com auditoria, mantendo originais, versões, fontes dos dossiers eeventos. Preferir reconciliação/restauro numaQA distinta comdump íntegro/chave preservada antes de corte; não reativar o cluster danificado nem eliminar tabelas utilizadas. Conservados o original danificado e a cópia física de{copy['files']}ficheiros (nomes/tamanhos/hashes iguais), sem afirmar restauro lógico de todos os históricos no novo runtime. Plano não executado na base ativa.
|
||
|
||
As secções abaixo preservam a evolução anterior; referências aC71aberto ou lote apenas preparado foram superadas pelas provas atuais, sem apagar dependências independentes.
|
||
<!-- qa-c71-sectors-result-20261010:end -->
|
||
'''
|
||
reports = {'relatorio-executivo.md': block, 'legado-piloto-qa.md': block, 'backlog.md': legible(backlog_block), 'plano-ativacao.md': legible(activation_block)}
|
||
for filename, current_block in reports.items():
|
||
path = DOC / filename
|
||
original = path.read_text(encoding='utf-8')
|
||
archive = OUT / (filename + '.before')
|
||
if not archive.exists(): archive.write_text(original, encoding='utf-8')
|
||
original = re.sub(r'<!-- qa-c71-sectors-result-20261010:begin -->.*?<!-- qa-c71-sectors-result-20261010:end -->\s*', '', original, flags=re.S)
|
||
title, body = original.split('\n', 1)
|
||
path.write_text(title + '\n\n' + current_block + '\n' + body.lstrip(), encoding='utf-8')
|
||
case_path = DOC / 'casos-reproducao.md'
|
||
case = case_path.read_text(encoding='utf-8')
|
||
case_block = f'''<!-- qa-c71-sector-cases-20261010:begin -->
|
||
## Estado dos casos C71–C76 após o lote — {stamp}
|
||
|
||
**C71 / AUD-OPS-01:** causa/operação/reprodução históricas preservadas abaixo. CorrigidoQA: recuperação emcluster novo, comparação295tabelas/34.902linhas/31sequências e schema/permissões compatíveis; cópia física{copy['files']}ficheiros com hashes iguais. Prévia22itens renovada antes de aplicação; backup/restauro final295/103verificado. Processo que removeu26catálogos continua não identificado; nenhum remendo de catálogo ou rotação de chave. Requisito inteiro parcial pelas demais dependências/ativação. A manutenção foi retirada; GET/login200no18097. Ver provas no relatório atual.
|
||
|
||
**C72 / AUD-LEG-02/07:** título deInfraestruturas desaparecia pelo sanitizador excluirh1/filhos; h1→h2 preserva conteúdo e limpeza. Agora exemplar importado/scaneado/consultável e título observado no Chromium, captura `infra-original-heading`; original/hash intacto. CorrigidoQA, não ativo.
|
||
|
||
**C73 / AUD-UI-01/C37:** a manutenção técnica é independente das3rejeições de palavra-passe15:38–15:39UTC; estas ocorreram antes do MFA. QA18secret/chave/credencial reconfirmados15:57:57porREADONLY. 2FAS Auth já suportaTOTP; não requer nova aplicação/remoção da entrada antiga. C37continua pendente no navegador do responsável, sem novo ensaio MFA18 deste lote.
|
||
|
||
**C74 / AUD-LEG-07, consumidor documental:** reproduzir comimagem do manifesto semtema: login gestorQA14→PUT `/management/portal-services/resources/24` comAssuntovazio→HTTP422campo`topic`. Esperado: guardar metadados originais autorizados seminventarassociação. Causa: importador admite vazio, validaçãoAPI/frontend exigiamvalor. CorreçãoQA: tema nullable sobguarda realQA, vazio normalizado para stringcompatível; interfaceAssuntoopcional. RepetiçãoPUTs das5imagens+recuperaçãoSQL/download passaram; originais/hashes/scans/ausência de relações preservados. Teste dedicado1/11asserções; visualdoeditor ainda pendente. DivulgaçãoPOSTseparada, semcontorno da autorização.
|
||
|
||
**C75 / AUD-LEG-02/03, regressão detectada antes da divulgação:** GET `/explorar/agronegocio` no testeLegacyContentTest retornava500 na nova parametrização, `Undefined property stdClass::$title`. Causa: projeçãoSQL selecionava documento mas omitia título do recurso usado nas leituras relacionadas. Corrigido incluindo`r.title`; teste4/81eHTTP/Chromium passaram. Não atribuir ao middleware. Nenhuma ocorrência ativa alegada.
|
||
|
||
**C76 / AUD-LEG-03/06, regressão detectada antes da divulgação:** POST `/investimentos` comartigo válido retornava422. Esperado: validar ID da biblioteca e guardar fonte numdossier próprio. Causa: `value(d.external_id)`sobrebuilder comprojeção pré-existente lia primeiro campoUUID; não encontrava a identidade configurada. Correção: leitura explícita`first()?->external_id`, preservando controles público/hash/scan/contexto. Testes4/81; HTTP4dossiers/Chromium4dossiers eREADONLY8referências únicas. CorrigidoQA, nenhuma escrita ativa.
|
||
|
||
Falhas do harness conservadas separadamente: primeira leitura usou indevidamente rota pública de download para exemplar privado404 (a rota protegida correta é `/management/documents/{{UUID}}/download`); recompilação durante sessãoInertia produziu409/reload esperado; primeiras esperasnetworkidle/imagem ainda não decodificada falharam sob concorrência. Corrigida ordenação/espera no teste, sem alterar autenticação/aplicação para fabricar sucesso. Histórico de tentativasprivadas preservado; resultado final sófoi declarado após percursos completos.
|
||
<!-- qa-c71-sector-cases-20261010:end -->
|
||
'''
|
||
case = re.sub(r'<!-- qa-c71-sector-cases-20261010:begin -->.*?<!-- qa-c71-sector-cases-20261010:end -->\s*', '', case, flags=re.S)
|
||
title, body = case.split('\n', 1)
|
||
case_path.write_text(title + '\n\n' + legible(case_block) + '\n' + body.lstrip(), encoding='utf-8')
|
||
data, digest = table('inventario-fontes.csv'); h = data[0]; patches = []; source_updates = []
|
||
for i, values in enumerate(data[1:], 1):
|
||
item = dict(zip(h, values)); exemplar = Path(item['Exemplar/caminho'])
|
||
if exemplar.parent == DOC and exemplar.name in ['legado-piloto-qa.md', 'legado-inventario.csv', 'legado-conteudos-reconciliados.csv']:
|
||
patches.append({'row': i, 'values': {'Nota de leitura': 'C71 recuperado e 22 originais QA importados/scaneados; 21 divulgados separadamente; 16 novos artigos e 4 dossiers demonstrados. Históricos/restrições preservados. | Nota anterior: ' + item['Nota de leitura'],
|
||
'Edição/versão identificada': item['Edição/versão identificada'] + ' | loteQAsetores' + stamp + '; exemplar anteriorSHA256=' + item['SHA256']}})
|
||
source_updates.append({'row': i})
|
||
add('inventario-fontes.csv', data, digest, patches, ['Nota de leitura', 'Edição/versão identificada', 'SHA256', 'Bytes'], source_hash_updates=source_updates)
|
||
(OUT / 'csv-edits.json').write_text(json.dumps(packet, ensure_ascii=False), encoding='utf-8')
|
||
(OUT / 'counts.json').write_text(json.dumps({'requirements': len(canonical), 'rows': len(rows) - 1, 'source_occurrences': 6845,
|
||
'states': dict(states), 'canonical_backlog_missing_rows_added': len(appended), 'active_writes': 0}, ensure_ascii=False, indent=2), encoding='utf-8')
|
||
print(json.dumps({'prepared_csv_tables': 5, 'matrix_rows': len(updates), 'backlog_missing_rows': len(appended), 'states': dict(states), 'database_access': False}, ensure_ascii=False))
|