Fix StudioTeam DI gap and prevent regression#499
Conversation
Mainnet host startup fails ValidateOnBuild because ProjectionStudioTeamQueryPort needs IProjectionDocumentReader< StudioTeamCurrentStateDocument, string>, which was never registered: ADR-0017 step 6+9 added the projector, document, metadata provider, and query port but missed wiring the ES/InMemory store in StudioProjectionReadModelServiceCollectionExtensions. Fix: - Register StudioTeamCurrentStateDocument with both ES and InMemory document stores; add to HasAllStudioDocumentReaders predicate. - Add StudioTeamState.Descriptor to the state TypeRegistry used by ES state-event deserialization. Prevent regression: - New CI guard tools/ci/studio_projection_readmodel_registration_guard.sh scans every IProjectionReadModel<TDoc> in Studio.Projection ReadModels and requires the hosting file to call RegisterElasticsearch<TDoc>, RegisterInMemory<TDoc>, and HasDocumentReaderForProvider<TDoc>. Wired into architecture_guards.sh (runs in fast-gates). - New CI job host-composition-smoke runs MainnetHostCompositionTests on every PR. The existing test exercises the full Mainnet container with ValidateOnBuild and would have caught this gap, but the test only ran in slow-test-guards / split-test-guards which are gated to scheduled / workflow_dispatch -- never on PRs. Validation: - Guard FAILS against pre-fix state with the exact missing-call list, PASSES against fixed state. - MainnetHostCompositionTests FAILS against pre-fix state with the ValidateService stack trace prod hit, PASSES against fixed state. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Review SummaryLGTM — PR质量很好,可以合并。 修复正确性
防护层设计
CI
一个小建议(非阻塞)guard脚本的 |
Review: Guard 不完整 — 缺少
|
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## dev #499 +/- ##
==========================================
+ Coverage 71.06% 71.52% +0.45%
==========================================
Files 1235 1235
Lines 89463 89467 +4
Branches 11705 11705
==========================================
+ Hits 63575 63989 +414
+ Misses 21331 20895 -436
- Partials 4557 4583 +26
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 35 files with indirect coverage changes 🚀 New features to boost your workflow:
|
eanzhao
left a comment
There was a problem hiding this comment.
Overall the fix is correct and the defense-in-depth approach (static guard + CI smoke) is well designed. A few observations:
1. host_composition_smoke.sh — silent pass risk
If the test class MainnetHostCompositionTests is ever renamed or the FQN changes, the --filter will silently match zero tests and dotnet test returns exit code 0. This turns the smoke into a no-op CI check. Consider adding an explicit count guard:
output=$(dotnet test ... --filter "FullyQualifiedName~MainnetHostCompositionTests" 2>&1)
if ! echo "$output" | grep -q "Total tests:"; then
echo "No tests matched — MainnetHostCompositionTests may have been renamed"
exit 1
fiOr alternatively, filter at the test-project level and validate the test count result.
2. Guard script regex robustness (minor)
The regex \bIProjectionReadModel<\s*(\w+)\s*> works for all current read models, but \w+ won't match generic-parameterized types (e.g. IProjectionReadModel<Foo<T>>). If a read model ever takes a type parameter, the guard will silently miss it. Consider using [\w<>]+ or a more permissive capture group. Not blocking, just a forward-looking note.
3. Everything else LGTM
- DI registrations (Elasticsearch + InMemory) match the existing pattern exactly
HasAllStudioDocumentReadersis consistent with the registration blocksStudioTeamState.DescriptorinBuildStudioStateTypeRegistryfollows the same pattern asStudioMemberState.Descriptor- CI integration is clean and properly gated to PR/push events only
- Branch naming follows the repo convention (
fix/YYYY-MM-DD_purpose)
Problem
Mainnet host startup fails on dev:
ADR-0017 step 6+9 (
StudioTeamprojection + application service layer) added theread model, projector, metadata provider, query port, and command port but
missed wiring
StudioTeamCurrentStateDocumentintoStudioProjectionReadModelServiceCollectionExtensions. WithValidateOnBuild = trueonAevatar.Mainnet.Host.Api, the container buildfails immediately and the pod can't start.
Unrelated to PR #495 — that merge happened to be the dev tip when the gap
surfaced.
Solution
Fix the DI gap (
StudioProjectionReadModelServiceCollectionExtensions)RegisterElasticsearch<StudioTeamCurrentStateDocument>(...)RegisterInMemory<StudioTeamCurrentStateDocument>(...)HasAllStudioDocumentReaderspredicate to require both providers.StudioTeamState.DescriptortoBuildStudioStateTypeRegistry(ESstate-event deserialization).
Prevent regression (two layers, both validated)
Static guard —
tools/ci/studio_projection_readmodel_registration_guard.sh:scans every
IProjectionReadModel<TDoc>undersrc/Aevatar.Studio.Projection/ReadModels/and requires the hosting fileto call
RegisterElasticsearch<TDoc>,RegisterInMemory<TDoc>, andHasDocumentReaderForProvider<TDoc>. Wired intoarchitecture_guards.sh(runs in
fast-gates). Cheap and immediate.Composition smoke — new CI job
host-composition-smoke:runs
MainnetHostCompositionTestson every PR. The existing test exercisesthe full
Aevatar.Mainnet.Host.Apicontainer with InMemory providers andwould have caught this gap — but the test only ran in
slow-test-guards/split-test-guards, both gated toschedule/workflow_dispatch.Adding a dedicated job ensures every PR validates DI composition.
The two layers are intentional: the guard catches the specific Studio
projection registration pattern at lint speed; the composition smoke catches
the broader class of "any singleton's transitive dep is missing".
Impact Paths
src/Aevatar.Studio.Hosting/StudioProjectionReadModelServiceCollectionExtensions.cstools/ci/studio_projection_readmodel_registration_guard.sh(new)tools/ci/host_composition_smoke.sh(new)tools/ci/architecture_guards.sh.github/workflows/ci.ymlValidation
bash tools/ci/studio_projection_readmodel_registration_guard.shbash tools/ci/host_composition_smoke.shValidateServicestack tracematching prod.
MainnetHostCompositionTests,all green).
dotnet build src/Aevatar.Studio.Hosting/Aevatar.Studio.Hosting.csprojsucceeds.
Test plan
ValidateOnBuild./api/studio/teams/...endpoints respond (proves the registeredreader actually serves queries).
🤖 Generated with Claude Code