Files
Investidor-V2/tools/portal-functional-fixed-registry.py
nala 287e991486
tests / ci (push) Waiting to run
oportunidades 7
2026-10-13 11:40:29 +02:00

34 lines
3.7 KiB
Python

"""Bind the final immutable candidate and shared COUNTRY02 compatibility proof."""
from pathlib import Path
from datetime import datetime,timezone
import csv,json,hashlib,collections
csv.field_size_limit(20000000)
root=Path(__file__).resolve().parent.parent;doc=root/'docs/investmoz/v2/auditoria-portal';private=root/'storage/app/private/investmoz-v2/portal-audit'
out=root/'outputs/investmoz-opportunity-workflow-candidate-20261011';p=json.loads((out/'pacote.json').read_text())
old=json.loads((private/'functional-finalize-20261011/counts.json').read_text());ids=set(old['changed_IDs'])|{'AUD-COUNTRY-02'}
folder=private/'functional-fixed-finalize-20261011';folder.mkdir(exist_ok=True);packet={'proof_filename':'csv-authoring-proof.json','files':[]}
tag='[Revisão fixa workflow QA 11/10/2026] '
for name in ['matriz-requisitos.csv','backlog-priorizado.csv']:
f=doc/name;raw=f.read_bytes()
with f.open(encoding='utf-8-sig',newline='')as stream:rows=list(csv.reader(stream))
h=rows[0];patches=[]
for number,row in enumerate(rows[1:],1):
rid=row[h.index('ID')]
if rid not in ids:continue
def append(k,v):
old_value=row[h.index(k)];assert tag not in old_value
return old_value+'\n'+tag+v
evidence=f"Candidata final {p['revision'][:12]}, código {p['code_revision'][:12]}, ZIP SHA-256 {p['sha256']}; outputs/investmoz-opportunity-workflow-candidate-20261011/pacote.json,manifesto.json,relatorio.md,procedimento.md. A preparação5a81cd3c3998 foi substituída apenas por complemento de evidência/efeito no fingerprint COUNTRY02; código/bundle/backup QA idênticos. functional-country-compatibility-qa-20261011.json: ativo162daff6ce08 intacto; candidato b244311e5b28, extensão QA instalada/ON."
dependency='A alteração futura de PortalProfileAccess muda o fingerprint de COUNTRY02/prévias, sem novas colunas, dados ou mudança de cifra. Renovar prévias/readiness/chaves quando necessário; não reaplicar050000 já instalado. COUNTRY02 ativo e A/B/C37 preservados. Candidata030/040 não autorizada para ativo;190000 apenas percurso integrado. AssinaturasClamD/worker/habilitações legítimas/backup-alvo e geometrias para limites continuam condições explicitadas.'
if name=='matriz-requisitos.csv':
values={'Evidência funcional':append('Evidência funcional',evidence),'Dependência':append('Dependência',dependency),'Versões divergentes':append('Versões divergentes','Revisão preparatória5a81substituída por3d9d apenas em prova/metadata, sem mudança de código df6be252f1a0. Fechos/IDs/fontes/aceitação anteriores conservados.')}
else:values={'Correção/componentes':append('Correção/componentes',evidence),'Dependência/pergunta':append('Dependência/pergunta',dependency)}
patches.append({'row':number,'values':values})
assert len(patches)==25
packet['files'].append({'filename':name,'input_sha256':hashlib.sha256(raw).hexdigest(),'rows':rows,'patches':patches,'allowed_columns':sorted({k for x in patches for k in x['values']})})
if name=='matriz-requisitos.csv':
counts={'at':datetime.now(timezone.utc).isoformat(),'requirements':len(rows)-1,'rows':len(rows)-1,'source_occurrences':sum(int(x[h.index('Quantidade de linhas de origem')])for x in rows[1:]),'states':dict(collections.Counter(x[h.index('Estado')]for x in rows[1:])),'updated_IDs':sorted(ids),'candidate':p['revision'],'active_writes':0}
assert counts['states']==old['states'] and counts['requirements']==3393 and counts['source_occurrences']==6845
(folder/'csv-edits.json').write_text(json.dumps(packet,ensure_ascii=False),encoding='utf-8');(folder/'counts.json').write_text(json.dumps(counts,ensure_ascii=False,indent=2),encoding='utf-8')
print(json.dumps({'matrix_rows':3393,'source_occurrences':6845,'updated_requirements':25,'states_preserved':True,'candidate':p['revision'][:12]}))