184 lines
9.6 KiB
JavaScript
184 lines
9.6 KiB
JavaScript
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
|
|
function reconcile(item, audit) {
|
|
const row = item.record;
|
|
const metadata = JSON.parse(row.metadata || '{}');
|
|
const evidence = JSON.parse(row.source_evidence || '[]');
|
|
const legal =
|
|
(audit.legal_sources || []).find(
|
|
(source) => source.id === row.legal_source_id,
|
|
) || null;
|
|
const dossiers = audit.dossiers.filter(
|
|
(d) => d.project_id === row.id || d.cluster_id === row.id,
|
|
);
|
|
const officialReferences = evidence.filter((source) =>
|
|
['government', 'institutional'].includes(source.source_type),
|
|
);
|
|
const documentaryRelations = Object.entries(
|
|
metadata.documented_location_sources || {},
|
|
).map(([key, source]) => ({ key, ...source }));
|
|
return {
|
|
kind: item.kind,
|
|
id: row.id,
|
|
reference: row.code || row.reference || String(row.id),
|
|
existing_record_validation: row.validation_status ?? null,
|
|
existing_legal_validation: legal?.validation_status ?? null,
|
|
legal_source: legal,
|
|
official_references: officialReferences,
|
|
non_official_references: evidence.filter(
|
|
(source) =>
|
|
!['government', 'institutional'].includes(source.source_type),
|
|
),
|
|
documentary_relations: documentaryRelations,
|
|
dossiers: dossiers.map((d) => ({
|
|
id: d.id,
|
|
source: d.source,
|
|
version: d.version_no,
|
|
})),
|
|
traceability:
|
|
legal || officialReferences.length
|
|
? 'official_reference_identified'
|
|
: documentaryRelations.length || dossiers.length
|
|
? 'documentary_bridge_to_official_source_to_recover'
|
|
: 'official_source_link_not_identified_in_records_reviewed',
|
|
official_validation_newly_granted: false,
|
|
validation_revoked: false,
|
|
calculation_activated: false,
|
|
};
|
|
}
|
|
|
|
module.exports = { reconcile };
|
|
if (require.main === module) {
|
|
const root = path.resolve(__dirname, '..');
|
|
const privateDir = path.join(root, 'storage/app/private/investmoz-v2');
|
|
const audit = JSON.parse(
|
|
fs.readFileSync(path.join(privateDir, 'territory-audit.json'), 'utf8'),
|
|
);
|
|
if (audit.identity.read_only !== 'on')
|
|
throw new Error('Read-only audit required');
|
|
const records = audit.records.map((item) => reconcile(item, audit));
|
|
const acceptancePath = path.join(
|
|
root,
|
|
'storage/app/private/geo-ine-review-20260928-v2',
|
|
);
|
|
const acceptanceFile = fs
|
|
.readdirSync(acceptancePath)
|
|
.find(
|
|
(name) =>
|
|
name.startsWith('owner-acceptance-') && name.endsWith('.json'),
|
|
);
|
|
const acceptance = JSON.parse(
|
|
fs.readFileSync(path.join(acceptancePath, acceptanceFile), 'utf8'),
|
|
);
|
|
const crypto = require('node:crypto');
|
|
const archiveHash = crypto
|
|
.createHash('sha256')
|
|
.update(fs.readFileSync(path.join(acceptancePath, 'original.pdf')))
|
|
.digest('hex');
|
|
if (archiveHash !== acceptance.source_checksums['original.pdf'])
|
|
throw new Error(
|
|
'Accepted INE archive hash mismatch; do not reuse acceptance',
|
|
);
|
|
const clean = (s) =>
|
|
String(s ?? '')
|
|
.replaceAll('|', '\\|')
|
|
.replaceAll('\n', ' ');
|
|
const lines = [
|
|
'# Reconciliação das fontes e validações territoriais',
|
|
'',
|
|
'Critério do responsável: documentos oficiais são a única fonte de validação oficial. Programação, promotores, testes e leitura do cadastro não substituem esses documentos. Ausência de um campo de fonte/data é uma lacuna de rastreabilidade, não uma decisão de invalidade nem revogação.',
|
|
'',
|
|
'Esta revisão conserva os estados existentes. Uma referência oficial identificada não significa que todas as afirmações da ficha estejam cobertas: o âmbito da citação deve ser conservado. Não foram concedidas novas validações nem ativados cálculos. A declaração do responsável sobre a origem oficial dos dados em uso é registada; as pontes técnicas ainda incompletas são identificadas abaixo, sem contradizer essa declaração.',
|
|
'',
|
|
'## Evidência oficial e aceitação já existentes',
|
|
'',
|
|
`INE — Codificador da Divisão Político-Administrativa: exemplar privado com SHA-256 \`${archiveHash}\`, coincidente com a aceitação de ${acceptance.decision_date}. Decisão preservada: \`${acceptance.validation}\` e \`${acceptance.authenticity}\`, por instrução explícita do responsável. A aceitação não é reaberta. O próprio registo distingue-a da correspondência técnica: \`${acceptance.technical_mapping_status}\`; zero territórios importados por essa decisão. Não se atribui automaticamente esse PDF aos 1 921 nós oriundos do workbook.`,
|
|
'',
|
|
'As seis fontes de diplomas existentes conservam `validation_status=pending` tal como já estava na base; esse estado não foi imposto por esta entrega. As 14 fichas de zonas com `validated` conservam esse estado, distinguindo validação do cadastro de validação jurídica do diploma associado. Referências de promotores não passam a fonte oficial por a ficha estar validada.',
|
|
'',
|
|
'## Matriz por registo',
|
|
'',
|
|
'| Registo | Validação já registada, preservada | Fonte/citação recuperada | Lacuna específica de rastreabilidade |',
|
|
'| --- | --- | --- | --- |',
|
|
];
|
|
for (const r of records) {
|
|
const sources = [
|
|
...(r.legal_source
|
|
? [
|
|
`${r.legal_source.diploma}; ${r.legal_source.title}; ${r.legal_source.article}; ${r.legal_source.url}; versão ${r.legal_source.version_no}`,
|
|
]
|
|
: []),
|
|
...r.official_references.map(
|
|
(s) => `${s.title}; ${s.url}; âmbito: ${s.supports}`,
|
|
),
|
|
...r.non_official_references.map(
|
|
(s) =>
|
|
`Referência ${s.source_type}, não oficial: ${s.title}; ${s.url}`,
|
|
),
|
|
...r.documentary_relations.map(
|
|
(s) =>
|
|
`${s.source_reference}; citação: ${s.source_quote}; dossier ${s.dossier_id}; auditoria ${s.applied_at || 'não identificada'}`,
|
|
),
|
|
...r.dossiers.map(
|
|
(d) => `Dossier ${d.id}, versão ${d.version}: ${d.source}`,
|
|
),
|
|
];
|
|
const state = `Cadastro: ${r.existing_record_validation ?? 'campo de validação não existente/não registado nesta entidade'}; fonte legal: ${r.existing_legal_validation ?? 'sem fonte legal ligada'}`;
|
|
const gap =
|
|
r.traceability === 'official_reference_identified'
|
|
? 'Referência oficial recuperada; ligar exemplar/citação ao atributo quando essa ponte não consta do cadastro. Não repetir validação já evidenciada; não alargar o âmbito da fonte.'
|
|
: r.traceability ===
|
|
'documentary_bridge_to_official_source_to_recover'
|
|
? 'Citação e histórico documentais recuperados; recuperar a ponte ao documento oficial utilizado. Não desvalidar a relação aplicada.'
|
|
: 'Ligação ao exemplar oficial não identificada nos registos revistos; recuperar proveniência da importação. Ausência de ligação não prova ausência de fonte oficial.';
|
|
lines.push(
|
|
`| ${clean(r.reference)} | ${clean(state)} | ${clean(sources.join('; ') || 'Sem ponte documental no cadastro revisto')} | ${clean(gap)} |`,
|
|
);
|
|
}
|
|
lines.push(
|
|
'',
|
|
'## Estados independentes e limites',
|
|
'',
|
|
'Consulta autorizada permanece independente da completude da referência. Validação oficial deriva apenas da evidência documental oficial no âmbito aceite; o estado cadastral é preservado e apresentado separadamente. Utilização em regras/cálculos permanece inalterada. Não se transforma a data de criação, data de aplicação ou início de vigência em data da fonte.',
|
|
'',
|
|
'O rótulo histórico de programação v4 foi preservado; a revisão anterior encontrou programação v5 corroborante, sem o exemplar v4. Esta diferença de rótulo é uma questão de proveniência, não uma revogação das 28 relações aplicadas. Programação não substitui o documento oficial na validação oficial.',
|
|
'',
|
|
'Nenhuma base ativa foi escrita. A matriz integral privada está em `territory-source-reconciliation.json`. Diferença de cobertura do inventário, questões jurídicas realmente não resolvidas, ClamD real e primeiro pedido real continuam separados.',
|
|
);
|
|
fs.writeFileSync(
|
|
path.join(privateDir, 'territory-source-reconciliation.json'),
|
|
JSON.stringify(
|
|
{
|
|
captured_at: audit.captured_at,
|
|
policy: 'official_documents_only_for_official_validation',
|
|
owner_origin_declaration_preserved: true,
|
|
ine_acceptance: acceptance,
|
|
records,
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
);
|
|
fs.writeFileSync(
|
|
path.join(
|
|
root,
|
|
'docs/investmoz/v2/reconciliacao-fontes-territoriais.md',
|
|
),
|
|
lines.join('\n') + '\n',
|
|
);
|
|
console.log(
|
|
JSON.stringify({
|
|
records: records.length,
|
|
official_references_identified: records.filter(
|
|
(r) => r.traceability === 'official_reference_identified',
|
|
).length,
|
|
record_validations_preserved: records.filter(
|
|
(r) => r.existing_record_validation === 'validated',
|
|
).length,
|
|
accepted_ine_hash_matches: true,
|
|
active_writes: 0,
|
|
}),
|
|
);
|
|
}
|