145 lines
21 KiB
Python
145 lines
21 KiB
Python
"""Publish readable reconciliation, preserving the sealed workflow candidate."""
|
||
from pathlib import Path
|
||
from datetime import datetime, timezone
|
||
from zipfile import ZipFile
|
||
from collections import Counter
|
||
import hashlib, json, csv, shutil, re, xml.etree.ElementTree as ET
|
||
|
||
csv.field_size_limit(20_000_000)
|
||
root=Path(__file__).resolve().parent.parent
|
||
private=root/'storage/app/private/investmoz-v2/portal-audit'
|
||
directory=private/'segmentation-reconciliation-20261011'
|
||
docs=root/'docs/investmoz/v2/auditoria-portal'
|
||
read=lambda name:json.loads((directory/name).read_text(encoding='utf-8'))
|
||
provenance=read('source-provenance.json');counts=read('counts.json');correspondence=read('correspondence.json')
|
||
aliases=read('document-aliases.json');blocks=read('request-blocks.json');legal=read('legal-reference-links.json')
|
||
digest=provenance['sha256']
|
||
matrix=list(csv.DictReader((docs/'matriz-requisitos.csv').open(encoding='utf-8-sig',newline='')))
|
||
by_id={r['ID']:r for r in matrix}
|
||
assert len(matrix)==counts['requirements'] and len(by_id)==len(matrix)
|
||
assert sum(int(r['Quantidade de linhas de origem']) for r in matrix)==counts['source_occurrences']
|
||
assert dict(Counter(r['Estado'] for r in matrix))==counts['states']
|
||
packet=read('csv-edits.json')
|
||
before=packet['files'][0];original={r[0]:dict(zip(before['rows'][0],r)) for r in before['rows'][1:]}
|
||
for rid,row in original.items():
|
||
for field in ['ID','Pedido/trecho','Estado','Critério de aceitação','Disponibilidade ativa']:
|
||
assert row[field]==by_id[rid][field], 'Prior decision/state changed: '+rid+' '+field
|
||
previous=json.loads(row['Critérios e versões por origem (JSON)'] or '[]')
|
||
current=json.loads(by_id[rid]['Critérios e versões por origem (JSON)'] or '[]')
|
||
assert current[:len(previous)]==previous,'Original source history lost'
|
||
for name,h in json.loads((private/'functional-active-files-before-20261011.json').read_text()).items():
|
||
assert hashlib.sha256((root/name).read_bytes()).hexdigest()==h,'Active application changed'
|
||
|
||
# Add to the existing source inventory JSON, retaining its entire previous snapshot.
|
||
inventory_path=private/'inventario-fontes.json'
|
||
backup=directory/'source-registry-before.json'
|
||
if not backup.exists():shutil.copy2(inventory_path,backup)
|
||
inventory=json.loads(inventory_path.read_text(encoding='utf-8-sig'))
|
||
known={(x['path'],x['sha256']) for x in inventory['files']}
|
||
prior_inventory=json.loads(backup.read_text(encoding='utf-8-sig'))
|
||
prior_known={(x['path'],x['sha256']) for x in prior_inventory['files']}
|
||
added=[]
|
||
for item in provenance['source_directory_inventory']:
|
||
if (item['path'],item['sha256']) in known:continue
|
||
entry={**item,'consultation':'Inventariado; original selecionado privadamente apenas em QA. Não inferir divulgação.',
|
||
'rule_use':'Nenhuma regra/cálculo ativado pela incorporação.',
|
||
'legal_document_state':'Preservar origem; documento de programação não equivale a diploma oficial.'}
|
||
if item['sha256']==digest:entry.update({'retained':provenance['retained'],'QA_library_resource':29,'requested_filename_identity_pending':True,'version_properties':provenance['version_properties']})
|
||
inventory['files'].append(entry);added.append(item['path'])
|
||
inventory['segmentation_source_added']={'at':datetime.now(timezone.utc).isoformat(),'sha256':digest,
|
||
'observed_filename':provenance['observed_filename'],'requested_filename':provenance['expected_filename'],
|
||
'exact_requested_exemplar_confirmed':False,'added_files':sum((x['path'],x['sha256']) not in prior_known for x in provenance['source_directory_inventory']),'inventory_restart':False,'publication':False,'calculation_activation':False}
|
||
inventory_path.write_text(json.dumps(inventory,ensure_ascii=False,indent=2),encoding='utf-8')
|
||
|
||
new_ids=set(counts['new_IDs'])
|
||
def clean(s):return s.replace('|','/').replace('\n',' ')
|
||
section_table=[]
|
||
for item in correspondence:
|
||
ids=item['requirements'];states=sorted({by_id[rid]['Estado'] for rid in ids})
|
||
if item['section']=='3.3.1':action='Reutilizar workflow6categorias/contratos, evidências e segregação; ofertas/modulares permanecem separados.'
|
||
elif item['section'].startswith('1.8'):action='Conferir artigo/âmbito/período por regra; conservar acesso/alterações/redação separados, sem reabrir fonte aceite.'
|
||
elif any(rid in new_ids for rid in ids):action='Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio.'
|
||
else:action='Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz.'
|
||
section_table.append('| '+clean(item['heading'])+' / p'+str(item['paragraphs'][0])+'–'+str(item['paragraphs'][-1])+' | '+', '.join(ids)+' | '+', '.join(states)+' | '+action+' |')
|
||
|
||
alias_table=[]
|
||
for alias,ids in aliases.items():
|
||
alias_table.append('| '+alias+' | '+', '.join(ids)+' | '+('Acrescentado, sem correspondência direta' if all(x in new_ids for x in ids) else 'Reutilizado/complementado')+' |')
|
||
increments=[
|
||
('Workflow base', ['AUD-OP-03','AUD-PROFILE-28'], 'Candidata3d9d392e0a0f: seis ramos ensaiados, materialidade, condições, recursos, mapas/filtros e9rotas de acessibilidade. Sem code/bundle novo nesta incorporação.', '030000→040000/permissões/ClamD/processamento;190000 só para percurso integrado. Variantes semânticas/documentais/§27 e restauro continuam delimitadas no relatório da candidata.'),
|
||
('Fiscal/contributivo', ['AUD-SIM-01','AUD-SIM-02'], 'SimulationFormDrafts, SimulationTaxParameterResolver/RuleGovernance/Execution e resultados/fontes existentes; provasA/B reutilizadas.', 'Fechar/recolher/reabrir preservando cenários; comparar/exportar com versões e memória. INSS e cada imposto exigem parâmetros/âmbito/período identificados; indeterminado em vez de zero. Não ativar regra fiscal pela importação.'),
|
||
('Negócios similares/importação', ['AUD-MARKET-01','AUD-ESTABLISHMENT-01'], 'Cadastros e serviços ExistingBusiness/MNE, organizações e cartografia mestres. DoisXLSX já constam do inventário do diretório de origem.', 'Inspecionar folhas/colunas, IDs, cobertura, datas e conflitos; correspondência inequívoca, rejeições e cargaQA idempotente. Não converter estabelecimento observado em oportunidade. Pesquisa por raio exige geometria/coordenada real.'),
|
||
('Fundos', ['AUD-FUND-01'], 'Biblioteca e parceiros/entidades como fontes; RF-CLU-005 como requisito relacionado.', 'Catálogo com gestor/cobertura/datas/estado/elegibilidade e explicação de correspondência. Obter os conteúdos reais; não inventar fundos ou datas e não aprovar financiamento.'),
|
||
('Societário/modelos', ['AUD-COMPANY-01','AUD-COMPANY-02'], 'Organização mestre, perfil/dossier e biblioteca/revisions/links.', 'Perguntas e alternativas com fontes/limites; distinguir sociedade/empresário/representação/consórcio. Localizar exemplares/URLs de modelos antes de afirmar disponibilidade; conferir a redação específica, sem segunda validação oficial.'),
|
||
('Capitalização/Bolsa', ['AUD-CAPITAL-01','AUD-CAPITAL-02'], 'Biblioteca, conteúdo público, dossier e encaminhamento existentes.', 'Guias versionados com preparação/riscos/documentos; distinguir Bolsa/Banco de Moçambique/operador; segmentos e atos específicos. Ofertas e competências modulares não são aprovadas por esta incorporação.'),
|
||
('Checklists configuráveis', ['AUD-CHECKLIST-01'], 'Catálogo config/document-requirements e requisitos/formulários/tarefas/documentos do Balcão.', 'Editor/preview/publicação de versões; três camadas independentes(comercial/registo/licença). Manter versão da submissão. Entidade/ato/artigo/canal concreto, sem regra/SLA inventados.'),
|
||
('Indicadores de utilização', ['MASTER-e1169a77-0018'], 'Eventos/auditoria/filas/tarefas existentes; estatísticas de origem são outro consumidor.', 'Definir denominador/eventos/período/dimensões para abandono/conclusão/tempo; não inferir investidor único de solicitações nem taxa de sucesso de investimento. Metas/calendário/responsáveis permanecem decisão operacional.'),
|
||
]
|
||
increment_table=['| '+name+' | '+', '.join(ids)+' | '+reuse+' | '+next_action+' |' for name,ids,reuse,next_action in increments]
|
||
report='''# Incorporação e reconciliação de segmentar processos
|
||
|
||
O exemplar acessível **segmentar processos v1.docx** foi conservado e importado privadamente na bibliotecaQA existente. **Ainda não foi localizado nem confirmado o exemplar solicitado segmentar processos v1(3).docx.** Não se declara identidade entre esses ficheiros; a pergunta sobre o caminho exato permanece pendente. O sufixo de nome(3) não é tratado como versão funcional3.
|
||
|
||
Esta reconciliação usa o original disponível e os pedidos expressos desta sessão, preservando o histórico. A confirmação do exemplar solicitado é o critério documental restante; se os bytes forem diferentes, comparar as secções antes de alterar os vínculos. Não repetir provas funcionais por uma simples cópia de nome diferente.
|
||
|
||
'''
|
||
report+=f"Original: `{provenance['source']}`. SHA-256 **{digest}**, {provenance['bytes']}bytes. PropriedadesOOXML: criador{provenance['version_properties']['creator']}, revision{provenance['version_properties']['revision']}, criação{provenance['version_properties']['created']}, alteração{provenance['version_properties']['modified']}. São propriedades do exemplar, sem inferir aprovação, autoria certificada ou vigência jurídica.\n\n"
|
||
report+='907parágrafos,14tabelas,74secções;0objetos/imagens incorporados,0alterações acompanhadas e notas/cabeçalhos/rodapés verificados estruturalmente. Referências usam `word/document.xml#pN` e tabela/linha/célula na extração; não foram inventados números de página. Não foi produzida nem editada uma versãoDOCX.\n\n'
|
||
report+=f"**Mesma matriz:** {counts['old_requirements']}→{counts['requirements']}requisitos/linhas;39IDs anteriores complementados,8IDs novos apenas para pedidos sem correspondência direta. {counts['source_request_blocks']}blocos de pedido deste exemplar, {counts['added_source_occurrences']}ligações acrescentadas, {counts['source_occurrences']}ocorrências totais. Estados: "+'; '.join(f'{n} {s}' for s,n in counts['states'].items())+'. Nenhum estado/critério de aceitação anterior foi alterado.327blocos não significam327novos requisitos; relações de um bloco a vários requisitos são contadas separadamente.\n\n'
|
||
report+='## Evidência do acervoQA\n\n'
|
||
report+='QA: `https://portal-investidor.test:18445`, base `stability_consumers_20261011_084534_test:55441`, guarda antes de providers e antes de qualquer escrita. Prévia sem mutação→importação existente por gestorQA17 autorizado→ClamDreal/mesmohash→repetição sem duplicação→recuperação dos mesmosbytes. Recurso29/documento589ed9ac-967e-439e-9dde-b0fb3996e546, revisão/auditoria de criação1, classificação interna, published=false. Nenhuma conta, organização, representação, oportunidade, tabela ou regra criada por este lote.\n\n'
|
||
report+='Chromium/HTTPS reconhecido: gestão mostra o exemplar, clique no download devolve o hash original, nova sessão recupera; PromotorQA21 não autorizado recebe403, download público29 recebe404. Não houve publicação ou cálculo. Recibos `segmentation-reconciliation-20261011/library-preview/apply/replay-qa.json` e `segmentation-library-chromium-20261011.json`. Estes ensaios comprovam o consumidor documental, não funcionalidades futuras descritas noDOCX.\n\n'
|
||
report+='## Aliases documentais para IDs existentes\n\n| Referência noDOCX | ID na mesma matriz | Tratamento |\n| --- | --- | --- |\n'+'\n'.join(alias_table)+'\n\n'
|
||
report+='## Secção para requisito, estado e próxima ação\n\nA extração completa conserva cada pedido e o seu locator. O ficheiroJSON de correspondência é uma projeção das referências acrescentadas à matriz, sem backlog independente. Estados abaixo são os do requisito completo; provas pontuaisQA não são fechos globais.\n\n| Secção/parágrafos do exemplar | Requisitos | Estado na matriz | Próxima ação |\n| --- | --- | --- | --- |\n'+'\n'.join(section_table)+'\n\n'
|
||
report+='## Incrementos executáveis\n\n| Incremento | Requisitos | Reutilização/progresso | Critério restante |\n| --- | --- | --- | --- |\n'+'\n'.join(increment_table)+'\n\n'
|
||
report+='## Divergências preservadas\n\n'
|
||
report+='- Versão anterior `segmentar processos .docx`, SHA256 `fef1f3b0835ce5e2a47ee4e7127b665c741f63d4f73a3a819b88dce2a5801b54`: §1.3 dizia compra/venda de terra; §3 listava formas/relações societárias e interpretações de responsabilidade/quotas. O v1§1.4/3.3.1/6.3/9 restringe terra às modalidades admitidas, separa empresário/sociedades/representações/consórcio e pede redação pertinente. Originais e variantes preservados; nenhuma conversão de cadastros ou adoção dessas frases como regra.\n'
|
||
report+='- §2 organiza releasesF0–F4; não substitui as cinco fases/19 etapas nem renumeraE0… existentes. §3.2.1 não unifica estados de domínios.\n'
|
||
report+='- §3.1 usa perfis genéricos; seguemRBAC/ABAC/perfisv1 existentes. Entidade externa não recebe papel ou poder por figurar no documento. Coedição organizacional previamente aprovada e demonstrada preservada.\n'
|
||
report+='- §3.3.1 usa agrupamentos funcionais; investimento/imobiliário/fundiário/venda/parceria/franquia mantêm códigos e contratos. Concessão/fornecimento/procura ou oferta de capital não se tornam uma categoria base nova. As ofertas e competências modulares permanecem decisões separadas.\n'
|
||
report+='- §6 afirma gestão básica/modelos ativos: contraposição com leitura ativa atual e exemplares/URLs concretos requerida. Ativo temCOUNTRY02 e020/050, sem030/040/190,0organizações/representações e0geometrias; workflow ampliado deste lote éQA. “Sem demonstração suficiente” não é prova de ausência de código.\n'
|
||
report+='- §7p811 pede validação de conteúdo institucional antes de publicação: a aceitação oficial de08/10 tem precedência sobre credibilidade/proveniência já aceites. Conferir artigo, âmbito, período, retificação, alteração ou revogação concreta continua necessário à aplicação; não exigir nova certificação genérica.\n'
|
||
report+='- §§2.2/4.1.1/7.3/8.4–8.5 propõem metas/calendário/responsáveis/SLA; não são compromissos aprovados nem prazos de entidade externa. Nenhuma nomeação realizada.\n\n'
|
||
report+='## Referências legais e regras\n\n'
|
||
report+='Referências dos§§1.0.2/1.8 estão ligadas aos requisitos de checklists, perfil, comparador, fiscalidade, capitalização e admissão pertinentes. O registo `legal-reference-links.json` separa acesso declarado, alterações/revogações declaradas e redação proposta pelo exemplar. Não atribui a esta execução a pesquisa que o documento relata; nem atribui artigo/competência a regra inexistente.\n\n'
|
||
report+='Regra fiscal/contributiva: usarSimulationTaxRuleGovernance/ParameterResolver existentes somente com fonte/artigo/período/parâmetros concretos; o vínculo documental não grava nem ativa uma versão no motor. Checklist: Código Comercial/obrigações gerais, registo/publicidade e regime setorial têm efeitos independentes. BVM: admissão, supervisão e patrocínio são competências distintas. Relações ainda sem artigo específico ficam pendentes e visíveis.\n\n'
|
||
report+='Verificação técnica adicional: o [PDF do Código do Mercado de Valores Mobiliários no Banco de Moçambique](https://www.bancomoc.mz/media/bvhi3j4e/decreto-lei-4_2009_24-de-julho_aprova-o-codigo-do-mercado-de-valores-mobiliarios.pdf) foi recuperado pela ferramentaweb. OsURLs doBR229 noINTIC e do regulamento de admissão naBVM não foram recuperados nessa tentativa. Isso não revoga a aceitação das fontes nem demonstra revogação/vigência. Nenhum artigo novo foi adotado no motor.\n\n'
|
||
report+='## Candidata e condições de disponibilização\n\n'
|
||
report+='Candidata de workflow **3d9d392e0a0f**, código **df6be252f1a0**, ZIP SHA256 **6366c49d44cdc4242f4f93da5f5c1a53f2292d9eb485f70ef2b4e9a9f88589e9** preservados: nenhuma alteração de código/bundle pelas referências deste documento. Relatório, manifesto e procedimento selados não foram sobrescritos. A importação documental é um incremento de dados privadoQA posterior ao backup dessa candidata e fica fora doZIP e do ensaio de restauro de12:10:22UTC. Renovar snapshot/restauro se este acervo for incluído num pacote futuro.\n\n'
|
||
report+='Dependências ativas continuam concretas: atualizar/manter assinaturasClamD3310, demonstrarworker supervisionado, designações/perfis/representações legítimos e backup/restauro/prévias correspondentes. Para o workflow:020→030→040 somente se ausentes por ação autenticada;190 só quando se disponibilizar o percurso integrado. Mapas ativos exigem ativação cartográfica separada. Não foram ativados030/040/190, importações, legado, ofertas, módulos ouSLA.\n\n'
|
||
report+='COUNTRY02 ativo e fechosA/B/C37 conservados. Contenção futura do workflow desabilita apenas as suasflags, preservandoHTTPS/cookie/cifra/COUNTRY02/schema/documentos/histórico. O original desta incorporação não é publicado; eventual retirada do recurso será lógica/auditada, sem apagar bytes. Restauro integral ou eliminação de dados ativos exige decisão própria. R-ARCHIVE/R-DRAFT continuam propostas; a incorporação não decide restauração de oportunidades.\n'
|
||
|
||
# Plain prose spacing; identifiers and hashes retain their exact bytes.
|
||
report=re.sub(r'(\d+)(bytes|parágrafos|tabelas|secções|objetos|alterações|requisitos|linhas|blocos|ligações|ocorrências|IDs|rotas|categorias|contas|organizações|geometrias)(?=\b)',r'\1 \2',report)
|
||
report=report.replace('v1.docx**','v1.docx**').replace('COUNTRY02ON','COUNTRY02 ON')
|
||
(docs/'segmentacao-processos-reconciliacao-20261011.md').write_text(report,encoding='utf-8')
|
||
out=root/'outputs/investmoz-segmentation-reconciliation-20261011';out.mkdir(exist_ok=True)
|
||
(out/'relatorio.md').write_text(report,encoding='utf-8')
|
||
for name in ['correspondence.json','document-aliases.json','legal-reference-links.json','counts.json']:
|
||
shutil.copy2(directory/name,out/name)
|
||
summary='''<!-- segmentation-reconciliation-20261011:begin -->
|
||
|
||
## Segmentação de processos incorporada em QA com confirmação de exemplar pendente
|
||
|
||
[Correspondência completa por secção, requisito, estado e próxima ação](segmentacao-processos-reconciliacao-20261011.md). Exemplar local`segmentar processos v1.docx`,SHA256`bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5`,OOXMLrevision15/11-10. O pedido identifica`v1(3).docx`,ainda não localizado/confirmado; não declarar os exemplares equivalentes.
|
||
|
||
Mesma matriz3401requisitos/linhas,7739ocorrências;39IDs anteriores complementados,8IDs novos por ausência de correspondência direta.327blocos/74secções. Estados:7concluídos,3236parciais,152não implementados,1implementado/não ativo,5dependentes de decisão. Nenhum fecho anterior reaberto.
|
||
|
||
AcervoQA:prévia/ClamDreal/mesmoSHA/repetição sem duplicação/recuperação, recurso29privado. Chromium gestão/download/nova sessão passaram; Promotor403/público404. Não publicou, não ativou regra/cálculo, não criou identidade/tabela. Workflow6categorias/candidata3d9d392e0a0f reutilizados, sem alterarZIP. COUNTRY02 ativo,A/B/C37 fechados preservados. Dados desta incorporação são posteriores ao backupQA da candidata; incluir num pacote futuro exige renovar o snapshot correspondente.
|
||
|
||
Próximos incrementos: fiscal/contributivo(AUD-SIM-01/02), negócios similares/importação(AUD-MARKET-01/ESTABLISHMENT-01), fundos(AUD-FUND-01), comparador/modelos(AUD-COMPANY-01/02), capitalização/BVM(AUD-CAPITAL-01/02), editor de checklists(AUD-CHECKLIST-01), utilização(MASTER-e1169a77-0018). Ofertas/competências modulares/SLA e restauro proposto continuam decisões separadas. Nenhuma ativação adicional autorizada.
|
||
|
||
<!-- segmentation-reconciliation-20261011:end -->
|
||
|
||
'''
|
||
for filename in ['backlog.md','relatorio-executivo.md']:
|
||
file=docs/filename;current=file.read_text(encoding='utf-8-sig');assert 'segmentation-reconciliation-20261011:begin' not in current
|
||
file.write_text(summary+current,encoding='utf-8')
|
||
receipt={'result':'passed','at':datetime.now(timezone.utc).isoformat(),'counts':counts,
|
||
'preserved_original_requirements':len(original),'protected_fields_and_old_source_history_preserved':True,
|
||
'active_critical_files_preserved':True,'actual_requested_exemplar_pending':True,'active_writes':0,
|
||
'sealed_workflow_candidate_not_rewritten':True,'files':{f.name:hashlib.sha256(f.read_bytes()).hexdigest() for f in out.iterdir() if f.is_file()}}
|
||
(directory/'reconciliation-integrity.json').write_text(json.dumps(receipt,ensure_ascii=False,indent=2),encoding='utf-8')
|
||
(out/'verificacao.json').write_text(json.dumps(receipt,ensure_ascii=False,indent=2),encoding='utf-8')
|
||
print(json.dumps({'result':'passed','requirements':len(matrix),'old_requirements_preserved':len(original),'added_source_files':len(added),'active_writes':0},ensure_ascii=False))
|