feat(caching): ICache port + InMemoryCache adapter (POM-512)#115
Merged
Conversation
…keys (POM-512)
Introduce the framework's first cache abstraction:
- src/Abstractions/Compendium.Abstractions.Caching — new ICache port
(Get/Set/Remove/Exists, optional TTL, Result-pattern throughout) plus
CachingErrors (InvalidTtl, BackendFailure). Mirrors the per-port
package layout already used for Storage, Search, etc.
- src/Infrastructure/Compendium.Infrastructure/Caching/InMemoryCache —
IMemoryCache-backed implementation. Tenant isolation via optional
ITenantContext: non-empty TenantId scopes every key as `{tenantId}:{key}`.
Misses are Result.Success(null), never failures. Argument validation
throws ArgumentException, matching the conventions of
InMemoryIdempotencyStore.
- ServiceCollectionExtensions.AddInMemoryCache registers IMemoryCache (if
not already) and ICache → InMemoryCache as a singleton, optionally
configuring MemoryCacheOptions.
- Tests: 23 unit tests on InMemoryCache (100% line, 100% branch) covering
round-trip for string/int/complex records, TTL configuration via NSubstitute
to avoid wall-clock dependency, TTL validation, removal, existence,
tenant prefix isolation, no-tenant pass-through, empty-tenant treated
as no-tenant, and DI registration. 3 unit tests on CachingErrors
(100% line, 100% branch).
Microsoft.Extensions.Caching.{Abstractions,Memory} 9.0.16 pinned in
Directory.Packages.props matching the existing 9.0.16 Microsoft.Extensions
band.
No changes to the Redis adapter — that repo's README will be updated in
a separate follow-up.
There was a problem hiding this comment.
Pull request overview
This PR introduces a new caching port (ICache) under Compendium.Abstractions and provides a first-party IMemoryCache-backed adapter in Compendium.Infrastructure, along with DI registration and unit tests, to enable provider-agnostic caching across the framework.
Changes:
- Added new
Compendium.Abstractions.Cachingproject defining theICachecontract and standardizedCachingErrors. - Added
Compendium.Infrastructure.Caching.InMemoryCacheimplementation plusAddInMemoryCache(...)DI extension. - Updated solution/package references and added unit test projects covering the new port/errors and in-memory adapter behavior.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/Abstractions/Compendium.Abstractions.Caching/ICache.cs |
Defines the caching port API and behavioral contract (Result-based, TTL, miss semantics). |
src/Abstractions/Compendium.Abstractions.Caching/CachingErrors.cs |
Adds standardized error codes/messages for caching operations. |
src/Abstractions/Compendium.Abstractions.Caching/GlobalUsings.cs |
Adds Results global using for the new abstractions project. |
src/Abstractions/Compendium.Abstractions.Caching/Compendium.Abstractions.Caching.csproj |
Introduces the new abstractions assembly and test visibility. |
src/Infrastructure/Compendium.Infrastructure/Caching/InMemoryCache.cs |
Implements ICache using IMemoryCache with optional tenant key scoping. |
src/Infrastructure/Compendium.Infrastructure/Caching/ServiceCollectionExtensions.cs |
Adds AddInMemoryCache(...) to wire up IMemoryCache + ICache via DI. |
src/Infrastructure/Compendium.Infrastructure/Compendium.Infrastructure.csproj |
Adds project/package references needed for the caching adapter. |
tests/Unit/Compendium.Infrastructure.Tests/Caching/InMemoryCacheTests.cs |
Adds unit tests for adapter behavior (TTL, isolation, DI registration). |
tests/Unit/Compendium.Abstractions.Caching.Tests/* |
Adds unit tests for CachingErrors and test project scaffolding. |
Directory.Packages.props |
Pins Microsoft.Extensions.Caching.* package versions centrally. |
Compendium.sln |
Adds the new abstractions + test projects to the solution. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+83
to
+84
| _memoryCache.Set(ScopeKey(key), value, options); | ||
| return Task.FromResult(Result.Success()); |
Comment on lines
+55
to
+60
| if (_memoryCache.TryGetValue(scopedKey, out var raw) && raw is T typed) | ||
| { | ||
| return Task.FromResult(Result.Success<T?>(typed)); | ||
| } | ||
|
|
||
| return Task.FromResult(Result.Success<T?>(default)); |
Comment on lines
+88
to
+103
| public Task<Result> RemoveAsync(string key, CancellationToken cancellationToken = default) | ||
| { | ||
| ArgumentException.ThrowIfNullOrWhiteSpace(key); | ||
|
|
||
| _memoryCache.Remove(ScopeKey(key)); | ||
| return Task.FromResult(Result.Success()); | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public Task<Result<bool>> ExistsAsync(string key, CancellationToken cancellationToken = default) | ||
| { | ||
| ArgumentException.ThrowIfNullOrWhiteSpace(key); | ||
|
|
||
| var exists = _memoryCache.TryGetValue(ScopeKey(key), out _); | ||
| return Task.FromResult(Result.Success(exists)); | ||
| } |
Comment on lines
+326
to
+330
| var services = new ServiceCollection(); | ||
| services.AddInMemoryCache(opts => opts.SizeLimit = 123); | ||
|
|
||
| using var sp = services.BuildServiceProvider(); | ||
|
|
2 tasks
Pomdapis
added a commit
that referenced
this pull request
May 21, 2026
… + Hugging Face (#116) ## Summary Phase 6 shipped 4 more public adapters today. README \`## Adapters\` catches up to 22 entries. | New adapter | Repo | |---|---| | Mistral AI (EU) | [\`compendium-adapter-mistral\`](https://github.com/sassy-solutions/compendium-adapter-mistral) | | DeepSeek (V3 / R1) | [\`compendium-adapter-deepseek\`](https://github.com/sassy-solutions/compendium-adapter-deepseek) | | Mercury (Inception Labs) | [\`compendium-adapter-mercury\`](https://github.com/sassy-solutions/compendium-adapter-mercury) | | Hugging Face Inference Endpoints | [\`compendium-adapter-huggingface\`](https://github.com/sassy-solutions/compendium-adapter-huggingface) | Phase 6 also shipped a framework-internal **\`Compendium.Abstractions.Caching\`** + **\`Compendium.Infrastructure.Caching.InMemoryCache\`** (POM-512, see PR #115 → \`v1.0.3\`). Not an adapter — lives in the framework. Drop-in alternative to \`compendium-adapter-redis\` for dev / single-instance / unit-test scenarios. Per memory \`project_compendium_readme_adapter_index.md\`, every public adapter ship updates this table. ## Test plan - [ ] CI green. - [ ] Visual render check of the updated table. Co-authored-by: sacha <sacha@scojhconsult.com>
This was referenced May 21, 2026
Open
Open
Open
Open
Open
Open
Open
Open
Open
Open
Open
Open
Open
Open
Open
Open
This was referenced Jun 1, 2026
Open
Open
Open
Open
Open
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Decision: define
ICachehere (Option B)Investigation confirmed there is no existing
ICacheport in eitherCompendium.Abstractionsor any sibling assembly (verified viagrepacrosssrc/and thecompendium-adapter-redis@1.0.0package contents — it ships onlyIdempotency/+Projections/, no caching). So the contract is defined here, in a new per-port assemblyCompendium.Abstractions.Caching, matching the project layout already used for Storage, Search, VectorStore, etc.Summary
Compendium.Abstractions.Caching— new port assembly withICache(Get/Set/Remove/Exists, optional TTL,Result<T>throughout) andCachingErrors(InvalidTtl,BackendFailure).Compendium.Infrastructure/Caching/InMemoryCache—IMemoryCache-backed implementation. OptionalITenantContextinjection: a non-emptyTenantIdscopes every key as{tenantId}:{key}. No tenant / empty tenant → keys are written verbatim. Cache misses areResult.Success(null), never failures.AddInMemoryCache(IServiceCollection, Action<MemoryCacheOptions>? configure = null)registersIMemoryCache(idempotent) +ICache → InMemoryCachesingleton.Microsoft.Extensions.Caching.{Abstractions,Memory}pinned at9.0.16inDirectory.Packages.props.Files
src/Abstractions/Compendium.Abstractions.Caching/{ICache,CachingErrors,GlobalUsings}.cs+.csprojsrc/Infrastructure/Compendium.Infrastructure/Caching/{InMemoryCache,ServiceCollectionExtensions}.cstests/Unit/Compendium.Abstractions.Caching.Tests/CachingErrorsTests.cs(3 tests)tests/Unit/Compendium.Infrastructure.Tests/Caching/InMemoryCacheTests.cs(23 tests)Directory.Packages.props,Compendium.Infrastructure.csproj,Compendium.slnCoverage (per-class, line / branch)
Compendium.Infrastructure.Caching.InMemoryCacheCompendium.Infrastructure.Caching.ServiceCollectionExtensionsCompendium.Abstractions.Caching.CachingErrorsICacheitself is an interface and contributes no IL to coverage instrumentation.Test plan
dotnet build Compendium.sln -c Release— 0 errors, warnings unchanged from baseline (104 → 104).dotnet test tests/Unit/Compendium.Infrastructure.Tests— 595 passed / 2 skipped (pre-existing) / 0 failed.dotnet test tests/Unit/Compendium.Abstractions.Caching.Tests— 3 passed.HexagonalLayeringTests, etc.) — 37 passed, no new layering violations.Constraints checked
feat/inmemory-cacheagainstmain. No tag.Microsoft.Extensions.Caching.*versions match the existing 9.0.16Microsoft.Extensions.*band.compendium-test-authorconventions (xUnit / FluentAssertions / NSubstitute, noThread.Sleep, TTL configuration verified viaICacheEntrysubstitution rather than wall-clock).