@polymorphism-tech/morph-spec 9.0.0 → 9.2.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 +8 -9
- package/README.md +38 -36
- package/bin/morph-spec.js +11 -63
- package/bin/validate.js +1 -39
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +2 -1
- package/framework/MORPH.md +3 -3
- package/framework/agents.json +19 -11
- package/framework/commands/morph-apply.md +1 -1
- package/framework/commands/morph-status.md +1 -1
- package/framework/docs/CLI.md +22 -31
- package/framework/evals/review-checklist.md +12 -2
- package/framework/hooks/README.md +8 -44
- package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +6 -49
- package/framework/hooks/claude-code/core/block-raw-worktree-add.js +2 -35
- package/framework/hooks/claude-code/core/chain.js +4 -65
- package/framework/hooks/claude-code/core/comment-guard.js +2 -16
- package/framework/hooks/claude-code/core/enforce-phase-writes.js +6 -50
- package/framework/hooks/claude-code/core/gate-guard.js +7 -67
- package/framework/hooks/claude-code/core/graph-refresh-kick.js +3 -24
- package/framework/hooks/claude-code/core/heavy-gate.js +3 -21
- package/framework/hooks/claude-code/core/heavy-release.js +2 -13
- package/framework/hooks/claude-code/core/loop-detect.js +2 -31
- package/framework/hooks/claude-code/core/pre-bash-denylist.js +0 -4
- package/framework/hooks/claude-code/core/protect-spec-files.js +7 -67
- package/framework/hooks/claude-code/core/state-sync.js +12 -68
- package/framework/hooks/claude-code/core/telemetry-log.js +12 -93
- package/framework/hooks/claude-code/core/validate-completion.js +11 -57
- package/framework/hooks/claude-code/core/warn-bash-source-write.js +1 -9
- package/framework/hooks/claude-code/core/worktree-context.js +10 -110
- package/framework/hooks/claude-code/core/worktree-create.js +6 -70
- package/framework/hooks/claude-code/core/worktree-env-inject.js +5 -56
- package/framework/hooks/claude-code/core/worktree-remove.js +5 -31
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/hooks/shared/activity-logger.js +9 -89
- package/framework/hooks/shared/agent-reap.js +2 -17
- package/framework/hooks/shared/build-check.js +6 -75
- package/framework/hooks/shared/claim-registry.js +9 -119
- package/framework/hooks/shared/command-tokens.js +6 -51
- package/framework/hooks/shared/comment-rules.js +5 -20
- package/framework/hooks/shared/comment-scanner.js +6 -25
- package/framework/hooks/shared/comment-stripper.js +11 -85
- package/framework/hooks/shared/e2e-check.js +0 -0
- package/framework/hooks/shared/errata.js +2 -15
- package/framework/hooks/shared/feature-locator.js +11 -95
- package/framework/hooks/shared/frontend-locations.js +1 -3
- package/framework/hooks/shared/gate-question.js +1 -7
- package/framework/hooks/shared/git-exclude.js +3 -20
- package/framework/hooks/shared/git-paths.js +8 -104
- package/framework/hooks/shared/graph-freshness.js +22 -166
- package/framework/hooks/shared/graph-refresh.js +21 -149
- package/framework/hooks/shared/heavy-command.js +4 -12
- package/framework/hooks/shared/hook-response.js +8 -83
- package/framework/hooks/shared/morph-cli.js +8 -52
- package/framework/hooks/shared/payload-utils.js +10 -132
- package/framework/hooks/shared/phase-utils.js +1 -42
- package/framework/hooks/shared/redact-secrets.js +4 -15
- package/framework/hooks/shared/reparse-scan.js +6 -66
- package/framework/hooks/shared/slice-progress.js +4 -23
- package/framework/hooks/shared/source-files.js +4 -17
- package/framework/hooks/shared/state-reader.js +13 -183
- package/framework/hooks/shared/state-writer.js +8 -52
- package/framework/hooks/shared/stdin-reader.js +1 -11
- package/framework/hooks/shared/telemetry-logger.js +7 -67
- package/framework/hooks/shared/transcript-usage.js +7 -29
- package/framework/hooks/shared/worktree-root.js +7 -29
- package/framework/rules/csharp-standards.md +1 -1
- package/framework/rules/frontend-standards.md +1 -0
- package/framework/rules/hangfire-standards.md +1 -1
- package/framework/rules/neon-standards.md +1 -1
- package/framework/rules/nextjs-standards.md +1 -1
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +4 -4
- package/framework/skills/core/morph-hotfix/SKILL.md +3 -3
- package/framework/skills/core/morph-machine/SKILL.md +1 -1
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +9 -7
- package/framework/skills/core/morph-review/SKILL.md +9 -6
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +29 -12
- package/framework/standards/STANDARDS.json +36 -14
- package/framework/standards/STANDARDS.meta.json +16 -2
- package/framework/standards/ai-agents/agent-archetypes.md +2 -2
- package/framework/standards/ai-agents/agent-session.md +1 -1
- package/framework/standards/ai-agents/conversational-agent-with-phases.md +4 -4
- package/framework/standards/ai-agents/durable-workflows-hitl.md +3 -3
- package/framework/standards/ai-agents/guardrails.md +1 -1
- package/framework/standards/ai-agents/multi-agent-patterns.md +2 -2
- package/framework/standards/ai-agents/observability-patterns.md +1 -1
- package/framework/standards/ai-agents/production.md +1 -1
- package/framework/standards/ai-agents/prompt-sources.md +2 -2
- package/framework/standards/ai-agents/providers/model-registry.md +1 -1
- package/framework/standards/ai-agents/rag-custom-pgvector.md +2 -2
- package/framework/standards/ai-agents/setup.md +2 -2
- package/framework/standards/ai-agents/sweet-spot.md +2 -2
- package/framework/standards/ai-agents/tool-adapters.md +0 -2
- package/framework/standards/ai-agents/vector-data-extensions.md +4 -4
- package/framework/standards/ai-agents/workflows.md +1 -1
- package/framework/standards/architecture/code-comments.md +1 -1
- package/framework/standards/architecture/vertical-slice/vertical-slice.md +1 -1
- package/framework/standards/backend/api/validation.md +1 -1
- package/framework/standards/backend/dotnet/testing.md +10 -4
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +5 -5
- package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +1 -1
- package/framework/standards/backend/integrations/neon-auth/neon-auth.md +2 -2
- package/framework/standards/data/nosql/cache/redis.md +1 -1
- package/framework/standards/data/nosql/cosmos-db.md +3 -3
- package/framework/standards/frontend/admin-app/forms.md +1 -1
- package/framework/standards/frontend/design-system/art-direction.md +88 -0
- package/framework/standards/frontend/design-system/premium-finish.md +77 -2
- package/framework/standards/frontend/nextjs/testing.md +10 -6
- package/framework/standards/infrastructure/neon/neon-pgvector.md +5 -5
- package/framework/templates/.idea/morph-templates.xml +92 -0
- package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
- package/framework/templates/CLAUDE.md.core.template +3 -3
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- package/framework/templates/REGISTRY.json +9 -9
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
- package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
- package/framework/templates/docs/plan.md +3 -1
- package/framework/templates/docs/ui-mockups.md +4 -0
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
- package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
- package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +1 -1
- package/src/commands/context/context-refresh.js +0 -16
- package/src/commands/dashboard/dashboard.js +2 -8
- package/src/commands/e2e/e2e.js +17 -104
- package/src/commands/graph/affected.js +0 -14
- package/src/commands/graph/build.js +11 -50
- package/src/commands/graph/explain.js +0 -16
- package/src/commands/graph/status.js +1 -12
- package/src/commands/mcp/mcp-setup.js +4 -62
- package/src/commands/observability/cost.js +5 -57
- package/src/commands/observability/telemetry.js +1 -14
- package/src/commands/project/branch.js +4 -45
- package/src/commands/project/claim.js +4 -48
- package/src/commands/project/doctor.js +48 -302
- package/src/commands/project/env.js +1 -27
- package/src/commands/project/fleet.js +3 -32
- package/src/commands/project/init.js +4 -68
- package/src/commands/project/install-plugin-cmd.js +0 -1
- package/src/commands/project/standards.js +1 -62
- package/src/commands/project/status.js +0 -53
- package/src/commands/project/update.js +31 -239
- package/src/commands/project/worktree.js +108 -882
- package/src/commands/scaffold/scaffold.js +0 -25
- package/src/commands/state/advance.js +14 -85
- package/src/commands/state/approve.js +15 -97
- package/src/commands/state/archive.js +12 -64
- package/src/commands/state/auto-approval.js +2 -5
- package/src/commands/state/create.js +22 -109
- package/src/commands/state/delete.js +11 -63
- package/src/commands/state/finish.js +98 -475
- package/src/commands/state/gate-check.js +22 -132
- package/src/commands/state/gate-decision.js +3 -39
- package/src/commands/state/handoff.js +3 -30
- package/src/commands/state/list.js +14 -84
- package/src/commands/state/report-check.js +8 -58
- package/src/commands/state/retype.js +4 -26
- package/src/commands/validation/index.js +0 -3
- package/src/commands/validation/mutate.js +11 -11
- package/src/commands/validation/plan-check.js +4 -2
- package/src/commands/validation/tests-audit.js +7 -0
- package/src/commands/validation/validate-feature.js +10 -97
- package/src/commands/validation/verify.js +30 -113
- package/src/core/paths/output-schema.js +2 -101
- package/src/core/state/feature-identity.js +1 -25
- package/src/core/state/gate-order.js +0 -27
- package/src/core/state/lifecycle-audit.js +8 -100
- package/src/core/state/state-manager.js +22 -304
- package/src/core/templates/template-registry.js +2 -97
- package/src/core/templates/template-renderer.js +13 -93
- package/src/core/templates/template-seed.js +0 -1
- package/src/core/work-types.js +1 -36
- package/src/dashboard/app/App.jsx +1 -8
- package/src/dashboard/app/components/ActivityFeed.jsx +0 -5
- package/src/dashboard/app/components/CommandPalette.jsx +0 -7
- package/src/dashboard/app/components/DetailPanel.jsx +1 -5
- package/src/dashboard/app/components/EntityLink.jsx +0 -12
- package/src/dashboard/app/components/ErrorBoundary.jsx +1 -8
- package/src/dashboard/app/components/KnowledgeMarkdown.jsx +0 -11
- package/src/dashboard/app/components/Markdown.jsx +0 -9
- package/src/dashboard/app/components/PhaseRail.jsx +0 -11
- package/src/dashboard/app/components/SearchFilter.jsx +0 -4
- package/src/dashboard/app/components/Sidebar.jsx +0 -5
- package/src/dashboard/app/hooks/useMorphQuery.js +1 -11
- package/src/dashboard/app/hooks/usePref.js +1 -5
- package/src/dashboard/app/lib/format.js +0 -2
- package/src/dashboard/app/lib/phases.js +1 -5
- package/src/dashboard/app/lib/project.js +0 -12
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/AgentMap.jsx +1 -8
- package/src/dashboard/app/pages/FeatureDetail.jsx +1 -5
- package/src/dashboard/app/pages/Features.jsx +1 -8
- package/src/dashboard/app/pages/Guide.jsx +0 -1
- package/src/dashboard/app/pages/HookInspector.jsx +2 -23
- package/src/dashboard/app/pages/PhasePipeline.jsx +0 -3
- package/src/dashboard/app/pages/Portfolio.jsx +0 -1
- package/src/dashboard/app/pages/RulesMap.jsx +1 -16
- package/src/dashboard/app/pages/SkillsLibrary.jsx +1 -16
- package/src/dashboard/app/pages/Standards.jsx +2 -17
- package/src/dashboard/scanner/activity-scanner.js +10 -69
- package/src/dashboard/scanner/agents-scanner.js +1 -23
- package/src/dashboard/scanner/docs-scanner.js +0 -6
- package/src/dashboard/scanner/feature-status.js +2 -5
- package/src/dashboard/scanner/features-scanner.js +10 -66
- package/src/dashboard/scanner/hooks-scanner.js +5 -28
- package/src/dashboard/scanner/index.js +0 -4
- package/src/dashboard/scanner/portfolio.js +5 -29
- package/src/dashboard/scanner/project-api.js +8 -54
- package/src/dashboard/scanner/rules-scanner.js +1 -2
- package/src/dashboard/scanner/skills-scanner.js +2 -12
- package/src/dashboard/scanner/standards-scanner.js +2 -6
- package/src/dashboard/vite-plugin-morph-data.js +5 -19
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/ai/ai-checks.js +7 -52
- package/src/lib/ai/ai-project-scan.js +14 -108
- package/src/lib/ai/code-audit.js +7 -63
- package/src/lib/ai/pin-drift.js +8 -51
- package/src/lib/ai/registry-audit.js +11 -90
- package/src/lib/ci/ci-verify.js +4 -19
- package/src/lib/ci/github-ci.js +9 -37
- package/src/lib/ci/workflow-scaffold.js +14 -10
- package/src/lib/detectors/claude-config-detector.js +13 -74
- package/src/lib/detectors/index.js +4 -50
- package/src/lib/e2e/applicability.js +37 -0
- package/src/lib/e2e/compose-env.js +5 -66
- package/src/lib/e2e/stack-teardown.js +6 -40
- package/src/lib/generators/architecture-scanner.js +18 -156
- package/src/lib/generators/handoff-generator.js +9 -53
- package/src/lib/generators/scaffold-generator.js +5 -101
- package/src/lib/generators/settings-generator.js +4 -37
- package/src/lib/git/branch-classifier.js +11 -84
- package/src/lib/git/default-branch.js +14 -169
- package/src/lib/git/evidence-staleness.js +1 -0
- package/src/lib/git/gh.js +2 -17
- package/src/lib/git/pending-prs.js +6 -37
- package/src/lib/git/pr-files.js +3 -28
- package/src/lib/git/pr-index.js +3 -34
- package/src/lib/git/tree-fingerprint.js +3 -15
- package/src/lib/git/tree-state.js +6 -33
- package/src/lib/graph/god-nodes.js +2 -22
- package/src/lib/graph/graph-health.js +3 -24
- package/src/lib/graph/graph-loader.js +5 -56
- package/src/lib/graph/graphify-runtime.js +7 -37
- package/src/lib/graph/graphifyignore.js +8 -74
- package/src/lib/graph/sanitize.js +16 -136
- package/src/lib/heavy/cleanup.js +1 -1
- package/src/lib/installers/effects.js +8 -93
- package/src/lib/installers/mcp-installer.js +9 -169
- package/src/lib/installers/memory-installer.js +4 -27
- package/src/lib/installers/templates-reconcile.js +5 -60
- package/src/lib/mutation/adapters.js +6 -17
- package/src/lib/mutation/dotnet-introspection.js +20 -106
- package/src/lib/mutation/runner.js +23 -75
- package/src/lib/mutation/subset.js +1 -4
- package/src/lib/mutation/trx.js +0 -1
- package/src/lib/plan/artifact-vocabulary.js +5 -25
- package/src/lib/plan/checks.js +34 -33
- package/src/lib/plan/plan-parser.js +7 -8
- package/src/lib/projects/registry.js +7 -44
- package/src/lib/review-reports.js +11 -26
- package/src/lib/risk-detector.js +41 -173
- package/src/lib/specs/adr-index.js +6 -34
- package/src/lib/specs/frontmatter.js +2 -15
- package/src/lib/specs/gfm-table.js +1 -7
- package/src/lib/specs/revocations.js +1 -14
- package/src/lib/specs/screen-checklist.js +47 -124
- package/src/lib/stack/dotnet-build-ignores.js +2 -6
- package/src/lib/stack/stack-profile.js +1 -28
- package/src/lib/stack/stack-scan.js +1 -8
- package/src/lib/stack-filter.js +4 -27
- package/src/lib/standards/registry.js +1 -7
- package/src/lib/standards/sections.js +2 -13
- package/src/lib/standards/verified-against.js +19 -191
- package/src/lib/tasks/eval-node.js +21 -169
- package/src/lib/tasks/linux-runner.js +18 -142
- package/src/lib/tasks/test-nodes.js +43 -240
- package/src/lib/tasks/test-runner.js +43 -341
- package/src/lib/telemetry/metrics.js +7 -36
- package/src/lib/telemetry/telemetry-reader.js +13 -125
- package/src/lib/telemetry/verify-event.js +2 -30
- package/src/lib/tests-audit/audit.js +96 -0
- package/src/lib/validators/code-budget/code-budget-validator.js +4 -44
- package/src/lib/validators/code-budget/index.js +0 -7
- package/src/lib/validators/contracts/contract-compliance-validator.js +2 -24
- package/src/lib/validators/contracts/index.js +0 -6
- package/src/lib/validators/nextjs/index.js +0 -5
- package/src/lib/validators/nextjs/next-component-validator.js +4 -81
- package/src/lib/validators/packages/index.js +0 -6
- package/src/lib/validators/packages/package-validator.js +6 -56
- package/src/lib/validators/reuse/index.js +0 -8
- package/src/lib/validators/reuse/reuse-validator.js +11 -101
- package/src/lib/validators/reuse/symbol-scanner.js +6 -62
- package/src/lib/validators/traceability-check.js +5 -63
- package/src/lib/validators/validation-runner.js +21 -158
- package/src/lib/validators/verify-runner.js +85 -376
- package/src/lib/work-type-detector.js +5 -67
- package/src/lib/worktree/docker-audit.js +17 -136
- package/src/lib/worktree/env-allocator.js +10 -98
- package/src/lib/worktree/feature-truth.js +12 -115
- package/src/lib/worktree/finish-backup.js +32 -242
- package/src/lib/worktree/fleet-scanner.js +13 -95
- package/src/lib/worktree/ignored-triage.js +15 -91
- package/src/lib/worktree/vscode-settings.js +2 -3
- package/src/lib/worktree/worktree-audit.js +21 -213
- package/src/lib/worktree/worktree-include.js +3 -5
- package/src/scripts/global-install.js +3 -9
- package/src/scripts/install-plugin.js +1 -13
- package/src/scripts/setup-infra.js +17 -147
- package/src/utils/agents-installer.js +29 -276
- package/src/utils/banner.js +4 -25
- package/src/utils/claude-md-injector.js +1 -37
- package/src/utils/claude-settings-manager.js +1 -52
- package/src/utils/file-copier.js +11 -95
- package/src/utils/hooks-installer.js +21 -298
- package/src/utils/skills-installer.js +4 -101
- package/src/utils/version-checker.js +4 -83
- package/framework/commands/morph-proposal.md +0 -9
- package/framework/hooks/git/commit-msg/conventional-commits.sh +0 -33
- package/framework/hooks/git/pre-commit/agents.sh +0 -25
- package/framework/hooks/git/pre-commit/orchestrator.sh +0 -64
- package/framework/hooks/git/pre-push/run-tests.sh +0 -44
- package/src/commands/utils/index.js +0 -3
- package/src/lib/detectors/design-system-detector.js +0 -188
- package/src/lib/generators/design-system-generator.js +0 -508
- package/src/lib/specs/old-format.js +0 -68
- package/src/utils/agent-id-mapper.js +0 -11
|
@@ -628,7 +628,7 @@
|
|
|
628
628
|
"tool": "#vectorsearchtool-tool-maf",
|
|
629
629
|
"multi-tenant": "#multi-tenant"
|
|
630
630
|
},
|
|
631
|
-
"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
|
|
631
|
+
"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 plan.md (## Decisões) 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."
|
|
632
632
|
},
|
|
633
633
|
{
|
|
634
634
|
"id": "ai-agents-service-tier-flex",
|
|
@@ -801,7 +801,7 @@
|
|
|
801
801
|
"rules": "#padrões-obrigatórios",
|
|
802
802
|
"cqrs": "#anti-patterns-nunca-fazer-em-vsa"
|
|
803
803
|
},
|
|
804
|
-
"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 `
|
|
804
|
+
"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 `plan.md` (`## Decisões`). Não misture VSA com DDD."
|
|
805
805
|
},
|
|
806
806
|
{
|
|
807
807
|
"id": "backend-api-validation",
|
|
@@ -821,7 +821,7 @@
|
|
|
821
821
|
"rules": "#validation-patterns",
|
|
822
822
|
"state": "#state-checks-in-the-handler"
|
|
823
823
|
},
|
|
824
|
-
"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
|
|
824
|
+
"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 plan.md (## Decisões) and test each."
|
|
825
825
|
},
|
|
826
826
|
{
|
|
827
827
|
"id": "backend-database-postgresql-database",
|
|
@@ -966,7 +966,7 @@
|
|
|
966
966
|
"errorbody": "#rule-2--error-path-tests-assert-the-response-body-not-just-the-status-code",
|
|
967
967
|
"test-budget": "#test-budget"
|
|
968
968
|
},
|
|
969
|
-
"digest": "Inject TimeProvider (never DateTime.UtcNow / DateOnly.FromDateTime(DateTime.UtcNow) directly in a handler or validator) and fake it with FakeTimeProvider (Microsoft.Extensions.TimeProvider.Testing) in integration tests — deterministic, no midnight-UTC flake, boundary dates (today vs. yesterday) become facts about the fake clock instead of when the suite happens to run. xUnit + WebApplicationFactory error-path tests (400/404/409) must assert the ProblemDetails response BODY (title/detail/violated field or error code), never just the HTTP status code — a status-only assertion lets the wrong validation rule or the wrong error branch pass silently as long as the status matches.
|
|
969
|
+
"digest": "Inject TimeProvider (never DateTime.UtcNow / DateOnly.FromDateTime(DateTime.UtcNow) directly in a handler or validator) and fake it with FakeTimeProvider (Microsoft.Extensions.TimeProvider.Testing) in integration tests — deterministic, no midnight-UTC flake, boundary dates (today vs. yesterday) become facts about the fake clock instead of when the suite happens to run. xUnit + WebApplicationFactory error-path tests (400/404/409) must assert the ProblemDetails response BODY (title/detail/violated field or error code), never just the HTTP status code — a status-only assertion lets the wrong validation rule or the wrong error branch pass silently as long as the status matches. Tests are paid for by risk, not new code: one test per plan scenario with risco: (rule, money, contract, concurrency, data, regression) plus the regression test of the bug fixed, more only with a one-line justification on the scenario; a scenario without risk (CRUD, DTO, mapping, wiring, constants) is prova: leitura and gets no test; one layer per behavior (handler or endpoint, not both); scenarios of the same behavior (edge cases included) are rows of one [Theory], never copied [Fact]s; no test whose only assertion is a copy, config or prose string (that is an analyzer or a publish-time validation, outside the suite count); shared fixtures before new helpers; bugs and risky scenarios get tests in any order — the implementer runs its own filter once, never red-green cycles nor production mutation (the Gate 3 mutation proof shows the test bites); a surviving mutant is killed by tightening an assertion or adding a row, not by a new test."
|
|
970
970
|
},
|
|
971
971
|
{
|
|
972
972
|
"id": "backend-dotnet-vsa-handler-patterns",
|
|
@@ -988,7 +988,7 @@
|
|
|
988
988
|
"endpoint": "#complete-endpoint-example",
|
|
989
989
|
"registration": "#programcs-di-registration-order"
|
|
990
990
|
},
|
|
991
|
-
"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 `
|
|
991
|
+
"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 `plan.md` (`## Decisões`) justification."
|
|
992
992
|
},
|
|
993
993
|
{
|
|
994
994
|
"id": "backend-integrations-asaas-asaas-api",
|
|
@@ -1028,7 +1028,7 @@
|
|
|
1028
1028
|
"jobs": "#job-types",
|
|
1029
1029
|
"retry": "#retry--error-handling"
|
|
1030
1030
|
},
|
|
1031
|
-
"digest": "Hangfire 1.8.25 on .NET 10, only with a real reason (survive restarts, schedules, deferred retries) recorded in
|
|
1031
|
+
"digest": "Hangfire 1.8.25 on .NET 10, only with a real reason (survive restarts, schedules, deferred retries) recorded in plan.md (## Decisões); 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)."
|
|
1032
1032
|
},
|
|
1033
1033
|
{
|
|
1034
1034
|
"id": "backend-integrations-neon-auth-neon-auth",
|
|
@@ -1055,7 +1055,7 @@
|
|
|
1055
1055
|
"rls": "#row-level-security-integration",
|
|
1056
1056
|
"postmortem": "#known-failure-modes-postmortem"
|
|
1057
1057
|
},
|
|
1058
|
-
"digest": "Use @neondatabase/auth SDK for Next.js. Auth data lives in neon_auth schema — no external provider, no webhooks. Server: createNeonAuth() with NEON_AUTH_BASE_URL + NEON_AUTH_COOKIE_SECRET. Client: createAuthClient(). Pages: AuthView component. Protection: auth.middleware() with runtime='nodejs' (Edge times out minting the session cookie). Register every dev/preview origin in trusted_origins before testing login. Two named prefix constants (BACKEND_API_PREFIX / PROXY_API_PREFIX) — never share one between server-direct and client-proxy calls. Frontend never queries Neon directly for business data by default — only its own auth/session SDK; a Data API bypass requires a
|
|
1058
|
+
"digest": "Use @neondatabase/auth SDK for Next.js. Auth data lives in neon_auth schema — no external provider, no webhooks. Server: createNeonAuth() with NEON_AUTH_BASE_URL + NEON_AUTH_COOKIE_SECRET. Client: createAuthClient(). Pages: AuthView component. Protection: auth.middleware() with runtime='nodejs' (Edge times out minting the session cookie). Register every dev/preview origin in trusted_origins before testing login. Two named prefix constants (BACKEND_API_PREFIX / PROXY_API_PREFIX) — never share one between server-direct and client-proxy calls. Frontend never queries Neon directly for business data by default — only its own auth/session SDK; a Data API bypass requires a plan.md (## Decisões) ADR. .NET: tokens are EdDSA/Ed25519 (OKP) — Microsoft.IdentityModel.Tokens can't verify OKP keys and there's no OIDC discovery; fetch+cache the JWKS yourself and verify signatures manually via BouncyCastle.Cryptography + TokenValidationParameters.SignatureValidator (must return Microsoft.IdentityModel.JsonWebTokens.JsonWebToken, not JwtSecurityToken — else IDX10506). NeonAuth:BaseUrl is mandatory in appsettings.Development.json (public value). RLS: auth.user_id() via pg_session_jwt."
|
|
1059
1059
|
},
|
|
1060
1060
|
{
|
|
1061
1061
|
"id": "backend-integrations-resend-resend-email",
|
|
@@ -1096,7 +1096,7 @@
|
|
|
1096
1096
|
"patterns": "#cache-aside-pattern",
|
|
1097
1097
|
"invalidation": "#ttl-strategy"
|
|
1098
1098
|
},
|
|
1099
|
-
"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
|
|
1099
|
+
"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 plan.md (## Decisões) decision, implemented once at the cache boundary)."
|
|
1100
1100
|
},
|
|
1101
1101
|
{
|
|
1102
1102
|
"id": "data-nosql-cosmos-db",
|
|
@@ -1116,7 +1116,7 @@
|
|
|
1116
1116
|
"modeling": "#container-design",
|
|
1117
1117
|
"queries": "#handler-in-the-slice"
|
|
1118
1118
|
},
|
|
1119
|
-
"digest": "OPTIONAL — outside the baked-in stack. The default store is Neon (Postgres) via EF Core; Cosmos needs a
|
|
1119
|
+
"digest": "OPTIONAL — outside the baked-in stack. The default store is Neon (Postgres) via EF Core; Cosmos needs a plan.md (## Decisões) 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."
|
|
1120
1120
|
},
|
|
1121
1121
|
{
|
|
1122
1122
|
"id": "data-vector-search-rag-chunking",
|
|
@@ -1250,9 +1250,10 @@
|
|
|
1250
1250
|
"atmosphere": "#section-2-atmosphere-never-flat-color",
|
|
1251
1251
|
"loadin": "#section-3-one-orchestrated-load-in-beats-ten-micro-interactions",
|
|
1252
1252
|
"legibility": "#section-4-legibility-over-video-close-to-a-hard-rule",
|
|
1253
|
-
"order": "#section-7-order-of-application"
|
|
1253
|
+
"order": "#section-7-order-of-application",
|
|
1254
|
+
"apppatterns": "#section-8-patterns-for-app-screens"
|
|
1254
1255
|
},
|
|
1255
|
-
"digest": "The finish layer that separates a working build from one a client reads as expensive, applied from the start rather than as a final polish pass. Principles, never a fixed recipe, and never converge on the same choices across projects: commit to a display font chosen from the brand (stack defaults and the AI-tell faces like Space Grotesk/Playfair announce machine-generated); use atmosphere instead of flat color (feTurbulence film grain at low opacity, radial brand glow, vignette); concentrate effort on ONE orchestrated hero load-in with staggered animation-delay rather than scattered micro-interactions; text over media always gets a DIRECTIONAL scrim (dark where the copy lives, clear over the subject) plus text-shadow as insurance against bright frames; one precious accent used in three places or fewer. Define brand tokens as CSS variables first, then atmosphere, then hero, then accent, then details."
|
|
1256
|
+
"digest": "The finish layer that separates a working build from one a client reads as expensive, applied from the start rather than as a final polish pass. Principles, never a fixed recipe, and never converge on the same choices across projects: commit to a display font chosen from the brand (stack defaults and the AI-tell faces like Space Grotesk/Playfair announce machine-generated); use atmosphere instead of flat color (feTurbulence film grain at low opacity, radial brand glow, vignette); concentrate effort on ONE orchestrated hero load-in with staggered animation-delay rather than scattered micro-interactions; text over media always gets a DIRECTIONAL scrim (dark where the copy lives, clear over the subject) plus text-shadow as insurance against bright frames; one precious accent used in three places or fewer. Define brand tokens as CSS variables first, then atmosphere, then hero, then accent, then details. App screens too (every ui-designer surface): bottom sheet on mobile with 44px targets, stories-style progress and synchronized highlight sharing --i/--beat via animation-delay, scene cards without real data (never a made-up number), dot grid faded with mask-image, and a composed static frame for prefers-reduced-motion."
|
|
1256
1257
|
},
|
|
1257
1258
|
{
|
|
1258
1259
|
"id": "frontend-gsap-core",
|
|
@@ -1515,7 +1516,7 @@
|
|
|
1515
1516
|
"e2e": "#test-file-co-location",
|
|
1516
1517
|
"test-budget": "#test-budget"
|
|
1517
1518
|
},
|
|
1518
|
-
"digest": "Vitest for unit tests, React Testing Library for component tests. Mock next/navigation with vi.mock. Test Server Actions with direct function calls. Use MSW for API mocking in component tests. Playwright for E2E tests against running app. Never test implementation details — test user behavior and output.
|
|
1519
|
+
"digest": "Vitest for unit tests, React Testing Library for component tests. Mock next/navigation with vi.mock. Test Server Actions with direct function calls. Use MSW for API mocking in component tests. Playwright for E2E tests against running app. Never test implementation details — test user behavior and output. Tests are paid for by risk, not new code: one test per plan scenario with risco: plus the regression test of the bug fixed, more only with a one-line justification on the scenario; a component is not a budget unit — rendering, layout and copy are prova: leitura or e2e; scenarios of the same behavior are rows of one it.each, never copied it() blocks; no test whose only assertion is a copy string (lint or publish-time validation instead); shared wrappers, MSW handlers and factories before new helpers; bugs and risky scenarios get tests in any order — the implementer runs its own filter once, never red-green cycles nor production mutation."
|
|
1519
1520
|
},
|
|
1520
1521
|
{
|
|
1521
1522
|
"id": "frontend-scroll-driven-frame-scrub",
|
|
@@ -1689,7 +1690,7 @@
|
|
|
1689
1690
|
"setup": "#enable-pgvector",
|
|
1690
1691
|
"queries": "#similarity-search"
|
|
1691
1692
|
},
|
|
1692
|
-
"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
|
|
1693
|
+
"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 plan.md (## Decisões) 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."
|
|
1693
1694
|
},
|
|
1694
1695
|
{
|
|
1695
1696
|
"id": "infrastructure-neon-setup",
|
|
@@ -1829,7 +1830,7 @@
|
|
|
1829
1830
|
"not-worth": "#o-que-não-merece",
|
|
1830
1831
|
"size": "#tamanho"
|
|
1831
1832
|
},
|
|
1832
|
-
"digest": "Default is NO comment: code explains itself through names, types and tests. Before commenting, rename, extract a function or named constant, encode the state in the type, or write a test; comment only what none of these can express: an invariant the type does not express, an order that matters, an external quirk (third-party API, library bug with its link), or the contract of a package published for consumers outside the repo. Never process history (task, UC, ADR, FR, Gate, evaluator, spec.md, mockup: commit message and
|
|
1833
|
+
"digest": "Default is NO comment: code explains itself through names, types and tests. Before commenting, rename, extract a function or named constant, encode the state in the type, or write a test; comment only what none of these can express: an invariant the type does not express, an order that matters, an external quirk (third-party API, library bug with its link), or the contract of a package published for consumers outside the repo. Never process history (task, UC, ADR, FR, Gate, evaluator, spec.md, mockup: commit message and plan.md (## Decisões); in a test the link to the postcondition goes in the test NAME), never restate the code, no XML doc/JSDoc on application members that repeats the signature, no file headers, section banners, #region, commented-out code or loose TODOs, no claims about behavior (make them test assertions). One line is normal, ~3 is the ceiling; more than one comment line per ten code lines means the names are not doing the work. A heavily commented neighbour file is not a model. The comment-guard hook blocks an edit that ADDS process history, a banner/#region, a block over 3 lines or a doc-comment outside a published package; the verify validators node (code-budget) warns on added comments that cite process and on added comment density."
|
|
1833
1834
|
},
|
|
1834
1835
|
{
|
|
1835
1836
|
"id": "ai-agents-tool-adapters",
|
|
@@ -1857,6 +1858,27 @@
|
|
|
1857
1858
|
"regras": "#regras"
|
|
1858
1859
|
},
|
|
1859
1860
|
"digest": "A tool that carries business rule keeps apart three things that change for different reasons: the RULE (sealed class XOps(...), primary constructor, explicit AddScoped; never *Service, which MORPH.md bans as a layer between handler and data), the sentence the MODEL reads, and the EFFECT a human sees. Each Ops method returns a typed outcome (abstract record XDesfecho, one sealed record per case); the model-facing text (description, refusal, self-correction, success, the ToolUnavailable decision) lives in the adapter, in public static object Render(XDesfecho), while human text delivered by code (task body, note, ack) stays in Ops because it is an effect. Checkable by grep: Ops names no tool and instructs no model. The adapter (AIFunctionFactory.Create) only builds the typed request, calls Ops and returns Render: zero rule, not a line count, and a long dynamic description stays byte for byte. Two test layers: Ops tests assert outcome, calls and order on the fake, never text; contract tests assert Render's exact literal and .Description, with a golden of name, description and schema per real tenant. A neutral refactor is proven before any test moves: a proof commit with the old suite untouched and green (offline evals included), then the migration, with mutation run only against the new tests. \"Already covered\" needs proof assertion by assertion (11 of 22 such claims had lost one); the tests left at the origin must be identical to the base; mutation on the new tests found rules the old suite never protected. The C# blocks were compiled against the pin and the three xunit tests run."
|
|
1861
|
+
},
|
|
1862
|
+
{
|
|
1863
|
+
"id": "frontend-design-system-art-direction",
|
|
1864
|
+
"name": "art direction",
|
|
1865
|
+
"path": "frontend/design-system/art-direction.md",
|
|
1866
|
+
"category": "frontend",
|
|
1867
|
+
"subcategory": "design-system",
|
|
1868
|
+
"tags": [
|
|
1869
|
+
"frontend",
|
|
1870
|
+
"design-system"
|
|
1871
|
+
],
|
|
1872
|
+
"anchors": {
|
|
1873
|
+
"direction": "#section-1-write-the-direction-first",
|
|
1874
|
+
"explore": "#section-2-explore-two-or-three-directions",
|
|
1875
|
+
"examples": "#section-3-good-and-bad-directions",
|
|
1876
|
+
"tells": "#section-4-template-tells-to-avoid",
|
|
1877
|
+
"mobile": "#section-5-mobile-is-designed-not-derived",
|
|
1878
|
+
"motion": "#section-6-motion-with-intent",
|
|
1879
|
+
"prototype": "#section-7-prototype-and-self-review"
|
|
1880
|
+
},
|
|
1881
|
+
"digest": "Order beats talent: before any component of a new or changed screen, write 1-design/direcao.md with the concept in one sentence, the visual metaphor, what makes it memorable, and what it must NOT look like. New screens and brand moments (login, onboarding, first screen, empty state, success) explore 2-3 DISTINCT directions and recommend one with a product reason. Avoid template tells (raw shadcn look, white card centered on gray, generic icon list, default fonts, flat backgrounds, mobile as stacked desktop, decorative fade-ins, made-up numbers); three or more means raise it. Mobile is composed at 390px on its own (bottom sheet, thumb zone, 44px targets). Motion tells something with the lightest tool (CSS keyframes > scroll-driven CSS > Framer Motion > GSAP), transform/opacity only, and a composed reduced-motion version. Prove it in 1-design/prototipos/{screen}.html with the project REAL tokens, screenshotted at 1280 and 390 and revised until it passes."
|
|
1860
1882
|
}
|
|
1861
1883
|
]
|
|
1862
1884
|
}
|
|
@@ -406,7 +406,7 @@
|
|
|
406
406
|
"spec publicado",
|
|
407
407
|
"reconciliação de prompt"
|
|
408
408
|
],
|
|
409
|
-
"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 `
|
|
409
|
+
"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 `plan.md` (`## Decisões`), 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**.",
|
|
410
410
|
"provedBy": []
|
|
411
411
|
},
|
|
412
412
|
"ai-agents-providers-model-registry": {
|
|
@@ -842,7 +842,7 @@
|
|
|
842
842
|
"metallic accent",
|
|
843
843
|
"looks like a template"
|
|
844
844
|
],
|
|
845
|
-
"verifiedAgainst": "Production landing pages, CSS-only techniques, no runtime dependency.",
|
|
845
|
+
"verifiedAgainst": "Production landing pages, CSS-only techniques, no runtime dependency; app patterns from an approved login prototype (2026-10-06).",
|
|
846
846
|
"provedBy": []
|
|
847
847
|
},
|
|
848
848
|
"frontend-gsap-core": {
|
|
@@ -1209,6 +1209,20 @@
|
|
|
1209
1209
|
],
|
|
1210
1210
|
"verifiedAgainst": "Microsoft.Extensions.AI 10.9.0 + Microsoft.Agents.AI 1.20.0 (ai-pin 2026-09-08); os dois blocos C# abaixo foram extraídos com `scripts/extract-doc-csharp.mjs` e compilados contra o pin com `TreatWarningsAsErrors`, e os três testes do segundo bloco foram executados e passam. **A separação em si e a migração de teste são verificação documental:** vêm da feature `tools-finas` do MORPH_GHLBrain e o ai-kit não as traz.",
|
|
1211
1211
|
"provedBy": []
|
|
1212
|
+
},
|
|
1213
|
+
"frontend-design-system-art-direction": {
|
|
1214
|
+
"aliases": [
|
|
1215
|
+
"direção de arte",
|
|
1216
|
+
"direcao de arte",
|
|
1217
|
+
"conceito visual",
|
|
1218
|
+
"cara de template",
|
|
1219
|
+
"tela sem graça",
|
|
1220
|
+
"design genérico",
|
|
1221
|
+
"metáfora visual",
|
|
1222
|
+
"momento de marca"
|
|
1223
|
+
],
|
|
1224
|
+
"verifiedAgainst": "the `login-ciclo-do-produto` design round (2026-10-06): a correct, plain design was rejected; a second round with a written direction, an HTML prototype and a screenshot self-review was approved on first sight.",
|
|
1225
|
+
"provedBy": []
|
|
1212
1226
|
}
|
|
1213
1227
|
},
|
|
1214
1228
|
"sharedAliases": {
|
|
@@ -128,13 +128,13 @@ não escolhe o histórico; escolher "chat com histórico" não escolhe as fases.
|
|
|
128
128
|
| Agente de batch no caminho síncrono de uma requisição | Latência de LLM no p99 do endpoint, sem retry e sem visibilidade | Job assíncrono |
|
|
129
129
|
| Imagem descrita numa chamada e tipada noutra | Duas chamadas pagas, e o erro de descrição deixa de ser rastreável | Uma chamada multimodal com `RunAsync<T>` |
|
|
130
130
|
| Projeção papel → `ChatMessage` em dois arquivos | Os dois divergem, e o bug aparece como "o agente esqueceu" | Uma projeção, pura e testável |
|
|
131
|
-
| Escolher o arquétipo na implementação | A forma muda o desenho das tasks; escolhida depois, ela vira refactor | Escolha na fase de plano, e registre em `
|
|
131
|
+
| Escolher o arquétipo na implementação | A forma muda o desenho das tasks; escolhida depois, ela vira refactor | Escolha na fase de plano, e registre em `plan.md` (`## Decisões`) |
|
|
132
132
|
|
|
133
133
|
---
|
|
134
134
|
|
|
135
135
|
## Checklist (verifiable in review)
|
|
136
136
|
|
|
137
|
-
- [ ] O arquétipo escolhido está **nomeado** no `
|
|
137
|
+
- [ ] O arquétipo escolhido está **nomeado** no `plan.md` (`## Decisões`) da feature, com a pergunta de
|
|
138
138
|
`## Como escolher` que o decidiu
|
|
139
139
|
- [ ] Nenhum agente novo por fase de conversa — a fase é dado do turno
|
|
140
140
|
- [ ] Agente one-shot recebe prompt e alias como parâmetro, e não guarda estado entre invocações
|
|
@@ -228,7 +228,7 @@ O histórico cresce a cada turno. Quando estoura o context window do modelo, as
|
|
|
228
228
|
|
|
229
229
|
## Checklist (verifiable in review)
|
|
230
230
|
|
|
231
|
-
- [ ] A escolha da fonte de histórico foi feita pela tabela de critério — e está escrita em `
|
|
231
|
+
- [ ] A escolha da fonte de histórico foi feita pela tabela de critério — e está escrita em `plan.md` (`## Decisões`) quando não foi a conversa própria
|
|
232
232
|
- [ ] O provider de histórico é registrado como **uma** instância compartilhada
|
|
233
233
|
- [ ] Nenhum campo de instância do provider guarda estado de conversa; o que é por sessão está em `ProviderSessionState<TState>` e declarado em `StateKeys`
|
|
234
234
|
- [ ] Existe teste com **duas sessões concorrentes** sobre o mesmo provider
|
|
@@ -170,7 +170,7 @@ comprar a única coisa que o aninhamento oferece — deixar o modelo decidir.
|
|
|
170
170
|
contabilidade por agente); o teto de tool calls do externo não governa o interno; o timeout do turno
|
|
171
171
|
passa a cobrir duas chamadas de LLM em série; e o span do interno pendura-se sob `execute_tool`, onde
|
|
172
172
|
nenhum painel de agente procura. Quando a decisão **é** do modelo, esses quatro custos continuam
|
|
173
|
-
valendo — a diferença é que aí eles foram escolhidos, e o `
|
|
173
|
+
valendo — a diferença é que aí eles foram escolhidos, e o `plan.md` (`## Decisões`) diz por quê.
|
|
174
174
|
|
|
175
175
|
Os dois lados de campo, e é raro ter os dois:
|
|
176
176
|
|
|
@@ -198,7 +198,7 @@ A composição legítima — quando ela é mesmo necessária — é assunto de
|
|
|
198
198
|
| Teto tratado como opção de chamada | Vai ao provider, onde não significa nada | É opção do pipeline, nível de agente |
|
|
199
199
|
| `RequireAny` adotado sem medir `recovered` | Troca uma recuperação medida por uma falha nova | Aplique o critério de saída antes |
|
|
200
200
|
| Etapa FIXA do turno aninhada numa tool call | Paga custo, teto, timeout e span quebrados sem comprar nada — ninguém precisava decidir | Sequência, no código |
|
|
201
|
-
| Agent-as-Tool adotado sem registrar a decisão, ou além de 2 níveis | Os quatro custos viram surpresa, e o 3º nível é sinal de que devia ser sequência | Decisão no `
|
|
201
|
+
| Agent-as-Tool adotado sem registrar a decisão, ou além de 2 níveis | Os quatro custos viram surpresa, e o 3º nível é sinal de que devia ser sequência | Decisão no `plan.md` (`## Decisões`), teto ≤ 2 níveis (`ai-agents-multi-agent-patterns`) |
|
|
202
202
|
|
|
203
203
|
---
|
|
204
204
|
|
|
@@ -212,8 +212,8 @@ A composição legítima — quando ela é mesmo necessária — é assunto de
|
|
|
212
212
|
- [ ] Há teto de tool calls por turno, com tool isenta, e bater o teto é observável
|
|
213
213
|
- [ ] O teto está no nível de agente, não nas opções de chamada
|
|
214
214
|
- [ ] Se `RequireAny` foi adotado: a taxa de `recovered` e o custo da segunda chamada estão no
|
|
215
|
-
`
|
|
216
|
-
- [ ] Nenhuma etapa **fixa** do turno é invocada de dentro de uma tool call. Onde há aninhamento, quem decide é o **modelo**, está registrado no `
|
|
215
|
+
`plan.md` (`## Decisões`). Se não foi: o critério de saída está escrito
|
|
216
|
+
- [ ] Nenhuma etapa **fixa** do turno é invocada de dentro de uma tool call. Onde há aninhamento, quem decide é o **modelo**, está registrado no `plan.md` (`## Decisões`), e respeita o teto de ≤ 2 níveis de `ai-agents-multi-agent-patterns`
|
|
217
217
|
|
|
218
218
|
---
|
|
219
219
|
|
|
@@ -226,7 +226,7 @@ public sealed class PostgresCheckpointStore(NpgsqlDataSource dataSource) : IChec
|
|
|
226
226
|
|
|
227
227
|
`Microsoft.Agents.AI.DurableTask` (prerelease) adds durability backed by the **Azure Durable Task Scheduler**, including cost-efficient multi-day HITL waits with zero compute cost while paused. Even its "bring-your-own-compute / self-hosted" mode still requires a Durable Task Scheduler backend (`Microsoft.DurableTask.*.AzureManaged` packages) — self-hosted means your own worker process, not an Azure-free backend.
|
|
228
228
|
|
|
229
|
-
This framework deploys to VPS/Coolify by default and does not adopt Azure as a default dependency (see `ai-agents-setup` §3.4 on Azure OpenAI). For that reason, `Microsoft.Agents.AI.DurableTask` is **not adopted as default** here. The `CheckpointManager` + custom `ICheckpointStore` pattern above covers the same durability need without an Azure dependency. Only reach for the Durable Task extension when a specific client already runs on Azure and needs multi-day/serverless HITL waits — record that decision in `
|
|
229
|
+
This framework deploys to VPS/Coolify by default and does not adopt Azure as a default dependency (see `ai-agents-setup` §3.4 on Azure OpenAI). For that reason, `Microsoft.Agents.AI.DurableTask` is **not adopted as default** here. The `CheckpointManager` + custom `ICheckpointStore` pattern above covers the same durability need without an Azure dependency. Only reach for the Durable Task extension when a specific client already runs on Azure and needs multi-day/serverless HITL waits — record that decision in `plan.md` (`## Decisões`).
|
|
230
230
|
|
|
231
231
|
---
|
|
232
232
|
|
|
@@ -248,12 +248,12 @@ This framework deploys to VPS/Coolify by default and does not adopt Azure as a d
|
|
|
248
248
|
|
|
249
249
|
## Checklist (verifiable in review)
|
|
250
250
|
|
|
251
|
-
- [ ] `ai-agents-workflows`' HITL or long-running criterion is documented in `
|
|
251
|
+
- [ ] `ai-agents-workflows`' HITL or long-running criterion is documented in `plan.md` (`## Decisões`) before this standard is applied.
|
|
252
252
|
- [ ] Every HITL wait point uses `RequestPort` + handles `RequestInfoEvent`.
|
|
253
253
|
- [ ] A `CheckpointManager` is wired whenever the workflow can pause across a process restart — `CreateInMemory()` is acceptable only for tests/demos.
|
|
254
254
|
- [ ] If a custom `ICheckpointStore` was implemented, it persists to infrastructure already owned by the project (e.g., Neon Postgres), not a new ad hoc store.
|
|
255
255
|
- [ ] Executors with instance state implement `OnCheckpointingAsync` and `OnCheckpointRestoredAsync`.
|
|
256
|
-
- [ ] `Microsoft.Agents.AI.DurableTask` is present only if the project already runs on Azure and the choice is recorded in `
|
|
256
|
+
- [ ] `Microsoft.Agents.AI.DurableTask` is present only if the project already runs on Azure and the choice is recorded in `plan.md` (`## Decisões`) — ciente de que, desde a 1.17, o pacote vive em repositório separado e ficou para trás do framework.
|
|
257
257
|
- [ ] Toda tool com efeito irreversível está embrulhada em `ApprovalRequiredAIFunction` **ou** tem um guard determinístico documentado — e a escolha entre os dois está escrita.
|
|
258
258
|
- [ ] A resposta de aprovação é enviada na **mesma** `AgentSession`, num laço que checa pendências depois de cada run.
|
|
259
259
|
- [ ] Nenhum `Workflow` foi criado apenas para pausar uma tool de um agente único.
|
|
@@ -189,7 +189,7 @@ primeira pergunta a fazer quando um guard "nunca reprova nada".
|
|
|
189
189
|
## Checklist (verifiable in review)
|
|
190
190
|
|
|
191
191
|
- [ ] Toda regra com consequência real existe como condição em código, não apenas no prompt
|
|
192
|
-
- [ ] O choke-point escolhido está nomeado no `
|
|
192
|
+
- [ ] O choke-point escolhido está nomeado no `plan.md` (`## Decisões`), com o que ele pega
|
|
193
193
|
- [ ] O middleware de tool devolve **vocabulário fechado** de desfecho
|
|
194
194
|
- [ ] Argumento obrigatório ausente é barrado **sem** executar a tool, lendo o schema da própria função
|
|
195
195
|
- [ ] Nenhum identificador com efeito vem do modelo — todos vêm da closure do turno
|
|
@@ -178,13 +178,13 @@ Tenho múltiplos agents — qual padrão usar?
|
|
|
178
178
|
| Handoff sem `turnLimit` nem condição de término | Dois agentes devolvem a conversa um ao outro indefinidamente | `.WithAutonomousMode(turnLimit:)` ou `.WithTerminationCondition(...)` |
|
|
179
179
|
| `Id` de agente gerado a cada boot num workflow de handoff | O destino do handoff deixa de existir entre reinícios | `Id` estável, vindo de configuração |
|
|
180
180
|
| Group chat com 5+ agentes | O gerente gasta os turnos escolhendo quem fala | ≤ 3 agentes; acima disso, repense a decomposição |
|
|
181
|
-
| Agents com responsabilidades sobrepostas | Nenhum dos dois sabe quando agir; o LLM fica confuso | Fronteiras claras de responsabilidade; documente em `
|
|
181
|
+
| Agents com responsabilidades sobrepostas | Nenhum dos dois sabe quando agir; o LLM fica confuso | Fronteiras claras de responsabilidade; documente em `plan.md` (`## Decisões`). |
|
|
182
182
|
|
|
183
183
|
---
|
|
184
184
|
|
|
185
185
|
## Checklist (verifiable in review)
|
|
186
186
|
|
|
187
|
-
- [ ] Foi verificado em `
|
|
187
|
+
- [ ] Foi verificado em `plan.md` (`## Decisões`) que single agent não resolve?
|
|
188
188
|
- [ ] O padrão escolhido é o mais simples que atende ao requisito? (Tool < Sequential imperativo < Workflow)
|
|
189
189
|
- [ ] `agent.AsAIFunction()` usado para composição local (não `AIFunctionFactory.Create` desnecessariamente)?
|
|
190
190
|
- [ ] Agents usando alias do Model Registry — nenhum model string hardcoded?
|
|
@@ -313,7 +313,7 @@ Workflow para diagnosticar um incidente relatado ("o agente X respondeu errado/l
|
|
|
313
313
|
2. **Suba do trace raiz para os spans filhos.** O span raiz mostra a duração total; os filhos (`Function Calling`, `IChatClient`) mostram onde o tempo/erro realmente está. Não assuma — meça. Um "agente lento" é quase sempre UM tool call específico (chamada de API externa, query sem índice), não o LLM.
|
|
314
314
|
3. **Correlacione com métricas antes de teorizar.** Confira a tabela "What to Monitor" abaixo pelo período do incidente — um pico de `tool call failure rate` ou `token usage` aponta a causa mais rápido que ler traces individuais um a um.
|
|
315
315
|
4. **Reproduza com Debug ligado, nunca em produção.** Se a causa não estiver clara nos atributos estruturados, habilite `Debug` (com dados sensíveis, se necessário) num ambiente de staging com o mesmo input — nunca habilite log de prompt/response completo em produção para investigar.
|
|
316
|
-
5. **Documente a causa raiz em `
|
|
316
|
+
5. **Documente a causa raiz em `plan.md` (`## Decisões`)** se a investigação levar a uma mudança de arquitetura (novo middleware de retry, novo timeout, novo cache) — não só no commit message.
|
|
317
317
|
|
|
318
318
|
### What to Monitor
|
|
319
319
|
|
|
@@ -202,7 +202,7 @@ Na **1.18** (2026-08-18) essa superfície foi renomeada. Nomes atuais, medidos p
|
|
|
202
202
|
|
|
203
203
|
**Duas advertências que valem mais que os nomes:**
|
|
204
204
|
|
|
205
|
-
1. **O pacote é prerelease.** `Microsoft.Agents.AI.Hosting` não tem versão estável (apurado 2026-09-08). Isolamento multi-tenant por esse caminho é adoção de preview — registre em `
|
|
205
|
+
1. **O pacote é prerelease.** `Microsoft.Agents.AI.Hosting` não tem versão estável (apurado 2026-09-08). Isolamento multi-tenant por esse caminho é adoção de preview — registre em `plan.md` (`## Decisões`).
|
|
206
206
|
2. **A chave vem da credencial, nunca do payload.** Uma chave derivada de algo que o cliente envia é uma chave que o cliente escolhe. `UseClaimsBasedAgentIsolation()` existe exatamente para não deixar essa decisão passar pelo corpo do request.
|
|
207
207
|
|
|
208
208
|
### Invocação concorrente de tools é opt-in desde 1.18
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
> **Keywords:** prompt sources, prompts in db, agent prompts, prompt versioning, prompt hot-reload, editable instructions, prompt management, prompt por tenant, spec publicado, reconciliação de prompt
|
|
6
6
|
> **Read by Claude in:** implement (quando as instruções de um agente precisam viver fora do código) e troubleshoot (quando a versão que rodou não é a que se esperava)
|
|
7
7
|
|
|
8
|
-
**Verified against:** 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 `
|
|
8
|
+
**Verified against:** 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 `plan.md` (`## Decisões`), 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**. Last-verified: 2026-09-08.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -356,7 +356,7 @@ rastreabilidade (hash em span, prompt cru só em harness) está em `ai-agents-ob
|
|
|
356
356
|
- [ ] `GetActivePromptAsync` throws `InvalidOperationException` (not returns null) when no active prompt found
|
|
357
357
|
- [ ] Versionamento pattern followed: INSERT + flip, never UPDATE content
|
|
358
358
|
- [ ] At least one seed row per `agent_key` in migrations or seed script
|
|
359
|
-
- [ ] A fonte escolhida (banco versionado × composição por tenant) está nomeada no `
|
|
359
|
+
- [ ] A fonte escolhida (banco versionado × composição por tenant) está nomeada no `plan.md` (`## Decisões`),
|
|
360
360
|
com a pergunta "o texto varia por cliente?" respondida
|
|
361
361
|
- [ ] No caminho composto: a moldura e o YAML estão versionados no repo, e o blob publicado **não** é
|
|
362
362
|
editado à mão
|
|
@@ -185,7 +185,7 @@ Going through `Microsoft.Extensions.AI` (`IChatClient`) or the MAF (`AIAgent`) k
|
|
|
185
185
|
| **Anthropic Claude** | `anthropic` | Confirm current SDK on NuGet before use | ignora o campo | Adapt provider client to `IChatClient` |
|
|
186
186
|
| **Azure OpenAI** (opt-in, not default) | `azure-openai` | `Azure.AI.OpenAI` + `Azure.Identity` — confirm exact versions on NuGet before use | segue o OpenAI | Add only when a client requires data residency |
|
|
187
187
|
|
|
188
|
-
> **Restore trap, measured 2026-09-08:** `Microsoft.Extensions.AI.OpenAI` 10.9.0 declares `OpenAI (>= 2.12.0 && < 2.13.0)`. Pairing it with the pinned `OpenAI` 2.13.0 emits **NU1608** on restore. Either pin `OpenAI` to 2.12.x alongside the bridge, or accept the warning knowingly and write the decision in `
|
|
188
|
+
> **Restore trap, measured 2026-09-08:** `Microsoft.Extensions.AI.OpenAI` 10.9.0 declares `OpenAI (>= 2.12.0 && < 2.13.0)`. Pairing it with the pinned `OpenAI` 2.13.0 emits **NU1608** on restore. Either pin `OpenAI` to 2.12.x alongside the bridge, or accept the warning knowingly and write the decision in `plan.md` (`## Decisões`). Do not discover this in CI.
|
|
189
189
|
|
|
190
190
|
**No floating ranges.** Every `PackageReference` above is an exact version. A floating `2.*` on a weekly-cadence SDK is how ProspectPRO bought a `MissingMethodException` on the Responses API **after paying for the call** (`docs/specs/elevacao-9/brutos/scan-prospectpro.md:55`).
|
|
191
191
|
|
|
@@ -179,7 +179,7 @@ Registered on the agent with `tools: [AIFunctionFactory.Create(tool.SearchAsync)
|
|
|
179
179
|
|
|
180
180
|
The `tenant_id` filter is **never a tool parameter** (that would allow the LLM to cross tenant boundaries). It is injected via a constructor dependency — e.g., a scoped `ITenantContext` or a `Guid currentTenantId` resolved from the authenticated request. See §Multi-tenant below.
|
|
181
181
|
|
|
182
|
-
Note on raw Npgsql vs EF Core: the EF Core LINQ form above is the default (`ApplicationDbContext` in the slice, no raw SQL). A raw `NpgsqlDataSource` query is acceptable only with a `
|
|
182
|
+
Note on raw Npgsql vs EF Core: the EF Core LINQ form above is the default (`ApplicationDbContext` in the slice, no raw SQL). A raw `NpgsqlDataSource` query is acceptable only with a `plan.md` (`## Decisões`) justification (e.g. a project with no EF Core model for this table). The legacy `VectorSearchTool.cs.template` still uses raw SQL and `EmbeddingService`; prefer the block above.
|
|
183
183
|
|
|
184
184
|
---
|
|
185
185
|
|
|
@@ -319,7 +319,7 @@ ALTER TABLE kb_embeddings ENABLE ROW LEVEL SECURITY;
|
|
|
319
319
|
- [ ] `VectorSearchTool` registered on the agent via `AIFunctionFactory.Create(tool.SearchAsync)`.
|
|
320
320
|
- [ ] No `Microsoft.SemanticKernel` references in the project.
|
|
321
321
|
- [ ] Vector dimensions consistent between embedding model and `vector(N)` column definition.
|
|
322
|
-
- [ ] RLS enabled on `kb_embeddings` (or equivalent app-level guard documented in `
|
|
322
|
+
- [ ] RLS enabled on `kb_embeddings` (or equivalent app-level guard documented in `plan.md` (`## Decisões`)).
|
|
323
323
|
- [ ] Ingestion follows §*Ingestão delta por lookup-key*: a pure `Plan(...)` produces `Added`/`Updated`/`Removed`/`Unchanged`, and `Unchanged` is never re-embedded.
|
|
324
324
|
- [ ] No `DELETE`-everything-then-reinsert: `Removed` is applied **after** `Added`/`Updated`, in the same transaction — there is no window where the search returns empty.
|
|
325
325
|
- [ ] `Updated` is an **upsert** on a deterministic id, never delete+insert.
|
|
@@ -62,7 +62,7 @@ Está adicionando um agente AI a um projeto .NET?
|
|
|
62
62
|
<!-- Azure OpenAI (somente se data residency exigir) — confira Azure.AI.OpenAI + Azure.Identity no NuGet -->
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
> **Armadilha de restore, medida em 2026-09-08:** `Microsoft.Extensions.AI.OpenAI` 10.9.0 declara a dependência `OpenAI (>= 2.12.0 && < 2.13.0)`. Com o `OpenAI` **2.13.0** do pin, o `dotnet restore` emite **NU1608** (*"Versão detectada do pacote fora da restrição de dependência"*). Duas saídas honestas: fixar `OpenAI` em 2.12.x ao lado da ponte, **ou** aceitar o aviso conscientemente e registrar a decisão em `
|
|
65
|
+
> **Armadilha de restore, medida em 2026-09-08:** `Microsoft.Extensions.AI.OpenAI` 10.9.0 declara a dependência `OpenAI (>= 2.12.0 && < 2.13.0)`. Com o `OpenAI` **2.13.0** do pin, o `dotnet restore` emite **NU1608** (*"Versão detectada do pacote fora da restrição de dependência"*). Duas saídas honestas: fixar `OpenAI` em 2.12.x ao lado da ponte, **ou** aceitar o aviso conscientemente e registrar a decisão em `plan.md` (`## Decisões`). Não descubra isso no CI.
|
|
66
66
|
|
|
67
67
|
> **De onde vem cada extensão** (medido por reflexão sobre as assemblies do pin, 2026-09-08):
|
|
68
68
|
> | Extensão | Assembly que a publica | Namespace do `using` |
|
|
@@ -155,7 +155,7 @@ Fontes, ambas lidas em 2026-09-08:
|
|
|
155
155
|
|
|
156
156
|
A Responses API **armazena por padrão**. OpenAI, mesmo guia, verbatim: *"Responses are stored by default. Chat completions are stored by default for new accounts. To disable storage when using either API, set `store: false`."* Respostas retidas ficam 30 dias no provedor.
|
|
157
157
|
|
|
158
|
-
Projetos desta casa mantêm o histórico **próprio** (ver `ai-agents-agent-session`), então não se quer uma segunda cópia da conversa no provedor. **Regra: `store: false` explícito.** Quem quiser o oposto registra o porquê em `
|
|
158
|
+
Projetos desta casa mantêm o histórico **próprio** (ver `ai-agents-agent-session`), então não se quer uma segunda cópia da conversa no provedor. **Regra: `store: false` explícito.** Quem quiser o oposto registra o porquê em `plan.md` (`## Decisões`).
|
|
159
159
|
|
|
160
160
|
O MAF tem um atalho de primeira classe para isso — medido na assembly `Microsoft.Agents.AI.OpenAI` 1.20.0:
|
|
161
161
|
|
|
@@ -105,11 +105,11 @@ You may need to step outside the sweet spot when:
|
|
|
105
105
|
|
|
106
106
|
## Checklist (verifiable in review)
|
|
107
107
|
|
|
108
|
-
- [ ] Was each agent designed as single-agent BEFORE reaching for multi-agent? (Check `
|
|
108
|
+
- [ ] Was each agent designed as single-agent BEFORE reaching for multi-agent? (Check `plan.md` (`## Decisões`).)
|
|
109
109
|
- [ ] If a Workflow is used, is fan-in/out or HITL checkpointing genuinely present? Or could `foreach + LINQ` replace it?
|
|
110
110
|
- [ ] Are the 4 features (Chat, Structured Output, Tools, RAG Custom) all present where applicable?
|
|
111
111
|
- [ ] Are hosted agent services avoided?
|
|
112
|
-
- [ ] Nenhum agente carrega mais de ~12 tools sem uma decisão escrita em `
|
|
112
|
+
- [ ] Nenhum agente carrega mais de ~12 tools sem uma decisão escrita em `plan.md` (`## Decisões`) sobre a poda
|
|
113
113
|
|
|
114
114
|
---
|
|
115
115
|
|
|
@@ -210,8 +210,6 @@ MORPH_GHLBrain, `src/Morph.GHLBrain/Features/Conversation/Operator/`:
|
|
|
210
210
|
| `set_lead_fields` | `Tools/SetLeadFieldsTool.cs` | `Ops/DossieOps.cs` | `CamposDesfecho` |
|
|
211
211
|
| `route_lead` | `Tools/RouteLeadTool.cs` | `Ops/TriagemOps.cs` | `TriagemDesfecho` |
|
|
212
212
|
|
|
213
|
-
As decisões estão em `.morph/features/tools-finas/2-plan/decisions.md` (ADR-1 e ADR-2) daquele repositório.
|
|
214
|
-
|
|
215
213
|
## Regras
|
|
216
214
|
|
|
217
215
|
- **ALWAYS** a regra de uma tool vai numa `sealed class XOps(...)` com construtor primário e `AddScoped` explícito
|
|
@@ -86,7 +86,7 @@ Preview packages are subject to breaking API changes before GA (see the rename `
|
|
|
86
86
|
|-----------|-----|
|
|
87
87
|
| Default production RAG on Neon/Postgres (this framework's default stack), **already implemented and tested** | **`ai-agents-rag-custom-pgvector`** — framework-owned raw SQL, zero external connector, already the checklisted default. **Não se migra o que funciona** (item D4 da elevação-9) |
|
|
88
88
|
| **Projeto novo** onde a escolha do store ainda não foi cravada, e trocá-lo depois deve custar pouco | `Microsoft.Extensions.VectorData.Abstractions` 10.9.0 + `CommunityToolkit.VectorData.PgVector` 1.0.1 — hoje **ambos estáveis**, o que remove o argumento "é preview" que existia em julho/2026 |
|
|
89
|
-
| Project needs genuine portability across >1 vector backend (a client contract requires swapping Postgres for Qdrant or Azure AI Search later) | `Microsoft.Extensions.VectorData` + o conector correspondente — document the choice in `
|
|
89
|
+
| Project needs genuine portability across >1 vector backend (a client contract requires swapping Postgres for Qdrant or Azure AI Search later) | `Microsoft.Extensions.VectorData` + o conector correspondente — document the choice in `plan.md` (`## Decisões`) |
|
|
90
90
|
| Prototyping, tests, or demos where an in-memory store is enough | `CommunityToolkit.VectorData.InMemory` 1.0.1 |
|
|
91
91
|
| Ingestão em pipeline (reader → chunker → writer) hoje | Só com `Microsoft.Extensions.DataIngestion`, que **continua preview**: registre a aceitação e um lembrete de revisitar no GA |
|
|
92
92
|
|
|
@@ -175,10 +175,10 @@ This maps conceptually onto the existing custom pattern: `IngestionDocumentReade
|
|
|
175
175
|
|
|
176
176
|
- [ ] If `Microsoft.SemanticKernel.Connectors.*` appears in a `.csproj`, it is used only for `VectorStoreCollection`/`VectorStore` types — no `Kernel`, `KernelFunction`, or `ChatHistory` usage anywhere in the project.
|
|
177
177
|
- [ ] No plain `Microsoft.SemanticKernel` (core) package reference.
|
|
178
|
-
- [ ] If VectorData was chosen over custom pgvector, the reason is recorded in `
|
|
178
|
+
- [ ] If VectorData was chosen over custom pgvector, the reason is recorded in `plan.md` (`## Decisões`) per the decision matrix.
|
|
179
179
|
- [ ] No new `Microsoft.SemanticKernel.Connectors.*` reference — new work uses `CommunityToolkit.VectorData.*`.
|
|
180
|
-
- [ ] If a preview package (`Microsoft.Extensions.DataIngestion`, or any `*-preview` connector) was adopted, `
|
|
181
|
-
- [ ] Every VectorData/ingestion `PackageReference` carries an exact version — these packages are **not** in `framework/ai-pin.json`, so the project's own `
|
|
180
|
+
- [ ] If a preview package (`Microsoft.Extensions.DataIngestion`, or any `*-preview` connector) was adopted, `plan.md` (`## Decisões`) records the preview-acceptance and a revisit-at-GA note.
|
|
181
|
+
- [ ] Every VectorData/ingestion `PackageReference` carries an exact version — these packages are **not** in `framework/ai-pin.json`, so the project's own `plan.md` (`## Decisões`) (or a comment) states when the version was checked.
|
|
182
182
|
- [ ] Embedding model/dimensions consistent between the `VectorStoreVector(N)` attribute and the chosen embedding model.
|
|
183
183
|
|
|
184
184
|
---
|
|
@@ -186,7 +186,7 @@ Sempre use `await using` no `StreamingRun` / `Run` — é `IAsyncDisposable`.
|
|
|
186
186
|
## Checklist (verifiable in review)
|
|
187
187
|
|
|
188
188
|
- [ ] Foi verificado que um `foreach` ou single agent não resolve o problema?
|
|
189
|
-
- [ ] O critério de fan-in/out genuíno ou HITL está documentado em `
|
|
189
|
+
- [ ] O critério de fan-in/out genuíno ou HITL está documentado em `plan.md` (`## Decisões`)?
|
|
190
190
|
- [ ] `Microsoft.Agents.AI` 1.0.* presente no `.csproj` (sem pacotes preview separados)?
|
|
191
191
|
- [ ] Agents referenciando alias do Model Registry (não model strings hardcoded)?
|
|
192
192
|
- [ ] `await using` no `StreamingRun` / `Run`?
|
|
@@ -62,7 +62,7 @@ Só o **porquê que o código não mostra**:
|
|
|
62
62
|
## Tamanho
|
|
63
63
|
|
|
64
64
|
Uma linha é o normal; teto de ~3. Acima disso o comentário justifica o volume (algoritmo não
|
|
65
|
-
óbvio, armadilha de terceiro com a reprodução). Bloco longo narrando decisões é `
|
|
65
|
+
óbvio, armadilha de terceiro com a reprodução). Bloco longo narrando decisões é `plan.md` (`## Decisões`) com
|
|
66
66
|
outro nome. Em volume, código de aplicação fica perto de zero: mais de uma linha de comentário a
|
|
67
67
|
cada dez de código é sinal de que os nomes não estão fazendo o trabalho. Arquivo vizinho muito
|
|
68
68
|
comentado não é modelo: código novo segue este padrão, não a densidade do legado.
|
|
@@ -333,7 +333,7 @@ var page = await _db.Books
|
|
|
333
333
|
(ex.: `SELECT ... FOR UPDATE`, retry de `DbUpdateConcurrencyException`) ou SQL específico
|
|
334
334
|
que o LINQ não expressa, escreva um store hand-written e purpose-built (ex.: `OutboxStore`,
|
|
335
335
|
`LeaseStore`) com métodos nomeados pela intenção — e registre a justificativa em
|
|
336
|
-
`
|
|
336
|
+
`plan.md` (`## Decisões`). Nunca um genérico por entidade.
|
|
337
337
|
|
|
338
338
|
Veja `backend/dotnet/vsa-handler-patterns.md` → "Data Access: DbContext in the Slice".
|
|
339
339
|
|
|
@@ -173,7 +173,7 @@ The state check (`>= Completed`) and the business rule (`RequiresPayment && !IsP
|
|
|
173
173
|
- [ ] Failures come back as `ValidationError` → 400 ProblemDetails with `errors[]`, never an exception?
|
|
174
174
|
- [ ] Existence / uniqueness / state checks in the handler, returning typed `Error`s?
|
|
175
175
|
- [ ] State checks validate INVALID states, with the error range at 100+?
|
|
176
|
-
- [ ] All flows documented in
|
|
176
|
+
- [ ] All flows documented in plan.md (## Decisões) and tested?
|
|
177
177
|
|
|
178
178
|
---
|
|
179
179
|
|