@polymorphism-tech/morph-spec 9.0.0 → 9.1.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 +4 -62
- 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 +1 -1
- package/framework/MORPH.md +1 -1
- package/framework/agents.json +12 -4
- package/framework/commands/morph-apply.md +1 -1
- package/framework/commands/morph-status.md +1 -1
- package/framework/docs/CLI.md +6 -17
- 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 +11 -67
- 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/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/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 +2 -2
- package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
- 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 +2 -2
- package/framework/skills/core/morph-review/SKILL.md +1 -1
- 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 +34 -12
- 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/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/infrastructure/neon/neon-pgvector.md +5 -5
- package/framework/templates/CLAUDE.md.core.template +3 -3
- package/framework/templates/REGISTRY.json +9 -9
- package/framework/templates/docs/ui-mockups.md +4 -0
- 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 +14 -96
- 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 +2 -5
- package/src/commands/validation/validate-feature.js +5 -94
- package/src/commands/validation/verify.js +15 -98
- 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/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/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 +2 -10
- package/src/lib/detectors/claude-config-detector.js +13 -74
- package/src/lib/detectors/index.js +4 -50
- 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/dotnet-introspection.js +20 -106
- package/src/lib/mutation/subset.js +1 -4
- package/src/lib/plan/artifact-vocabulary.js +5 -25
- package/src/lib/plan/checks.js +5 -31
- package/src/lib/plan/plan-parser.js +1 -6
- package/src/lib/projects/registry.js +7 -44
- package/src/lib/review-reports.js +5 -23
- package/src/lib/risk-detector.js +39 -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/validators/code-budget/code-budget-validator.js +3 -43
- 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 +20 -125
- package/src/lib/validators/verify-runner.js +52 -358
- 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 +28 -275
- 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/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
|
@@ -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
|
|
|
@@ -225,13 +225,13 @@ public sealed class SearchBooksHandler(
|
|
|
225
225
|
When a slice needs concurrency control (`SELECT ... FOR UPDATE`, lease/outbox semantics,
|
|
226
226
|
`DbUpdateConcurrencyException` retry loops) or SQL that LINQ cannot express, write a
|
|
227
227
|
**hand-written, purpose-built store** with intention-named methods (e.g. `OutboxStore.ClaimBatchAsync`,
|
|
228
|
-
`LeaseStore.TryAcquireAsync`) — and document the justification in `
|
|
228
|
+
`LeaseStore.TryAcquireAsync`) — and document the justification in `plan.md` (`## Decisões`).
|
|
229
229
|
Never a generic-per-entity abstraction.
|
|
230
230
|
|
|
231
231
|
**Rule of thumb:** everything → `ApplicationDbContext` in the slice. Concurrency or
|
|
232
|
-
specific SQL → dedicated hand-written store + `
|
|
232
|
+
specific SQL → dedicated hand-written store + `plan.md` (`## Decisões`) entry. Never reach for raw SQL
|
|
233
233
|
(`FromSqlRaw`) unless a query genuinely cannot be expressed in LINQ — and document that
|
|
234
|
-
in `
|
|
234
|
+
in `plan.md` (`## Decisões`).
|
|
235
235
|
|
|
236
236
|
---
|
|
237
237
|
|
|
@@ -307,8 +307,8 @@ builder.Services.AddExceptionHandler<CustomExceptionHandler>()
|
|
|
307
307
|
| Share handlers across features | Each feature has its own handler, even if similar |
|
|
308
308
|
| Use constructor + field for DI | Use primary constructors: `class Handler(IDep dep)` |
|
|
309
309
|
| Group by technical concern (Controllers/, Services/) | Group by feature: `Features/BookFeature/CreateBook/` |
|
|
310
|
-
| Route data access through any indirection layer | Inject `DbContext` and write LINQ in the slice; dedicated store only with `
|
|
311
|
-
| Use raw SQL (`FromSqlRaw` / `ExecuteQuery(string)`) by default | Use LINQ; raw SQL only with a `
|
|
310
|
+
| Route data access through any indirection layer | Inject `DbContext` and write LINQ in the slice; dedicated store only with `plan.md` (`## Decisões`) justification |
|
|
311
|
+
| Use raw SQL (`FromSqlRaw` / `ExecuteQuery(string)`) by default | Use LINQ; raw SQL only with a `plan.md` (`## Decisões`) justification |
|
|
312
312
|
|
|
313
313
|
---
|
|
314
314
|
|
|
@@ -15,7 +15,7 @@ Background job processing for .NET 10 VSA applications with Hangfire on Neon Pos
|
|
|
15
15
|
|
|
16
16
|
## When to use Hangfire
|
|
17
17
|
|
|
18
|
-
Hangfire is in the stack **only with a real reason**: work that must survive a process restart, run on a schedule, or be retried later (daily reindex, delayed reminders, retrying a flaky third party). Work that fits in the request (send one email after a signup, index one uploaded document) runs in the slice handler. Record the reason in `
|
|
18
|
+
Hangfire is in the stack **only with a real reason**: work that must survive a process restart, run on a schedule, or be retried later (daily reindex, delayed reminders, retrying a flaky third party). Work that fits in the request (send one email after a signup, index one uploaded document) runs in the slice handler. Record the reason in `plan.md` (`## Decisões`).
|
|
19
19
|
|
|
20
20
|
Hangfire provides fire-and-forget, delayed and recurring (cron) jobs, continuations, a dashboard and automatic retries.
|
|
21
21
|
|
|
@@ -64,7 +64,7 @@ place to audit.
|
|
|
64
64
|
**The exception process:** a feature that genuinely needs the frontend to reach Neon directly for
|
|
65
65
|
business data (for example, via the Neon MCP `provision_neon_data_api` tool) is an exception, not a
|
|
66
66
|
default — treat it exactly like vertical-slice.md's "Stores dedicados (exceção justificada)" clause:
|
|
67
|
-
document the justification in the feature's `
|
|
67
|
+
document the justification in the feature's `plan.md` (`## Decisões`) before writing the code. A tool being
|
|
68
68
|
available is not, by itself, justification.
|
|
69
69
|
|
|
70
70
|
See [Row-Level Security Integration](#row-level-security-integration) for how to constrain a
|
|
@@ -727,7 +727,7 @@ Each Neon branch gets its own isolated auth data. This means:
|
|
|
727
727
|
fetch and cache the JWKS yourself and verify EdDSA signatures manually (BouncyCastle)
|
|
728
728
|
11. **Route business data through the .NET backend by default** — the frontend's only inherent
|
|
729
729
|
reason to talk to Neon directly is its own auth/session SDK; a direct Data API call needs a
|
|
730
|
-
`
|
|
730
|
+
`plan.md` (`## Decisões`) ADR (see [Data Access Boundary](#data-access-boundary--backend-first-by-default))
|
|
731
731
|
|
|
732
732
|
---
|
|
733
733
|
|
|
@@ -179,4 +179,4 @@ The minute comes from `TimeProvider` (testable with `FakeTimeProvider`), never `
|
|
|
179
179
|
- Never omit TTL -- unbounded keys fill memory
|
|
180
180
|
- Never wrap the cache in a `XService`/repository class -- cache-aside is three lines in the handler
|
|
181
181
|
- Never return `null` for "not found" -- the handler returns `Result` with `NotFound`
|
|
182
|
-
- Never swallow `RedisConnectionException` in an empty `catch`: a cache outage must be visible (health check + logs). Falling back to the database while Redis is down is a product decision: record it in `
|
|
182
|
+
- Never swallow `RedisConnectionException` in an empty `catch`: a cache outage must be visible (health check + logs). Falling back to the database while Redis is down is a product decision: record it in `plan.md` (`## Decisões`) and implement it once, at the cache boundary, not per call site
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> **Scope:** data-nosql
|
|
4
4
|
> **Layer:** 3 (opcional — nenhuma rule nem persona o carrega; só sob demanda via `morph-spec standards --find`, depois de a decisão existir)
|
|
5
5
|
> **Keywords:** cosmos-db, nosql, document-database, event-store, partition-key, azure-cosmos
|
|
6
|
-
> **Load When:** `
|
|
6
|
+
> **Load When:** `plan.md` (`## Decisões`) already records the choice of Cosmos DB over Neon for a specific store
|
|
7
7
|
|
|
8
8
|
**Verified against:** .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`. Last-verified: 2026-10-03.
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
## Overview
|
|
13
13
|
|
|
14
|
-
**Cosmos DB is not part of the stack.** The default store is Neon (Postgres) through EF Core, with the `ApplicationDbContext` used directly in the slice. Reach for Cosmos only when a requirement Postgres cannot meet is written down in `
|
|
14
|
+
**Cosmos DB is not part of the stack.** The default store is Neon (Postgres) through EF Core, with the `ApplicationDbContext` used directly in the slice. Reach for Cosmos only when a requirement Postgres cannot meet is written down in `plan.md` (`## Decisões`) (the "why not Neon" included). Everything below applies the stack conventions to that exception: the client is injected straight into the slice handler, ids are `Guid.CreateVersion7()`, expected failures are `Result` values, and classes are `sealed`.
|
|
15
15
|
|
|
16
16
|
## When It Can Be Justified
|
|
17
17
|
|
|
@@ -155,7 +155,7 @@ using var feed = container.GetItemQueryIterator<OrderEvent>(
|
|
|
155
155
|
|
|
156
156
|
| Do NOT | Do Instead |
|
|
157
157
|
|--------|------------|
|
|
158
|
-
| Pick Cosmos without a `
|
|
158
|
+
| Pick Cosmos without a `plan.md` (`## Decisões`) entry | Neon (Postgres) via EF Core is the default store |
|
|
159
159
|
| Wrap `Container` in a generic `CosmosRepository<T>` | Inject the keyed `Container` into the slice handler |
|
|
160
160
|
| `try/catch (CosmosException)` for 404/409 | Stream APIs + `StatusCode` → `Result` |
|
|
161
161
|
| `Guid.NewGuid()` for document ids | `Guid.CreateVersion7()` |
|
|
@@ -16,7 +16,7 @@ An admin app has **one** form pattern. It is the base pattern of `nextjs/forms.m
|
|
|
16
16
|
- **The Zod schema is shared.** The same schema types the form, validates it, and parses the API response (`admin-app/data-table.md` parses the list query with Zod too). One source of truth per entity.
|
|
17
17
|
- **react-hook-form keeps inputs uncontrolled** — a 30-field form does not re-render on every keystroke, which is what `useState` per field does.
|
|
18
18
|
- **shadcn's current form docs are written around it** (`Field`, `FieldLabel`, `FieldError` + `Controller`).
|
|
19
|
-
- **Coexisting styles are the defect this rule exists for.** Measured in a real admin app: three form styles side by side (react-hook-form in some screens, hand-rolled `useState` in others) — three validation behaviours for one product, and a redesign that changed none of them. A screen that needs something the pattern cannot do registers the exception in `
|
|
19
|
+
- **Coexisting styles are the defect this rule exists for.** Measured in a real admin app: three form styles side by side (react-hook-form in some screens, hand-rolled `useState` in others) — three validation behaviours for one product, and a redesign that changed none of them. A screen that needs something the pattern cannot do registers the exception in `plan.md` (`## Decisões`); it does not start a fourth style.
|
|
20
20
|
|
|
21
21
|
## Core Rules
|
|
22
22
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Art Direction — Decide What the Screen Is Before Drawing It
|
|
2
|
+
|
|
3
|
+
> **Scope:** frontend-design-system
|
|
4
|
+
> **Layer:** 3
|
|
5
|
+
> **Keywords:** art direction, concept, visual metaphor, design direction, template look, generic ui, memorable, mobile-first, brand moment
|
|
6
|
+
> **Load When:** ui-designer active, before any component of a new or changed screen
|
|
7
|
+
|
|
8
|
+
**Verified against:** 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. Last-verified: 2026-10-06.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
A design that follows the tokens, has every state and passes WCAG can still be forgettable. What made the difference in practice was not talent but order: a direction written before any component, a real prototype, and a critical look at the rendered result. This standard is the first of the three.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Section 1: Write the Direction First
|
|
17
|
+
|
|
18
|
+
Before the first component, answer four questions in `1-design/direcao.md`:
|
|
19
|
+
|
|
20
|
+
1. **Concept in one sentence.** What the screen says, not what it contains. *"The login tells the product cycle in scenes while you sign in."*
|
|
21
|
+
2. **Visual metaphor.** The image that organizes the layout. *Stories; a control room; a ticket being stamped; a garden that grows.*
|
|
22
|
+
3. **What makes it memorable.** The one thing someone would describe to a colleague. If nothing, the direction is not done.
|
|
23
|
+
4. **What it must NOT look like.** Name the generic version you are avoiding (Section 4).
|
|
24
|
+
|
|
25
|
+
Only then pick components. A component chosen before the direction is chosen by habit.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Section 2: Explore Two or Three Directions
|
|
30
|
+
|
|
31
|
+
For a new screen or a brand moment (login, onboarding, first screen, empty state, success, showcase), write two or three directions that are **distinct**, not three color variations of one layout. For each: concept, metaphor, the mobile idea, the motion idea, and the risk. Recommend one and say why, in terms of the product and the user, not taste.
|
|
32
|
+
|
|
33
|
+
A changed screen inside an established system may need only one direction, written the same way, with what changes and why.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Section 3: Good and Bad Directions
|
|
38
|
+
|
|
39
|
+
| Bad direction | Why it fails | Good direction |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| "Clean, modern login with the logo and a form." | Describes every login. Nothing to remember. | "The panel tells the product cycle in three scenes, stories-style; the form is a sheet the thumb reaches." |
|
|
42
|
+
| "Dashboard with cards for each metric." | Content, not concept. Layout by habit. | "A control room: one hero number the operator acts on, the rest as quiet instruments around it." |
|
|
43
|
+
| "Empty state with an icon and a button." | The default of every kit. | "The empty list is the first page of a notebook: an illustrated first entry shows what a good one looks like." |
|
|
44
|
+
| "Mobile: same layout, stacked." | Mobile derived, not designed. | "Mobile is an app: bottom sheet, thumb-zone actions, the scene compressed to a strip above." |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Section 4: Template Tells to Avoid
|
|
49
|
+
|
|
50
|
+
Each one is fine in isolation; together they read as "generated". If the screen has three or more, raise it.
|
|
51
|
+
|
|
52
|
+
- Raw shadcn look: default radius, default gray border, no brand in any surface.
|
|
53
|
+
- A white card centered on a gray background, logo on top, form inside.
|
|
54
|
+
- A generic icon list (three features, three Lucide icons, three lines of copy).
|
|
55
|
+
- Stack-default or AI-tell fonts with no tracking or scale decision (see `premium-finish` Section 1).
|
|
56
|
+
- Flat solid backgrounds with no light, layer or texture.
|
|
57
|
+
- Mobile as the desktop stacked: centered card, tiny targets, actions out of thumb reach.
|
|
58
|
+
- Motion as decoration: everything fades in, nothing tells a sequence.
|
|
59
|
+
- Made-up numbers on illustrative cards (`R$ 12.430`, `98% satisfaction`).
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Section 5: Mobile Is Designed, Not Derived
|
|
64
|
+
|
|
65
|
+
Draw the phone at 390 px as its own composition: bottom sheet for the primary task, actions in the thumb zone, targets of at least 44 px, the brand scene compressed rather than removed. Then check the desktop is not the phone blown up either.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Section 6: Motion With Intent
|
|
70
|
+
|
|
71
|
+
Motion should tell something (a sequence, a cause, a state change). Pick the lightest tool that delivers it: CSS transition and `@keyframes`, then CSS scroll-driven animation, then Framer Motion, then GSAP with ScrollTrigger and timelines. Budget: 60 fps, only `transform` and `opacity`, no layout thrash, lazy below the fold. `prefers-reduced-motion` gets a composed static version, designed as carefully as the animated one.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Section 7: Prototype and Self-Review
|
|
76
|
+
|
|
77
|
+
The direction is proved in a rendered prototype, not in prose: `1-design/prototipos/{screen}.html`, self-contained, using the project's REAL tokens read from its token CSS (the design-system doc can be stale), desktop and phone side by side in a device frame, with animated / static / pause controls. Serve it over local HTTP, screenshot at 1280 and 390, judge against this standard and the system bar (hierarchy, contrast, rhythm, mobile, "does it look like a template?"), fix, repeat. The final screenshots sit next to the HTML.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Checklist
|
|
82
|
+
|
|
83
|
+
- [ ] `direcao.md` answers concept, metaphor, memorable, must-not-look-like
|
|
84
|
+
- [ ] Two or three distinct directions for a new screen or brand moment, one recommended with a reason
|
|
85
|
+
- [ ] Fewer than three template tells on the final screen
|
|
86
|
+
- [ ] Mobile composed at 390 px on its own terms
|
|
87
|
+
- [ ] Motion tells something, with a composed reduced-motion version
|
|
88
|
+
- [ ] Prototype rendered, screenshotted at 1280 and 390, and revised until it passes
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
> **Scope:** frontend-design-system
|
|
4
4
|
> **Layer:** 3
|
|
5
5
|
> **Keywords:** premium, polish, typography, film grain, atmosphere, load-in, scrim, legibility over video, accent
|
|
6
|
-
> **Load When:** ui-designer active, or the brief asks for a premium or high-end feel
|
|
6
|
+
> **Load When:** ui-designer active (every surface), or the brief asks for a premium or high-end feel
|
|
7
7
|
|
|
8
|
-
**Verified against:** Production landing pages, CSS-only techniques, no runtime dependency. Last-verified: 2026-
|
|
8
|
+
**Verified against:** Production landing pages, CSS-only techniques, no runtime dependency; app patterns from an approved login prototype (2026-10-06). Last-verified: 2026-10-06.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -148,6 +148,78 @@ Finish with fresh eyes: open the page as if you were the client. Whatever looks
|
|
|
148
148
|
|
|
149
149
|
---
|
|
150
150
|
|
|
151
|
+
## Section 8: Patterns For App Screens
|
|
152
|
+
|
|
153
|
+
The finish is not only for marketing pages. Login, onboarding, the first screen after sign-up, an empty state and a success moment are brand moments inside the product, and a data screen also has to look designed: elegant density, illustrated empty states, skeletons with shimmer, transitions between states. These patterns come from an app login that was approved on first sight after a plain one was rejected.
|
|
154
|
+
|
|
155
|
+
### Bottom sheet on mobile
|
|
156
|
+
|
|
157
|
+
On a phone the form lives in a sheet anchored to the bottom, inside the thumb zone, with the brand scene above it. Never the desktop card centered and shrunk.
|
|
158
|
+
|
|
159
|
+
```css
|
|
160
|
+
.sheet {
|
|
161
|
+
position: fixed; inset: auto 0 0 0;
|
|
162
|
+
padding: 12px 20px calc(20px + env(safe-area-inset-bottom));
|
|
163
|
+
border-radius: 24px 24px 0 0;
|
|
164
|
+
background: var(--surface);
|
|
165
|
+
box-shadow: 0 -12px 40px color-mix(in oklab, var(--brand) 18%, transparent);
|
|
166
|
+
}
|
|
167
|
+
.sheet::before {
|
|
168
|
+
content: ''; display: block; width: 36px; height: 4px; margin: 0 auto 16px;
|
|
169
|
+
border-radius: 2px; background: var(--border);
|
|
170
|
+
}
|
|
171
|
+
.sheet button, .sheet input { min-height: 44px; }
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Stories-style progress
|
|
175
|
+
|
|
176
|
+
A sequence of scenes reads like stories: thin segmented bars at the top, each filling while its scene is on. One keyframe, the delay per segment, and the scene swap keyed to the same delays.
|
|
177
|
+
|
|
178
|
+
```css
|
|
179
|
+
.stories { display: flex; gap: 4px; }
|
|
180
|
+
.stories span { flex: 1; height: 3px; border-radius: 2px; background: color-mix(in oklab, var(--fg) 20%, transparent); overflow: hidden; }
|
|
181
|
+
.stories span::after {
|
|
182
|
+
content: ''; display: block; height: 100%; background: var(--fg);
|
|
183
|
+
transform: scaleX(0); transform-origin: left;
|
|
184
|
+
animation: fill var(--beat) linear forwards;
|
|
185
|
+
animation-delay: calc(var(--i) * var(--beat));
|
|
186
|
+
}
|
|
187
|
+
@keyframes fill { to { transform: scaleX(1); } }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Synchronized highlight by `animation-delay`
|
|
191
|
+
|
|
192
|
+
When a scene card lights up while its story bar runs, both share `--i` and `--beat`. No JavaScript timer: the browser keeps them in step, and pausing is one `animation-play-state: paused` on the parent.
|
|
193
|
+
|
|
194
|
+
### Scene cards without real data
|
|
195
|
+
|
|
196
|
+
A card that illustrates the product cycle shows shapes, icons and labels, never a metric. A made-up number on a real screen reads as a real number ("R$ 12.430 recovered") and becomes a claim nobody can back. Use bars without values, avatars without names, a check without a count.
|
|
197
|
+
|
|
198
|
+
### Dot grid faded with `mask-image`
|
|
199
|
+
|
|
200
|
+
Texture for a hero or a sheet backdrop, cheaper than an image and on brand:
|
|
201
|
+
|
|
202
|
+
```css
|
|
203
|
+
.dots {
|
|
204
|
+
background-image: radial-gradient(color-mix(in oklab, var(--fg) 22%, transparent) 1px, transparent 1px);
|
|
205
|
+
background-size: 16px 16px;
|
|
206
|
+
mask-image: radial-gradient(ellipse at 50% 30%, #000 30%, transparent 75%);
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Static version for reduced motion
|
|
211
|
+
|
|
212
|
+
`prefers-reduced-motion: reduce` gets a composed still frame (the best scene, every bar full, the highlight on), not the first frame of a stopped animation.
|
|
213
|
+
|
|
214
|
+
```css
|
|
215
|
+
@media (prefers-reduced-motion: reduce) {
|
|
216
|
+
.stories span::after { animation: none; transform: scaleX(1); }
|
|
217
|
+
.scene { animation: none; opacity: 1; }
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
151
223
|
## Checklist
|
|
152
224
|
|
|
153
225
|
- [ ] Display font chosen from the brand, not from stack defaults or the AI-tell list
|
|
@@ -157,4 +229,7 @@ Finish with fresh eyes: open the page as if you were the client. Whatever looks
|
|
|
157
229
|
- [ ] Directional scrim plus text-shadow on every text-over-media block
|
|
158
230
|
- [ ] Accent used in three places or fewer
|
|
159
231
|
- [ ] Details swept: scrollbar, selection, hairlines, hover micro-transitions
|
|
232
|
+
- [ ] App screen: mobile designed on its own (bottom sheet, thumb zone, 44px targets), never the desktop stacked
|
|
233
|
+
- [ ] No invented number or data on a real screen
|
|
234
|
+
- [ ] Reduced motion gets a composed static frame
|
|
160
235
|
- [ ] Fresh-eyes pass done, and it does not read as a template
|
|
@@ -19,7 +19,7 @@ Stack: .NET VSA + Neon Serverless Postgres. For the end-to-end RAG pipeline (ing
|
|
|
19
19
|
- ALWAYS call `UseVector()` on the `UseNpgsql(...)` options builder (EF Core); `NpgsqlDataSourceBuilder.UseVector()` is only for raw Npgsql
|
|
20
20
|
- ALWAYS register the `vector` extension in `OnModelCreating` (`HasPostgresExtension("vector")`)
|
|
21
21
|
- Map vector properties as `Pgvector.Vector` -- EF Core does not map `float[]` or `ReadOnlyMemory<float>` to the `vector` column
|
|
22
|
-
- Query through the `ApplicationDbContext` in the slice handler with the `CosineDistance`/`L2Distance`/`MaxInnerProduct` LINQ translations -- no repository class, no raw SQL from C# without a `
|
|
22
|
+
- Query through the `ApplicationDbContext` in the slice handler with the `CosineDistance`/`L2Distance`/`MaxInnerProduct` LINQ translations -- no repository class, no raw SQL from C# without a `plan.md` (`## Decisões`) justification
|
|
23
23
|
- IDs come from the app (`Guid.CreateVersion7()`), never from a `gen_random_uuid()` column default
|
|
24
24
|
|
|
25
25
|
## Enable pgvector
|
|
@@ -39,7 +39,7 @@ CREATE EXTENSION IF NOT EXISTS vector;
|
|
|
39
39
|
<PackageReference Include="Pgvector.EntityFrameworkCore" Version="0.3.0" />
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
`Pgvector.EntityFrameworkCore` 0.3.0 requires `Npgsql.EntityFrameworkCore.PostgreSQL` >= 9.0.1 and brings `Pgvector` (the `Vector` type and the raw-Npgsql plugin) transitively. The configuration below maps each column to the snake_case names of `backend/database/postgresql/database.md` (`embedding`, `created_at`) with `HasColumnName`; without it EF creates `"Embedding"`, `"CreatedAt"` and every SQL snippet below would have to quote PascalCase names. (A project that wants this for every entity can add `EFCore.NamingConventions` and `UseSnakeCaseNamingConvention()` once, instead of per column -- a project-wide decision for `
|
|
42
|
+
`Pgvector.EntityFrameworkCore` 0.3.0 requires `Npgsql.EntityFrameworkCore.PostgreSQL` >= 9.0.1 and brings `Pgvector` (the `Vector` type and the raw-Npgsql plugin) transitively. The configuration below maps each column to the snake_case names of `backend/database/postgresql/database.md` (`embedding`, `created_at`) with `HasColumnName`; without it EF creates `"Embedding"`, `"CreatedAt"` and every SQL snippet below would have to quote PascalCase names. (A project that wants this for every entity can add `EFCore.NamingConventions` and `UseSnakeCaseNamingConvention()` once, instead of per column -- a project-wide decision for `plan.md` (`## Decisões`).)
|
|
43
43
|
|
|
44
44
|
### Entity Definition
|
|
45
45
|
|
|
@@ -196,9 +196,9 @@ public sealed class SearchDocumentsHandler(
|
|
|
196
196
|
|
|
197
197
|
Storing an embedding is an ordinary EF write in the handler that owns the document: `document.Embedding = new Vector(await embeddings.GenerateVectorAsync(text, cancellationToken: ct));` followed by `SaveChangesAsync`. No `UPDATE ... SET embedding` from C#.
|
|
198
198
|
|
|
199
|
-
### SQL Functions (only with a `
|
|
199
|
+
### SQL Functions (only with a `plan.md` (`## Decisões`) justification)
|
|
200
200
|
|
|
201
|
-
When the query must live in the database (called from several apps, or a hybrid score the LINQ translation cannot express), a SQL function is acceptable -- record why in `
|
|
201
|
+
When the query must live in the database (called from several apps, or a hybrid score the LINQ translation cannot express), a SQL function is acceptable -- record why in `plan.md` (`## Decisões`), call it through EF Core with interpolated parameters, and keep the same distance rules:
|
|
202
202
|
|
|
203
203
|
```sql
|
|
204
204
|
CREATE OR REPLACE FUNCTION match_documents(
|
|
@@ -218,7 +218,7 @@ $$;
|
|
|
218
218
|
|
|
219
219
|
## Hybrid Search (Vector + Full-Text)
|
|
220
220
|
|
|
221
|
-
Blends the vector score with `ts_rank`. Same rule as above: a SQL function, justified in `
|
|
221
|
+
Blends the vector score with `ts_rank`. Same rule as above: a SQL function, justified in `plan.md` (`## Decisões`).
|
|
222
222
|
|
|
223
223
|
```sql
|
|
224
224
|
CREATE OR REPLACE FUNCTION hybrid_search(
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
VSA + .NET 10 + EF Core + Neon (Postgres) + Microsoft Agent Framework + Next.js (App Router) + Tailwind + Framer Motion + Shadcn + Hangfire (quando necessário).
|
|
8
8
|
|
|
9
|
-
Padrões proibidos por padrão: `Guid.NewGuid()` (use `Guid.CreateVersion7()`), classes não-sealed sem justificativa, exceptions como fluxo de controle, camada de Service/Manager entre handler e dados, repository genérico (`IRepository<T>`/`IUnitOfWork`), SQL cru sem justificativa. Acesso a dados: `ApplicationDbContext` direto no slice (`DbSet<T>` já é repository, `DbContext` já é unit of work); para concorrência ou SQL específico, store dedicado hand-written com justificativa em `
|
|
9
|
+
Padrões proibidos por padrão: `Guid.NewGuid()` (use `Guid.CreateVersion7()`), classes não-sealed sem justificativa, exceptions como fluxo de controle, camada de Service/Manager entre handler e dados, repository genérico (`IRepository<T>`/`IUnitOfWork`), SQL cru sem justificativa. Acesso a dados: `ApplicationDbContext` direto no slice (`DbSet<T>` já é repository, `DbContext` já é unit of work); para concorrência ou SQL específico, store dedicado hand-written com justificativa em `plan.md` (`## Decisões`).
|
|
10
10
|
|
|
11
11
|
## Harness
|
|
12
12
|
|
|
@@ -18,5 +18,5 @@ morph-spec NLH — leia `.morph/framework/MORPH.md` ao iniciar cada sessão. Em
|
|
|
18
18
|
|
|
19
19
|
## Slash commands
|
|
20
20
|
|
|
21
|
-
- `/morph-
|
|
22
|
-
- `/morph-apply {feature}` —
|
|
21
|
+
- `/morph-plan {feature}` — entrevista, `plan.md`, `plan-check` e gate do plano
|
|
22
|
+
- `/morph-apply {feature}` — fatias do plano, `verify` e review (Gate 3)
|