83 lines
11 KiB
Python
83 lines
11 KiB
Python
"""Append verified lease criteria to the existing matrix; preserve all previous evidence."""
|
|
from pathlib import Path
|
|
from datetime import datetime, timezone
|
|
from collections import Counter
|
|
import csv, hashlib, json, sys
|
|
csv.field_size_limit(20_000_000)
|
|
root=Path(__file__).resolve().parent.parent
|
|
private=root/'storage/app/private/investmoz-v2/portal-audit'
|
|
docs=root/'docs/investmoz/v2/auditoria-portal'
|
|
packet=private/'functional-lease-consolidation-20261011'
|
|
read=lambda p:json.loads(p.read_text(encoding='utf-8-sig'))
|
|
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
|
|
ui=read(private/'functional-lease-workflow-chromium-20261011.json')
|
|
sql=read(private/'functional-lease-workflow-persistence-qa-20261011.json')
|
|
assert ui['result']==sql['result']=='passed' and sql['id']==ui['opportunity_id']==54
|
|
tag='[QA 11/10/2026 — arrendamento54 completo / consolidada] '
|
|
ids={'AUD-OP-01','AUD-OP-02','AUD-OP-03','AUD-OP-04','AUD-PROFILE-01','AUD-PROFILE-07','AUD-PROFILE-25','AUD-PROFILE-28','AUD-UI-01'}
|
|
evidence='Arrendamento54: três PDFs próprios de título/registo, licença de utilização e avaliação, explicitamente SIMULAÇÃO QA, upload por UI→scan real ClamD→download/hash em nova sessão; Promotor21 submete→Validador24 solicita correção fundamentada→Promotor21 corrige/resubmete→três revisões independentes24→aprovação24→Publicador25 disponibiliza com acesso restrito. Quatorze recuperações de UI/Response mantêm renda4500 MZN/periodicidade monthly; SQL, snapshots de edição e auditoria coincidem. QA23/organização distinta recebe403 no contrato e no documento; autor não tem ações de aprovação/publicação. Provas functional-lease-workflow-chromium-20261011.json / functional-lease-workflow-persistence-qa-20261011.json. Provas anteriores de múltiplos papéis, seis categorias, coedição, A/B e C37 reutilizadas sem repetição.'
|
|
remaining='Substitui a pendência de submissão/correção/documentos/revisão/publicação da variante arrendamento54 registada no lote anterior: esses critérios passaram em QA, com renda/periodicidade preservadas. Permanecem variantes de construção planeada/ocupação/limites urbanísticos, demais variantes das seis categorias, Response§27 integral, ACL documental individual, restauração da oportunidade por decisão distinta, leitor de ecrã/dispositivos reais/PDFs etiquetados e dependências de ativação. Não confere contrato/direito real nem publicação pública.'
|
|
if sys.argv[1]=='prepare':
|
|
assert not packet.exists();packet.mkdir()
|
|
edits=[]
|
|
for name in ['matriz-requisitos.csv','backlog-priorizado.csv']:
|
|
rows=list(csv.reader((docs/name).open(encoding='utf-8-sig',newline='')));headers=rows[0];patches=[]
|
|
for i,row in enumerate(rows[1:],1):
|
|
if row[headers.index('ID')] not in ids:continue
|
|
notes={'Evidência funcional':evidence,'Lacuna':remaining,'Interface':'Workflow por três perfis na mesma QA HTTPS; recuperação de correção e resultado publicado noutra sessão.','API':'POST workflow200 em submissão/correção/revisões/aprovação/publicação; GET response200 a cada transição, QA23 contrato/anexo403.','Gravação':'JSON canónico existente conserva4500/monthly/MZN; três documentos próprios cifrados e scaneados; atores e decisões auditados.','Recuperação':'Novas sessões e SQL verificam dados, documentos, hash da versão aprovada/publicada e âmbito restrito.','Resultado apresentado':'Arrendamento publicado apenas com acesso restrito autorizado; nenhuma reposição automática de publicação nem direito real certificado.','Consolidação':'C125/f07f34a11eab integrado na próxima revisão única; candidata3d9d392e0a0f preservada. Apenas critérios acima encerrados; requisito geral conserva o estado.'} if name=='matriz-requisitos.csv' else {'Pendência':remaining,'Correção/componentes':'Reutilizar os contratos/recursos/workflow existentes; '+evidence,'Ordem do próximo lote':'Candidata única do âmbito demonstrado com C125. Próximos critérios: variantes explicitadas por categoria, Response compatível versus normativo, ACL individual e decisões R-ARCHIVE/R-DRAFT; não bloquear workflow isolado com190000. Backup/restauro QA renovado com acervo29/metadata3 e três PDFs próprios54; alvo ativo requer verificação futura própria.'}
|
|
patch={}
|
|
for key,value in notes.items():
|
|
assert tag not in row[headers.index(key)]
|
|
patch[key]=row[headers.index(key)]+'\n'+tag+value
|
|
patches.append({'row':i,'values':patch})
|
|
assert len(patches)==len(ids)
|
|
edits.append({'filename':name,'input_sha256':sha(docs/name),'rows':rows,'patches':patches,'allowed_columns':sorted({k for x in patches for k in x['values']}),'source_hash_updates':[]})
|
|
(packet/'csv-edits.json').write_text(json.dumps({'files':edits},ensure_ascii=False),encoding='utf-8')
|
|
print(json.dumps({'existing_requirements_updated':len(ids),'new_requirements':0,'files':2}))
|
|
elif sys.argv[1]=='finalize':
|
|
for e in read(packet/'csv-edits.json')['files']:
|
|
rows=list(csv.reader((docs/e['filename']).open(encoding='utf-8-sig',newline='')));expected=[list(r) for r in e['rows']]
|
|
for p in e['patches']:
|
|
for k,v in p['values'].items():expected[p['row']][rows[0].index(k)]=v
|
|
assert rows==expected
|
|
rows=list(csv.DictReader((docs/'matriz-requisitos.csv').open(encoding='utf-8-sig',newline='')))
|
|
assert len(rows)==3401 and sum(int(r['Quantidade de linhas de origem']) for r in rows)==7739
|
|
counts=Counter(r['Estado'] for r in rows)
|
|
assert counts==Counter(read(private/'segmentation-reconciliation-20261011/counts.json')['states'])
|
|
criteria=[
|
|
['Projeto', '30; rascunho52', 'Contrato, materialidade/condições, correção/revisão/aprovação/publicação recuperadas.', 'Cenários económicos/licenças externos aplicáveis; análise interna não certifica viabilidade.'],
|
|
['Imobiliário', 'Venda31; arrendamento54', 'Venda preservada. Arrendamento com documentos próprios, correção, três gates independentes e publicação restrita;4500 MZN/mês preservados.', 'Construção planeada/em curso, ocupação contratada, encargos e limite urbanístico por ramo; sem inventar ato/direito real.'],
|
|
['Fundiário', '32', 'Dependência externa bloqueia publicação; ramo positivo sintético explicitamente identificado, aprovação/publicação restrita e recuperação.', 'Casos reais de consulta/conflitos/encargos/área/cadastro.173 correspondências pendentes e Mandie/Guro ambíguo preservados.'],
|
|
['Venda de negócio', '33', 'Identidade societária, confidencialidade, condição, aprovação independente e teaser público com documentos protegidos.', 'Interesse no anúncio /negocios/{slug}/manifestar-interesse e suas estatísticas; financeiros/histórico por variante; entidade sem histórico é decisão separada.'],
|
|
['Parceria', '34', 'Voto reabre só dois gates; demais pareceres conservados; condição/aprovação/publicação restrita recuperadas.', 'Contribuições monetárias/não monetárias por modalidade e documentação própria; ACL documental individual de oportunidade não demonstrada.'],
|
|
['Franquia', '35', 'Registo societário reabre apenas gate aplicável, preservando financeiro/licença/confidencialidade; aprovação/publicação restrita recuperadas.', 'Exclusividade, royalties, titularidade de licença e território por ramo próprio.'],
|
|
]
|
|
table='| Categoria | Casos reutilizados | Critérios demonstrados | Critérios restantes |\n| --- | --- | --- | --- |\n'+''.join('| '+' | '.join(r)+' |\n' for r in criteria)
|
|
marker='<!-- workflow-lease-consolidated-20261011 -->'
|
|
text=f'''{marker}
|
|
## Arrendamento completo e critérios atuais — 11/10/2026
|
|
|
|
{evidence}
|
|
|
|
{table}
|
|
|
|
Comuns: Response de compatibilidade recuperável (`normative_response_complete=false`), sem conversões de IDs/história; §27 integral continua parcial. R-ARCHIVE e R-DRAFT são decisões distintas pendentes, sem implementar restauração automática. Acessibilidade das9rotas/320/390px já demonstrada é preservada; teclado/leitor real, PDFs etiquetados e dispositivos físicos não se tornam concluídos por este ensaio. Legado, ofertas, competências modulares e SLA permanecem frentes separadas. COUNTRY02 ativo e fechos A/B/C37 preservados. Nenhuma alteração ativa.
|
|
|
|
Matriz:3401requisitos/linhas;7739ocorrências.9linhas existentes atualizadas em cada projeção,0novosIDs, estados gerais preservados; o percurso específico de arrendamento fica demonstrado em QA.
|
|
'''
|
|
# Replace current contradictory lease criteria; historical reports/receipts remain immutable.
|
|
f=docs/'workflow-criterios-saida-20261011.md';existing=f.read_text(encoding='utf-8')
|
|
assert marker not in existing
|
|
existing=existing.replace('O caso visual é venda; os ensaios semânticos de arrendamento são só em memória. Não encerra o percurso específico de arrendamento.', 'Arrendamento54 teve agora ensaio completo de UI/API/SQL com documentos próprios; consultar a atualização consolidada abaixo.')
|
|
lines=existing.splitlines()
|
|
for i,line in enumerate(lines):
|
|
if line.startswith('| Imobiliário,31 |'):
|
|
lines[i]='| Imobiliário,31 e arrendamento54 | Venda31 preservada;54 mantém renda4500 MZN/monthly, três documentos próprios scaneados, nova sessão e erros junto à renda previamente demonstrados. | Promotor21 submete→Validador24 solicita correção→Promotor21 corrige/resubmete→três gates24→aprovação24→Publicador25 disponibiliza com acesso restrito;14 recuperações de UI/Response e SQL confirmam renda/periodicidade. | Construção planeada, ocupação contratada, encargos e limites urbanísticos por variante; sem direito real ou decisão externa presumidos. |'
|
|
elif line.startswith('| Imobiliário |'):
|
|
lines[i]='| Imobiliário | Venda31 e arrendamento54 demonstrados;54 preserva4500 MZN/mês. Construção/ocupação/limites urbanísticos ainda por variante. | Venda: titular alterado reabre registry_urban_review; arrendamento: correção/revisão independente nos três gates, hashes assinados recuperados. | Três documentos próprios de54: título/registo, licença e avaliação, todos SIMULAÇÃO QA com scan real/recuperação por hash; ramos documentais restantes pendentes. | Response compatível recuperado, forma normativa§27 ainda parcial; IDs/história preservados. |'
|
|
f.write_text('\n'.join(lines)+'\n\n'+text,encoding='utf-8')
|
|
for filename in ['relatorio-executivo.md','backlog.md']:
|
|
f=docs/filename;old=f.read_text(encoding='utf-8');assert marker not in old;f.write_text(text+'\n'+old,encoding='utf-8')
|
|
(packet/'verification.json').write_text(json.dumps({'at':datetime.now(timezone.utc).isoformat(),'result':'passed','requirements':3401,'source_occurrences':7739,'states':dict(counts),'rows_updated':9,'new_requirements':0,'matrix_sha256':sha(docs/'matriz-requisitos.csv'),'backlog_sha256':sha(docs/'backlog-priorizado.csv'),'A_B_C37_closures_preserved':True},ensure_ascii=False,indent=2),encoding='utf-8')
|
|
print(json.dumps({'result':'passed','requirements':3401,'source_occurrences':7739,'states_unchanged':True,'rows_updated':9}))
|