@polymorphism-tech/morph-spec 8.38.0 → 8.41.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 +20 -9
- package/README.md +2 -2
- package/bin/morph-spec.js +60 -43
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +4 -3
- package/framework/MORPH.md +10 -9
- package/framework/agents.json +43 -26
- package/framework/docs/CLI.md +7 -5
- package/framework/evals/rubrics/code-quality.md +4 -4
- package/framework/evals/rubrics/condensed.md +2 -2
- package/framework/hooks/README.md +1 -1
- package/framework/hooks/claude-code/core/telemetry-log.js +39 -8
- package/framework/hooks/claude-code/core/worktree-create.js +22 -6
- package/framework/hooks/shared/git-paths.js +38 -5
- package/framework/mcp/registry.json +58 -66
- package/framework/rules/infrastructure-standards.md +0 -1
- package/framework/rules/morph-workflow.md +9 -4
- 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 +59 -25
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +2 -2
- package/framework/skills/core/morph-implement/SKILL.md +48 -24
- package/framework/skills/core/morph-media/SKILL.md +2 -2
- package/framework/skills/core/morph-plan/SKILL.md +10 -3
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +1 -1
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +7 -6
- package/framework/standards/PROVENANCE.json +4 -4
- package/framework/standards/STANDARDS.json +9 -9
- package/framework/standards/ai-agents/context-providers.md +16 -26
- package/framework/standards/ai-agents/durable-workflows-hitl.md +15 -21
- package/framework/standards/ai-agents/modalities-image-gen.md +21 -25
- package/framework/standards/ai-agents/modalities-speech-to-text.md +4 -15
- package/framework/standards/ai-agents/modalities-text-to-speech.md +2 -11
- package/framework/standards/ai-agents/modalities-vision.md +1 -18
- package/framework/standards/ai-agents/prompt-sources.md +0 -4
- package/framework/standards/architecture/code-comments.md +52 -16
- package/framework/standards/backend/dotnet/testing.md +4 -2
- package/framework/standards/backend/integrations/neon-auth/neon-auth.md +63 -50
- package/framework/standards/frontend/design-system/ai-image-generation.md +42 -28
- package/framework/standards/frontend/design-system/ai-video-generation.md +24 -9
- package/framework/standards/frontend/nextjs/testing.md +4 -2
- package/framework/standards/integration/mcp/mcp-tools.md +64 -126
- package/framework/templates/code/dotnet/abstractions/result.cs +0 -2
- package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +26 -39
- package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +28 -68
- package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +99 -117
- package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +2 -44
- package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +40 -61
- package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +54 -107
- package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +53 -58
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +192 -281
- package/framework/templates/code/dotnet/database/migration.cs +49 -83
- package/framework/templates/code/dotnet/database/vector-entity.cs +2 -46
- package/framework/templates/code/dotnet/extensions/result-extensions.cs +0 -2
- package/framework/templates/code/dotnet/feature/validator.cs.hbs +11 -15
- package/framework/templates/code/dotnet/jobs/agent.cs +3 -51
- package/framework/templates/code/dotnet/jobs/job.cs +2 -97
- package/framework/templates/code/dotnet/test.cs +2 -87
- package/framework/templates/code/typescript/contracts.ts +140 -167
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +1 -48
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +3 -79
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +1 -70
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +1 -47
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +2 -99
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +0 -6
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +3 -88
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +1 -41
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +0 -21
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +1 -25
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +2 -63
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +0 -30
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +1 -52
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +3 -78
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +4 -109
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +0 -22
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +1 -36
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +2 -57
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +0 -75
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +2 -59
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +4 -111
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +0 -34
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +1 -57
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +0 -19
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +2 -74
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +2 -33
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +1 -43
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +1 -96
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +0 -13
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +0 -27
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +0 -33
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +0 -31
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +3 -75
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +0 -42
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +0 -39
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +1 -55
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +3 -59
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +0 -46
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +3 -28
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +7 -61
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +2 -37
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +1 -23
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +2 -82
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +1 -68
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +1 -62
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +2 -62
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +1 -25
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +0 -124
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +1 -73
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +1 -66
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +0 -41
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +2 -112
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +2 -43
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +5 -110
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +7 -103
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +1 -42
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +1 -30
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +1 -19
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +0 -48
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +1 -29
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +2 -38
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +1 -14
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +4 -69
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +1 -10
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +1 -57
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +0 -26
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +1 -19
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +0 -32
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +0 -14
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +0 -24
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +0 -32
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +0 -37
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +0 -24
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +0 -78
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +0 -53
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +0 -44
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +0 -44
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +0 -19
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +0 -24
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +6 -48
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +1 -13
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +2 -71
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +5 -100
- package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +39 -43
- package/framework/templates/frontend/nextjs/env.mjs.hbs +29 -32
- package/framework/templates/frontend/nextjs/page.tsx.hbs +21 -22
- package/framework/templates/frontend/nextjs/use-feature.ts.hbs +42 -54
- package/framework/templates/integrations/asaas-client.cs +332 -387
- package/framework/templates/integrations/asaas-webhook.cs +290 -351
- package/framework/templates/integrations/neon-auth-config.cs +9 -105
- package/framework/templates/project/validate.js +97 -120
- package/package.json +2 -2
- package/src/commands/dashboard/dashboard.js +80 -53
- package/src/commands/mcp/mcp-setup.js +37 -9
- package/src/commands/project/doctor.js +12 -6
- package/src/commands/project/init.js +6 -3
- package/src/commands/project/install-plugin-cmd.js +1 -1
- package/src/commands/project/update.js +5 -0
- package/src/commands/project/worktree.js +60 -4
- package/src/commands/state/gate-check.js +5 -0
- package/src/commands/tasks/dag.js +27 -4
- package/src/commands/validation/verify.js +22 -38
- package/src/dashboard/app/App.jsx +80 -16
- package/src/dashboard/app/components/ActivityFeed.jsx +172 -0
- package/src/dashboard/app/components/CommandPalette.jsx +155 -0
- package/src/dashboard/app/components/DetailPanel.jsx +47 -11
- package/src/dashboard/app/components/EntityLink.jsx +55 -0
- package/src/dashboard/app/components/ErrorBoundary.jsx +54 -0
- package/src/dashboard/app/components/FlowGraph.jsx +19 -17
- package/src/dashboard/app/components/KnowledgeMarkdown.jsx +53 -0
- package/src/dashboard/app/components/Markdown.jsx +47 -0
- package/src/dashboard/app/components/PhaseRail.jsx +111 -0
- package/src/dashboard/app/components/SearchFilter.jsx +40 -22
- package/src/dashboard/app/components/Sidebar.jsx +146 -37
- package/src/dashboard/app/hooks/useMorphQuery.js +54 -0
- package/src/dashboard/app/hooks/usePref.js +38 -0
- package/src/dashboard/app/lib/format.js +69 -0
- package/src/dashboard/app/lib/phases.js +56 -0
- package/src/dashboard/app/lib/project.js +50 -0
- package/src/dashboard/app/pages/Activity.jsx +24 -0
- package/src/dashboard/app/pages/AgentMap.jsx +371 -370
- package/src/dashboard/app/pages/FeatureDetail.jsx +604 -0
- package/src/dashboard/app/pages/Features.jsx +400 -0
- package/src/dashboard/app/pages/Guide.jsx +146 -0
- package/src/dashboard/app/pages/HookInspector.jsx +357 -322
- package/src/dashboard/app/pages/PhasePipeline.jsx +277 -408
- package/src/dashboard/app/pages/Portfolio.jsx +156 -0
- package/src/dashboard/app/pages/Rubrics.jsx +101 -0
- package/src/dashboard/app/pages/RulesMap.jsx +300 -273
- package/src/dashboard/app/pages/SkillsLibrary.jsx +483 -366
- package/src/dashboard/app/pages/Standards.jsx +407 -332
- package/src/dashboard/app/styles/index.css +187 -47
- package/src/dashboard/index.html +14 -12
- package/src/dashboard/package.json +32 -24
- package/src/dashboard/scanner/activity-scanner.js +351 -0
- package/src/dashboard/scanner/agents-scanner.js +59 -1
- package/src/dashboard/scanner/docs-scanner.js +59 -0
- package/src/dashboard/scanner/feature-status.js +10 -0
- package/src/dashboard/scanner/features-scanner.js +360 -0
- package/src/dashboard/scanner/index.js +14 -7
- package/src/dashboard/scanner/phases-scanner.js +14 -15
- package/src/dashboard/scanner/portfolio.js +153 -0
- package/src/dashboard/scanner/project-api.js +195 -0
- package/src/dashboard/scanner/rules-scanner.js +42 -37
- package/src/dashboard/scanner/skills-scanner.js +105 -43
- package/src/dashboard/scanner/standards-scanner.js +2 -0
- package/src/dashboard/vite-plugin-morph-data.js +134 -17
- package/src/lib/detectors/claude-config-detector.js +2 -7
- package/src/lib/detectors/index.js +5 -1
- package/src/lib/evaluator-report.js +22 -0
- package/src/lib/generators/settings-generator.js +208 -209
- package/src/lib/installers/mcp-installer.js +724 -719
- package/src/lib/installers/memory-installer.js +1 -2
- package/src/lib/projects/registry.js +154 -0
- package/src/lib/risk-detector.js +13 -0
- package/src/lib/tasks/tasks-json-parser.js +21 -0
- package/src/lib/validators/code-budget/code-budget-validator.js +32 -4
- package/src/lib/worktree/env-allocator.js +9 -3
- package/src/scripts/install-plugin.js +1 -1
- package/src/scripts/setup-infra.js +2 -4
- package/src/utils/agents-installer.js +108 -13
- package/src/utils/banner.js +1 -1
- package/src/commands/index.js +0 -13
- package/src/commands/project/checkpoint.js +0 -209
- package/src/core/state/phase-state-machine.js +0 -197
- package/src/dashboard/app/hooks/useDetailPanel.js +0 -15
- package/src/dashboard/app/pages/LiveState.jsx +0 -206
- package/src/dashboard/scanner/squads-scanner.js +0 -13
- package/src/dashboard/scanner/state-scanner.js +0 -85
- package/src/lib/generators/index.js +0 -10
- package/src/lib/hooks/hook-executor.js +0 -167
- package/src/lib/validators/checkpoint-persistence.js +0 -39
- package/src/lib/validators/shared/emit-validator-dispatch.js +0 -14
- package/src/lib/validators/shared/index.js +0 -12
- package/src/lib/validators/shared/issue-counter.js +0 -14
- package/src/lib/validators/shared/result-formatter.js +0 -124
|
@@ -4,7 +4,7 @@ description: Guia a execução de cada tarefa de implementação com standard e
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar cada task de implementação listada em tasks.json
|
|
6
6
|
user-invokable: false
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.41.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-implement
|
|
@@ -54,12 +54,14 @@ Ao iniciar cada task de `tasks.json` — antes de escrever qualquer código. Nor
|
|
|
54
54
|
|
|
55
55
|
> **Relação com `morph-spec dag`:** a decisão do DAG (na `morph-apply` §2) governa o **paralelismo ENTRE tasks** — quantos sub-agents rodam ao mesmo tempo. Os gatilhos acima governam o **dispatch INDIVIDUAL desta task**. São ortogonais e coexistem: `DAG: sequencial` NÃO significa "tudo inline" — significa "uma task por vez, na ordem". Exemplo: cadeia única backend de 12 tasks (DAG: sequencial); T7 tem effort L → despache T7 sozinha para `morph-dotnet-senior` e aguarde o retorno antes de seguir; T8 (S, mesmo domínio) roda inline.
|
|
56
56
|
|
|
57
|
-
**Se for despachar — use `subagent_type: "morph-{id}"` do agente identificado no passo 3.** Os subagents são gerados de `agents.json` na instalação (`.claude/agents/morph-{id}.md`) e a persona é o **system prompt** deles — não a cole no prompt. **Fallback:** se `morph-{id}` não estiver na sua lista de subagent types (stack não instalado), use `general-purpose` colando o campo `persona` no prompt e registre nas `notes` da task: `dispatch-fallback: general-purpose ({id} não registrado)`. Template do prompt (cláusulas do relatório em forma curta — racional completo em `MORPH.md` §6):
|
|
57
|
+
**Se for despachar — use `subagent_type: "morph-{id}"` do agente identificado no passo 3.** Os subagents são gerados de `agents.json` na instalação (`.claude/agents/morph-{id}.md`) e a persona é o **system prompt** deles — não a cole no prompt. **Fallback:** se `morph-{id}` não estiver na sua lista de subagent types (stack não instalado), use `general-purpose` colando o campo `persona` no prompt e registre nas `notes` da task: `dispatch-fallback: general-purpose ({id} não registrado)`. Template do prompt (cláusulas do relatório em forma curta — racional completo em `MORPH.md` §6). **Cole-o literal**: só os campos entre colchetes mudam; não parafraseie cláusula nem omita os parágrafos de leitura, ferramentas e comentário — foi assim que regras chegaram tortas ao sub-agent em campo:
|
|
58
58
|
```
|
|
59
59
|
Implementar [ID]: [title da task]
|
|
60
60
|
|
|
61
61
|
Spec: [description completa do tasks.json]
|
|
62
|
-
|
|
62
|
+
Standards: [por standard: `id` + o digest do `standards --find` + as 3-8 regras
|
|
63
|
+
do .md que ESTA task aplica, coladas. O path vai junto só para consulta
|
|
64
|
+
pontual — o sub-agente não relê standards inteiros]
|
|
63
65
|
Arquivos relevantes: [os `target` de task.reuse + o que o scout/grafo apontou
|
|
64
66
|
— este campo não é decorativo: é por ele que o código já existente chega
|
|
65
67
|
ao sub-agente, que trabalha em contexto fresco e não conhece o projeto.
|
|
@@ -74,9 +76,25 @@ Ao iniciar cada task de `tasks.json` — antes de escrever qualquer código. Nor
|
|
|
74
76
|
a ausência de grafo nunca bloqueia. Se algo cobre o caso, reuse ou estenda;
|
|
75
77
|
se criar mesmo assim, diga por que em uma linha no relatório.
|
|
76
78
|
|
|
77
|
-
Leitura:
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
Leitura e turnos: cada turno custa ~10 s antes de a tool rodar, e o teto de
|
|
80
|
+
turnos corta sem aviso. Chamadas que não dependem uma da outra vão no MESMO
|
|
81
|
+
turno: leia de uma vez todos os arquivos que este prompt lista, dispare os
|
|
82
|
+
Grep juntos. Use Read/Grep/Glob — nunca `grep`, `sed -n`, `cat`, `find`,
|
|
83
|
+
`ls` via Bash. Não releia o que este prompt já traz. Em arquivo grande, `Grep`
|
|
84
|
+
acha a linha e `Read` com `offset`/`limit` lê só o trecho; log de build/teste
|
|
85
|
+
se lê pelo `Grep` do erro, não inteiro.
|
|
86
|
+
|
|
87
|
+
Ferramentas: antes de supor a API de uma biblioteca (MAF, EF Core, Next,
|
|
88
|
+
shadcn, SDK de provedor), consulte o MCP `context7` (`resolve-library-id` →
|
|
89
|
+
`query-docs`). Impacto e vizinhança de símbolo vêm do grafo
|
|
90
|
+
(`morph-spec graph`), não de varredura por grep. Tool `mcp__…` que não esteja
|
|
91
|
+
carregada se carrega com `ToolSearch` (`select:<nome>`); MCP ausente nunca
|
|
92
|
+
bloqueia — siga com o fallback.
|
|
93
|
+
|
|
94
|
+
Comentário: o padrão é nenhum. Nome, tipo e teste explicam o código; sem
|
|
95
|
+
`///`/JSDoc em membro de aplicação, cabeçalho, banner de seção ou história
|
|
96
|
+
da task. Só o porquê que o código não mostra, em uma linha
|
|
97
|
+
(`architecture-code-comments`).
|
|
80
98
|
|
|
81
99
|
Contrato do relatório final:
|
|
82
100
|
1. GRAVE `.morph/features/{feature}/3-implement/reports/[ID].md` ANTES de
|
|
@@ -84,25 +102,28 @@ Ao iniciar cada task de `tasks.json` — antes de escrever qualquer código. Nor
|
|
|
84
102
|
cortesia best-effort e pode não chegar inteira). NÃO chame SendMessage.
|
|
85
103
|
2. NÃO toque em tasks.json, feature.json, state.json nem no board de sessão
|
|
86
104
|
— todo estado é gravado exclusivamente pelo orquestrador.
|
|
87
|
-
3.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
`
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
105
|
+
3. TESTE — a prova é do orquestrador (`morph-spec verify {feature} {task}`,
|
|
106
|
+
logo depois do seu retorno), não sua. Escreva os testes pelo orçamento:
|
|
107
|
+
um por pós-condição, um de regressão por bug, variantes numa tabela
|
|
108
|
+
(`[Theory]`/`it.each`). NÃO rode teste a cada marco nem faça ciclo
|
|
109
|
+
red→green: escreva código e testes, compile, e rode SÓ o filtro dos seus
|
|
110
|
+
testes UMA vez, antes do relatório; se falhar, corrija e rode só os que
|
|
111
|
+
falharam. Em batch paralelo SEM isolamento, só compile — o teste roda no
|
|
112
|
+
verify pós-batch. Em batch COM `isolation: "worktree"`, o mesmo vale no
|
|
113
|
+
seu worktree, e o último ato antes do relatório é o commit na branch do
|
|
114
|
+
worktree — nunca faça merge; worktree não commitado NÃO é removido pelo
|
|
115
|
+
hook e vira pendência do `doctor`. Ao rodar: compile uma vez e rode sem
|
|
116
|
+
recompilar (`dotnet test --no-build`), com `--filter`. Grave a saída em
|
|
117
|
+
arquivo uma vez (`… > .morph/logs/test-last.log 2>&1`, sem nada depois)
|
|
118
|
+
e leia o arquivo: rodar de novo com outro `| tail`/`| grep` repete o teste
|
|
119
|
+
para ver outras linhas, e com pipe ou `; echo` o exit é o do último
|
|
120
|
+
comando, não o do teste.
|
|
100
121
|
|
|
101
122
|
4. ESCOPO: no máximo 3 tasks e ~4 arquivos por dispatch. Escopo maior falha e
|
|
102
123
|
volta — fatie antes, não depois.
|
|
103
124
|
5. SOBREVIVÊNCIA: o limite de turnos (`maxTurns`, no seu system prompt)
|
|
104
|
-
corta sem aviso: commite `wip({taskId})` a cada marco (arquivo
|
|
105
|
-
|
|
125
|
+
corta sem aviso: commite `wip({taskId})` a cada marco (um arquivo ou
|
|
126
|
+
uma fatia coerente escrita — sem rodar teste para isso), não só ao fim da task — e só os seus arquivos
|
|
106
127
|
(`git add <paths>`, nunca `-A`). Sem commit, a retomada recomeça do zero.
|
|
107
128
|
A ~70% do limite, grave o relatório parcial no arquivo canônico: `PARCIAL`
|
|
108
129
|
na 1ª linha, o feito e o que falta, sem auto-score. Depois siga ou pare,
|
|
@@ -112,6 +133,9 @@ Ao iniciar cada task de `tasks.json` — antes de escrever qualquer código. Nor
|
|
|
112
133
|
sessões). Encerre dev server pelo PID que você mesmo subiu.
|
|
113
134
|
7. RETORNO: o relatório no arquivo canônico é o retorno. `SendMessage` não é
|
|
114
135
|
substituto do relatório e não deve ser chamado.
|
|
136
|
+
8. MUTAÇÃO: nunca altere, reverta, mova ou apague código de produção para ver
|
|
137
|
+
um teste falhar (`sed`, `mv`, `git show HEAD:… >`, `git stash`, `git
|
|
138
|
+
checkout --`). A prova de que o teste morde é do avaliador no Gate 3.
|
|
115
139
|
|
|
116
140
|
Seu relatório (no arquivo, e na mensagem final quando ela chega) deve conter
|
|
117
141
|
APENAS: (1) o que foi feito em 2-3 frases, (2) arquivos modificados,
|
|
@@ -151,8 +175,8 @@ Ao iniciar cada task de `tasks.json` — antes de escrever qualquer código. Nor
|
|
|
151
175
|
5. Implemente a tarefa seguindo o standard e a persona identificados.
|
|
152
176
|
Se encontrar ambiguidade de escopo não coberta pelo mandate, registre no decisions.md
|
|
153
177
|
e resolva da forma mais conservadora — não pause para perguntar, a menos que seja bloqueante.
|
|
154
|
-
Testes rodados durante a implementação inline seguem
|
|
155
|
-
|
|
178
|
+
Testes rodados durante a implementação inline seguem a cláusula 3 do template do passo 4
|
|
179
|
+
(sem red→green, uma rodada do filtro no fim, saída em arquivo) e a 8 (sem mutação).
|
|
156
180
|
|
|
157
181
|
**Task com `3-implement/evidencias/{ID}.md` em `outputs`** (critério sobre saída de LLM —
|
|
158
182
|
`morph-plan` §5): rode o eval ANTES de marcar `done` — e só o eval. Com nó `runner: "evals"`
|
|
@@ -241,7 +265,7 @@ Ao iniciar cada task de `tasks.json` — antes de escrever qualquer código. Nor
|
|
|
241
265
|
> tasks.json + recap.md + `taskScores` do feature.json. **NÃO escreva o trace
|
|
242
266
|
> manualmente** — a escrita manual foi removida da cerimônia por task.
|
|
243
267
|
|
|
244
|
-
9. Quando invocada por `morph-apply`, retornar o controle à skill orquestradora — ela decide qual task vem em seguida via `getReadyTasks(data)`. Não rode a suíte de testes inteira do projeto por conta própria ao fim da task quando invocada pela `morph-apply` — a verificação determinística (`morph-spec verify {feature} {task}`) é do orquestrador, logo após seu retorno (ver morph-apply §3a). **Única exceção:** a execução de evidência do passo 5 — só o nó `evals`, filtrado, com `--skip-e2e`, nunca persistida (`--no-persist`); ela não é a verificação da task e não substitui a do orquestrador. **A divisão:** no loop por task o recorte é **automático** — o `group` da task escolhe as suítes e os arquivos de teste dos `outputs` (passo 8) estreitam o comando dentro de cada uma (o relógio de uma task não paga a suíte inteira); `--filter {ids}` só força a escolha de suítes (um nó não casado aparece como `skip` nomeando o filtro, e um filtro que não casa nada é erro de uso, exit 2) e `--full` desliga o recorte. A suíte **inteira** roda no Gate 3 e no CI, sem filtro — `verify {feature}` nunca recorta. A suíte completa de um projeto grande não cabe numa invocação de Bash do harness — rode em background ou por partes, nunca "suba o limite" (não há constante de timeout global no CLI). Detalhe e forma de `project.tests[]`: `.morph/framework/CLI.md`, seção "Suítes de teste". Quando invocada manualmente, verificar se há próxima task ready e iniciá-la imediatamente aplicando esta skill desde o passo 1 (auto-advance). Pause apenas se encontrar ambiguidade bloqueante não coberta pelo mandate.
|
|
268
|
+
9. Quando invocada por `morph-apply`, retornar o controle à skill orquestradora — ela decide qual task vem em seguida via `getReadyTasks(data)`. Não rode a suíte de testes inteira do projeto por conta própria ao fim da task quando invocada pela `morph-apply` — a verificação determinística (`morph-spec verify {feature} {task}`) é do orquestrador, logo após seu retorno (ver morph-apply §3a). **Única exceção:** a execução de evidência do passo 5 — só o nó `evals`, filtrado, com `--skip-e2e`, nunca persistida (`--no-persist`); ela não é a verificação da task e não substitui a do orquestrador. **A divisão:** no loop por task o recorte é **automático** — o `group` da task escolhe as suítes e os arquivos de teste dos `outputs` (passo 8) estreitam o comando dentro de cada uma (o relógio de uma task não paga a suíte inteira); `--filter {ids}` só força a escolha de suítes (um nó não casado aparece como `skip` nomeando o filtro, e um filtro que não casa nada é erro de uso, exit 2) e `--full` desliga o recorte. O sub-agent despachado roda só o filtro dos próprios testes, uma vez (cláusula 3), e nunca o `verify`. A suíte **inteira** roda no Gate 3 e no CI, sem filtro — `verify {feature}` nunca recorta. A suíte completa de um projeto grande não cabe numa invocação de Bash do harness — rode em background ou por partes, nunca "suba o limite" (não há constante de timeout global no CLI). Detalhe e forma de `project.tests[]`: `.morph/framework/CLI.md`, seção "Suítes de teste". Quando invocada manualmente, verificar se há próxima task ready e iniciá-la imediatamente aplicando esta skill desde o passo 1 (auto-advance). Pause apenas se encontrar ambiguidade bloqueante não coberta pelo mandate.
|
|
245
269
|
|
|
246
270
|
## Output esperado
|
|
247
271
|
- Código implementado conforme o standard consultado (direto ou via sub-agent)
|
|
@@ -4,7 +4,7 @@ description: Conduz a AUTORIA de mídia gerada por IA — escolher o modelo pelo
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: quando a tarefa é PRODUZIR imagem ou vídeo por IA (catálogo, marketing, asset de LP) e alguém precisa decidir modelo, prompt e aprovação
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.41.0"
|
|
8
8
|
stacks:
|
|
9
9
|
- dotnet
|
|
10
10
|
- nextjs
|
|
@@ -212,4 +212,4 @@ trabalho de design". Tratar a saída como entregável vetorial é o erro clássi
|
|
|
212
212
|
|
|
213
213
|
- Os cinco standards da tabela do topo — a fonte de API, custo, prazo e conformidade.
|
|
214
214
|
- Proveniência do conhecimento absorvido: `.morph/framework/standards/PROVENANCE.json`
|
|
215
|
-
(`
|
|
215
|
+
(`morph-image`, `cinematic-lp`, `brand-design`).
|
|
@@ -4,7 +4,7 @@ description: Guia a produção dos artefatos de planejamento de uma feature (use
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar a fase plan de uma feature, após o Gate 1 (proposal aprovado)
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.41.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-plan
|
|
@@ -220,8 +220,9 @@ Ao iniciar a fase plan — após o `proposal.md` ser aprovado e antes de qualque
|
|
|
220
220
|
proibidos: o orçamento por task do passo 5 (um teste por pós-condição + um de regressão por
|
|
221
221
|
bug, justificativa acima disso, tabela antes de cópia, nenhum teste que só fixa texto);
|
|
222
222
|
fixture compartilhada antes de helper novo; TDD onde paga (bug: regressão primeiro; lógica
|
|
223
|
-
pura), teste depois aceito em UI e integração; comentário
|
|
224
|
-
|
|
223
|
+
pura), teste depois aceito em UI e integração; comentário: o padrão é nenhum (nome, tipo e teste
|
|
224
|
+
explicam), só o porquê que o código não mostra, nunca `///`/JSDoc que repete a assinatura
|
|
225
|
+
nem história de task/UC/ADR. Nos standards obrigatórios, liste
|
|
225
226
|
`architecture-code-comments` e o standard de teste do stack (seção *Test budget*).
|
|
226
227
|
- **Baseline é um COMANDO, nunca um número.** O mandate congela no Gate 2 e é lido por
|
|
227
228
|
implementadores durante dias — todo número cravado nele (`Suíte: 2366 passando`, cobertura,
|
|
@@ -307,6 +308,12 @@ Ao iniciar a fase plan — após o `proposal.md` ser aprovado e antes de qualque
|
|
|
307
308
|
|
|
308
309
|
**Preencha `outputs` (paths planejados) em cada task** — o `morph-spec dag` usa os outputs para detectar colisão de arquivos entre fluxos paralelos e recomendar `isolation: "worktree"`. Task sem `outputs` entra como footprint desconhecido (não força isolamento, mas o dag não consegue protegê-la de colisão).
|
|
309
310
|
|
|
311
|
+
**Tamanho da task: no máximo 8 `outputs`** (testes incluídos). Uma task inteira cabe num
|
|
312
|
+
dispatch; acima disso o sub-agente bate no teto de turnos e a retomada recomeça fria. Fatie por
|
|
313
|
+
pós-condição (uma task por pós-condição ou par delas, com a dependência explícita). Antes do
|
|
314
|
+
Gate 2, o `morph-spec dag` recusa (exit 1) e o `gate-check plan` pausa com `oversizedTasks`;
|
|
315
|
+
depois do Gate 2 é só aviso.
|
|
316
|
+
|
|
310
317
|
**Critério sobre saída de LLM vira eval de runtime — nunca "suíte estrutural".** Duas etapas,
|
|
311
318
|
como na `morph-review`: (1) **filtro mecânico** — o `mandate.md` cita ao menos um standard
|
|
312
319
|
`ai-agents`; senão, a regra não se aplica. (2) **determinação sua, por task** — o
|
|
@@ -4,7 +4,7 @@ description: Orquestra a fase de proposta+plano de uma feature morph-spec. Encad
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber instrução "use /morph-proposal" do usuário, ou ao iniciar uma nova feature
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.41.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-proposal
|
|
@@ -4,7 +4,7 @@ description: Conduz a fase de revisão e produz o review-report.md para o Gate 3
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar a fase review, após todas as tasks de tasks.json estarem com status `done`
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.41.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-review
|
|
@@ -4,7 +4,7 @@ description: Varre o codebase existente, detecta stack atual, compara com o stac
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar uma feature em projeto brownfield (codebase já existente)
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.41.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-stack-scan
|
|
@@ -4,7 +4,7 @@ description: Localiza um standard específico via busca server-side (morph-spec
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: quando precisar consultar um standard específico durante a implementação
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.41.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-standards
|
|
@@ -4,7 +4,7 @@ description: Conduz a fase opcional de UI/UX — design system, mockups, compone
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao tomar o ramo uiux (morph-spec advance --design), depois do Gate 1 e antes do morph-plan
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.41.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-uiux
|
|
@@ -32,11 +32,11 @@ Ao tomar o ramo opcional uiux: feature/bug cuja mudança cria ou altera superfí
|
|
|
32
32
|
- **Sistemas, não telas isoladas** — mesmo critério da persona `ui-designer`: componentes reutilizáveis antes de composições de uso único.
|
|
33
33
|
- **Toda tela sai com o checklist de tela preenchido** (template no passo 3) — a superfície, o volume esperado de dados, paginação, ordenação, filtro, os três estados (vazio, carregando, erro), o comportamento no mobile e abas × página longa. "Não se aplica" vale, **desde que escrito**. É o checklist que faz a lista de 2 000 linhas paginar: o que o design não decide não vira `doneCriteria` (`morph-plan` §5d), e o que não é critério ninguém entrega. Tela de dados segue os standards de `admin-app` (lista/tabela, formulário, feedback, estrutura de página), que a persona cita na superfície `admin-app`.
|
|
34
34
|
|
|
35
|
-
3. **Despache `morph-ui-designer`** para o trabalho visual — dispatch é o default aqui (domínio diferente do Orchestrator, MORPH.md §6). `morph-ui-designer` tem `
|
|
35
|
+
3. **Despache `morph-ui-designer`** para o trabalho visual — dispatch é o default aqui (domínio diferente do Orchestrator, MORPH.md §6). `morph-ui-designer` tem o escopo das implementadoras (com Bash) + `Skill` + MCPs `stitch`/`playwright`/`context7`/`graphify` + o MCP de mídia morph-assets (imagem e vídeo). Bash serve para `morph-spec standards --find`, `npx`, screenshot e leitura de `git`; build/test da suíte, `verify` e aprovação de gate continuam do orquestrador (cláusula 3, como nas outras personas).
|
|
36
36
|
|
|
37
37
|
**Persona universal** (`ui-designer.stack = ["*"]` em `agents.json`, mesmo mecanismo de `evaluator`/`scout`): UI/UX importa sempre que há superfície de UI, então o subagent está registrado em **todo** projeto — .NET/Blazor incluído, não só Next.js. **Fallback** (caso raro: instalação anterior a essa mudança, `.claude/agents/morph-ui-designer.md` ainda não regenerado): `general-purpose` colando o campo `persona` (Read em `.morph/framework/agents.json`) no prompt, registrando o fallback no relatório — resolvido rodando `morph-spec setup-infra --reinstall`.
|
|
38
38
|
|
|
39
|
-
Template do prompt (contrato do relatório em forma curta — copia o padrão de `morph-implement` §4
|
|
39
|
+
Template do prompt (contrato do relatório em forma curta — copia o padrão de `morph-implement` §4; a cláusula de build/isolamento vira "sem build/test da suíte", porque o design não entrega código a verificar):
|
|
40
40
|
```
|
|
41
41
|
Produzir os artefatos de UI/UX de [feature] em `.morph/features/{feature}/1-design/`.
|
|
42
42
|
|
|
@@ -46,7 +46,7 @@ Ao tomar o ramo opcional uiux: feature/bug cuja mudança cria ou altera superfí
|
|
|
46
46
|
Produza, NESTA ORDEM — design-system.md primeiro, os demais só como aplicável ao escopo:
|
|
47
47
|
1. `design-system.md` — tokens (cor, tipografia, espaço, motion) consistentes com o projeto
|
|
48
48
|
2. `mockups.md` — descrição estruturada de cada tela nova/alterada (+ imagem via MCP
|
|
49
|
-
|
|
49
|
+
stitch ou o MCP de mídia (imagem/vídeo) quando disponível; fallback: descrição textual detalhada).
|
|
50
50
|
Cada tela é um `## Tela: <nome>` e traz, dentro dela, o checklist abaixo, com cada `…`
|
|
51
51
|
trocado pela decisão — "não se aplica" vale se escrito; `…`, vazio ou "a definir" não.
|
|
52
52
|
O que cada item decide: Superfície (admin-app | marketing-site — ela escolhe que
|
|
@@ -82,8 +82,9 @@ Ao tomar o ramo opcional uiux: feature/bug cuja mudança cria ou altera superfí
|
|
|
82
82
|
`1-design/reports/[artefato]-report.md` (ex.: `1-design/reports/design-system-report.md`)
|
|
83
83
|
ANTES de encerrar — é o retorno autoritativo, não a sua mensagem final (cortesia
|
|
84
84
|
best-effort, pode não chegar inteira). NÃO chame SendMessage.
|
|
85
|
-
2.
|
|
86
|
-
|
|
85
|
+
2. Bash só para consulta (`morph-spec standards --find`, `npx`, screenshot, `git log/diff`):
|
|
86
|
+
NÃO rode build, testes nem `morph-spec verify`/`approve`/`advance` — a verificação e a
|
|
87
|
+
aprovação do Gate uiux são do orquestrador.
|
|
87
88
|
3. NÃO toque em tasks.json, feature.json, state.json nem no board de sessão.
|
|
88
89
|
|
|
89
90
|
Cada relatório contém: (1) o que foi feito em 2-3 frases, (2) o artefato produzido,
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
"skills": []
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
|
-
"id": "
|
|
41
|
+
"id": "morph-image",
|
|
42
42
|
"repo": "morph-HUB",
|
|
43
|
-
"path": "skills/
|
|
43
|
+
"path": "skills/morph-image",
|
|
44
44
|
"envVar": "MORPH_HUB",
|
|
45
45
|
"defaultCheckout": "R:/Polymorphism Tech/repos/morph-HUB",
|
|
46
|
-
"sourceTree": "
|
|
47
|
-
"sourceCommit": "
|
|
46
|
+
"sourceTree": "e55dcf307278583120601c3c5d55118302335f7b",
|
|
47
|
+
"sourceCommit": "c4c9164",
|
|
48
48
|
"distilledOn": "2026-09-09",
|
|
49
49
|
"distilledFrom": [
|
|
50
50
|
"SKILL.md"
|
|
@@ -1551,7 +1551,7 @@
|
|
|
1551
1551
|
"errorbody": "#rule-2--error-path-tests-assert-the-response-body-not-just-the-status-code",
|
|
1552
1552
|
"test-budget": "#test-budget"
|
|
1553
1553
|
},
|
|
1554
|
-
"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. Test budget per task: one test per postcondition plus one regression test per bug, more only with a one-line justification in the task; 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;
|
|
1554
|
+
"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. Test budget per task: one test per postcondition plus one regression test per bug, more only with a one-line justification in the task; 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 pure logic 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.",
|
|
1555
1555
|
"verifiedAgainst": ".NET 10 + xUnit 2 + `Microsoft.Extensions.TimeProvider.Testing`.",
|
|
1556
1556
|
"provedBy": []
|
|
1557
1557
|
},
|
|
@@ -1850,8 +1850,8 @@
|
|
|
1850
1850
|
"favicon-og": "#the-two-assets-everyone-forgets",
|
|
1851
1851
|
"variations": "#variations-and-cost"
|
|
1852
1852
|
},
|
|
1853
|
-
"digest": "Guidelines for generating project images with the
|
|
1854
|
-
"verifiedAgainst": "
|
|
1853
|
+
"digest": "Guidelines for generating project images with the morph-assets MCP (OpenRouter; default openai/gpt-image-2.5-flare, drafts on mai-image-2.6-flash, gemini-3.1-flash-image for 2K/4K or 6-14 refs; models: [...] compares): when to use AI versus stock versus SVG, prompt patterns, aspect ratios, iterative editing and assets.md format. Core principle is brand fidelity over invention: always pass the client's real assets as references (or @brand with a project) via edit_image rather than generating in a vacuum, never AI-recreate a property developer's architectural render or a physical product (animate or reference the real one), and chain derivatives from an approved hero so the whole set shares light, palette and identity. Frame anything destined to become video WITHOUT a face, because video moderation is stricter (E005), and generate scrub frames at the video's exact ratio with the subject opposite the copy. Always produce the two forgotten assets: a favicon derived from the real logo (never a new one) and a 1200x630 OG share image. Offer two to three genuinely different variations per image (variants returns a contact sheet), varying angle, light or composition since seed is not supported by the GPT Image/Gemini models, and never advance with a weak image because every derivative inherits it. Copy to render goes between double quotes; CONFIRMATION_REQUIRED needs human approval and a confirmToken.",
|
|
1854
|
+
"verifiedAgainst": "morph-assets MCP (OpenRouter; default model `openai/gpt-image-2.5-flare`) + Next.js 15 `next/image`.",
|
|
1855
1855
|
"provedBy": []
|
|
1856
1856
|
},
|
|
1857
1857
|
{
|
|
@@ -1889,8 +1889,8 @@
|
|
|
1889
1889
|
"cost-ladder": "#section-4-the-cost-ladder",
|
|
1890
1890
|
"prompt-skeleton": "#section-5-prompt-skeleton"
|
|
1891
1891
|
},
|
|
1892
|
-
"digest": "The decisive rule: a perfect loop has an end frame identical to its start, which is right for a self-playing ambient background and WRONG for scroll scrubbing, because start and end look the same and the page reads as frozen while the user scrolls. Scroll-driven footage needs directional movement via generate_video with an endImage (push-in/dolly is the most reliable, then reveal, pull-back, slow tilt); avoid orbits and any movement that returns to its origin. Client architectural renders are animated with img2vid, never AI-recreated. Human faces repeatedly trip moderation (E005), so crop the face out of frame (neck down, hands, product) and reserve faces for static image generation. Always climb the cost ladder:
|
|
1893
|
-
"verifiedAgainst": "
|
|
1892
|
+
"digest": "The decisive rule: a perfect loop has an end frame identical to its start, which is right for a self-playing ambient background and WRONG for scroll scrubbing, because start and end look the same and the page reads as frozen while the user scrolls. Scroll-driven footage needs directional movement via generate_video with an endImage (push-in/dolly is the most reliable, then reveal, pull-back, slow tilt); avoid orbits and any movement that returns to its origin. Client architectural renders are animated with img2vid, never AI-recreated. Human faces repeatedly trip moderation (E005), so crop the face out of frame (neck down, hands, product) and reserve faces for static image generation. Always climb the cost ladder: seedance-1-5-pro 480p draft to judge framing and movement, then promoteFrom to seedance-2.0 1080p only after approval (same prompt, frames and seed), then re-extract frames with a bumped cache-bust. seedance-2.0-mini does NOT respect endImage and Veo 3.1 Lite/Fast are inconclusive, so scrub only on Seedance 1.5 Pro/2.0 and check the last-frame SSIM QA. Video has no ZDR on OpenRouter: nothing sensitive in the frames. Prompts read like director notes with no hype words, and must reserve a calm dark region for the page copy with the subject on the opposite side. Generation is async via the morph-assets MCP (OpenRouter): a running job is polled with get_video (several ids at once), never by resending generate_video; library reads local history and spends no credits; media_tool extracts scrub frames and posters.",
|
|
1893
|
+
"verifiedAgainst": "morph-assets MCP (generate_video, generate_loop_video, get_video, library, media_tool) over OpenRouter; models `bytedance/seedance-1-5-pro` and `bytedance/seedance-2.0`.",
|
|
1894
1894
|
"provedBy": []
|
|
1895
1895
|
},
|
|
1896
1896
|
{
|
|
@@ -2371,7 +2371,7 @@
|
|
|
2371
2371
|
"e2e": "#test-file-co-location",
|
|
2372
2372
|
"test-budget": "#test-budget"
|
|
2373
2373
|
},
|
|
2374
|
-
"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. Test budget per task: one test per postcondition plus one regression test per bug, more only with a one-line justification in the task; 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;
|
|
2374
|
+
"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. Test budget per task: one test per postcondition plus one regression test per bug, more only with a one-line justification in the task; 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 pure logic get tests in any order — the implementer runs its own filter once, never red-green cycles nor production mutation.",
|
|
2375
2375
|
"verifiedAgainst": "Vitest 3 + React Testing Library 16 + MSW 2.",
|
|
2376
2376
|
"provedBy": []
|
|
2377
2377
|
},
|
|
@@ -2689,8 +2689,8 @@
|
|
|
2689
2689
|
"tools": "#mcp-providers-by-phase",
|
|
2690
2690
|
"setup": "#mcp-availability-detection"
|
|
2691
2691
|
},
|
|
2692
|
-
"digest": "MCP tools extend Claude with external data and actions. Tools are synchronous request-response with typed inputSchema. Resources provide read-only data access. Prompts are reusable templates. Register MCP servers in .claude/settings.json. Prefer @context7 for live library docs. Test tools with MCP Inspector before integrating.",
|
|
2693
|
-
"verifiedAgainst": "Claude Code MCP tooling — context7, Playwright; GitHub via `gh` CLI; Neon via `neonctl`.",
|
|
2692
|
+
"digest": "MCP tools extend Claude with external data and actions. Tools are synchronous request-response with typed inputSchema. Resources provide read-only data access. Prompts are reusable templates. Register MCP servers in .claude/settings.json. Prefer @context7 for live library docs. Tool names follow where the server is configured: mcp__context7__query-docs from .mcp.json, mcp__plugin_context7_context7__query-docs from the plugin; a deferred tool loads via ToolSearch. Test tools with MCP Inspector before integrating.",
|
|
2693
|
+
"verifiedAgainst": "Claude Code 2.1.282 MCP tooling — context7, Playwright (as plugin and as a project MCP server); GitHub via `gh` CLI; Neon via its MCP or `neonctl`.",
|
|
2694
2694
|
"provedBy": []
|
|
2695
2695
|
},
|
|
2696
2696
|
{
|
|
@@ -2848,7 +2848,7 @@
|
|
|
2848
2848
|
"not-worth": "#o-que-não-merece",
|
|
2849
2849
|
"size": "#tamanho"
|
|
2850
2850
|
},
|
|
2851
|
-
"digest": "
|
|
2851
|
+
"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 decisions.md), 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. The verify validators node (code-budget) warns on added comments that cite process and on added comment density.",
|
|
2852
2852
|
"verifiedAgainst": "C#, TypeScript e JavaScript (convenção de linguagem, sem pacote externo).",
|
|
2853
2853
|
"provedBy": []
|
|
2854
2854
|
}
|
|
@@ -30,8 +30,7 @@ Preciso que o agente saiba X.
|
|
|
30
30
|
Plano por fase (instruções + **allow-list de tools** conforme o estado do funil) **não** é caso de provider. É C# puro, montado antes de criar a requisição:
|
|
31
31
|
|
|
32
32
|
```csharp
|
|
33
|
-
//
|
|
34
|
-
// que um provider não consegue dar: AIContext.Tools ACRESCENTA tools, não remove.
|
|
33
|
+
// A allow-list não cabe num provider: AIContext.Tools ACRESCENTA tools, não remove.
|
|
35
34
|
public sealed record OperatorPlan(string Instructions, IReadOnlyList<AITool> Tools);
|
|
36
35
|
|
|
37
36
|
public static OperatorPlan PlanFor(FunnelStage stage) => stage switch
|
|
@@ -92,10 +91,8 @@ Use um `AIContextProvider` quando o agente precisa de **contexto dinâmico compu
|
|
|
92
91
|
|
|
93
92
|
**Método a sobrescrever:**
|
|
94
93
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
// StoreAIContextAsync → chamado APÓS o LLM (after-run hook) — persiste estado se necessário
|
|
98
|
-
```
|
|
94
|
+
- `ProvideAIContextAsync` → chamado ANTES do LLM (before-run hook) — injeta contexto
|
|
95
|
+
- `StoreAIContextAsync` → chamado APÓS o LLM (after-run hook) — persiste estado se necessário (opcional)
|
|
99
96
|
|
|
100
97
|
### A invariante de instância — a mesma de `ai-agents-agent-session`
|
|
101
98
|
|
|
@@ -122,32 +119,33 @@ Consequência prática: **compaction só faz sentido com histórico local**. Com
|
|
|
122
119
|
|
|
123
120
|
## Exemplo C# — context provider que injeta data atual e perfil do tenant
|
|
124
121
|
|
|
122
|
+
O bloco tem três partes: o provider, o registro do agente com o provider no DI (`Program.cs`) e o uso
|
|
123
|
+
normal. `ITenantContext` é implementado via `IHttpContextAccessor` ou `AsyncLocal` para resolver o
|
|
124
|
+
tenant em runtime, nunca registrado como instância estática. O contexto volta como instrução
|
|
125
|
+
adicional, não como mensagem do usuário, e `StoreAIContextAsync` fica vazio porque o provider é
|
|
126
|
+
stateless. No uso, o provider é invocado a cada `RunAsync`: o agente já sabe a data, o nome do tenant
|
|
127
|
+
e o idioma, sem código extra no caller.
|
|
128
|
+
|
|
125
129
|
```csharp
|
|
126
130
|
using Microsoft.Agents.AI;
|
|
127
131
|
using Microsoft.Extensions.AI;
|
|
128
132
|
|
|
129
|
-
// ── 1. Definir o provider ──
|
|
130
133
|
public sealed class TenantContextProvider : AIContextProvider
|
|
131
134
|
{
|
|
132
135
|
private readonly ITenantService _tenantService;
|
|
133
136
|
private readonly ITenantContext _tenantContext;
|
|
134
137
|
|
|
135
|
-
//
|
|
136
|
-
// para resolver o tenant atual em runtime — não registre como instância estática.
|
|
137
|
-
// O AIAgent é singleton, então o provider também é singleton; o tenant corrente
|
|
138
|
-
// é lido de forma ambient (IHttpContextAccessor/AsyncLocal) a cada chamada.
|
|
138
|
+
// Singleton como o AIAgent: o tenant corrente é lido ambient a cada chamada, nunca guardado.
|
|
139
139
|
public TenantContextProvider(ITenantService tenantService, ITenantContext tenantContext)
|
|
140
140
|
{
|
|
141
141
|
_tenantService = tenantService;
|
|
142
142
|
_tenantContext = tenantContext;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
// Sobrescreva: injetado ANTES de cada chamada ao LLM
|
|
146
145
|
protected override async ValueTask<AIContext> ProvideAIContextAsync(
|
|
147
146
|
InvokingContext context,
|
|
148
147
|
CancellationToken cancellationToken = default)
|
|
149
148
|
{
|
|
150
|
-
// Tenant resolvido via serviço injetado (ambient context, ex: IHttpContextAccessor)
|
|
151
149
|
var tenantId = _tenantContext.TenantId ?? "unknown";
|
|
152
150
|
var tenant = await _tenantService.GetTenantAsync(tenantId, cancellationToken);
|
|
153
151
|
|
|
@@ -159,20 +157,16 @@ public sealed class TenantContextProvider : AIContextProvider
|
|
|
159
157
|
|
|
160
158
|
return new AIContext
|
|
161
159
|
{
|
|
162
|
-
// Injeta como instrução adicional — não como mensagem do usuário
|
|
163
160
|
Instructions = instructions,
|
|
164
161
|
};
|
|
165
162
|
}
|
|
166
163
|
|
|
167
|
-
// Sobrescreva (opcional): chamado APÓS o LLM — use para persistir estado derivado da resposta
|
|
168
164
|
protected override ValueTask StoreAIContextAsync(
|
|
169
165
|
InvokedContext context,
|
|
170
166
|
CancellationToken cancellationToken = default)
|
|
171
|
-
=> ValueTask.CompletedTask;
|
|
167
|
+
=> ValueTask.CompletedTask;
|
|
172
168
|
}
|
|
173
169
|
|
|
174
|
-
// ── 2. Registrar o agente com o provider no DI ──
|
|
175
|
-
// Program.cs
|
|
176
170
|
builder.Services.AddSingleton<AIAgent>(sp =>
|
|
177
171
|
{
|
|
178
172
|
var registry = sp.GetRequiredService<ModelRegistry>();
|
|
@@ -187,19 +181,15 @@ builder.Services.AddSingleton<AIAgent>(sp =>
|
|
|
187
181
|
});
|
|
188
182
|
});
|
|
189
183
|
|
|
190
|
-
// ── Alternativa: pipeline de chat (compacta/injeta SÓ o request em voo) ──
|
|
191
|
-
// using Microsoft.Extensions.AI; // a extensão vive na assembly Microsoft.Agents.AI
|
|
192
|
-
// IChatClient enriched = chatClient.AsBuilder()
|
|
193
|
-
// .UseAIContextProviders(new TenantContextProvider(tenantSvc, tenantContext))
|
|
194
|
-
// .Build();
|
|
195
|
-
|
|
196
|
-
// ── 3. Uso normal — provider é invocado automaticamente a cada RunAsync ──
|
|
197
184
|
AgentSession session = await agent.CreateSessionAsync();
|
|
198
185
|
AgentResponse response = await agent.RunAsync("Quais são meus benefícios do plano?", session);
|
|
199
186
|
Console.WriteLine(response.Text);
|
|
200
|
-
// O agente já sabe a data, o nome do tenant e o idioma — sem código extra no caller
|
|
201
187
|
```
|
|
202
188
|
|
|
189
|
+
**Alternativa: pipeline de chat**, que compacta/injeta **só** o request em voo: registre o provider
|
|
190
|
+
com `.UseAIContextProviders(...)` no `ChatClientBuilder` (`chatClient.AsBuilder()`). O `using` é
|
|
191
|
+
`Microsoft.Extensions.AI`, mas a extensão vive na assembly `Microsoft.Agents.AI`.
|
|
192
|
+
|
|
203
193
|
---
|
|
204
194
|
|
|
205
195
|
## Context Provider vs Tools vs RAG
|
|
@@ -22,12 +22,11 @@ If neither applies, a plain workflow (or no workflow at all — see `ai-agents-s
|
|
|
22
22
|
|
|
23
23
|
## Human-in-the-Loop via `RequestPort`
|
|
24
24
|
|
|
25
|
-
HITL is modeled with `RequestPort` — a special node in the workflow graph that pauses execution and waits for an external (human) response instead of processing automatically.
|
|
25
|
+
HITL is modeled with `RequestPort` — a special node in the workflow graph that pauses execution and waits for an external (human) response instead of processing automatically. Its two type arguments are the request type the port sends out and the response type it expects back.
|
|
26
26
|
|
|
27
27
|
```csharp
|
|
28
28
|
using Microsoft.Agents.AI.Workflows;
|
|
29
29
|
|
|
30
|
-
// Request type the port sends out, response type it expects back.
|
|
31
30
|
RequestPort<ApprovalRequest, bool> approvalPort =
|
|
32
31
|
RequestPort.Create<ApprovalRequest, bool>("RefundApproval");
|
|
33
32
|
|
|
@@ -47,8 +46,7 @@ await foreach (WorkflowEvent evt in run.WatchStreamAsync())
|
|
|
47
46
|
switch (evt)
|
|
48
47
|
{
|
|
49
48
|
case RequestInfoEvent requestEvt:
|
|
50
|
-
//
|
|
51
|
-
// This is where execution pauses until an external answer arrives.
|
|
49
|
+
// Execution pauses here until the human's answer arrives (dashboard, email, Slack, ...).
|
|
52
50
|
bool approved = await GetHumanDecisionAsync(requestEvt.Request);
|
|
53
51
|
await run.SendResponseAsync(requestEvt.Request.CreateResponse(approved));
|
|
54
52
|
break;
|
|
@@ -77,8 +75,14 @@ O caso do agente único é o que a casa realmente tem (MORPH_OS: billing, envio
|
|
|
77
75
|
|
|
78
76
|
### O ciclo, medido em `Microsoft.Extensions.AI` 10.9.0
|
|
79
77
|
|
|
78
|
+
Quatro passos: (1) embrulhe a tool — `ApprovalRequiredAIFunction : DelegatingAIFunction`; (2) o run
|
|
79
|
+
**termina** pedindo aprovação — não bloqueia, não espera —, e `ToolApprovalRequestContent.ToolCall` é
|
|
80
|
+
um `ToolCallContent` (medido; **não** é `FunctionCallContent`, que aparece em
|
|
81
|
+
`ToolAutoApprovalRuleContext`); (3) responda **na mesma sessão**, com
|
|
82
|
+
`CreateResponse(bool approved, string? reason)`; (4) **repita** o passo 2 até não restar pendência —
|
|
83
|
+
uma volta pode pedir **outra** tool.
|
|
84
|
+
|
|
80
85
|
```csharp
|
|
81
|
-
// 1. Embrulhe a tool. ApprovalRequiredAIFunction : DelegatingAIFunction.
|
|
82
86
|
AIFunction charge = AIFunctionFactory.Create(BillingTools.ChargeCustomer);
|
|
83
87
|
AITool guarded = new ApprovalRequiredAIFunction(charge);
|
|
84
88
|
|
|
@@ -88,22 +92,16 @@ AIAgent agent = registry.GetChatClient("text-default")
|
|
|
88
92
|
AgentSession session = await agent.CreateSessionAsync();
|
|
89
93
|
AgentResponse response = await agent.RunAsync("Cobre o cliente 42.", session);
|
|
90
94
|
|
|
91
|
-
// 2. O run TERMINA pedindo aprovação — não bloqueia, não espera.
|
|
92
|
-
// ToolApprovalRequestContent.ToolCall é um ToolCallContent (medido; NÃO é
|
|
93
|
-
// FunctionCallContent — este último aparece em ToolAutoApprovalRuleContext).
|
|
94
95
|
var pending = response.Messages
|
|
95
96
|
.SelectMany(m => m.Contents)
|
|
96
97
|
.OfType<ToolApprovalRequestContent>()
|
|
97
98
|
.ToList();
|
|
98
99
|
|
|
99
|
-
// 3. Responda NA MESMA SESSÃO. CreateResponse(bool approved, string? reason).
|
|
100
100
|
if (pending.Count > 0)
|
|
101
101
|
{
|
|
102
102
|
var approvals = pending.Select(r => (AIContent)r.CreateResponse(approved: true, reason: "aprovado por lucas@…"));
|
|
103
103
|
response = await agent.RunAsync(new ChatMessage(ChatRole.User, [.. approvals]), session);
|
|
104
104
|
}
|
|
105
|
-
|
|
106
|
-
// 4. REPITA o passo 2 até não restar pendência. Uma volta pode pedir OUTRA tool.
|
|
107
105
|
```
|
|
108
106
|
|
|
109
107
|
**Os quatro pontos que erram na primeira tentativa:**
|
|
@@ -157,10 +155,11 @@ Checkpointing is part of the **base, GA** `Microsoft.Agents.AI.Workflows` namesp
|
|
|
157
155
|
| `CheckpointManager.CreateJson(new FileSystemJsonCheckpointStore(dir))` | Local disk, survives process restart | Single-instance VPS deployments — no Azure, no preview package |
|
|
158
156
|
| Custom `ICheckpointStore` implementation | Whatever backend you implement it against | **Recommended for production** — implement against the project's own Neon Postgres table, matching the ownership model already used by `ai-agents-rag-custom-pgvector` |
|
|
159
157
|
|
|
158
|
+
Local-disk durability, with no Azure dependency:
|
|
159
|
+
|
|
160
160
|
```csharp
|
|
161
161
|
using Microsoft.Agents.AI.Workflows;
|
|
162
162
|
|
|
163
|
-
// Local-disk durability — no Azure dependency:
|
|
164
163
|
var checkpointFolder = Directory.CreateDirectory("./checkpoints");
|
|
165
164
|
CheckpointManager checkpointManager = CheckpointManager.CreateJson(
|
|
166
165
|
new FileSystemJsonCheckpointStore(checkpointFolder));
|
|
@@ -171,13 +170,12 @@ await foreach (WorkflowEvent evt in run.WatchStreamAsync())
|
|
|
171
170
|
if (evt is SuperStepCompletedEvent stepEvt)
|
|
172
171
|
{
|
|
173
172
|
CheckpointInfo? checkpoint = stepEvt.CompletionInfo?.Checkpoint;
|
|
174
|
-
// Persist checkpoint.CheckpointId
|
|
175
|
-
// (e.g. the refund request row) so it can be resumed after a restart.
|
|
173
|
+
// Persist checkpoint.CheckpointId with the business record (e.g. the refund row) to resume after a restart.
|
|
176
174
|
}
|
|
177
175
|
}
|
|
178
176
|
```
|
|
179
177
|
|
|
180
|
-
Resuming after a restart — rehydrate into a **new** run instance from the last known checkpoint:
|
|
178
|
+
Resuming after a restart — rehydrate into a **new** run instance from the last known checkpoint. A pending `RequestPort` request is re-emitted as a `RequestInfoEvent`, so the paused approval survives the restart:
|
|
181
179
|
|
|
182
180
|
```csharp
|
|
183
181
|
StreamingRun resumedRun = await InProcessExecution.ResumeStreamingAsync(
|
|
@@ -185,8 +183,6 @@ StreamingRun resumedRun = await InProcessExecution.ResumeStreamingAsync(
|
|
|
185
183
|
|
|
186
184
|
await foreach (WorkflowEvent evt in resumedRun.WatchStreamAsync())
|
|
187
185
|
{
|
|
188
|
-
// A pending RequestPort request is re-emitted here as a RequestInfoEvent —
|
|
189
|
-
// the paused approval survives the restart.
|
|
190
186
|
if (evt is RequestInfoEvent requestEvt) { /* re-surface to the human */ }
|
|
191
187
|
}
|
|
192
188
|
```
|
|
@@ -211,14 +207,12 @@ internal sealed class RefundAnalyzerExecutor() : Executor("RefundAnalyzer")
|
|
|
211
207
|
|
|
212
208
|
### `ICheckpointStore` — Neon/Postgres-backed (recommended production pattern)
|
|
213
209
|
|
|
214
|
-
Implementing `ICheckpointStore` against the project's own Postgres database keeps checkpoint durability inside the same infrastructure the rest of the project already trusts (see `infrastructure-neon-setup`), instead of introducing a new storage dependency:
|
|
210
|
+
Implementing `ICheckpointStore` against the project's own Postgres database keeps checkpoint durability inside the same infrastructure the rest of the project already trusts (see `infrastructure-neon-setup`), instead of introducing a new storage dependency. The store persists and retrieves checkpoint blobs in a `workflow_checkpoints` table (`workflow_id`, `checkpoint_id`, `payload` jsonb/bytea, `created_at`), implemented per the `ICheckpointStore` contract in the `Microsoft.Agents.AI.Workflows` docs:
|
|
215
211
|
|
|
216
212
|
```csharp
|
|
217
213
|
public sealed class PostgresCheckpointStore(NpgsqlDataSource dataSource) : ICheckpointStore
|
|
218
214
|
{
|
|
219
|
-
//
|
|
220
|
-
// (workflow_id, checkpoint_id, payload jsonb/bytea, created_at).
|
|
221
|
-
// Implement per the ICheckpointStore contract — see Microsoft.Agents.AI.Workflows docs.
|
|
215
|
+
// ICheckpointStore members over workflow_checkpoints — elided.
|
|
222
216
|
}
|
|
223
217
|
```
|
|
224
218
|
|