From 00a24ee4b284c76d2a01b4dd9cdb20a9186fba73 Mon Sep 17 00:00:00 2001 From: Elson Lopes Date: Thu, 27 Aug 2026 22:14:20 -0300 Subject: [PATCH] docs(agents): preservar diagnosticos do front --- .claude/agent-memory/lp-front-dev/MEMORY.md | 4 ++ ...oject_bff_dns_multihome_lookup_override.md | 54 +++++++++++++++++++ ...roject_mqseries_field_length_regression.md | 37 +++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 .claude/agent-memory/lp-front-dev/project_bff_dns_multihome_lookup_override.md create mode 100644 .claude/agent-memory/lp-front-dev/project_mqseries_field_length_regression.md diff --git a/.claude/agent-memory/lp-front-dev/MEMORY.md b/.claude/agent-memory/lp-front-dev/MEMORY.md index a63b4a2..28f6ccf 100644 --- a/.claude/agent-memory/lp-front-dev/MEMORY.md +++ b/.claude/agent-memory/lp-front-dev/MEMORY.md @@ -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. diff --git a/.claude/agent-memory/lp-front-dev/project_bff_dns_multihome_lookup_override.md b/.claude/agent-memory/lp-front-dev/project_bff_dns_multihome_lookup_override.md new file mode 100644 index 0000000..927c843 --- /dev/null +++ b/.claude/agent-memory/lp-front-dev/project_bff_dns_multihome_lookup_override.md @@ -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=,` 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`. diff --git a/.claude/agent-memory/lp-front-dev/project_mqseries_field_length_regression.md b/.claude/agent-memory/lp-front-dev/project_mqseries_field_length_regression.md new file mode 100644 index 0000000..42fc17d --- /dev/null +++ b/.claude/agent-memory/lp-front-dev/project_mqseries_field_length_regression.md @@ -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.