@polymorphism-tech/morph-spec 8.45.0 → 8.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +6 -5
- package/README.md +2 -2
- package/bin/morph-spec.js +2 -4
- package/bin/validate.js +4 -25
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +2 -2
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +2 -2
- package/framework/MORPH.md +9 -9
- package/framework/commands/create-umbraco-lp.md +2 -0
- package/framework/commands/migrate-lp-to-umbraco.md +2 -0
- package/framework/commands/morph-archive.md +1 -1
- package/framework/commands/morph-hotfix.md +1 -1
- package/framework/commands/morph-infra.md +17 -203
- package/framework/commands/morph-media.md +3 -0
- package/framework/commands/morph-preflight.md +5 -28
- package/framework/commands/morph-proposal.md +2 -2
- package/framework/commands/morph-troubleshoot.md +2 -14
- package/framework/docs/CLI.md +8 -7
- package/framework/hooks/claude-code/core/state-sync.js +13 -1
- package/framework/hooks/shared/e2e-check.js +3 -4
- package/framework/hooks/shared/state-writer.js +1 -0
- package/framework/rules/ai-agents-standards.md +18 -16
- package/framework/rules/asaas-standards.md +3 -1
- package/framework/rules/csharp-standards.md +10 -8
- package/framework/rules/data-standards.md +5 -5
- package/framework/rules/dotnet-templates.md +1 -1
- package/framework/rules/frontend-standards.md +4 -2
- package/framework/rules/gsap-standards.md +10 -5
- package/framework/rules/hangfire-standards.md +3 -1
- package/framework/rules/infrastructure-standards.md +4 -2
- package/framework/rules/morph-workflow.md +2 -2
- package/framework/rules/neon-auth-standards.md +3 -1
- package/framework/rules/neon-standards.md +6 -4
- package/framework/rules/nextjs-standards.md +13 -11
- package/framework/rules/nextjs-templates.md +1 -1
- package/framework/rules/resend-standards.md +3 -1
- package/framework/schemas/config.schema.json +4 -0
- package/framework/schemas/feature.schema.json +4 -4
- package/framework/skills/README.md +1 -1
- package/framework/skills/core/create-umbraco-lp/SKILL.md +3 -3
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +3 -3
- package/framework/skills/core/morph-apply/SKILL.md +3 -3
- package/framework/skills/core/morph-brainstorming/SKILL.md +3 -3
- package/framework/skills/core/morph-hotfix/SKILL.md +4 -4
- package/framework/skills/core/morph-implement/SKILL.md +3 -3
- package/framework/skills/core/morph-machine/SKILL.md +3 -3
- package/framework/skills/core/morph-media/SKILL.md +3 -3
- package/framework/skills/core/morph-plan/SKILL.md +3 -3
- package/framework/skills/core/morph-proposal/SKILL.md +3 -3
- package/framework/skills/core/morph-review/SKILL.md +30 -17
- package/framework/skills/core/morph-stack-scan/SKILL.md +3 -3
- package/framework/skills/core/morph-standards/SKILL.md +6 -6
- package/framework/skills/core/morph-uiux/SKILL.md +3 -3
- package/framework/standards/STANDARDS.json +59 -56
- package/framework/standards/ai-agents/evals-with-cache.md +1 -1
- package/framework/standards/ai-agents/llm-runtime-defaults.md +1 -1
- package/framework/standards/ai-agents/modalities-speech-to-text.md +36 -26
- package/framework/standards/ai-agents/prompt-sources.md +6 -4
- package/framework/standards/ai-agents/providers/model-registry.md +1 -1
- package/framework/standards/ai-agents/rag-custom-pgvector.md +67 -39
- package/framework/standards/ai-agents/setup.md +1 -1
- package/framework/standards/ai-agents/structured-output.md +1 -1
- package/framework/standards/ai-agents/sweet-spot.md +1 -1
- package/framework/standards/architecture/code-comments.md +2 -2
- package/framework/standards/architecture/vertical-slice/vertical-slice.md +18 -9
- package/framework/standards/backend/api/validation.md +135 -47
- package/framework/standards/backend/database/postgresql/database.md +11 -7
- package/framework/standards/backend/database/vector-search-rag.md +207 -324
- package/framework/standards/backend/dotnet/fluent-validation-vsa.md +14 -8
- package/framework/standards/backend/dotnet/result-pattern.md +40 -6
- package/framework/standards/backend/dotnet/scalar-ui.md +13 -7
- package/framework/standards/backend/dotnet/scrutor.md +1 -1
- package/framework/standards/backend/dotnet/testing.md +1 -1
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +7 -7
- package/framework/standards/backend/integrations/asaas/asaas-api.md +309 -165
- package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +134 -154
- package/framework/standards/data/nosql/cache/redis.md +120 -44
- package/framework/standards/data/nosql/cosmos-db.md +114 -71
- package/framework/standards/frontend/design-system/animations.md +1 -1
- package/framework/standards/frontend/design-system/naming.md +1 -1
- package/framework/standards/frontend/nextjs/motion-patterns.md +45 -29
- package/framework/standards/frontend/nextjs/naming-conventions.md +1 -1
- package/framework/standards/infrastructure/docker/coolify-deploy.md +8 -6
- package/framework/standards/infrastructure/neon/neon-pgvector.md +120 -75
- package/framework/standards/infrastructure/neon/neon-setup.md +53 -31
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +2 -2
- package/framework/templates/code/dotnet/extensions/database-extensions.cs +1 -1
- package/framework/templates/code/dotnet/extensions/result-extensions.cs +27 -0
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +2 -2
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +1 -1
- package/framework/templates/infrastructure/docker/coolify.template.json +3 -3
- package/framework/templates/infrastructure/github/README.md +2 -1
- package/framework/templates/infrastructure/github/workflows/deploy-coolify.yml.hbs +2 -1
- package/package.json +1 -1
- package/src/commands/observability/telemetry.js +3 -5
- package/src/commands/project/init.js +2 -1
- package/src/commands/project/update.js +16 -18
- package/src/commands/state/approve.js +17 -0
- package/src/commands/state/gate-check.js +4 -14
- package/src/commands/validation/verify.js +99 -57
- package/src/core/paths/output-schema.js +1 -1
- package/src/dashboard/app/App.jsx +0 -2
- package/src/dashboard/app/components/CommandPalette.jsx +2 -3
- package/src/dashboard/app/components/EntityLink.jsx +0 -1
- package/src/dashboard/app/components/Markdown.jsx +1 -1
- package/src/dashboard/app/components/Sidebar.jsx +1 -2
- package/src/dashboard/app/pages/RulesMap.jsx +3 -3
- package/src/dashboard/app/pages/SkillsLibrary.jsx +3 -3
- package/src/dashboard/scanner/activity-scanner.js +1 -1
- package/src/dashboard/scanner/docs-scanner.js +5 -23
- package/src/dashboard/scanner/features-scanner.js +1 -1
- package/src/dashboard/scanner/index.js +0 -2
- package/src/dashboard/scanner/rules-scanner.js +15 -10
- package/src/dashboard/scanner/skills-scanner.js +2 -3
- package/src/lib/ci/ci-verify.js +118 -0
- package/src/lib/ci/github-ci.js +192 -0
- package/src/lib/ci/workflow-scaffold.js +122 -0
- package/src/lib/evaluator-report.js +13 -0
- package/src/lib/risk-detector.js +8 -0
- package/src/lib/stack/stack-profile.js +1 -1
- package/src/lib/telemetry/verify-event.js +3 -2
- package/src/lib/validators/reuse/reuse-validator.js +2 -3
- package/src/lib/validators/reuse/symbol-scanner.js +2 -4
- package/src/lib/validators/validation-runner.js +8 -88
- package/src/lib/validators/verify-runner.js +22 -72
- package/src/scripts/setup-infra.js +33 -22
- package/src/utils/agents-installer.js +20 -8
- package/src/utils/file-copier.js +7 -5
- package/framework/commands/commit.md +0 -166
- package/framework/hooks/claude-code/__pycache__/statusline.cpython-313.pyc +0 -0
- package/framework/rubrics/backend.json +0 -41
- package/framework/rubrics/default.json +0 -36
- package/framework/rubrics/frontend.json +0 -36
- package/framework/templates/project/validate.js +0 -97
- package/src/dashboard/app/pages/Rubrics.jsx +0 -97
- package/src/dashboard/scanner/rubrics-scanner.js +0 -12
- package/src/lib/validators/architecture/architecture-validator.js +0 -270
- package/src/lib/validators/architecture/index.js +0 -7
- package/src/lib/validators/css/css-validator.js +0 -340
- package/src/lib/validators/css/index.js +0 -7
- package/src/lib/validators/design-system/design-system-validator.js +0 -237
- package/src/lib/validators/design-system/index.js +0 -7
- package/src/lib/validators/score-aggregator.js +0 -244
- package/src/lib/validators/ui/index.js +0 -7
- package/src/lib/validators/ui/ui-contrast-validator.js +0 -422
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
name: morph-uiux
|
|
3
3
|
description: Conduz a fase opcional de UI/UX — design system, mockups, componentes e fluxos — entre o Gate 1 e o plan, despachando a persona ui-designer para o trabalho visual.
|
|
4
4
|
version: core
|
|
5
|
-
|
|
6
|
-
user-
|
|
7
|
-
cliVersion: "8.
|
|
5
|
+
when_to_use: Use quando o ramo uiux for tomado (morph-spec advance --design), depois do Gate 1 e antes do morph-plan
|
|
6
|
+
user-invocable: true
|
|
7
|
+
cliVersion: "8.47.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-uiux
|
|
@@ -721,8 +721,8 @@
|
|
|
721
721
|
"example": "#exemplo-c-completo",
|
|
722
722
|
"formats": "#formatos-e-limites"
|
|
723
723
|
},
|
|
724
|
-
"digest": "Use STT
|
|
725
|
-
"verifiedAgainst": "OpenAI 2.13.0 + Microsoft.Extensions.AI 10.9.0 (ai-pin 2026-09-08). **Verificação documental**, sem cláusula `provado por` — o ai-kit não transcreve áudio. `AudioClient.TranscribeAudioAsync` e a ponte `AsISpeechToTextClient` foram **medidas por reflexão sobre as assemblies do pin** em 2026-09-08.",
|
|
724
|
+
"digest": "Use STT só quando o input real é áudio; se já é texto, use-o direto. Transcrição é chamada de serviço, não agente: registre o `AudioClient` (OpenAI 2.13.0) UMA vez no DI com modelo (`whisper-1`) e API key vindos de config e injete-o pelo construtor do `TranscriptionService` (nunca `new AudioClient` no chamador), e passe o texto como `string` ao `AIAgent` downstream; NÃO crie `AIAgent` para transcrever. API: `TranscribeAudioAsync(path, options)` NÃO aceita `CancellationToken` — para cancelar, `File.OpenRead` e a sobrecarga `(Stream, fileName, options, ct)`, que exige o nome do arquivo (dele se deduz o formato); `ResponseFormat = Verbose` com `TimestampGranularities = AudioTimestampGranularities.Word | Segment` (enum de flags, não coleção) dá timestamps. Limites: mp3/mp4/mpeg/mpga/m4a/wav/webm, 25 MB por request (acima, erro 413): divida client-side em chunks de ≤20 MB, com alguns segundos de overlap se o corte for crítico. Defina `Language = \"pt\"` quando o idioma é conhecido. Opcional: `ISpeechToTextClient` via `AsISpeechToTextClient()`.",
|
|
725
|
+
"verifiedAgainst": "OpenAI 2.13.0 + Microsoft.Extensions.AI 10.9.0 (ai-pin 2026-09-08). **Verificação documental**, sem cláusula `provado por` — o ai-kit não transcreve áudio. `AudioClient.TranscribeAudioAsync` e a ponte `AsISpeechToTextClient` foram **medidas por reflexão sobre as assemblies do pin** em 2026-09-08. Em 2026-10-03 os blocos da API, do `TranscriptionService`, do agente downstream (dentro de um método-invólucro) e do registro DI compilaram com `TreatWarningsAsErrors` contra `OpenAI` 2.13.0 + `Microsoft.Agents.AI` 1.20.0 (o pin de 2026-09-08, que é a data que este campo carrega).",
|
|
726
726
|
"provedBy": []
|
|
727
727
|
},
|
|
728
728
|
{
|
|
@@ -791,7 +791,7 @@
|
|
|
791
791
|
"example": "#exemplo-c-completo",
|
|
792
792
|
"content-types": "#datacontent-vs-uricontent"
|
|
793
793
|
},
|
|
794
|
-
"digest": "
|
|
794
|
+
"digest": "Vision em MAF usa ChatMessage multimodal (Microsoft.Extensions.AI): new ChatMessage(ChatRole.User, [new TextContent(pergunta), imagem]) passado a agent.RunAsync. Imagem em URL pública: UriContent(uri, mediaType); arquivo local: DataContent.LoadFromAsync(path), o helper canônico e preferido; bytes já em memória: new DataContent(BinaryData, mediaType). Upload de usuário ou imagem privada usa DataContent, nunca URL temporária (pode expirar); CDN estável usa UriContent. O modelo vem do alias vision no Model Registry, pois nem todo provider suporta visão. Dado tipado: RunAsync<T> com sealed record, nunca regex em response.Text. Proibido: base64 manual, imagem 4K sem resize (tokens cobrados por resolução; ex.: 800px para OCR), vision quando já há texto extraído ou um parser/OCR determinístico basta. PDF: confirme application/pdf no provider.",
|
|
795
795
|
"verifiedAgainst": "Microsoft.Extensions.AI 10.9.0 + Microsoft.Agents.AI 1.20.0 (ai-pin 2026-09-08). **Verificação documental**, sem cláusula `provado por` — o ai-kit não exercita conteúdo multimodal. Os três tipos de conteúdo citados (`TextContent`, `UriContent`, `DataContent`) foram **conferidos por reflexão sobre `Microsoft.Extensions.AI.Abstractions` 10.9.0** em 2026-09-08 e continuam existindo com esses nomes.",
|
|
796
796
|
"provedBy": []
|
|
797
797
|
},
|
|
@@ -941,7 +941,7 @@
|
|
|
941
941
|
"tenant": "#fonte-2-yaml-por-tenant",
|
|
942
942
|
"reconciliacao": "#reconciliação"
|
|
943
943
|
},
|
|
944
|
-
"digest": "WHERE an agent prompt lives, and how to prove which version actually ran. Two legitimate sources, and the one-sentence rule that picks between them: if the text varies per customer, the prompt is not a record — it is the OUTPUT OF A COMPOSITION, and what you version is the source. (1) Versioned table agent_prompts (agent_key + version + is_active, INSERT + flip, never UPDATE, unique partial index, IMemoryCache with a short TTL) for single-tenant. (2) Repo YAML per tenant + a product frame with named holes -> a deterministic composer -> a rendered spec published to a jsonb column, for product x tenant; editing prompts then costs a repo cycle, which is a product trade-off, not a free upgrade. RECONCILIATION is the section that was missing: versioning and publishing do NOT prove the active version ran (measured: v7/v8 ignored in 6 of 9 executions). The execution record must carry the EFFECTIVE version, plus the hash of the rendered blob on the composed path; the two field-proven techniques are byte-identity equivalence between source and published blob, and a single structural prompt-as-text test asserting the ABSENCE of a revoked instruction.",
|
|
944
|
+
"digest": "WHERE an agent prompt lives, and how to prove which version actually ran. Two legitimate sources, and the one-sentence rule that picks between them: if the text varies per customer, the prompt is not a record — it is the OUTPUT OF A COMPOSITION, and what you version is the source. (1) Versioned table agent_prompts (id app-assigned with Guid.CreateVersion7(), no gen_random_uuid() default; agent_key + version + is_active, INSERT + flip in one transaction, never UPDATE, unique partial index, IMemoryCache with a short TTL) for single-tenant. (2) Repo YAML per tenant + a product frame with named holes -> a deterministic composer -> a rendered spec published to a jsonb column, for product x tenant; editing prompts then costs a repo cycle, which is a product trade-off, not a free upgrade. RECONCILIATION is the section that was missing: versioning and publishing do NOT prove the active version ran (measured: v7/v8 ignored in 6 of 9 executions). The execution record must carry the EFFECTIVE version, plus the hash of the rendered blob on the composed path; the two field-proven techniques are byte-identity equivalence between source and published blob, and a single structural prompt-as-text test asserting the ABSENCE of a revoked instruction.",
|
|
945
945
|
"verifiedAgainst": "Microsoft.Agents.AI 1.20.0 + Microsoft.Extensions.AI 10.9.0 (ai-pin 2026-09-08). **Verificação documental**, sem cláusula `provado por` — o ai-kit não traz loader de prompt, e os dois mecanismos descritos aqui são destilados de três produtos em produção. As **quatro** superfícies de API que este standard cita foram medidas por reflexão, e vivem em **três assemblies diferentes** — o carimbo diz onde remedir, então o nome importa: `IChatClient.AsAIAgent(instructions:, name:)` é `Microsoft.Extensions.AI.ChatClientExtensions`, em **`Microsoft.Agents.AI` 1.20.0** (medida em 2026-09-08); `AIAgent.RunAsync` (as oito sobrecargas) e `AIAgent.CreateSessionAsync` são de `Microsoft.Agents.AI.AIAgent`, na assembly **`Microsoft.Agents.AI.Abstractions` 1.20.0** — **remedidas** em 2026-09-09, porque a leitura de 2026-09-08 estava errada no *quê*, e a de 2026-09-09 estava errada no *onde* (as duas retificações estão no callout abaixo); e `builder.AddAIAgent` (§Keyed singleton) é `Microsoft.Agents.AI.Hosting.HostApplicationBuilderAgentExtensions` — cinco sobrecargas, na assembly **`Microsoft.Agents.AI.Hosting` 1.20.0.0**, que vem do pacote **`Microsoft.Agents.AI.Hosting` `1.20.0-preview.260831.1`**: ele é **prerelease** e está **FORA do `ai-pin.json`** (apurado em `scripts/api-probe/companions.json`, 2026-09-08) — quem adotar esta seção registra a dependência prerelease em `decisions.md`, como manda `ai-agents-production`. **Duas ressalvas de escopo**, porque um carimbo que não as diz promete mais do que mediu: `Microsoft.Agents.AI.Abstractions` e `Microsoft.Extensions.AI.Abstractions` são nomes de **assembly** (elas viajam dentro dos pacotes `Microsoft.Agents.AI` e `Microsoft.Extensions.AI`), não ids de pacote; e `IMemoryCache`/`DbContext`, usados no padrão de cache e na §Keyed singleton, são superfícies de ASP.NET Core e EF Core — **fora do pin, não medidas aqui, verificação documental**.",
|
|
946
946
|
"provedBy": []
|
|
947
947
|
},
|
|
@@ -1026,8 +1026,8 @@
|
|
|
1026
1026
|
"tool": "#vectorsearchtool-tool-maf",
|
|
1027
1027
|
"multi-tenant": "#multi-tenant"
|
|
1028
1028
|
},
|
|
1029
|
-
"digest": "Custom RAG on pgvector/Neon you control: chunking, embedding model via the Model Registry `embeddings` alias, HNSW with vector_cosine_ops, tenant_id filtered in every query and never exposed to the LLM. Owns DELTA INGESTION by lookup-key: a pure Plan(incoming, lookupKey, contentHash, existingHashes) returning Added/Updated/Removed/Unchanged, where Unchanged is never re-embedded, Updated is an upsert on a deterministic id, Removed is applied AFTER the writes (no empty window), and a duplicate lookup-key fails the run naming both positions. Microsoft.Extensions.DataIngestion (still preview) solves hygiene, not embedding cost — its IncrementalIngestion deletes all pre-existing chunks of a document before rewriting. Open item: similarity threshold and k per scope.",
|
|
1030
|
-
"verifiedAgainst": "Microsoft.Agents.AI 1.20.0 + Microsoft.Extensions.AI 10.9.0 (ai-pin 2026-09-08); `provado por templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs` **restrito à seção \"Ingestão delta por lookup-key\"** — é a única parte deste standard que o ai-kit compila. Todo o resto (pgvector, SQL, HNSW, embeddings, multi-tenant) é **verificação documental**; a versão e o status de `Microsoft.Extensions.DataIngestion` foram apurados no nuget.org em 2026-09-08.",
|
|
1029
|
+
"digest": "Custom RAG on pgvector/Neon you control: chunking, embedding model via the Model Registry `embeddings` alias with `IEmbeddingGenerator<string, Embedding<float>>` injected directly into the ingestion handler and the VectorSearchTool (no EmbeddingService wrapper; batch GenerateAsync at ingestion, GenerateVectorAsync per query), the tool querying through EF Core (`CosineDistance` LINQ, raw NpgsqlDataSource only with a decisions.md reason), ids app-assigned (deterministic V5 for delta chunks, else Guid.CreateVersion7(); no gen_random_uuid() default), HNSW with vector_cosine_ops, tenant_id filtered in every query and never exposed to the LLM. Owns DELTA INGESTION by lookup-key: a pure Plan(incoming, lookupKey, contentHash, existingHashes) returning Added/Updated/Removed/Unchanged, where Unchanged is never re-embedded, Updated is an upsert on a deterministic id, Removed is applied AFTER the writes (no empty window), and a duplicate lookup-key fails the run naming both positions. Microsoft.Extensions.DataIngestion (still preview) solves hygiene, not embedding cost — its IncrementalIngestion deletes all pre-existing chunks of a document before rewriting. Open item: similarity threshold and k per scope.",
|
|
1030
|
+
"verifiedAgainst": "Microsoft.Agents.AI 1.20.0 + Microsoft.Extensions.AI 10.9.0 (ai-pin 2026-09-08); `provado por templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs` **restrito à seção \"Ingestão delta por lookup-key\"** — é a única parte deste standard que o ai-kit compila. Todo o resto (pgvector, SQL, HNSW, embeddings, multi-tenant) é **verificação documental**; a versão e o status de `Microsoft.Extensions.DataIngestion` foram apurados no nuget.org em 2026-09-08. Em 2026-10-03, contra o mesmo pin, compilaram com `TreatWarningsAsErrors` os blocos de registro do `IEmbeddingGenerator`, do `VectorSearchTool` (EF Core + Pgvector.EntityFrameworkCore 0.3.0) e do *Exemplo de uso* (a ponte `Microsoft.Extensions.AI.OpenAI` 10.9.0 resolveu `OpenAI` 2.12.0); a forma anterior `RunAsync(question, ct)` não compilava (CS1503).",
|
|
1031
1031
|
"provedBy": [
|
|
1032
1032
|
"templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs"
|
|
1033
1033
|
]
|
|
@@ -1312,8 +1312,8 @@
|
|
|
1312
1312
|
"rules": "#padrões-obrigatórios",
|
|
1313
1313
|
"cqrs": "#anti-patterns-nunca-fazer-em-vsa"
|
|
1314
1314
|
},
|
|
1315
|
-
"digest": "
|
|
1316
|
-
"verifiedAgainst": ".NET 10 + EF Core 10 + FluentValidation 12 + Scrutor 7.",
|
|
1315
|
+
"digest": "Uma slice por operação em Features/{Entity}Feature/{Verb}{Entity}/: Request e Response (sealed records) no mesmo arquivo do Handler, Validator FluentValidation (nenhum em GetAll) e Endpoint `IApiEndpoint` `internal sealed`. O handler implementa o `IHandler<TRequest, TResponse>` próprio, devolve `Result<T>` (erros em `{Entity}Errors`, 1 por feature), injeta `ApplicationDbContext` direto e chama `SaveChangesAsync` nas escritas; IDs com `Guid.CreateVersion7()`, nunca `Guid.NewGuid()`; o endpoint usa `result.Match()`: o sucesso recebe o valor no lambda (nunca `result.Value`) e a falha vira `error.ToHttpResult()` (status pelo `ErrorType`, ProblemDetails), nunca `Results.BadRequest` para todo erro, declarando cada status com `.ProducesProblem`. Decorators Scrutor: Logging -> Validation -> Handler. PROIBIDO: MediatR/IRequest, AggregateRoot, DomainEvent, CQRS formal, Application Service layer, DTOs compartilhados entre features e `IRepository<T>`/`IUnitOfWork` (DbSet já é repository, vira código morto); store dedicado só com justificativa em `decisions.md`. Não misture VSA com DDD.",
|
|
1316
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview) + EF Core 10.0.12 + FluentValidation 12.1.1 + Scrutor 7. Os blocos da slice (Handler, Validator, Endpoint) compilam com `TreatWarningsAsErrors` sobre o `Result`/`Error`/`ErrorHttpMapping` de `result-pattern.md` nos namespaces da árvore acima (`{ProjectName}` substituído; o Handler com `global using` de Abstractions/Database/Entities, o Endpoint só com os próprios `using`); Abstractions, Pipelines e DI são verificação documental.",
|
|
1317
1317
|
"provedBy": []
|
|
1318
1318
|
},
|
|
1319
1319
|
{
|
|
@@ -1337,11 +1337,12 @@
|
|
|
1337
1337
|
"model validation"
|
|
1338
1338
|
],
|
|
1339
1339
|
"anchors": {
|
|
1340
|
-
"fluent": "#
|
|
1341
|
-
"rules": "#validation-patterns"
|
|
1340
|
+
"fluent": "#fluentvalidation-validator-in-the-slice",
|
|
1341
|
+
"rules": "#validation-patterns",
|
|
1342
|
+
"state": "#state-checks-in-the-handler"
|
|
1342
1343
|
},
|
|
1343
|
-
"digest": "
|
|
1344
|
-
"verifiedAgainst": ".NET 10 (
|
|
1344
|
+
"digest": "Request/DTO validation in the VSA slice: one sealed `AbstractValidator<TRequest>` (FluentValidation) next to the handler, checking SHAPE only (required, length, range, format, child items via RuleForEach/ChildRules; no DbContext; time rules read an injected TimeProvider inside the rule). The ValidationDecorator runs it before the handler and short-circuits with `Result.Failure(new ValidationError([...]))`; the endpoint maps it with `error.ToHttpResult()` to 400 ProblemDetails with `errors[]` (decorator and conversion in fluent-validation-vsa.md, ValidationError/ErrorHttpMapping in result-pattern.md). Never throw (ValidationException/InvalidOperationException), never validate in the endpoint lambda, never mix DataAnnotations with FluentValidation (minimal APIs have no ModelState). Existence/uniqueness/state checks live in the handler and return typed `{Entity}Errors` (NotFound 404, Conflict 409, Failure 400), never `Result.Failure(\"string\")`. State checks validate what is INVALID, not what is valid, so a new flow (e.g. a free flow that skips PendingPayment) does not break: ordered status enum (Created=0 ... EmailSent=4) with error states at 100+ (Failed=100, Cancelled=101, Refunded=102), blocked by `status >= Completed`, an error-state list, or `status >= Failed`. FORBIDDEN: `if (status != Expected)`, exhaustive switches over valid states, business rules mixed into the state check (keep `RequiresPayment && !IsPaid` separate). Document all flows in decisions.md and test each.",
|
|
1345
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview) + FluentValidation 12.1.1 + EF Core 10.0.12. The validator, `OrderStatus`, `OrderErrors` and state-check handler blocks compile with `TreatWarningsAsErrors` over the `Result`/`Error`/`ValidationError` of `result-pattern.md`.",
|
|
1345
1346
|
"provedBy": []
|
|
1346
1347
|
},
|
|
1347
1348
|
{
|
|
@@ -1369,8 +1370,8 @@
|
|
|
1369
1370
|
"schema": "#schema-design",
|
|
1370
1371
|
"indexes": "#indexes"
|
|
1371
1372
|
},
|
|
1372
|
-
"digest": "
|
|
1373
|
-
"verifiedAgainst": "PostgreSQL 16/17 + EF Core 10 + @neondatabase/serverless.",
|
|
1373
|
+
"digest": "Neon PostgreSQL schema rules: snake_case plural tables and snake_case columns, PK 'id uuid primary key' with NO column default -- the app sets it with Guid.CreateVersion7() (rows inserted outside the app pass an explicit id; never gen_random_uuid() defaults for app ids), FK '{table}_id', booleans prefixed is_/has_, indexes 'idx_{table}_{column}'. Always include created_at/updated_at as timestamptz default now() not null, kept fresh by a handle_updated_at trigger. Always enable RLS on user-facing tables, with policies like 'auth.user_id() = user_id' (update takes both using and with check). Migrations via EF Core: dotnet ef migrations add, database update, and migrations script --idempotent to review the SQL; hand-written SQL migrations enable RLS, create indexes and always include a rollback. Index FKs and WHERE/ORDER BY/GROUP BY columns; GIN for full-text search. Select only needed columns, limit results, batch inserts, set a statement timeout, keep RLS policies simple. The Next.js frontend reads through the .NET API (proxy + TanStack Query); @neondatabase/serverless is only for Node-side tooling.",
|
|
1374
|
+
"verifiedAgainst": "PostgreSQL 16/17 + EF Core 10.0.12 (Npgsql provider 10.0.3) + @neondatabase/serverless. The EF Core query blocks compile with `TreatWarningsAsErrors` inside a wrapper method over stand-in entities; the SQL is documentary.",
|
|
1374
1375
|
"provedBy": []
|
|
1375
1376
|
},
|
|
1376
1377
|
{
|
|
@@ -1399,7 +1400,9 @@
|
|
|
1399
1400
|
"chunking": "#📥-indexação-de-documentos",
|
|
1400
1401
|
"retrieval": "#🔍-vector-search-com-ef-core-10"
|
|
1401
1402
|
},
|
|
1402
|
-
"digest": "
|
|
1403
|
+
"digest": "Pipeline RAG em slices VSA sobre EF Core 10 + PostgreSQL/pgvector (Npgsql.EntityFrameworkCore.PostgreSQL 10.0.3, Pgvector.EntityFrameworkCore 0.3.0; Microsoft.Extensions.AI 10.9.0 e Microsoft.Agents.AI 1.20.0 do pin). Mapeamento (Document com `Pgvector.Vector` `vector(1536)`, EF não mapeia `float[]`; `UseVector()` no `UseNpgsql`; HNSW `vector_cosine_ops`) vem de neon-pgvector.md. Cada operação é um handler que injeta `ApplicationDbContext` e `IEmbeddingGenerator<string, Embedding<float>>` direto — sem EmbeddingService/SearchService; ids `Guid.CreateVersion7()`, `CreatedAt` do `TimeProvider`. Busca: `d.Embedding!.CosineDistance(query)` + OrderBy da distância (traduz para `<=>` ASC e usa o índice; o `HasOperators` tem de casar com a função ou cai em seq scan), similaridade = 1 - distância. Slice AskDocuments: top 3 por distância, `NotFound` (Result) antes de chamar o LLM quando nada é relevante, contexto no `instructions` de `chatClient.AsAIAgent(...)`, `RunAsync(...).Text`; prompt manda usar APENAS os documentos e citar o id; endpoint via `error.ToHttpResult()`. Indexação em lote com uma chamada `GenerateAsync(IEnumerable<string>)` e um SaveChanges; job Hangfire só com razão real, como entrada fina que chama o handler. text-embedding-3-small (1536) recomendado, large 3072; HNSW (m=16, ef_construction=64) padrão; IVFFlat só após popular (lists 50/100/500+).",
|
|
1404
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview) + Npgsql.EntityFrameworkCore.PostgreSQL 10.0.3 + Pgvector.EntityFrameworkCore 0.3.0 + Microsoft.Extensions.AI 10.9.0 + Microsoft.Agents.AI 1.20.0 (ai-pin 2026-09-08). Os blocos de indexação, indexação em lote, busca+geração (RAG), endpoint e job compilam com `TreatWarningsAsErrors` sobre o `Result`/`IHandler`/`ErrorHttpMapping` de `result-pattern.md`/`vertical-slice.md` e o `Document`/`ApplicationDbContext` de `neon-pgvector.md`; o registro do `IEmbeddingGenerator` por provedor, os custos e o SQL são verificação documental.",
|
|
1405
|
+
"provedBy": []
|
|
1403
1406
|
},
|
|
1404
1407
|
{
|
|
1405
1408
|
"id": "backend-dotnet-fluent-validation-vsa",
|
|
@@ -1427,8 +1430,8 @@
|
|
|
1427
1430
|
"decorator": "#validationdecorator-pattern",
|
|
1428
1431
|
"conversion": "#fluentvalidation-to-validationerror-conversion"
|
|
1429
1432
|
},
|
|
1430
|
-
"digest": "
|
|
1431
|
-
"verifiedAgainst": ".NET 10 + FluentValidation
|
|
1433
|
+
"digest": "One sealed `AbstractValidator<TRequest>` per request DTO (FluentValidation 12), in the same feature folder as the handler; no `RuleSet` grouping and no `IValidateOptions<T>`. Never validate request shape inside the handler or endpoint (existence/state checks do belong in the handler): `ValidationDecorator<TRequest, TResponse>` wraps every `IHandler` via Scrutor, collects all `IValidator<TRequest>`, runs them in parallel (`Task.WhenAll`) and on failure short-circuits to `Result.Failure(ValidationError)` (an array of `Error.Validation(code, message)`), supporting both `Result` and `Result<T>`. Never throw `ValidationException`. In Program.cs call `AddValidatorsFromAssembly()` BEFORE `AddHandlersFromAssembly()` so the decorator can resolve validators. Always give user-facing `.WithMessage()` text. Inject `TimeProvider` instead of reading `DateTime.UtcNow` and read it INSIDE the rule (`LessThanOrEqualTo(_ => timeProvider.GetUtcNow().Year)`), so the year is evaluated per validation (a value captured in the constructor goes stale in a singleton/cached validator; AddValidatorsFromAssembly defaults to Scoped) and stays testable with `FakeTimeProvider`.",
|
|
1434
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview) + FluentValidation 12.1.1. The validator block and the decorator (its three blocks assembled into one class) compile with `TreatWarningsAsErrors` over the `Result`/`ValidationError` of `result-pattern.md`, and the validator was run with `FakeTimeProvider` across a year change to show the year is read per validation.",
|
|
1432
1435
|
"provedBy": []
|
|
1433
1436
|
},
|
|
1434
1437
|
{
|
|
@@ -1457,8 +1460,8 @@
|
|
|
1457
1460
|
"errors": "#error-types-7--custom",
|
|
1458
1461
|
"match": "#match-pattern"
|
|
1459
1462
|
},
|
|
1460
|
-
"digest": "
|
|
1461
|
-
"verifiedAgainst": ".NET 10 (
|
|
1463
|
+
"digest": "Expected failures are Result/Result<T> values, never exceptions. Endpoints convert with result.Match(onSuccess: value => Results.Ok(value), onFailure: error => error.ToHttpResult()); never read .Value outside Match (it throws on failure). Implicit conversions let a handler return the value or the Error directly. Error = record(Code, Description, ErrorType) from factories Failure/Unexpected/Validation/Conflict/NotFound/Unauthorized/Forbidden; ValidationError aggregates FluentValidation errors. Status comes from ErrorType, never a blanket BadRequest: Failure/Validation/Custom 400, NotFound 404, Conflict 409, Unauthorized 401, Forbidden 403, Unexpected 500, via Results.Problem. Each feature owns a static {Feature}Errors class. FORBIDDEN: try/catch in handlers (unexpected exceptions bubble to the global handler), returning null, codeless string errors.",
|
|
1464
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview) + the shared framework `Microsoft.AspNetCore.App` 10 — the HTTP mapping uses `Results`/`IResult`/`StatusCodes`; the `Error`, `ValidationError`, `ResultExtensions`, `ErrorHttpMapping`, endpoint usage and `BookErrors` blocks compile with `TreatWarningsAsErrors` (the Anatomy blocks carry `{ ... }` placeholders and were compiled through a concrete stand-in).",
|
|
1462
1465
|
"provedBy": []
|
|
1463
1466
|
},
|
|
1464
1467
|
{
|
|
@@ -1487,8 +1490,8 @@
|
|
|
1487
1490
|
"tags": "#apitags-organization",
|
|
1488
1491
|
"metadata": "#endpoint-metadata"
|
|
1489
1492
|
},
|
|
1490
|
-
"digest": "
|
|
1491
|
-
"verifiedAgainst": ".NET 10 + Scalar.AspNetCore 2.x + Microsoft.AspNetCore.OpenApi 10.",
|
|
1493
|
+
"digest": "Scalar replaces Swagger UI: packages Microsoft.AspNetCore.OpenApi 10.0.0 + Scalar.AspNetCore 2.12.40, never Swashbuckle (ASP.NET Core 9+ generates OpenAPI natively). Program.cs order: builder.Services.AddOpenApi(); app.MapOpenApi() only inside IsDevelopment() (never expose OpenAPI in production); then app.MapScalarApiReference with WithTheme(ScalarTheme.DeepSpace) and WithDefaultHttpClient(ScalarTarget.CSharp, ScalarClient.HttpClient). MapOpenApi must come before Scalar; the UI is served at /scalar/v1. Every endpoint needs .WithTags(ApiTags.X), with tags as constants in Constants/ApiTags.cs (no magic strings), and .Produces<T>(status) for success plus .ProducesProblem(status) for every failure status the slice can return (failures go out as ProblemDetails via error.ToHttpResult()), so the docs show accurate response types. Also available: .WithName (operation id), .WithSummary, .WithDescription, .ProducesProblem, .RequireAuthorization.",
|
|
1494
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview) + Scalar.AspNetCore 2.x + Microsoft.AspNetCore.OpenApi 10. The `ApiTags` and tagged-endpoint blocks compile with `TreatWarningsAsErrors` over the `Result`/`ErrorHttpMapping` of `result-pattern.md` (ApiTags placed in `ProjectName.Constants`); the startup and metadata snippets (`async (...) => { ... }`) are fragments, checked against the docs only.",
|
|
1492
1495
|
"provedBy": []
|
|
1493
1496
|
},
|
|
1494
1497
|
{
|
|
@@ -1517,7 +1520,7 @@
|
|
|
1517
1520
|
"decorators": "#decorator-order",
|
|
1518
1521
|
"endpoints": "#endpoint-auto-discovery"
|
|
1519
1522
|
},
|
|
1520
|
-
"digest": "
|
|
1523
|
+
"digest": "Scrutor 7 (.NET 10) handler/decorator registration for VSA. `AddHandlersFromAssembly` reflects over concrete classes filtered by `!t.ContainsGenericParameters` (so open-generic decorators are excluded), registers each `IHandler<,>` as `AddScoped` (handlers use DbContext, never Singleton), then calls `Decorate` for `ValidationDecorator<,>` first and `LoggingDecorator<,>` second: the last registered wraps outermost, so execution is Logging -> Validation -> Handler and logging sees validation failures. `RegisterApiEndpointsFromAssembly` adds every `IApiEndpoint` as Transient via `TryAddEnumerable`; `MapApiEndpoints` calls `MapEndpoint` on each. Program.cs order: DbContext, endpoints, `AddValidatorsFromAssembly` (must precede handlers so the ValidationDecorator can resolve validators), handlers + decorators, cross-cutting. Never register handlers one by one.",
|
|
1521
1524
|
"verifiedAgainst": ".NET 10 + Scrutor 7 (`Scan`/`Decorate` API).",
|
|
1522
1525
|
"provedBy": []
|
|
1523
1526
|
},
|
|
@@ -1582,8 +1585,8 @@
|
|
|
1582
1585
|
"endpoint": "#complete-endpoint-example",
|
|
1583
1586
|
"registration": "#programcs-di-registration-order"
|
|
1584
1587
|
},
|
|
1585
|
-
"digest": "Each VSA feature is 5 files: Request, Response, Handler, Validator, Endpoint.
|
|
1586
|
-
"verifiedAgainst": ".NET 10 (minimal APIs, primary constructors, `Guid.CreateVersion7()`).",
|
|
1588
|
+
"digest": "Each VSA feature is a slice in `Features/{Feature}/{UseCase}/` with 5 files: Request, Response (sealed records, may be inline), Handler, Validator, Endpoint; feature errors in `{Feature}Errors.cs` (`Error.NotFound/Conflict/Failure`). Handlers implement `IHandler<TRequest, TResponse>` (resolved from DI; NOT MediatR, decorators via Scrutor), are `sealed class` with primary constructors, inject `ApplicationDbContext` directly (`DbSet<T>` is the repository, `DbContext` the unit of work: no service layer, no `IRepository<T>`/`IUnitOfWork`), use `Guid.CreateVersion7()` (never `Guid.NewGuid()`), pass `CancellationToken` everywhere and return `Result<T>` instead of throwing for expected failures. Endpoints are `internal sealed` `IApiEndpoint`, only map HTTP and call `Match()`: success lambda receives the value (never read `.Value`), failure is `error.ToHttpResult()` (status by `ErrorType`, never `Results.BadRequest` for every error), with `.ProducesProblem` per failure status. Raw SQL or a dedicated hand-written store (outbox, lease) only with a `decisions.md` justification.",
|
|
1589
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview; minimal APIs, primary constructors, `Guid.CreateVersion7()`). The \"Complete Endpoint Example\" block compiles with `TreatWarningsAsErrors` over the `Result`/`ErrorHttpMapping` of `result-pattern.md` (in `ProjectName.Abstractions`/`ProjectName.Extensions`, reached only through the block's own `using`s); the other blocks are documentary.",
|
|
1587
1590
|
"provedBy": []
|
|
1588
1591
|
},
|
|
1589
1592
|
{
|
|
@@ -1611,8 +1614,8 @@
|
|
|
1611
1614
|
"payments": "#create-pix-payment",
|
|
1612
1615
|
"webhooks": "#webhook-handler"
|
|
1613
1616
|
},
|
|
1614
|
-
"digest": "
|
|
1615
|
-
"verifiedAgainst": "Asaas REST API v3 (
|
|
1617
|
+
"digest": "Asaas from the .NET 10 backend (the Next.js frontend never calls Asaas; it calls the backend through the proxy). No official .NET SDK: REST v3 through a typed HttpClient `AsaasClient` (an external-API port, injected into the slice handler next to the DbContext), registered with AddHttpClient + options bound from config `Asaas` (ValidateOnStart; key in user-secrets/Coolify env, never in code). Base URL https://api.asaas.com/v3/ or https://api-sandbox.asaas.com/v3/ WITH trailing slash and relative paths without leading slash (otherwise HttpClient drops /v3). Every request sends `access_token` (not Bearer), Content-Type and `User-Agent` (mandatory for root accounts created from 06/11/2024). Responses become Result: 400 `{ errors: [{ code, description }] }` -> Error.Validation (ValidationError if several, e.g. invalid_cpfCnpj), 404 -> NotFound, other non-success -> Unexpected; endpoints map with error.ToHttpResult(); no try/catch, network failures propagate. No duplicate charges: Asaas documents no idempotency-key header and create is not idempotent, so set `externalReference` to your id and `GET /payments?externalReference=` before creating; never auto-retry payWithCreditCard. PIX: POST /payments billingType PIX with dueDate as today in America/Sao_Paulo via TimeProvider, then GET /payments/{id}/pixQrCode (payload + encodedImage). Webhooks are not HMAC-signed: compare the `asaas-access-token` header to the configured authToken with CryptographicOperations.FixedTimeEquals, 401 on mismatch; delivery is at-least-once, so store processed event ids (unique) and answer 200 (only 200 counts; 15 consecutive failures interrupt the queue). Validate CPF (11 digits) and CNPJ (14, alphanumeric from July 2026, ASCII-48 mod-11), never store card data; local ids via Guid.CreateVersion7(), no gen_random_uuid defaults.",
|
|
1618
|
+
"verifiedAgainst": "Asaas REST API v3 (docs read via context7 on 2026-10-03: headers, `POST /payments`, `GET /payments?externalReference=`, `pixQrCode`, webhook payload, delivery and error rules) + .NET 10 (SDK 10.0.400-preview, `IHttpClientFactory` from the ASP.NET Core shared framework) + EF Core 10.0.12. The options, client, registration, PIX slice, webhook slice/endpoint and CPF/CNPJ blocks compile with `TreatWarningsAsErrors` over the `Result`/`ErrorHttpMapping` of `result-pattern.md`; the CPF/CNPJ validator was run against valid and invalid documents (numeric and the alphanumeric `12.ABC.345/01DE-35`), and the `BaseUrl` trailing-slash rule and the `dueDate` JSON shape were checked by running them; the SQL is documentary.",
|
|
1616
1619
|
"provedBy": []
|
|
1617
1620
|
},
|
|
1618
1621
|
{
|
|
@@ -1641,8 +1644,8 @@
|
|
|
1641
1644
|
"jobs": "#job-types",
|
|
1642
1645
|
"retry": "#retry--error-handling"
|
|
1643
1646
|
},
|
|
1644
|
-
"digest": "
|
|
1645
|
-
"verifiedAgainst": ".NET 10 + Hangfire 1.8 (
|
|
1647
|
+
"digest": "Hangfire 1.8.25 on .NET 10, only with a real reason (survive restarts, schedules, deferred retries) recorded in decisions.md; work that fits in the request stays in the slice handler. Storage is Neon Postgres via Hangfire.PostgreSql 1.21.1 with `UsePostgreSqlStorage(o => o.UseNpgsqlConnection(cs))` (the string overloads are [Obsolete]) and `HangfireConnection` on the direct/unpooled endpoint (schema install at startup is a migration, which Neon routes to the direct string; EnableLongPolling uses LISTEN/NOTIFY, unsupported by Neon's PgBouncer transaction mode); reference Newtonsoft.Json 13.0.4 explicitly or restore fails with NU1903 (Hangfire.Core pulls 11.0.1). A job is a thin sealed class in the slice that calls the slice handler (`IHandler<TRequest, Result>`); no XService layer. Hangfire.AspNetCore's AspNetCoreJobActivator opens a DI scope per job, so inject the ApplicationDbContext/handler directly (IDbContextFactory only for parallel work inside one job); never capture request-scoped services into Enqueue. Jobs are idempotent (check state, return). Expected failures come back as Result and the job logs and completes; unexpected ones are the exceptions EF/HttpClient already throw, uncaught, which `[AutomaticRetry(Attempts = 3, DelaysInSeconds = [60, 300, 900])]` retries; no try/catch, no manual retry loops. API: `BackgroundJob.Enqueue<TJob>(j => j.RunAsync(id, CancellationToken.None))`, `Schedule`, `RecurringJob.AddOrUpdate` with a stable id and cron (UTC), `ContinueJobWith`. Dashboard: IDashboardAuthorizationFilter requiring authenticated Admin, dev bypass only via IHostEnvironment.IsDevelopment() (never Request.Host, which the client controls).",
|
|
1648
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview) + Hangfire.Core/Hangfire.AspNetCore 1.8.25 + Hangfire.PostgreSql 1.21.1 + Newtonsoft.Json 13.0.4. The startup, job/handler, dashboard-filter and idempotency blocks compile with `TreatWarningsAsErrors`; the Job Types calls compile inside a wrapper method; the per-job DI scope (`AspNetCoreJobActivator` → `IServiceScopeFactory`) and the `PostgreSqlStorageOptions` defaults were read by reflection on those assemblies; the pooled-endpoint limits (LISTEN/NOTIFY, migrations on the direct string) come from the Neon connection-pooling docs. Cron strings are documentary.",
|
|
1646
1649
|
"provedBy": []
|
|
1647
1650
|
},
|
|
1648
1651
|
{
|
|
@@ -1719,7 +1722,7 @@
|
|
|
1719
1722
|
"sending": "#send-email-api-route",
|
|
1720
1723
|
"templates": "#common-email-templates"
|
|
1721
1724
|
},
|
|
1722
|
-
"digest": "
|
|
1725
|
+
"digest": "Resend transactional email via REST API (not SMTP; 100 free emails/day) for Next.js and .NET. Next.js: `resend` + React Email templates, one `new Resend(process.env.RESEND_API_KEY)` in `lib/resend.ts`. .NET: `Resend` package, `AddHttpClient<ResendClient>()` plus `IResend` registered transient, token from the `Resend:ApiKey` config. Always send asynchronously: do not block HTTP requests, enqueue with Hangfire (`BackgroundJob.Enqueue`); retry with Polly (3 attempts, exponential backoff); rate-limit sends (Upstash sliding window, 10/hour). Webhooks are signed with Svix: verify the RAW body with `resend.webhooks.verify()` using the `svix-id`/`svix-timestamp`/`svix-signature` headers and `RESEND_WEBHOOK_SECRET`; do NOT hand-roll an HMAC (it rejects valid webhooks). Handle `email.delivered`/`bounced`/`complained`. Verify the sending domain first (SPF, DKIM, DMARC; up to 72 hours).",
|
|
1723
1726
|
"verifiedAgainst": "Resend Node SDK 4 + Resend .NET SDK + React Email.",
|
|
1724
1727
|
"provedBy": []
|
|
1725
1728
|
},
|
|
@@ -1750,8 +1753,8 @@
|
|
|
1750
1753
|
"patterns": "#cache-aside-pattern",
|
|
1751
1754
|
"invalidation": "#ttl-strategy"
|
|
1752
1755
|
},
|
|
1753
|
-
"digest": "
|
|
1754
|
-
"verifiedAgainst": ".NET 10 + StackExchange.Redis 2.
|
|
1756
|
+
"digest": "Redis (on the Coolify VPS or managed) is a distributed cache for sessions, rate limiting and hot reads, never the primary store. Packages: Microsoft.Extensions.Caching.StackExchangeRedis 10.0.12 (depends on StackExchange.Redis >= 2.7.27); reference StackExchange.Redis explicitly at the latest 2.x (2.13.17) only when injecting IConnectionMultiplexer -- 3.x is a new major the caching package has not adopted. Register one shared IConnectionMultiplexer as a LAZY singleton and hand it to the cache via AddOptions<RedisCacheOptions>().Configure<IServiceProvider>(... ConnectionMultiplexerFactory ...) -- never Connect during registration (an unreachable Redis would block boot) and never BuildServiceProvider inside the factory, InstanceName prefix (e.g. 'myapp:'), connection string from configuration (user-secrets / Coolify env ConnectionStrings__Redis). Cache-aside lives in the slice handler with IDistributedCache next to the ApplicationDbContext (no CachedXService/repository wrapper): read the key, on a miss project the response DTO from the DbContext, return Result NotFound (never null) when absent, write with DistributedCacheEntryOptions; the writing handler invalidates the exact key with RemoveAsync after SaveChangesAsync; key builders in one static class per feature. TTLs: user session 30 min sliding, product catalog 15 min absolute, rate-limit counters 1 min, computed aggregates 1 h, reference data 24 h. Rate limit across instances: StringIncrementAsync, KeyExpireAsync 1 min when count == 1, minute from TimeProvider (single instance: built-in AddRateLimiter). FORBIDDEN: caching passwords/tokens/PII without encryption, omitting TTL, swallowing RedisConnectionException in an empty catch (DB fallback during an outage is a decisions.md decision, implemented once at the cache boundary).",
|
|
1757
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview) + Microsoft.Extensions.Caching.StackExchangeRedis 10.0.12 + StackExchange.Redis 2.13.17 + EF Core 10.0.12. The registration, cache-aside handler, invalidation and rate-limit blocks compile with `TreatWarningsAsErrors` over the `Result` of `result-pattern.md`; package dependencies read from the nuget.org nuspec on 2026-10-03.",
|
|
1755
1758
|
"provedBy": []
|
|
1756
1759
|
},
|
|
1757
1760
|
{
|
|
@@ -1777,10 +1780,10 @@
|
|
|
1777
1780
|
],
|
|
1778
1781
|
"anchors": {
|
|
1779
1782
|
"modeling": "#container-design",
|
|
1780
|
-
"queries": "#
|
|
1783
|
+
"queries": "#handler-in-the-slice"
|
|
1781
1784
|
},
|
|
1782
|
-
"digest": "
|
|
1783
|
-
"verifiedAgainst": ".NET 10 + Microsoft.Azure.Cosmos
|
|
1785
|
+
"digest": "OPTIONAL — outside the baked-in stack. The default store is Neon (Postgres) via EF Core; Cosmos needs a decisions.md entry saying why Neon does not serve (multi-region writes, event-stream throughput, per-tenant schema never joined) — never for joined data, small datasets or 'flexible schema' (jsonb covers it). Stack rules still hold: one singleton CosmosClient with System.Text.Json, the Container as a keyed singleton injected straight into the slice handler (no CosmosRepository<T>), ids from Guid.CreateVersion7(), time from TimeProvider. Use ReadItemStreamAsync/CreateItemStreamAsync and map StatusCode 404/409 to Result errors instead of catching CosmosException. Parameterized queries with the PartitionKey pinned in QueryRequestOptions (no fan-out). Microsoft.Azure.Cosmos 3.x needs an explicit Newtonsoft.Json reference or the build fails.",
|
|
1786
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview) + Microsoft.Azure.Cosmos 3.63.2 + Newtonsoft.Json 13.0.4 — every `csharp` block below compiles with `TreatWarningsAsErrors` against the `Result`/`Error` types of `backend-dotnet-result-pattern`.",
|
|
1784
1787
|
"provedBy": []
|
|
1785
1788
|
},
|
|
1786
1789
|
{
|
|
@@ -1808,7 +1811,7 @@
|
|
|
1808
1811
|
"strategies": "#chunking-strategies",
|
|
1809
1812
|
"retrieval": "#chunking-strategies"
|
|
1810
1813
|
},
|
|
1811
|
-
"digest": "
|
|
1814
|
+
"digest": "Strategies: fixed-size baseline (sample defaults size 512, overlap 50, applied to characters), sentence-aware (recommended for prose, `maxTokens` 256) and semantic (best quality, higher cost; split at markdown headers `^#{1,3} `). By document type: legal -> sentence-aware 256 tokens; technical docs -> semantic by headers; Q&A -> keep whole Q+A; code -> whole function; news -> paragraph, 512 tokens. Estimate tokens as chars/4 for English (about 3 chars per token for Portuguese), or tiktoken if available. Always store chunk metadata (DocumentId, DocumentTitle, SourceUrl, ChunkIndex, StartCharIndex, Section, IndexedAt) for filtering and citation. Checklist: overlap 10-20% so boundaries do not cut context, minimum 50 tokens, maximum about 512 (far below the 8192-token embedding input limit), and re-index when a document changes, detected via a content hash.",
|
|
1812
1815
|
"verifiedAgainst": ".NET 10 (chunking algorithms — language-level, no external package).",
|
|
1813
1816
|
"provedBy": []
|
|
1814
1817
|
},
|
|
@@ -1918,7 +1921,7 @@
|
|
|
1918
1921
|
"tokens": "#stagger--timing",
|
|
1919
1922
|
"principles": "#css-animation-patterns"
|
|
1920
1923
|
},
|
|
1921
|
-
"digest": "
|
|
1924
|
+
"digest": "CSS animation library for design-system.css: keyframes (fadeIn/Out, slideIn Up/Down/Left/Right, scaleIn, bounce, pulse, spin, shimmer) exposed as `.animate-*` classes (0.3s fade/scale, 0.5s slides; bounce 1s, pulse 2s, spin 1s infinite) plus `.duration-fast/normal/slow` (150/300/500ms), `.stagger-1..10` (0.1s steps) and `.ease-bounce`. For staggered lists set `animation-delay` AND `animation-fill-mode: backwards` (marked CRITICAL: otherwise elements flash before the delay). Skeletons use `.shimmer` (1.5s infinite). Hover/focus transitions run 0.15s to 0.3s. Always include the `@media (prefers-reduced-motion: reduce)` block (0.01ms durations, one iteration). Beyond CSS: Motion (formerly Framer Motion) for simple enter/exit, layout and gesture transitions (`frontend/nextjs/motion-patterns.md`); GSAP for ScrollTrigger, SVG morph, timelines (`frontend/gsap/gsap-core.md`).",
|
|
1922
1925
|
"verifiedAgainst": "CSS animations/transitions (language-level, no framework).",
|
|
1923
1926
|
"provedBy": []
|
|
1924
1927
|
},
|
|
@@ -1946,7 +1949,7 @@
|
|
|
1946
1949
|
"blocks": "#bem-for-reusable-components",
|
|
1947
1950
|
"tokens": "#css-variables-with-namespace"
|
|
1948
1951
|
},
|
|
1949
|
-
"digest": "BEM for
|
|
1952
|
+
"digest": "CSS naming rests on four principles: a page prefix prevents conflicts, BEM for components gives clear hierarchy, namespaced variables avoid library collisions, and state suffixes keep modifiers consistent. Page-specific elements take the page name as prefix (.home-hero, .checkout-form, .dashboard-stats, .auth-form); reusable components use BEM: block .card, element .card__header, modifier .card--featured. Rule: BEM for reusable components, page prefix for page-specific elements. Custom properties go in :root under the --app- namespace (--app-primary, --app-spacing-md, --app-font-heading). State modifiers use fixed suffixes: --active, --disabled, --loading, --error (.button, .button--active, .button--disabled).",
|
|
1950
1953
|
"verifiedAgainst": "CSS (BEM + custom properties — language-level, no framework).",
|
|
1951
1954
|
"provedBy": []
|
|
1952
1955
|
},
|
|
@@ -2017,7 +2020,7 @@
|
|
|
2017
2020
|
"performance": "#section-7-performance",
|
|
2018
2021
|
"accessibility": "#section-8-accessibility"
|
|
2019
2022
|
},
|
|
2020
|
-
"digest": "
|
|
2023
|
+
"digest": "GSAP 3.13 + `@gsap/react` in Next.js. Use GSAP for ScrollTrigger, SVG morph/draw, complex timelines, SplitText and Draggable+Inertia; use Framer Motion for simple enter/exit, layout, gestures and AnimatePresence. NEVER animate one DOM element with both (they fight over inline styles). All GSAP code lives in `'use client'` components, inside `useGSAP()` (never `useEffect`) with ALWAYS `{ scope: containerRef }`, which cleans up automatically; handlers outside the callback need `contextSafe()`. Register plugins once at app init (`layout.tsx`/`providers.tsx`), not in components. Prefer `autoAlpha` over `opacity`; animate only transforms and opacity, never width/height/top/left; `gsap.quickTo()` for cursor followers. Honoring `prefers-reduced-motion` is MANDATORY (`gsap.matchMedia()`). Never hardcode durations or easings: import `durations`/`easings` from `@/lib/design-tokens`.",
|
|
2021
2024
|
"verifiedAgainst": "GSAP 3.13 + @gsap/react.",
|
|
2022
2025
|
"provedBy": []
|
|
2023
2026
|
},
|
|
@@ -2051,7 +2054,7 @@
|
|
|
2051
2054
|
"morphsvg": "#morphsvg",
|
|
2052
2055
|
"drawsvg": "#drawsvg"
|
|
2053
2056
|
},
|
|
2054
|
-
"digest": "Flip
|
|
2057
|
+
"digest": "GSAP 3.13 + @gsap/react: core and every plugin (Flip, SplitText, MorphSVG, DrawSVG, MotionPath, Draggable...) are free from the public `gsap` package (`npm install gsap @gsap/react`); the old `gsap@npm:@gsap/shockingly` private-registry instruction is obsolete. Call `gsap.registerPlugin(...)` ONCE at app init (`'use client'`); animate with `useGSAP` + `scope`. Flip: `Flip.getState()`, change the DOM, `Flip.from(state, { absolute: true })`; with ScrollTrigger, call `ScrollTrigger.refresh()` after the layout change. SplitText: `SplitText.create` with `autoSplit: true`, animate inside `onSplit`; it adds `<div>` wrappers that affect layout, and `useGSAP` reverts it. MorphSVG needs `<path>` elements (`convertToPath` for others); DrawSVG needs a visible stroke (not fill); ScrollToPlugin `autoKill: true`; Draggable `throwProps` needs InertiaPlugin; Observer normalizes wheel/touch/pointer.",
|
|
2055
2058
|
"verifiedAgainst": "GSAP 3.13 + @gsap/react.",
|
|
2056
2059
|
"provedBy": []
|
|
2057
2060
|
},
|
|
@@ -2084,7 +2087,7 @@
|
|
|
2084
2087
|
"pin": "#section-4-pinning",
|
|
2085
2088
|
"batch": "#section-5-batch-processing"
|
|
2086
2089
|
},
|
|
2087
|
-
"digest": "
|
|
2090
|
+
"digest": "GSAP 3.13 ScrollTrigger in Next.js: all code lives in 'use client' components inside useGSAP(() => {...}, { scope }), which auto-kills tweens and triggers on unmount (without it, use gsap.context() and ctx.revert()); orphaned triggers leak memory and break later routes. gsap.registerPlugin(ScrollTrigger) once at app init, never inside useEffect or loops; never ScrollTrigger.create() at module scope. Scrub needs ease 'none'; scrub: true is 1:1, use 0.3-1 in production. Pin: pin: true with anticipatePin: 1; pinSpacing: false only for intentional overlap; never nest pins. Use ScrollTrigger.batch for grids (20+ items), snap durations under 0.8s. Responsive: define both desktop and mobile cases, exclusive breakpoints (767/768). Call ScrollTrigger.refresh() after dynamic content, layout shifts, route changes and image onLoad; normalizeScroll(true) helps iOS Safari.",
|
|
2088
2091
|
"verifiedAgainst": "GSAP 3.13 ScrollTrigger + @gsap/react.",
|
|
2089
2092
|
"provedBy": []
|
|
2090
2093
|
},
|
|
@@ -2112,7 +2115,7 @@
|
|
|
2112
2115
|
"layout": "#root-layout--required-providers",
|
|
2113
2116
|
"routing": "#app-directory-structure"
|
|
2114
2117
|
},
|
|
2115
|
-
"digest": "Server Components by default
|
|
2118
|
+
"digest": "Next.js 15 App Router, TypeScript only (no .js/.jsx). Server Components by default; add `'use client'` only for interaction (onClick, useState/useEffect/useRef), browser APIs, TanStack Query hooks and interactive shadcn/ui. `app/` is for routing only: business logic goes to `features/`, never in `page.tsx`. Never fetch data in a Client Component when a Server Component can, and never fetch in `useEffect`: use a Server Component or TanStack Query. Co-locate `loading.tsx` and `error.tsx` (`error.tsx` must be a Client Component) beside `page.tsx`. Server Components call the .NET backend directly using the dedicated `BACKEND_API_PREFIX` from `@/lib/api/prefixes`, never the same-origin proxy prefix used by Client Components; always check `res.ok`. Avoid `route.ts` API routes (use the .NET API). The root `layout.tsx` wraps children in `QueryProvider` and the sonner `Toaster`.",
|
|
2116
2119
|
"verifiedAgainst": "Next.js 15.",
|
|
2117
2120
|
"provedBy": []
|
|
2118
2121
|
},
|
|
@@ -2140,7 +2143,7 @@
|
|
|
2140
2143
|
"patterns": "#three-tier-hierarchy",
|
|
2141
2144
|
"shadcn": "#tier-1--shadcnui-primitives"
|
|
2142
2145
|
},
|
|
2143
|
-
"digest": "Three tiers: components/ui is shadcn CLI output (
|
|
2146
|
+
"digest": "Three tiers (Next.js 16 + shadcn 4 CLI): `components/ui/` is shadcn CLI output (add via `npx shadcn@latest add`, NEVER edit because the CLI regenerates it; wrap it in `components/` instead); `components/` holds shared composed components with no business logic and NEVER imports from `features/`; `features/*/components/` is feature-scoped and may know the domain. Add `'use client'` only if the component uses hooks, events or browser APIs (not on every component: unnecessary client JS). Never pass raw API/fetch data as props: transform it into typed props and validate with Zod first. Props interfaces always accept an optional `className` for Tailwind override. The shared data table is specified once in `admin-app/data-table.md`: do not write a second `components/data-table.tsx`; a feature list is a Tier 3 component that owns the columns and the URL-to-table mapping.",
|
|
2144
2147
|
"verifiedAgainst": "Next.js 16 + shadcn 4 CLI (the code blocks typecheck under `tsc --strict`).",
|
|
2145
2148
|
"provedBy": []
|
|
2146
2149
|
},
|
|
@@ -2168,7 +2171,7 @@
|
|
|
2168
2171
|
"server": "#server-component--tanstack-query-handoff",
|
|
2169
2172
|
"client": "#usequery-hook-pattern"
|
|
2170
2173
|
},
|
|
2171
|
-
"digest": "Server Components
|
|
2174
|
+
"digest": "Server Components do the initial load and call the .NET backend directly with BACKEND_API_PREFIX; Client Components never call the backend — they hit a same-origin proxy route with PROXY_API_PREFIX. Two named constants, never one shared API_PREFIX: the side that drifts breaks silently at runtime. Client data is TanStack Query 5: useQuery for reads, useMutation for writes, then invalidateQueries({ queryKey: userKeys.lists() }) (object syntax). Keys come from a per-feature key factory, never hardcoded ['users']. Every response is parsed with a Zod schema. QueryClient: staleTime 60s, retry 1, created once in useState; the Server Component passes initialData to the client hook. FORBIDDEN: useEffect(() => fetch…, []) and fetching a whole collection to page/sort/filter in the browser — page on the server, query in the URL.",
|
|
2172
2175
|
"verifiedAgainst": "Next.js 15 + TanStack Query 5 + Zod 4.",
|
|
2173
2176
|
"provedBy": []
|
|
2174
2177
|
},
|
|
@@ -2227,8 +2230,8 @@
|
|
|
2227
2230
|
"scroll": "#section-3-scroll-animations",
|
|
2228
2231
|
"accessibility": "#section-7-wcag-accessibility-mandatory"
|
|
2229
2232
|
},
|
|
2230
|
-
"digest": "
|
|
2231
|
-
"verifiedAgainst": "Motion for React 12 (`motion`, imports from `motion/react`).",
|
|
2233
|
+
"digest": "Component-level motion with Motion for React (the stack table's 'Framer Motion', its former name; motion 12+, current npm major 14): npm install motion and import from 'motion/react'. framer-motion is not deprecated (motion depends on it and re-exports it), but a codebase keeps one import path, motion/react, and never adds framer-motion alongside it. Variants live in motion/variants.ts (fadeIn, slideInUp/Down/Left/Right, scaleIn, staggerContainer, staggerItem, pageTransition) and take durations and easings from @/lib/design-tokens (fast 0.15, base 0.3); never hardcode duration numbers or easing arrays. Scroll reveals: whileInView with viewport once: true for simple cases, useInView for control. Page transitions: AnimatePresence mode='wait' keyed by usePathname(), subtle (y: 8), inside a 'use client' PageTransition provider -- the root app/layout.tsx stays a Server Component (no 'use client', keeps metadata) and just renders the provider. WCAG is mandatory: useReducedMotion() strips x/y/scale and keeps opacity, plus a prefers-reduced-motion CSS fallback. Skeletons use CSS animate-pulse, not motion. Limit motion to 3-5 moments per page. Scroll-driven scenes (ScrollTrigger, Lenis) belong to GSAP; never share an element with it.",
|
|
2234
|
+
"verifiedAgainst": "Motion for React 12+ (`motion`, imports from `motion/react`); the npm registry and the `motion`/`framer-motion`/`motion-dom` 14.0.0 typings were read on 2026-10-03 (`motion/react` re-exports `framer-motion`, which re-exports `motion-dom`: `Variants`, `useInView`, `AnimatePresence`, `useReducedMotion`, `staggerChildren`/`delayChildren` all present). The TSX snippets are documentary.",
|
|
2232
2235
|
"provedBy": []
|
|
2233
2236
|
},
|
|
2234
2237
|
{
|
|
@@ -2255,7 +2258,7 @@
|
|
|
2255
2258
|
"files": "#complete-reference-table",
|
|
2256
2259
|
"components": "#complete-reference-table"
|
|
2257
2260
|
},
|
|
2258
|
-
"digest": "
|
|
2261
|
+
"digest": "Next.js naming (prevents Linux case-sensitivity bugs). File names are ALWAYS kebab-case (`user-card.tsx`, never `UserCard.tsx`); exports are PascalCase for components (`UserCard`) and camelCase with a `use` prefix for hooks, whose files are kebab-case too (`use-users.ts` -> `useUsers`, `use-user.ts` for a single GET, `use-create-user.ts`, `use-update-user.ts`, `use-delete-user.ts`). Zod schema files end in `.schemas.ts` (`createUserSchema`) and type files in `.types.ts`, with types derived via `z.infer` instead of hand-written duplicates. Components use named exports (`export function UserCard`, not `export default`); `page.tsx` exports `default`. A feature `index.ts` re-exports. Never mix cases within a category (no `UserCard.tsx` next to `user-profile.tsx`).",
|
|
2259
2262
|
"verifiedAgainst": "Next.js 15 + Zod 4.",
|
|
2260
2263
|
"provedBy": []
|
|
2261
2264
|
},
|
|
@@ -2283,7 +2286,7 @@
|
|
|
2283
2286
|
"auth": "#route-handlers-bff-pattern",
|
|
2284
2287
|
"caching": "#react-query--neon"
|
|
2285
2288
|
},
|
|
2286
|
-
"digest": "
|
|
2289
|
+
"digest": "Next.js 15 App Router (not Pages Router): Server Components by default, `'use client'` only for state, effects, events or browser APIs; colocate `loading.tsx` and `error.tsx` (the latter MUST be `'use client'`) with `page.tsx`. Route Handlers act as a BFF: check `auth.getSession()` (401 if absent) and delegate to the .NET API; database access lives in the .NET backend via EF Core, NEVER in Next.js route handlers. Validate input with Zod on client and server (`safeParse`, 400). Fetch with TanStack Query (`useQuery`/`useMutation`, `staleTime: 60_000`, `retry: 1`, `invalidateQueries` on success), never `useEffect` for data fetching. Forms: react-hook-form + `zodResolver`. shadcn is copied via `npx shadcn@latest add`, not an npm dependency. Keep `\"strict\": true` plus `noUncheckedIndexedAccess` (agents self-correct from compiler errors); no `any` for API responses (Zod schema + `z.infer`).",
|
|
2287
2290
|
"verifiedAgainst": "Next.js 15 + TanStack Query 5 + Zod 4 + react-hook-form 7.",
|
|
2288
2291
|
"provedBy": []
|
|
2289
2292
|
},
|
|
@@ -2310,7 +2313,7 @@
|
|
|
2310
2313
|
"structure": "#canonical-folder-tree",
|
|
2311
2314
|
"organization": "#feature-index-pattern"
|
|
2312
2315
|
},
|
|
2313
|
-
"digest": "src/
|
|
2316
|
+
"digest": "Next.js 15 App Router, src/ layout with the @/ alias, feature-based. src/app/ is routing only (layout, page, loading, error) and imports from features/, never the reverse. Each src/features/{feature-name}/ holds components/, hooks/ (TanStack Query hooks such as use-users.ts, use-create-user.ts), types/ (*.types.ts plus *.schemas.ts with Zod and z.infer) and an index.ts that is the explicit public API: import from '@/features/users', never from deep paths. NEVER import one feature from another (extract to components/ or lib/); components/ must not import features/, is presentation only with NO business logic, and components/ui/ is shadcn, never edited directly. Shared hooks/ make no API calls. lib/ holds api-client.ts (typed fetch wrapper for the .NET API) and query-client.tsx; types/api.ts has PaginatedResponse<T> and ApiError; env.mjs validates env vars with Zod.",
|
|
2314
2317
|
"verifiedAgainst": "Next.js 15 (App Router, `src/` layout).",
|
|
2315
2318
|
"provedBy": []
|
|
2316
2319
|
},
|
|
@@ -2338,7 +2341,7 @@
|
|
|
2338
2341
|
"patterns": "#state-decision-tree",
|
|
2339
2342
|
"server": "#server-state-tanstack-query"
|
|
2340
2343
|
},
|
|
2341
|
-
"digest": "TanStack Query
|
|
2344
|
+
"digest": "Server state (anything from the .NET API) lives in TanStack Query, never copied into `useState` via `useEffect`; derive state from server data instead of syncing it. Local UI state (modal open, form step, selected id) uses `useState`. A list's page, sort and filters, and a page's active tab, go in the URL (`searchParams`), never `useState`, so a refresh or shared link reopens the same view. Do not use React Context for server state (no caching or dedup); Context is for truly global theme, auth user or locale, and prop drilling 2-3 levels is fine. NEVER install Zustand or Redux before exhausting Server Components + TanStack Query. Zustand is justified only if ALL hold: state needed in 5+ unrelated components, complex update logic, Context causes measurable re-render problems, and the state is not from the server.",
|
|
2342
2345
|
"verifiedAgainst": "Next.js 15 + TanStack Query 5 + Zustand 5.",
|
|
2343
2346
|
"provedBy": []
|
|
2344
2347
|
},
|
|
@@ -2542,8 +2545,8 @@
|
|
|
2542
2545
|
"deployment": "#zero-downtime-deploys",
|
|
2543
2546
|
"ssh": "#triggering-a-deploy-via-ssh--api"
|
|
2544
2547
|
},
|
|
2545
|
-
"digest": "Coolify is the self-hosted Docker PaaS.
|
|
2546
|
-
"verifiedAgainst": ".NET 10 + Next.js 15 + Node 22 (Docker base images).",
|
|
2548
|
+
"digest": "Coolify is the self-hosted Docker PaaS. We use no Coolify MCP/CLI — all access is via SSH into the VPS, hitting the Coolify API at localhost:8000/api/v1 with a server-side token (never printed, never leaves the SSH session). Configure environment variables in Coolify UI/API — not in Dockerfile. Configure /health endpoint for health checks. HTTPS via Let's Encrypt automatic (Traefik). Redeploys trigger via POST /api/v1/deploy?uuid={uuid} over SSH (Coolify 4.3.23 answers GET with \"This endpoint has changed to a POST request\" and deploys nothing); a queued deploy returns a deployment_uuid, its absence means nothing was deployed.",
|
|
2549
|
+
"verifiedAgainst": ".NET 10 + Next.js 15 + Node 22 (Docker base images) + Coolify 4.x API. The `POST /api/v1/deploy` contract was checked against the Coolify docs/OpenAPI on 2026-10-03, and Coolify 4.3.23 was observed answering `GET /deploy` with \"This endpoint has changed to a POST request\"; Dockerfiles and snippets are documentary.",
|
|
2547
2550
|
"provedBy": []
|
|
2548
2551
|
},
|
|
2549
2552
|
{
|
|
@@ -2606,7 +2609,7 @@
|
|
|
2606
2609
|
"setup": "#install-pgrag",
|
|
2607
2610
|
"pipeline": "#full-rag-pipeline-example"
|
|
2608
2611
|
},
|
|
2609
|
-
"digest": "
|
|
2612
|
+
"digest": "pgrag (Neon `rag` extension family) is EXPERIMENTAL: use it for prototyping and simple SQL-only RAG, not production without testing. Run `SET neon.allow_unstable_extensions='true'` before `CREATE EXTENSION rag CASCADE` (also `rag_bge_small_en_v15`, `rag_jina_reranker_v1_tiny_en`). Local bge-small embeddings are 384 dims, OpenAI text-embedding-3-small is 1536: NEVER mix models in one column or use the local one when the app uses another model (dimension mismatch breaks search). Chunk with `rag.chunks_by_character_count` (1000 chars, 200 overlap); `embedding_for_passage` for documents, `embedding_for_query` for queries; create the pgvector HNSW index (m=16, ef_construction=64) after the initial load; rerank with `rerank_distance` (sort ASC). Keep API keys out of SQL scripts. For production .NET needing custom logic, use a typed MAF tool over pgvector (`ai-agents-rag-custom-pgvector`).",
|
|
2610
2613
|
"verifiedAgainst": "Neon pgrag (`rag` extension family — experimental, see Core Rules).",
|
|
2611
2614
|
"provedBy": []
|
|
2612
2615
|
},
|
|
@@ -2635,8 +2638,8 @@
|
|
|
2635
2638
|
"setup": "#enable-pgvector",
|
|
2636
2639
|
"queries": "#similarity-search"
|
|
2637
2640
|
},
|
|
2638
|
-
"digest": "
|
|
2639
|
-
"verifiedAgainst": ".NET 10 + Pgvector.EntityFrameworkCore +
|
|
2641
|
+
"digest": "pgvector on Neon with .NET VSA: packages Npgsql.EntityFrameworkCore.PostgreSQL 10.0.3 + Pgvector.EntityFrameworkCore 0.3.0 (snake_case columns mapped with HasColumnName, no naming-convention package); HasPostgresExtension('vector') in OnModelCreating emits CREATE EXTENSION in the migration. Map the column as Pgvector `Vector` (`vector(1536)` for text-embedding-3-small; EF does not map float[] or ReadOnlyMemory<float>) and call `npgsql.UseVector()` inside UseNpgsql (NpgsqlDataSourceBuilder.UseVector only for raw Npgsql). ALWAYS an HNSW index (HasMethod('hnsw'), vector_cosine_ops, m 16, ef_construction 64); the operator class must match the LINQ function (CosineDistance/L2Distance/MaxInnerProduct) or Postgres seq-scans. Query in the slice handler through ApplicationDbContext: `d.Embedding!.CosineDistance(query)`, filter by distance <= 1 - minSimilarity, OrderBy distance ASC (similarity = 1 - distance, never ORDER BY similarity DESC), return Result; no DocumentRepository, no raw SQL from C# (SQL functions such as match_documents/hybrid search only with a decisions.md justification). Ids from Guid.CreateVersion7() in the handler, never gen_random_uuid() defaults. ef_search (default 40) on the pooled endpoint needs SET LOCAL inside the query's transaction.",
|
|
2642
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview) + Npgsql.EntityFrameworkCore.PostgreSQL 10.0.3 + Pgvector.EntityFrameworkCore 0.3.0 + Microsoft.Extensions.AI 10.9.0 (ai-pin 2026-09-08). The entity, configuration, DbContext, search-handler and raw-Npgsql blocks compile with `TreatWarningsAsErrors` (handler over the `Result`/`IHandler` of `result-pattern.md`/`vertical-slice.md`), and the handler's query shape was translated with `ToQueryString()` to `ORDER BY d.embedding <=> @query`; the SQL (index DDL, `ef_search`, the two SQL functions) is documentary, checked against the pgvector README.",
|
|
2640
2643
|
"provedBy": []
|
|
2641
2644
|
},
|
|
2642
2645
|
{
|
|
@@ -2664,8 +2667,8 @@
|
|
|
2664
2667
|
"setup": "#neon-cli-setup",
|
|
2665
2668
|
"connection": "#connection-strings"
|
|
2666
2669
|
},
|
|
2667
|
-
"digest": "
|
|
2668
|
-
"verifiedAgainst": ".NET 10 + Npgsql
|
|
2670
|
+
"digest": "Neon serverless Postgres with .NET/EF Core. Two connection strings read through IConfiguration: `ConnectionStrings:DefaultConnection` = pooled `-pooler` endpoint for application traffic (Neon's DATABASE_URL) and `ConnectionStrings:MigrationConnection` = direct endpoint for migrations, `dotnet ef` and advisory locks (Neon's DATABASE_URL_UNPOOLED; PgBouncer does not support advisory locks; the `IDesignTimeDbContextFactory` reads it via appsettings + AddUserSecrets + AddEnvironmentVariables). Never hardcode or commit them: user-secrets in development, Coolify env vars (`ConnectionStrings__DefaultConnection`) in production, appsettings.json keeps empty values. Use the keyword format (`Host=...;SSL Mode=Require`): Npgsql 10 rejects the console's `postgresql://` URI, and `Trust Server Certificate` is obsolete (does nothing). Scale-to-zero suspends compute after 5 minutes idle by default (about 300-500ms cold start), so configure `EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: 10s)` and `CommandTimeout(30)`; suspend timeout is set at branch creation (`--suspend-timeout`, `--cu` range) or for an existing compute via Console/API (`suspend_timeout_seconds`, 60-604800), never by recreating main. Branches are copy-on-write: never leave them without expiration (`--expires-at`); `feature/*` 7 days, `ci-*` 1 day, `main` and `dev` never. neonctl: `auth`, `branches create|reset|delete`.",
|
|
2671
|
+
"verifiedAgainst": ".NET 10 (SDK 10.0.400-preview) + Npgsql.EntityFrameworkCore.PostgreSQL 10.0.3 + neonctl. The DbContext registration, design-time factory and cold-start blocks compile with `TreatWarningsAsErrors`; that Npgsql 10 rejects `postgresql://` URIs and marks `Trust Server Certificate` as \"no longer needed and does nothing\" was measured on 10.0.3; the suspend-timeout API and `--cu` ranges were checked against the Neon docs (context7). neonctl commands are documentary.",
|
|
2669
2672
|
"provedBy": []
|
|
2670
2673
|
},
|
|
2671
2674
|
{
|
|
@@ -252,7 +252,7 @@ O detector é por caminho, e as três formas conhecidas de escapar dele estão d
|
|
|
252
252
|
alta, porque um detector que se apresenta como completo e não é vale menos que nenhum:
|
|
253
253
|
|
|
254
254
|
1. **eval trivialmente verde** — um cenário só, asserção vazia. É a mesma classe de contorno
|
|
255
|
-
de um teste vazio, e a resposta é
|
|
255
|
+
de um teste vazio, e a resposta é o avaliador do Gate 3 (bloqueador `teste`: teste que não morde), não uma segunda regra determinística
|
|
256
256
|
que também seria contornável;
|
|
257
257
|
2. **prompt publicado direto no banco**, sem tocar arquivo;
|
|
258
258
|
3. **modelo trocado por variável de ambiente** no provedor de deploy — invisível ao
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
## Fronteira com o Model Registry
|
|
13
13
|
|
|
14
|
-
`ai-agents-providers-model-registry` é **Layer 0** (
|
|
14
|
+
`ai-agents-providers-model-registry` é **Layer 0** (lido pela persona `maf-expert` e pela rule `ai-agents-standards`) e continua dono do **schema**:
|
|
15
15
|
o formato do documento, `defaultAlias`, o fallback e a tabela de providers. **Este** standard é dono
|
|
16
16
|
dos **valores e dos botões de runtime**: timeout, retry, strict, amostragem, esforço de raciocínio e
|
|
17
17
|
o pin de versão do SDK.
|