diff --git a/instructions/cache-usage.md b/instructions/cache-usage.md
index c7b3d99..c95b872 100644
--- a/instructions/cache-usage.md
+++ b/instructions/cache-usage.md
@@ -51,7 +51,7 @@ var entryOptions = new MemoryCacheEntryOptions()
.SetSize(1);
```
- In the code: `Program.cs` registers the cache with `SizeLimit` taken from the `TextServices:CacheMaxEntries` setting (default 20; read directly from configuration because options binding isn't available at that point in startup). `TextCache` sets `.SetSize(1)` on every entry — both `Text` and `AutoComplete` objects share the same slot budget.
+ In the code: `Program.cs` registers the cache with `SizeLimit` taken from the `TextServices:CacheMaxEntries` setting (default 20; read directly from configuration because options binding isn't available at that point in startup). The config key is looked up via `nameof(SearchApiOptions.CacheMaxEntries)` rather than a string literal, so the `SearchApiOptions` property — otherwise unreferenced in code, since this path bypasses options binding — stays in lockstep with the setting it documents. `TextCache` sets `.SetSize(1)` on every entry — both `Text` and `AutoComplete` objects share the same slot budget.
2. **Add an absolute expiration floor.** ✅ **Implemented.** Sliding expiration alone means a popular text stays cached forever. Adding an absolute cap forces periodic refresh and bounds LOH lifetime. `TextCache` applies `.SetAbsoluteExpiration()` from the `TextServices:CacheAbsoluteExpirationHours` setting (default 4 hours) alongside the sliding expiration.
diff --git a/src/TextServices.Search.Api/Configuration/SearchApiOptions.cs b/src/TextServices.Search.Api/Configuration/SearchApiOptions.cs
index e63f628..91b8461 100644
--- a/src/TextServices.Search.Api/Configuration/SearchApiOptions.cs
+++ b/src/TextServices.Search.Api/Configuration/SearchApiOptions.cs
@@ -14,10 +14,11 @@ public class SearchApiOptions
public int CacheSlidingExpirationMinutes { get; set; } = 30;
///
- /// Absolute expiration cap for cached objects (hours).
+ /// Absolute expiration cap for cached objects (hours). Fractional values are allowed
+ /// (e.g. 0.25 for 15 minutes), for deployments that need a tighter cap than whole hours.
/// Prevents popular texts from staying in the LOH indefinitely.
///
- public int CacheAbsoluteExpirationHours { get; set; } = 4;
+ public double CacheAbsoluteExpirationHours { get; set; } = 4;
///
/// Maximum number of Text objects to hold in the memory cache simultaneously.
diff --git a/src/TextServices.Search.Api/Program.cs b/src/TextServices.Search.Api/Program.cs
index d806eb1..46cdf1b 100644
--- a/src/TextServices.Search.Api/Program.cs
+++ b/src/TextServices.Search.Api/Program.cs
@@ -97,7 +97,8 @@
// ---- Cache ------------------------------------------------------------------
builder.Services.AddMemoryCache(opts =>
- opts.SizeLimit = builder.Configuration.GetSection("TextServices").GetValue("CacheMaxEntries") ?? 20);
+ opts.SizeLimit = builder.Configuration.GetSection("TextServices")
+ .GetValue(nameof(SearchApiOptions.CacheMaxEntries)) ?? 20);
builder.Services.AddSingleton(new AsyncKeyedLocker());
builder.Services.AddSingleton();