"""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]}))