Present financial institutions with professional investor-facing descriptions and products
tests / ci (push) Canceled after 0s

This commit is contained in:
2026-11-11 11:19:27 +02:00
parent 8ebe734d0d
commit a59142caa2
16 changed files with 306 additions and 126 deletions
+4
View File
@@ -1,3 +1,7 @@
## Comunicação pública — orientação expressa do proprietário,11/11/2026
Apresentar conteúdos públicos com linguagem profissional,clara e apelativa,centrada na entidade,oportunidade,produtos e serviços úteis ao investidor. Não usar descrições de importação,cadastro,fichas,ficheiros ou documentos geradores como apresentação comercial. Preservar as fontes,versões e rastreabilidade no cadastro/editor;ligações institucionais e datas úteis podem ser consultadas separadamente. Não inventar ofertas,condições,disponibilidade,cobertura ou garantias para preencher lacunas. Esta orientação aplica-se transversalmente aos conteúdos do portal.
## Simulação de viabilidade — clarificação expressa do proprietário,11/11/2026
O InvesteMoz simula impostos para avaliar a viabilidade do negócio; não actua como entidade que executa pagamentos. Apresentar PPC/PEC e distribuição por meses como estimativas fiscais e projecções de tesouraria,com fontes e pressupostos. Montantes já pagos,quando fornecidos,são dados documentais para o cálculo. Não confundir uma hipótese de caixa com pagamento efectuado,declaração submetida ou cumprimento fiscal certificado. Preservar os cálculos,históricos e dados aceites; não criar serviços de cobrança/execução de pagamentos como requisito de conclusão deste simulador.
@@ -1,3 +1,13 @@
## 11/11/2026 — apresentação pública profissional do directório financeiro em QA
**Pedido do proprietário:** descrições profissionais e apelativas,com descrição/produtos/serviços úteis ao investidor,sem texto de fichas,importação ou documento gerador;orientação transversal registada emAGENTS. O directório e o detalhe passam a uma apresentação editorial comum:reconhece exclusivamente o resumo genérico exacto da importação e usa a natureza publicada da entidade;descrições editoriais específicas são preservadas e limpas da fórmula genérica final. Produtos identificados são apresentados pelos nomes/instrumentos existentes;os sete catálogos específicos disponíveis não são extrapolados para outras entidades. Nas restantes,apresentam-se áreas de serviço conhecidas ou contacto para conhecer soluções,sem inventar produtos/condições.
Retirados da apresentação pública nomes de ficheiros,hashes,linhas de importação,códigos de sucessora e descrições de registo interno. Ligações institucionais e datas úteis continuam acessíveis;metadados e fontes permanecem intactos no cadastro/editor. Instituições históricas/fundidas continuam identificadas como tal. Instituições sem chamada não mostram uma secção vazia de candidatura. Textos da selecção guardada e chamadas públicas dePorque investir/Serviços ajustados à linguagem do investidor. Fluxos de interesse,dossier,edição,revisão/publicação e filtros preservados.
**QA:** nove verificações afectadas aprovadas,três novas incluindo270referências fornecidas,descrições específicas preservadas,produtos não inventados e renderização dos componentes públicos reais de lista/detalhe. Sem escrita em dados activos ou nova publicação do lote;é uma projecção editorial dos dados já publicados. Evidência `outputs/funding-public-editorial-20261111/verification.json` e quatroHTMLs;isto não constitui conferência visual no navegador. Tipos/lint/compilação aprovados;pacote Git com aplicação/reversão conferidas no fecho.
**Estado:** implementado em QA,não instalado;homologação mantém `8f295f05` e270instituições publicadas. Restam instalação/visual e enriquecimento de produtos específicos quando houver informação disponível. O saldo dos outros módulos e resíduos fiscais permanece inalterado. Não é necessário seleccionar ou publicar novamente as270instituições para esta alteração de apresentação.
## 11/11/2026 — rectificação do volume PEC instalada em8f295f05
Instalação expressamente autorizada,executada pelo processo Git existente e conferida às11:03:24Africa/Johannesburg(09:03:24UTC): `8f295f05510c786afeb8ea1dfa692e08d90a0d30`. No simulador fiscal,L8,**Rectificar volume na simulação PEC** conserva o valor original e o corrigido,com escolha explícita/fonte e efeito na estimativa apresentados no relatório. A hipótese de tesouraria anterior exige reconciliação se o total mudar;nenhum comprovativo pago,dedução ou saldo oficial é duplicado. Não executa pagamentos nem submete declaração rectificativa.
@@ -1,3 +1,13 @@
## 11/11/2026 — apresentação pública profissional do directório financeiro em QA
**Pedido do proprietário:** descrições profissionais e apelativas,com descrição/produtos/serviços úteis ao investidor,sem texto de fichas,importação ou documento gerador;orientação transversal registada emAGENTS. O directório e o detalhe passam a uma apresentação editorial comum:reconhece exclusivamente o resumo genérico exacto da importação e usa a natureza publicada da entidade;descrições editoriais específicas são preservadas e limpas da fórmula genérica final. Produtos identificados são apresentados pelos nomes/instrumentos existentes;os sete catálogos específicos disponíveis não são extrapolados para outras entidades. Nas restantes,apresentam-se áreas de serviço conhecidas ou contacto para conhecer soluções,sem inventar produtos/condições.
Retirados da apresentação pública nomes de ficheiros,hashes,linhas de importação,códigos de sucessora e descrições de registo interno. Ligações institucionais e datas úteis continuam acessíveis;metadados e fontes permanecem intactos no cadastro/editor. Instituições históricas/fundidas continuam identificadas como tal. Instituições sem chamada não mostram uma secção vazia de candidatura. Textos da selecção guardada e chamadas públicas dePorque investir/Serviços ajustados à linguagem do investidor. Fluxos de interesse,dossier,edição,revisão/publicação e filtros preservados.
**QA:** nove verificações afectadas aprovadas,três novas incluindo270referências fornecidas,descrições específicas preservadas,produtos não inventados e renderização dos componentes públicos reais de lista/detalhe. Sem escrita em dados activos ou nova publicação do lote;é uma projecção editorial dos dados já publicados. Evidência `outputs/funding-public-editorial-20261111/verification.json` e quatroHTMLs;isto não constitui conferência visual no navegador. Tipos/lint/compilação aprovados;pacote Git com aplicação/reversão conferidas no fecho.
**Estado:** implementado em QA,não instalado;homologação mantém `8f295f05` e270instituições publicadas. Restam instalação/visual e enriquecimento de produtos específicos quando houver informação disponível. O saldo dos outros módulos e resíduos fiscais permanece inalterado. Não é necessário seleccionar ou publicar novamente as270instituições para esta alteração de apresentação.
## 11/11/2026 — rectificação do volume PEC instalada em8f295f05
Instalação expressamente autorizada,executada pelo processo Git existente e conferida às11:03:24Africa/Johannesburg(09:03:24UTC): `8f295f05510c786afeb8ea1dfa692e08d90a0d30`. No simulador fiscal,L8,**Rectificar volume na simulação PEC** conserva o valor original e o corrigido,com escolha explícita/fonte e efeito na estimativa apresentados no relatório. A hipótese de tesouraria anterior exige reconciliação se o total mudar;nenhum comprovativo pago,dedução ou saldo oficial é duplicado. Não executa pagamentos nem submete declaração rectificativa.
File diff suppressed because one or more lines are too long
@@ -1,3 +1,13 @@
## 11/11/2026 — apresentação pública profissional do directório financeiro em QA
**Pedido do proprietário:** descrições profissionais e apelativas,com descrição/produtos/serviços úteis ao investidor,sem texto de fichas,importação ou documento gerador;orientação transversal registada emAGENTS. O directório e o detalhe passam a uma apresentação editorial comum:reconhece exclusivamente o resumo genérico exacto da importação e usa a natureza publicada da entidade;descrições editoriais específicas são preservadas e limpas da fórmula genérica final. Produtos identificados são apresentados pelos nomes/instrumentos existentes;os sete catálogos específicos disponíveis não são extrapolados para outras entidades. Nas restantes,apresentam-se áreas de serviço conhecidas ou contacto para conhecer soluções,sem inventar produtos/condições.
Retirados da apresentação pública nomes de ficheiros,hashes,linhas de importação,códigos de sucessora e descrições de registo interno. Ligações institucionais e datas úteis continuam acessíveis;metadados e fontes permanecem intactos no cadastro/editor. Instituições históricas/fundidas continuam identificadas como tal. Instituições sem chamada não mostram uma secção vazia de candidatura. Textos da selecção guardada e chamadas públicas dePorque investir/Serviços ajustados à linguagem do investidor. Fluxos de interesse,dossier,edição,revisão/publicação e filtros preservados.
**QA:** nove verificações afectadas aprovadas,três novas incluindo270referências fornecidas,descrições específicas preservadas,produtos não inventados e renderização dos componentes públicos reais de lista/detalhe. Sem escrita em dados activos ou nova publicação do lote;é uma projecção editorial dos dados já publicados. Evidência `outputs/funding-public-editorial-20261111/verification.json` e quatroHTMLs;isto não constitui conferência visual no navegador. Tipos/lint/compilação aprovados;pacote Git com aplicação/reversão conferidas no fecho.
**Estado:** implementado em QA,não instalado;homologação mantém `8f295f05` e270instituições publicadas. Restam instalação/visual e enriquecimento de produtos específicos quando houver informação disponível. O saldo dos outros módulos e resíduos fiscais permanece inalterado. Não é necessário seleccionar ou publicar novamente as270instituições para esta alteração de apresentação.
## 11/11/2026 — rectificação do volume PEC instalada em8f295f05
Instalação expressamente autorizada,executada pelo processo Git existente e conferida às11:03:24Africa/Johannesburg(09:03:24UTC): `8f295f05510c786afeb8ea1dfa692e08d90a0d30`. No simulador fiscal,L8,**Rectificar volume na simulação PEC** conserva o valor original e o corrigido,com escolha explícita/fonte e efeito na estimativa apresentados no relatório. A hipótese de tesouraria anterior exige reconciliação se o total mudar;nenhum comprovativo pago,dedução ou saldo oficial é duplicado. Não executa pagamentos nem submete declaração rectificativa.
@@ -69,45 +69,7 @@ export function ClassificationSummary({ value }: { value: Classification }) {
.map((k) => financialTypes[k] ?? k)
.join(' · ') || 'Por classificar'}
</p>
<p>
Situação segundo a fonte:{' '}
{value.institution_status === 'merged'
? 'Fundida/extinta segundo o documento; não apresentar como instituição activa'
: value.institution_status === 'historical'
? 'Registo histórico'
: value.institution_status === 'unknown'
? 'Situação actual por confirmar'
: 'Reportada no documento; não é confirmação independente de licença actual'}
{value.successor_key
? ` · Sucessora indicada: ${value.successor_key}`
: ''}
</p>
{value.register_reference && (
<p>
Referência de registo no documento:{' '}
{value.register_reference}
</p>
)}
<details>
<summary>
Rastrear o conteúdo até ao documento e à linha de origem
</summary>
<p>
{value.source_document_name} · SHA-256{' '}
{value.source_document_sha256}
</p>
{(value.source_rows ?? []).map((row) => (
<article key={row.id}>
<h3>{row.section}</h3>
<p>{row.id}</p>
<p>{row.text}</p>
</article>
))}
</details>
<p>
Categoria e presença física não confirmam cobertura de crédito,
oferta de seguro específica, garantia ou aceitação do processo.
</p>
{['merged','historical','unknown'].includes(value.institution_status??'') && <p>{value.institution_status==='merged'?'Instituição integrada noutra entidade ou com actividade encerrada.':value.institution_status==='historical'?'Informação histórica.':'Situação actual por confirmar junto da instituição.'}</p>}
</section>
);
}
@@ -127,8 +127,8 @@ export default function FundingCriteriaAssessment({
)}
{criteria.length === 0 && (
<p>
Esta ficha não contém critérios suficientes para conferir a
correspondência.
Consulte a entidade para conhecer as condições de acesso
aplicáveis ao seu investimento.
</p>
)}
{awaitingType > 0 && (
@@ -4,6 +4,7 @@ import {
evidenceLabels,
type Classification,
} from '@/components/funding-classification';
import {fundingPublicPresentation} from '@/lib/funding-public-presentation';
import { card, input, button } from '@/pages/investment/shared';
export type FundingSource = {
@@ -551,40 +552,7 @@ export function InstitutionFields({
</section>
);
}
function Source({ value }: { value: FundingSource }) {
return (
<div>
<p>
{value.source_url ? (
<a
className="underline"
href={value.source_url}
target="_blank"
rel="noopener noreferrer"
>
{value.source_reference}
</a>
) : (
value.source_reference
)}{' '}
· consulta {value.checked_on}
</p>
{value.source_document_name && (
<p>
Documento: {value.source_document_name} · SHA-256{' '}
{value.source_document_sha256}
</p>
)}
{value.evidence_status && (
<p>
{evidenceLabels[value.evidence_status] ??
value.evidence_status}{' '}
· {value.origin}
</p>
)}
</div>
);
}
function Source({value}:{value:FundingSource}){return <>{value.source_url&&<details><summary>Informação institucional</summary><a className="underline" href={value.source_url} target="_blank" rel="noopener noreferrer">Consultar informação da entidade</a><p>Consulta em {value.checked_on}.</p></details>}{value.evidence_status==='historical'&&<p>Informação histórica.</p>}{value.evidence_status==='conflict'&&<p>Informação por esclarecer junto da instituição.</p>}</>;}
export function InstitutionView({ value }: { value: InstitutionDetails }) {
return (
<section className={card}>
@@ -643,29 +611,28 @@ export function InstitutionView({ value }: { value: InstitutionDetails }) {
: l.role === 'branch'
? 'Balcão'
: 'Ponto de contacto institucional'}
: {l.label} · {l.address}
: {l.label && !/^(Morada|Localização).*(documento|fonte)/i.test(l.label) ? l.label+' · ' : ''}{l.address}
</p>
<p>
{l.territory_path?.map((n) => n.name).join(' / ') ||
'Correspondência ao cadastro territorial por confirmar'}
'Localização detalhada a confirmar'}
</p>
{l.location_text && (
<p>Local indicado: {l.location_text}</p>
)}
{l.hours && (
<p>
Horário indicado na fonte (pode ter mudado):{' '}
Horário de atendimento:{' '}
{l.hours}
</p>
)}
<Source value={l} />
</article>
))}
<h3>Produtos e programas</h3>
<h3>Produtos e serviços</h3>
{value.products.length === 0 && (
<p>
Produtos e condições por confirmar; a identificação da
instituição não confirma oferta disponível.
{fundingPublicPresentation({...value,title:"",kind:"institution",summary:""}).services.join(" · ") || "Consulte as soluções disponíveis junto da instituição."}
</p>
)}
{value.products.map((p) => (
@@ -0,0 +1,75 @@
type PublicFunding = {
title: string;
kind: string;
summary: string;
institution_types?: string[];
institution_services?: string[];
products?: {
title: string;
instrument?: string | null;
availability?: string;
}[];
};
const descriptions: Record<string, string> = {
commercial_bank: 'Instituição de banca comercial.',
investment_bank: 'Instituição especializada em banca de investimento.',
bank: 'Instituição bancária.',
microbank: 'Instituição de microfinanças.',
cooperative: 'Cooperativa de crédito.',
savings: 'Organização de poupança e empréstimo.',
investment_manager:
'Sociedade especializada na gestão de fundos de investimento.',
investment_company: 'Sociedade de investimento.',
pension_manager: 'Entidade gestora de fundos de pensões.',
insurer: 'Instituição do sector segurador.',
reinsurer: 'Instituição especializada em resseguros.',
microinsurer: 'Instituição de microsseguros.',
broker: 'Entidade de corretagem de seguros.',
agent: 'Entidade de mediação de seguros.',
reinsurance_broker: 'Entidade de corretagem de resseguros.',
exchange_house: 'Instituição de serviços cambiais.',
electronic_money: 'Instituição de moeda electrónica.',
interbank: 'Entidade de serviços interbancários.',
supervisor: 'Entidade de supervisão do sistema financeiro.',
};
const services: Record<string, string> = {
equity: 'Capital e participação no investimento',
foreign_exchange: 'Câmbio',
guarantee: 'Garantias',
insurance: 'Seguros',
investment: 'Financiamento do investimento',
investment_management: 'Gestão de investimentos',
payments: 'Serviços de pagamento',
pension: 'Pensões',
working_capital: 'Financiamento de tesouraria',
};
export function fundingPublicPresentation(p: PublicFunding) {
const generic =
p.summary.trim() ===
'Instituição identificada no documento fornecido. Categoria, localização e contactos são informativos; produtos, disponibilidade e condições não documentados permanecem por confirmar.';
const description = generic
? (descriptions[p.institution_types?.[0] ?? ''] ??
'Entidade do sector financeiro.')
: p.summary
.replace(
/\s*Referência informativa, não concessão de financiamento\.?$/,
'',
)
.replace(/Público\/finalidade:/g, 'Soluções para')
.replace(/\.\./g, '.')
.trim();
const products = (p.products ?? [])
.filter((x) => x.availability !== 'closed')
.map((x) => ({ title: x.title, detail: x.instrument?.trim() ?? '' }));
return {
description,
products,
services: [
...new Set(
(p.institution_services ?? [])
.map((s) => services[s])
.filter(Boolean),
),
],
};
}
+9 -7
View File
@@ -1,3 +1,4 @@
import {fundingPublicPresentation} from '@/lib/funding-public-presentation';
import {
financialCategories,
financialTypes,
@@ -64,11 +65,11 @@ export default function Index({
</Link>
)}
<Link className="underline" href="/fundos/guardados">
Programas que guardei
A minha selecção
</Link>
<p>
Consulte os programas e as condições documentadas. Cada chamada
tem as suas próprias datas e critérios.
Encontre bancos, seguradoras, fundos e outros parceiros financeiros.
Explore as soluções e os contactos adequados ao seu investimento.
</p>
<form
className={`${card} flex flex-wrap gap-4`}
@@ -273,7 +274,8 @@ export default function Index({
{item.payload.title}
</Link>
</h2>
<p>{item.payload.summary}</p>
<p>{fundingPublicPresentation(item.payload).description}</p>
{item.payload.kind==='institution' && <div><h3 className="font-semibold">Produtos e serviços</h3>{fundingPublicPresentation(item.payload).products.length ? <ul>{fundingPublicPresentation(item.payload).products.map(p=><li key={p.title}>{p.title}{p.detail ? ': '+p.detail : ''}</li>)}</ul> : <p>{fundingPublicPresentation(item.payload).services.join(' · ') || 'Consulte as soluções disponíveis junto da instituição.'}</p>}</div>}
<p>
{(item.payload.institution_categories ?? [])
.map((k) => financialCategories[k] ?? k)
@@ -283,16 +285,16 @@ export default function Index({
.map((k) => financialTypes[k] ?? k)
.join(' · ')}
</p>
<p>Gestor: {item.payload.manager_name}</p>
{item.payload.kind!=='institution' && <p>Entidade gestora: {item.payload.manager_name}</p>}
{Object.entries(item.filter_explanation ?? {}).map(
([key, message]) => (
<p key={key}>{message}</p>
),
)}
{item.payload.windows.length === 0 ? (
{item.payload.kind==='institution' && item.payload.windows.length===0 ? null : item.payload.windows.length === 0 ? (
<p>
Não existe uma janela de candidatura confirmada
nesta ficha.
para este programa.
</p>
) : (
<ul>
+3 -3
View File
@@ -18,7 +18,7 @@ export default function Saved({
};
}) {
return (
<Frame title="Programas que guardei">
<Frame title="A minha selecção">
<Link className="underline" href="/fundos">
Consultar fundos e programas
</Link>
@@ -39,7 +39,7 @@ export default function Saved({
className="underline"
href={`/fundos/${item.id}`}
>
Consultar ficha publicada
Consultar detalhes
</Link>
{item.current_version !== item.saved_version && (
<p>
@@ -51,7 +51,7 @@ export default function Saved({
</>
) : (
<p>
A ficha já não está disponível publicamente. A sua
Esta informação já não está disponível para consulta pública. A sua
referência guardada foi conservada.
</p>
)}
+12 -28
View File
@@ -1,3 +1,4 @@
import {fundingPublicPresentation} from '@/lib/funding-public-presentation';
import {
InstitutionView,
type InstitutionDetails,
@@ -32,7 +33,7 @@ export default function Show({
return (
<Frame title={payload.title}>
<Link className="underline" href="/fundos/guardados">
Programas que guardei
A minha selecção
</Link>
<Link
className="underline"
@@ -40,7 +41,7 @@ export default function Show({
>
Voltar aos fundos e programas
</Link>
<p>{payload.summary}</p>
<section><h2 className="text-xl font-semibold">Descrição</h2><p>{fundingPublicPresentation(payload).description}</p></section>
{payload.kind === 'institution' && (
<InstitutionView value={payload as InstitutionDetails} />
)}
@@ -55,8 +56,7 @@ export default function Show({
/>
)}
<p>
Gestor: {payload.manager_name}. Versão publicada:{' '}
{record.version}.
Entidade responsável: {payload.manager_name}.
</p>
{(payload.territory_paths ?? []).map((path, index) => (
<p key={index}>
@@ -82,30 +82,14 @@ export default function Show({
: 'Cobertura por confirmar'}
{payload.coverage_text ? ` — ${payload.coverage_text}` : ''}
</p>
<p>
<a
className="underline"
href={payload.source_url || undefined}
target="_blank"
rel="noopener noreferrer"
>
Consultar fonte: {payload.source_reference}
</a>
. Consultada em {payload.source_checked_on}.{' '}
{payload.source_document_name && (
<span>
Documento: {payload.source_document_name} · SHA-256{' '}
{payload.source_document_sha256}
</span>
)}
</p>
<section className={card}>
{payload.source_url && <details><summary>Informação institucional</summary><a className="underline" href={payload.source_url} target="_blank" rel="noopener noreferrer">Consultar informação da entidade</a><p>Actualização consultada em {payload.source_checked_on}.</p></details>}
{(payload.kind!=='institution'||payload.windows.length>0) && ( <section className={card}>
<h2 className="text-xl font-semibold">
Janelas de candidatura
</h2>
{payload.windows.length === 0 && (
<p>
Não há uma janela de candidatura confirmada nesta ficha.
Não há uma janela de candidatura confirmada para este programa.
</p>
)}
{payload.windows.map((item) => (
@@ -150,11 +134,11 @@ export default function Show({
)}
</article>
))}
</section>
<FundingCriteriaAssessment
</section>)}
{(payload.kind!=='institution'||payload.criteria.length>0||payload.windows.some(window=>window.criteria.length>0)) && ( <FundingCriteriaAssessment
key={record.id + ':' + record.version_id}
record={record}
/>
/>)}
{payload.documents.length > 0 && (
<section className={card}>
<h2>Documentos associados</h2>
@@ -179,7 +163,7 @@ export default function Show({
<section className={card}>
<h2>Guardar interesse</h2>
<p>
Guarda uma referência privada ao programa. Não envia uma
Guarde esta opção para retomar a preparação do investimento. Não envia uma
candidatura nem contacta a entidade.
</p>
{saved ? (
@@ -210,7 +194,7 @@ export default function Show({
})
}
>
Guardar programa na minha área privada
Guardar na minha selecção
</button>
) : (
<Link className="underline" href="/login">
+1 -1
View File
@@ -1272,7 +1272,7 @@ export default function Services(p: Props) {
</p>
))}
<Link href="/investidor" className="underline">
Abrir fichas e manifestações de interesse da
Consultar oportunidades e manifestações de interesse da
carteira
</Link>
</>
+2 -2
View File
@@ -131,7 +131,7 @@ export default function WhyInvest() {
],
[
'Território e ligações',
'Compare localizações, corredores e parques com o mercado que pretende servir. Confira acessos, logística, infra-estruturas e as condições documentadas de cada ficha.',
'Compare localizações, corredores e parques com o mercado que pretende servir. Confira acessos, logística, infra-estruturas e as condições de cada localização.',
'/oportunidades?view=map',
],
[
@@ -163,7 +163,7 @@ export default function WhyInvest() {
],
[
'Localizações e enquadramentos',
'Explore o mapa e as fichas de corredores, clusters, zonas, parques e projectos. Cada referência conserva a natureza e o fundamento que lhe estão associados.',
'Explore o mapa e os detalhes de corredores, clusters, zonas, parques e projectos. Cada referência conserva a natureza e o fundamento que lhe estão associados.',
'/oportunidades?view=map',
],
[
+4 -1
View File
@@ -1,3 +1,4 @@
import * as presentation from '../../resources/js/lib/funding-public-presentation.ts';
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
@@ -26,6 +27,7 @@ function load(file, mocks = {}) {
(name) =>
name in mocks
? mocks[name]
: name === "@/lib/funding-public-presentation" ? presentation
: name === "@/components/funding-classification"
? load("components/funding-classification.tsx", mocks)
: name === "@/pages/investment/shared"
@@ -87,7 +89,8 @@ test("actual institution view keeps physical address separate from product cover
assert.match(html, /Condições: Por confirmar/);
assert.match(html, /Disponibilidade: Por confirmar/);
assert.match(html, /https:\/\/example.invalid\/contact/);
assert.match(html, /SYNTHETIC QA source/);
assert.match(html, /https:\/\/example\.invalid\/source/);
assert.match(html, /Consultar informação da entidade/);
assert.match(html, /não é elegibilidade confirmada/);
});
test("adding a physical location does not fill product financing coverage", () => {
@@ -0,0 +1,153 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import { compileFunction } from 'node:vm';
import { createRequire } from 'node:module';
import React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import ts from 'typescript';
import * as presentation from '../../resources/js/lib/funding-public-presentation.ts';
const require = createRequire(import.meta.url),
records = Object.values(
JSON.parse(
fs.readFileSync(
new URL(
'../../database/data/funding-institutions-nov2026.json',
import.meta.url,
),
'utf8',
),
).references,
).map((x) => x.draft);
function load(file) {
const module = { exports: {} };
const output = ts.transpileModule(
fs.readFileSync(
new URL('../../resources/js/' + file, import.meta.url),
'utf8',
),
{
compilerOptions: {
module: ts.ModuleKind.CommonJS,
target: ts.ScriptTarget.ES2022,
jsx: ts.JsxEmit.ReactJSX,
},
},
).outputText;
compileFunction(output, ['require', 'module', 'exports'])(
(name) =>
name === '@/lib/funding-public-presentation'
? presentation
: name === '@/pages/investment/shared'
? {
Frame: ({ title, children }) =>
React.createElement(
'main',
null,
React.createElement('h1', null, title),
children,
),
card: 'card',
button: 'button',
input: 'input',
}
: name === '@inertiajs/react'
? {
Link: ({ children, href }) =>
React.createElement('a', { href }, children),
router: {},
useForm: (data) => ({ data, setData() {}, get() {} }),
}
: name === './shared'
? { windowLabels: {} }
: name === '@/lib/portal-api' ? {portalRequest:()=>{throw Error('Read-only rendering must not send requests');}} : name === '@/components/funding-classification'
? load('components/funding-classification.tsx')
: name === '@/components/funding-institution'
? load('components/funding-institution.tsx')
: name === '@/components/funding-dossier-choice'
? { FundingDossierChoice: () => null }
: name ===
'@/components/funding-criteria-assessment'
? load('components/funding-criteria-assessment.tsx')
: require(name),
module,
module.exports,
);
return module.exports;
}
test('all270 imported institutions get readable descriptions and evidenced services without changing the published payload', () => {
assert.equal(records.length, 270);
for (const p of records) {
const original = JSON.stringify(p),
m = presentation.fundingPublicPresentation(p);
assert.ok(m.description);
assert.doesNotMatch(
m.description,
/documento fornecido|ficha|SHA-256|Público\/finalidade/,
);
assert.equal(JSON.stringify(p), original);
assert.equal(
m.products.length,
(p.products ?? []).filter((x) => x.availability !== 'closed')
.length,
);
}
});
test('deliberate editorial descriptions survive and missing products are never fabricated', () => {
const m = presentation.fundingPublicPresentation({
title: 'Example',
kind: 'institution',
summary: 'Apoio especializado ao investimento rural.',
products: [],
institution_types: ['insurer'],
});
assert.equal(m.description, 'Apoio especializado ao investimento rural.');
assert.deepEqual(m.products, []);
assert.deepEqual(m.services, []);
});
test('actual public cards and detail lead with description/products and keep import metadata out of the visitor text', () => {
const Index = load('pages/funding/index.tsx').default,
Show = load('pages/funding/show.tsx').default;
for (const raw of [
records[0],
records.find((p) => p.institution_types.includes('investment_manager')),
]) {
const p = { ...raw, windows: [], documents: [] },
item = {
id: 'synthetic',
version_id: 'synthetic-version',
version: 1,
payload: p,
};
const index = renderToStaticMarkup(
React.createElement(Index, {
items: { data: [item], links: [] },
filters: {},
kinds: {},
options: { territories: [], sectors: [] },
management: false,
}),
);
const detail = renderToStaticMarkup(
React.createElement(Show, {
record: item,
authenticated: false,
saved: null,
}),
);
for (const html of [index, detail]) {
assert.doesNotMatch(
html,
/ficha|documento fornecido|SHA-256|linha de origem|Instituições financeiras em Moçambique\.docx/i,
);
assert.match(html, /Produtos e serviços/);
assert.match(
html,
new RegExp(raw.title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')),
);
}
const out=new URL('../../outputs/funding-public-editorial-20261111/',import.meta.url);fs.mkdirSync(out,{recursive:true});const name=p.products.length?'bank-with-products':'investment-manager';fs.writeFileSync(new URL(name+'-index.html',out),index);fs.writeFileSync(new URL(name+'-detail.html',out),detail);fs.writeFileSync(new URL('verification.json',out),JSON.stringify({publishedSourceRecords:270,descriptionsPreserved:true,productsNotFabricated:true,actualPublicComponents:true,metadataRemovedFromPresentation:true,privateEditorialFieldsUnchanged:true,activeDataWrites:0,visualBrowserReview:false},null,2));
assert.match(detail, /Descrição/);
if (p.products.length) assert.match(detail, /Soluções PME/);
}
});