GFramework/ai-plan/public/archive/cqrs-cache-docs-hardening/traces/cqrs-cache-docs-hardening-trace.md
gewuyou c82518aa0d docs(ai-plan): 收口公共计划主题索引
- 重构 ai-plan public 结构为按主题分组并引入归档层级
- 新增 public README worktree 映射并同步 boot 启动入口
- 更新治理 tracking trace 与仓库文档中的 ai-plan 路径约定
2026-04-19 10:46:27 +08:00

91 lines
5.1 KiB
Markdown

# CQRS Cache And Docs Hardening Trace
## 2026-04-17
### Stage: Discovery
- Read `AGENTS.md` and `.ai/environment/tools.ai.yaml` before selecting repository tools.
- Confirmed `README.md` quick-install guidance omits `GeWuYou.GFramework.Cqrs` and
`GeWuYou.GFramework.Cqrs.Abstractions` even though the module overview recommends CQRS as a first-class module.
- Confirmed `docs/zh-CN/source-generators/index.md` lists the split CQRS generator package but does not provide a
dedicated CQRS handler-registry section with package wiring, minimal usage, or compatibility notes.
- Confirmed `GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs` has a cross-container metadata-cache test that
only asserts reflection/attribute call counts and does not prove the second container still receives registrations.
- Confirmed `GFramework.Cqrs/Internal/CqrsDispatcher.cs` and
`GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs` currently use process-wide `ConcurrentDictionary<Type, ...>` /
`ConcurrentDictionary<Assembly, ...>` caches that strongly retain collectible types and assemblies.
- Reviewed `docs/zh-CN/getting-started/installation.md` as a related setup entry page; it also omits the CQRS runtime
packages from the installation snippets.
### Current Recovery Point
- `CQRS-CACHE-DOCS-HARDENING-RP-001`
### Immediate Next Step
1. Update the tracking document and then patch the docs, runtime caches, and tests in one pass.
### Stage: Implementation
- Updated `README.md` quick-install guidance to include:
- `GeWuYou.GFramework.Cqrs`
- `GeWuYou.GFramework.Cqrs.Abstractions`
- Updated `docs/zh-CN/getting-started/installation.md` to add CQRS runtime package rows and installation snippets, and
corrected the installation verification sample to the current `GFramework.Core.Architectures` /
`OnInitialize()` / `OnInit()` API shape.
- Updated `docs/zh-CN/core/cqrs.md` to add explicit CQRS package wiring and document the current namespace split
between message base types (`GFramework.Cqrs.*`) and handler base types (`GFramework.Cqrs.Cqrs.*`).
- Updated `docs/zh-CN/source-generators/index.md` to add a dedicated `CQRS Handler Registry 生成器` section covering:
- required runtime and generator packages
- a minimal working architecture example
- compatibility and migration notes for reflection fallback vs generated registries
- Added `GFramework.Cqrs/Internal/WeakKeyCache.cs` with unload-aware weak-key cache helpers built on
`ConditionalWeakTable`.
- Replaced the CQRS runtime's process-wide strong-reference type/assembly caches with weak-key caches in:
- `GFramework.Cqrs/Internal/CqrsDispatcher.cs`
- `GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs`
- Expanded `GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs` so the cross-container metadata-cache test now
proves both containers still resolve the expected handlers after the cache is reused.
- Updated `GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs` to assert cache reuse through observable cached
entries instead of assuming `ConcurrentDictionary`-specific count semantics.
- Evaluated the suggestion to change handler doc examples from `using GFramework.Cqrs.Cqrs.Command;` to
`using GFramework.Cqrs.Command;`. The repository's actual handler base types still live under
`GFramework.Cqrs.Cqrs.*`, so the implementation kept the real API and clarified the namespace split in the docs
instead of documenting a non-existent namespace.
### Stage: Validation
- Ran:
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release`
- Result:
- passed, `62` tests passed
- The first validation run surfaced one nullable warning in `GFramework.Cqrs/Internal/WeakKeyCache.cs` because the
nested weak cache lookup did not prove the secondary cache was non-null to the compiler.
### Stage: Validation Follow-up
- Fixed `WeakTypePairCache<TValue>.TryGetValue(...)` to guard the nested weak cache reference explicitly.
- Re-ran:
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --no-restore`
- Result:
- passed, `62` tests passed
### Immediate Next Step
1. Stop at `CQRS-CACHE-DOCS-HARDENING-RP-001` unless broader solution-level validation is requested.
### Stage: Minor Follow-up
- Updated `docs/zh-CN/core/cqrs.md` again so the standalone handler snippet now imports both:
- `GFramework.Cqrs.Command`
- `GFramework.Cqrs.Cqrs.Command`
- Added XML documentation to the private nested binding types in `GFramework.Cqrs/Internal/CqrsDispatcher.cs` so the
intent of the cached service-type/delegate bundles is explicit to future maintainers.
- Restored the explicit `using System.Runtime.CompilerServices;` directive at the top of
`GFramework.Cqrs/Internal/WeakKeyCache.cs` so `ConditionalWeakTable<,>` does not rely on ambient imports.
- Added a stateful `WeakKeyCache<TKey, TValue>.GetOrAdd<TState>(...)` overload and updated
`WeakTypePairCache<TValue>.GetOrAdd(...)` to use it, removing the captured lambda allocation from the secondary-key
lookup path.
- Updated both `WeakKeyCache<TKey, TValue>.GetOrAdd(...)` XML comments to state the full contract:
`valueFactory` itself must be non-null, and it must not produce a null cache value.