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
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
name: adr-layout-tree-425-connectus-decompile
description: Decompilação confirmatória do Connect Us (ilspycmd) para o endpoint de árvore dupla de layout (issue #425) — SysMiddle.Base.dll é o modelo real, GuidXPathCatalog já cobre 90%
metadata:
type: project
---

Issue #425 (LayoutParserApi, bloqueia LayoutParserReact#267) pede endpoint que
devolva árvore de layout origem+destino (com cardinalidade e vínculos de
regra) para um mapeador Sysmiddle **específico** (mapperGuid já conhecido —
diferente de #417, que é descoberta/catálogo por workspace).

**Achado da decompilação exploratória** (`ilspycmd`, disponível em
`~/.dotnet/tools`, DLLs de referência em `D:\ConnectUs\Assemblies\`):
- `SysMiddle.MapControl.Core.dll` está **ofuscada** (nomes de classe
ilegíveis, `[ObfuscationAttribute]`) e não tem tipos de layout — irrelevante.
- `SysMiddle.Base.dll` **não é ofuscada nos nomes de tipo/propriedade**
(só os corpos de método vêm stripped) e contém exatamente o modelo que
`ai/XslSynth.Contracts/Core/GuidXPathCatalog.cs` já parseia via XML puro:
`ElementVO` → `WithChildrenElementVO` → `ParentOccurrenceVO` (com
`MinimalOccurrence`/`MaximumOccurrence`, a cardinalidade que falta hoje) →
`GroupTagElementVO`/`TagElementVO`/`AttributeElementVO`/`ChoiceElementVO`/
`SequenceElementVO`. `LinkMappingItemVO` usa `InputLayoutGuid`/
`TargetLayoutGuid` — os mesmos GUIDs que `sourceRefs`/`targetRefs` da
`MappingExplanationController` (engine Sysmiddle) já expõem.
- Conclusão: **não existe superfície de dados paralela** (API in-process,
cache, banco separado) por trás da árvore do Connect Us. É o mesmo arquivo
LayoutVO exportado, o mesmo formato que `GuidXPathCatalog` já lê.

**Decisão registrada no ADR** (`docs/architecture/adr-layout-tree-endpoint-425.md`):
generalizar `GuidXPathCatalog` (extrair MinOccurs/MaxOccurs, integrar ao
lookup por GUID do banco em vez de path de arquivo local) em vez de
reimplementar. Ponto em aberto para `@lp-backend-dev`: `GuidXPathCatalog`
vive em `ai/XslSynth.Contracts` ([[xslsynth-trilha-a-overlap]], projeto
deliberadamente isolado) — decidir se migra para projeto compartilhado ou
duplica com testes de paridade; recomendação é compartilhado, não duplicar.

**Why:** o dono sugeriu decompilar só pra confirmar hipótese antes de
desenhar o endpoint — evitou reimplementar parsing que já existe e confirmou
que não tem nenhuma API/serviço externo escondido que precisaria ser
replicado.

**How to apply:** se qualquer tarefa futura tocar em "como o Connect Us
monta a árvore/cardinalidade/regra", a resposta já está aqui — não é preciso
decompilar de novo. Se o modelo mudar de versão do Connect Us, reconfirmar.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
name: contrato-correcao-guiada-humano-2026-09-08
description: ADR de contrato do endpoint de correção guiada por humano (field-correction), pedido cross-repo React #232/#234
metadata:
type: project
---

ADR entregue em `docs/architecture/adr-contrato-correcao-guiada-humano-2026-09-08.md`
(branch `docs/adr-contrato-correcao-humana`, não pusheada). Endpoint novo proposto
`POST /api/transformation/field-correction` — assíncrono (202, não re-executa síncrono),
autoria via `ICurrentUser` (padrão já usado em `MappingGovernanceController`), `documentId`
estável proposto como hash determinístico (não existia antes, `CorrelationId` é efêmero).

**Decisão central:** correção humana NÃO tem o mesmo critério de aceite "1:1 contra o
Sysmiddle" do [[fine-tuning-nichado-ollama-2026-09-02]]/loop automático — o usuário está por
definição discordando do oráculo Sysmiddle (ex. `<nNF>001</nNF>` vs `<nNF>1</nNF>`, nenhum
diff estrutural resolve isso). Reporte fica `pending` até curadoria humana aprovar antes de
virar exemplo de treino, pra não contaminar o dataset incremental (F3, issue #338,
`TrainingDataCaptureService`) com correções erradas do usuário.

**Why:** evitar que o pipeline de dataset incremental (que hoje só ingere convergências
automáticas confiáveis 1:1) misture dado não-verificado sem gate.

**How to apply:** se aparecer pedido de "aceitar correção humana automaticamente" no futuro,
apontar pra esta distinção — não é decisão técnica trivial, precisa de segundo oráculo ou
revisão humana explícita.

Recomendei ao `@lp-pm` 2 issues separadas (endpoint+persistência vs. fila de curadoria) —
não criei eu mesma.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
name: geracao-documento-exemplo-2026-09-09
description: ADR sobre gerar documento de exemplo a partir de layout Sysmiddle (XML e posicional); achado central é que SyntheticDataGeneratorService existe mas não cobre árvore XML, e CNPJ/CPF gerado hoje não tem DV real apesar do comentário dizer o contrário.
metadata:
type: project
---

Pedido do dono em 2026-09-09, a partir de uma POC Python (fora do repo) que anda a árvore de um
`LayoutVO` tipo `Xml` (`GroupTagElementVO`/`TagElementVO`/`AttributeElementVO`) e gera XML de
exemplo. ADR completo em
`docs/architecture/adr-geracao-documento-exemplo-2026-09-09.md` (branch
`docs/adr-geracao-documento-exemplo`, commit `04c8c5f`, não mergeada/não pushed).

## Achados principais

1. **`Services/Generation/Implementations/SyntheticDataGeneratorService.cs` já existe** e gera
dado sintético, mas só para layout `TextPositional` (`LineElement`/`FieldElement`,
`PadLeft`/`PadRight`) — não cobre o schema em árvore (`GroupTagElementVO` etc.) que a POC do
dono percorre. Confirmado por grep: **não existem classes C# para
`GroupTagElementVO`/`TagElementVO`/`AttributeElementVO`** em `Models/`/`Services/` — cobrir
layout `Xml` é capacidade nova, não extensão.
2. **`GenerateCnpj()`/`GenerateCpf()` têm comentário enganoso**: dizem "gerar CNPJ/CPF válido
sinteticamente" mas não calculam DV real (módulo 11) — são dígitos aleatórios com padding
fixo. Mesma limitação da POC do dono, escondida atrás de um comentário incorreto no código
já existente. Fix barato e desacoplado (Fase 1 do ADR).
3. **`request.UseAI` já é ignorado deliberadamente** nesse serviço desde o decommission de
Gemini/OpenAI (2026-08-10) — geração é 100% por regra hoje, sem caminho de nuvem a reativar
sem decisão nova.
4. **Risco de memorização de [[gemini-openai-decommission-decision]] não se aplica aqui** —
geração é por regra determinística, não por modelo treinado sobre documento real. Confirmado
explicitamente no ADR, não assumido.
5. **DV válido não destrava sozinho o backfill de #151/#352** — resolve rejeição estrutural
(Pollux por CNPJ/CPF matematicamente inválido), não resolve coerência semântica entre campos
nem existência fiscal real. Ressalva registrada explicitamente no ADR para não superprometer.

## How to apply

- Se o dono voltar a perguntar sobre geração de dado sintético/exemplo, este ADR é o ponto de
partida — não reabrir a análise do zero.
- Se `@lp-backend-dev` for implementar a Fase 1 (DV real), apontar direto para
`SyntheticDataGeneratorService.GenerateCnpj`/`GenerateCpf` — é o único código a tocar.
- Recomendei a `@lp-pm` avaliar issues para as Fases 1–3 e comentar na issue #151 conectando
esta linha — não executei nenhuma das duas (fora da minha autoridade).
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
name: geracao-documento-exemplo-correcao-mapper-obrigatorio-2026-09-09
description: Correção do dono ao ADR de geração de documento de exemplo — exige mapper TCL/XSL/XSLT já existente, não gera para layout "solto"
metadata:
type: project
---

Correção sobre [[geracao-documento-exemplo-2026-09-09]]: o dono esclareceu que gerar documento
de exemplo só faz sentido quando já existe mapper (TCL/XSL/XSLT) vinculado ao layout — serve pra
alimentar/testar esse mapper, não é amostra solta. `docs/architecture/adr-geracao-documento-exemplo-2026-09-09.md`
ganhou seção de correção (commit `1b98920`, branch `docs/adr-geracao-documento-exemplo`).

**Pré-condição do endpoint:** reaproveitar `MapperDatabaseService.GetBestMapperForLayoutGuidAsync`
(`Services/Database/MapperDatabaseService.cs:187`) — se retornar `null`, 404 explicativo, não
silenciar. Essa query já herda a landmine de `AllowedPackageGuids` vazio
([[lowcode-allowedpackageguids-empty-in-null-2026-08-15]]).

**Achado chave da reavaliação:** os 54 pares do held-out (#352) JÁ têm mapper por definição
(são pares schema-TCL+XSLT-alvo) — a pré-condição do dono não muda a viabilidade do backfill,
só confirma explicitamente o gate que [[repair-batch-convergencia-real-issue-352]] já achou por
outro caminho: falta é INSTÂNCIA real de entrada (2-4 de 54 casos), não mapper. Ainda faltam,
sem mudança: (1) coerência semântica do valor gerado, (2) cobertura Xml vs TextPositional dos
casos sem instância (não verificado).

**Decisão de fluxo:** exemplo gerado NÃO entra automático no `RepairOrchestrator`/
`RepairBatchRunner` — fica pra revisão humana antes de virar insumo de medição, mesmo princípio
de [[contrato-correcao-guiada-humano-2026-09-08]]. Fase 5 opt-in (`--allow-synthetic-instance`)
cogitada mas não comprometida.

**How to apply:** se alguém propuser conectar geração de exemplo ao backfill em lote sem
validação humana no meio, lembrar que o risco é contaminar a métrica de convergência com dado
semanticamente não confiável — reforçar o gate de revisão antes de aceitar.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
name: artifact-provenance-f2-issue-341-2026-09-09
description: F2 (proveniência real/sintético) do ADR de provedor de LLM plugável — issue #341, branch feat/artifact-provenance-341 a partir de feat/llm-provider-abstraction-340; teste bloqueado por quebra pré-existente não relacionada
metadata:
type: project
---

Issue #341 (F2 do ADR `docs/architecture/adr-llm-provider-plugavel-2026-09-08.md`) implementada em
`feat/artifact-provenance-341` (commit `d3783a3`), criada a partir de `feat/llm-provider-abstraction-340`
(#340, F1, ainda local/não mergeada em `develop`) — [[llm-provider-abstraction-f1-issue-340-2026-09-09]].

**O que mudou:** `ArtifactProvenance { Synthetic, RealCustomerSample }` novo em
`Models/Entities/Fiscal/PackageArtifact.cs`, com `ResolveSensitivity(string?)` fail-closed (ausência/
inválido → sempre `DataSensitivity.RealFiscalDocument`). Campo `Provenance` propagado ponta a ponta:
entidade → `ArtifactSummary`/`UploadedArtifactInput`/`ArtifactFileRef` → controller (form field opcional
`"{kind}Provenance"`) → `FiscalPackageService` → `SqlFiscalPackageStore` (coluna nova
`tbPackageArtifact.Provenance`, ALTER idempotente separado do CREATE TABLE) → `SqlMappingDraftStore` →
`MappingSuggestionService` (que agora resolve a sensibilidade real por artefato em vez do hardcode
incondicional anterior). `SyntheticDataGeneratorService` só ganhou comentário documentando o ponto de
religamento futuro — nada foi religado, `UseAI` continua 100% ignorado.

**CORREÇÃO (2026-09-09, mesmo dia):** minha hipótese original ("quebra pré-existente não relacionada,
assinatura de `EnqueueAsync` divergente") estava ERRADA e foi refutada por verificação independente do
dono em dois worktrees limpos (`origin/develop` e `feat/llm-provider-abstraction-340` isolados —
ambos compilavam limpo). A causa raiz real: os 6 arquivos de teste (`TransformationExecutionController*
Tests.cs` × 5 + `AiTransformationCandidateServiceXslSynthesizerTests.cs`) referenciavam
`Models.Entities.ParsedField`/`Models.Entities.Mapper`/`Models.Parsing.ParsingResult` **sem o prefixo
`LayoutParserApi.`** — como não havia `using LayoutParserApi.Models.Entities;`, o compilador resolvia
`Models.Entities` relativo ao namespace do arquivo (`LayoutParserApi.Tests`), procurando
`LayoutParserApi.Tests.Models.Entities` (inexistente) → `CS0234`, e por tabela o `SpyAiCandidateService`/
`NoopAiCandidateService` não implementava a interface (`CS0535`) porque o tipo do parâmetro nem
resolvia. **Não era mudança de assinatura de interface por outra branch — era erro de qualificação de
namespace já presente no meu próprio commit `d3783a3`.** Fix: qualificar totalmente com
`LayoutParserApi.Models.Entities.*`/`LayoutParserApi.Models.Parsing.*` (commit `84c8e7c`).
`dotnet test`: 719/719 passando depois do fix.

**Lição:** antes de declarar "pré-existente e não relacionado" no corpo de um commit, rodar
`dotnet build tests/.../*.csproj` isoladamente e ler o erro de perto (CS0234 é forte sinal de
namespace mal qualificado, não de assinatura de interface — CS0535 nesse caso era efeito colateral,
não causa) em vez de assumir a partir do nome do método na mensagem de erro.

**Decisão de design que não estava 100% fechada na issue:** o form field de proveniência no upload
multipart não estava especificado — escolhi `"{kind}Provenance"` (ex.: `"sampleProvenance"`) como
convenção nova, opcional, sem tocar no contrato existente de campos de arquivo por `Kind`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: cpf-cnpj-digito-verificador-fix-2026-09-09
description: SyntheticDataGeneratorService.GenerateCnpj/GenerateCpf mentiam "válido" no comentário mas não calculavam dígito verificador — fix aplicado
metadata:
type: project
---

Bug encontrado pelo `@lp-architect` (ADR `docs/architecture/adr-geracao-documento-exemplo-2026-09-09.md`):
`Services/Generation/Implementations/SyntheticDataGeneratorService.cs` tinha `GenerateCnpj()`/
`GenerateCpf()` com comentário afirmando gerar CPF/CNPJ "válido", mas só preenchia dígitos
aleatórios com `PadLeft` — sem dígito verificador (módulo 11) nenhum. Fix aplicado em
`fix/cpf-cnpj-digito-verificador-real` (branch a partir de `develop`, não commitada em cima de
`master`): 9 (CPF) / 12 (CNPJ) primeiros dígitos continuam aleatórios, mas os 2 dígitos
verificadores agora são calculados de verdade (`CalculateCpfCheckDigit`/`CalculateCnpjCheckDigit`,
métodos privados estáticos no mesmo arquivo). Assinatura pública e retorno (string) inalterados.

**Why:** dado sintético gerado por essa classe alimenta o pipeline de teste/geração de documento
de exemplo — CPF/CNPJ com dígito verificador falso pode invalidar XSD/regras de negócio a jusante
de forma silenciosa, e o comentário mentindo no código é o tipo de coisa que engana o próximo dev
que confiar nele sem reler a implementação.

**How to apply:** se aparecer outro gerador de campo "validado" (ex.: chave de acesso de NFe,
IE) que só faz padding de dígitos aleatórios, checar se o comentário promete validação real —
o padrão aqui (métodos privados são private, então o teste precisa passar pela API pública
`GenerateFieldValueAsync(field, context, dataType)` com `dataType` explícito tipo `"cpf"`/`"cnpj"`,
já que `InferFieldType` prioriza o parâmetro `dataType` sobre o nome do campo) serve de modelo:
teste com validação independente (não reaproveitar a lógica testada) rodando N iterações pra não
ser coincidência de RNG.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
name: field-correction-endpoint-issue-345-2026-09-08
description: Implementação do POST field-correction + tbFieldCorrectionContext/Report (issue #345), decisões de escopo tomadas sem violar o ADR
metadata:
type: project
---

Endpoint `POST /api/transformation/field-correction` implementado em
`Controllers/TransformationExecutionController.cs`, branch `feat/endpoint-field-correction-345`
(a partir de `develop`, não pusheada — exclusivo de `@lp-devops`). Store novo
`IFieldCorrectionStore`/`SqlFieldCorrectionStore` (banco `IdentityDatabase:*`, nunca
`172.31.249.51`), registrado no `FiscalSchemaInitializer` (autossuficiente, sem FK contra o
resto do grafo fiscal).

**Duas decisões de escopo que não estavam 100% fechadas no ADR** (contrato-correcao-guiada-
humano, ver memória equivalente de `@lp-architect`) e que resolvi sem quebrar o desenho:

1. **Sem FK física entre `tbFieldCorrectionReport.DocumentId` e `tbFieldCorrectionContext.DocumentId`**
— o controller já garante a existência do contexto (404 se ausente) antes de criar o
reporte; integridade fica em aplicação, não em schema. Motivo: o ADR já prevê um cron
futuro de TTL/retenção sobre o contexto — uma FK travaria essa limpeza depois.
2. **`MapperName` fica `null`** na primeira entrega — resolver exigiria uma consulta SQL
adicional só para esse campo (não há essa informação disponível no ponto de
`ExecuteTransformationCandidates` sem nova query), e é campo aditivo/best-effort no ADR,
não bloqueante. `MapperGuid`/`GroundTruthXml` vêm normalmente do candidato sysmiddle
quando existe.

**Why:** ambas reduzem acoplamento sem violar nenhuma garantia que o ADR exige (a Seção 4
do ADR já descreve a persistência como "best-effort" e "campo aditivo").

**How to apply:** se aparecer trabalho na Issue 2 (fila de curadoria, consumo no treino),
essas duas lacunas (FK ausente, MapperName null) são o primeiro lugar a revisitar — não são
bugs, são escopo deliberadamente cortado.

Persistência do contexto é fire-and-forget dentro de `ExecuteTransformationCandidates`
(`TryPersistFieldCorrectionContext`, mesmo padrão de `TryEnqueueAiCandidate`: `Task.Run` com
`IServiceScopeFactory` próprio, nunca atrasa a resposta síncrona). O endpoint de reporte em si
é síncrono/rápido (só valida + 1 leitura + 1 escrita no IdentityDatabase) — mas a
"correção" em si nunca reexecuta nada (ADR §3: nunca chama Ollama/RepairOrchestrator no
caminho do request).

11 testes novos em `tests/LayoutParserApi.Tests/Controllers/TransformationExecutionControllerFieldCorrectionTests.cs`
(fake `IFieldCorrectionStore` em memória — nunca toca SQL real), suíte completa 703/703 verde.
Comentado em `LayoutParserApi#345` e cross-repo em `LayoutParserReact#234` (ambos avisando que
não está em produção ainda).
Loading
Loading