Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .claude/agent-memory/lp-front-dev/MEMORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
hipótese não confirmada (dado de contrato); precisa do JSON real de `parseResult.fields` antes de mexer em `positionalFieldEdit.ts`.
- [Candidatos de transformação sem diferenciador](project_transformation_candidate_id_gap.md) —
`TransformationCandidate` não tem nome de mapper/`layoutOutputTarget`; só `candidateId`.
- [DNS multi-homed no BFF (produção)](project_bff_dns_multihome_lookup_override.md) — `dns.setServers()`
não afeta `fetch`/undici; usar lookup customizado + `setGlobalDispatcher`. `BFF_DNS_SERVERS`.
- [Regressão .mqseries: Len inflado](project_mqseries_field_length_regression.md) — `InformacoesParaEDI`
renderiza Len:500 em vez de 81; front só exibe `field.length` da API, causa raiz é dado do backend.

Regras duráveis: HTTP só em `services/`; tipos em `src/types`; sem `any` novo; preserve
`X-Correlation-ID`; payload TXT/XML não vai para logs/cache; produção nunca usa API absoluta.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
name: project-bff-dns-multihome-lookup-override
description: BFF em host Windows multi-homed sofria ~11s de latência de DNS no login; corrigido via custom lookup no dispatcher global do undici, não dns.setServers().
metadata:
type: project
---

Login em um host Windows com várias interfaces de rede ativas ficava lento ou falhava (usuário
só logava na 2ª/3ª tentativa). Causa raiz confirmada ao vivo no host: a resolução DNS _padrão do
SO_ (sem servidor explícito) para `login.microsoftonline.com` levava
~11-12s de forma determinística, por causa do "Smart Multi-Homed Name Resolution" do Windows —
ele aguarda resposta de todas as interfaces conectadas (várias sem DNS configurado) antes de
aceitar a resposta do adaptador correto. Resolver com um servidor DNS interno explícito era
rápido (dezenas de ms). Isso batia com os eventos reais
`auth.entra.acquire_token_failed` no log do BFF, `durationMs` ~10.6s.

**Decisão técnica implementada** (`server/src/dnsOverride.ts`, chamado em `server/src/index.ts`
logo após `loadConfig()`, antes de `buildApp`):

- `dns.setServers()` do `node:dns` **NÃO resolve o problema**. Ele só afeta as funções baseadas
em c-ares (`dns.resolve()`, `dns.resolve4()` etc.), não `dns.lookup()` — e o conector padrão do
undici (`server/node_modules/undici/lib/core/connect.js`, `buildConnector`) chama
`net.connect()`/`tls.connect()` sem um `lookup` customizado, o que internamente usa
`dns.lookup()` (getaddrinfo do SO). Como o `fetch` nativo do Node é undici por baixo, e o MSAL
Node (`@azure/msal-node`, usado em `server/src/oidc.ts`) usa esse `fetch` global, `setServers()`
sozinho não teria efeito nenhum na latência real.
- A mitigação funcional é registrar uma função `lookup` customizada (baseada em `dns.Resolver`
com `setServers()` fixando os IPs corretos, que usa c-ares e por isso respeita os servidores) e
injetá-la no dispatcher global do undici via `setGlobalDispatcher(new Agent({ connect: {
lookup } }))`. Isso cobre tanto o `fetch` global quanto qualquer cliente HTTP que use o
dispatcher padrão.
- Configurável via nova env var opcional `BFF_DNS_SERVERS` (CSV de IPs, validada com
`net.isIP` em `server/src/config.ts`). Sem a variável, comportamento padrão do Node é mantido —
não hardcoda infra de produção no código-fonte, e não afeta outros hosts/ambientes.

**Why:** hardcodar endereços de DNS internos direto no código versionado afetaria todo mundo
(dev, outros hosts), além de expor detalhes operacionais num repositório público. A env var isola
o efeito ao host confirmadamente afetado.

**How to apply:** se aparecer de novo lentidão/flakiness em chamadas de saída do BFF (MSAL, futuro
client HTTP), primeiro suspeitar de DNS multi-homed antes de mexer em timeout do MSAL. Configurar
`BFF_DNS_SERVERS=<DNS_INTERNO_PRIMARIO>,<DNS_INTERNO_SECUNDARIO>` no ambiente do host afetado.
Os endereços reais pertencem à configuração privada do ambiente e não devem ser versionados.
Ver `server/src/dnsOverride.ts` para a implementação e o porquê de não usar `dns.setServers()`
puro.

Validação local: `npm run typecheck` limpo em `server/`. Smoke test isolado confirmou que
`applyDnsOverride(['1.1.1.1','8.8.8.8'])` seguido de `fetch('https://example.com')` funciona
(200 OK) via o lookup customizado. Não foi possível reproduzir o cenário multi-homed real (que só
ocorre no host Windows de produção com múltiplas interfaces) neste ambiente de dev.

Implementação e testes foram incorporados em `develop` e promovidos para `main` pelos PRs de DNS
multi-homed. O comportamento é coberto por `server/test/dnsOverride.test.ts`; a propagação da
configuração opcional ao deploy está em `scripts/Deploy-Iis.ps1`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
name: mqseries-field-length-regression
description: Regressão reportada (2026-08-26) em .mqseries - InformacoesParaEDI renderizado com Len:500 em vez de 81; causa raiz é dado da API, não front
metadata:
type: project
---

Usuário reportou (2026-08-26) que, para a mesma linha lógica (LINHA081, sequencial 000037,
arquivo `.mqseries`), o campo `InformacoesParaEDI` às vezes renderiza com `Pos: 10-509 / Len:
500 / Valor: (vazio)` (errado — consome o espaço do `Filler` seguinte) e outras vezes com `Pos:
10-90 / Len: 81 / Valor: "Solicitante: ..."` (correto).

Investigação em [`src/components/analysis/FieldDisplay.tsx`](../../../src/components/analysis/FieldDisplay.tsx):

- O front **nunca calcula `field.length`**. `fieldLength = field.length || 1` (linha ~670) e o
título do botão (`Len: ${field.length || 'N/A'}`, linha ~882) usam o valor **exatamente como
veio de `field` (API/store)**. Confirmado via grep: nenhum lugar em `src/store`, `src/utils`
ou `src/services` atribui/recalcula `.length` de `Field` — só `startPosition` é sobrescrito
(bloco `calculatedPositions`, linhas 461-489), e mesmo assim `startPosition` bate (10) nos
dois casos relatados, então esse bloco não é a causa.
- `field.value` vazio → front preenche com espaços (`' '.repeat(fieldLength)`, linhas 674-699)
só para exibição; não é o front que "perde" o valor real — se `field.value` já chegou vazio
da API/store para esse `field.length`, o texto real nunca esteve disponível para renderizar.
- Conclusão: a variação de 81 → 500 para o mesmo campo lógico em ocorrências diferentes indica
que a API está retornando, em pelo menos um caso, o **tamanho declarado/máximo do layout**
(500) em vez do **tamanho calculado da ocorrência** (81) para esse campo de tamanho variável
— típico de campo dependente de indicador/tamanho dinâmico em layout `.mqseries`. Isso é
causa raiz de **contrato/dado da API**, não do front.

Não implementei fix especulativo no front (mascararia o problema real). Próximo passo:
reportar ao usuário para acionar a equipe da API com o `correlationId` do parse e, se possível,
o JSON bruto de `parseResult.fields` para essa linha/ocorrência (não colar TXT/XML real em
issue pública, ver `rules/product-management.md`).

Ver também [[project_positional_edit_multi_occurrence_investigation]] — mesmo padrão: suspeita
de `length`/`startPosition` inflados vindos da API para grupos/campos de tamanho variável em
layouts posicionais, ainda sem JSON real para confirmação definitiva byte a byte.
Loading