Repository navigation
Conversation
Reviewer's guide (collapsed on small PRs)Reviewer's GuideThe CLI now recovers from stale remote index caches by forcing one index refresh when a requested component is not found, while preserving existing cache, local-source, and explicit refresh semantics; documentation and project configuration were updated accordingly. Sequence diagram for automatic index refresh on missing componentsequenceDiagram
participant CLI as LLMsDocsClient
participant Cache as IndexCache
participant Remote as RemoteDocs
CLI->>Cache: TryReadFreshCache(llms.txt)
Cache-->>CLI: Cached index
CLI->>CLI: ParseIndex(index)
alt Component found
CLI-->>CLI: Return component document
else Component missing from cached index
CLI->>Remote: FetchAsync(llms.txt, ct, refresh: true)
Remote-->>CLI: Refreshed index
CLI->>CLI: ParseIndex(refreshed index)
alt Component found after refresh
CLI-->>CLI: Return component document
else Component still missing
CLI-->>CLI: throw FileNotFoundException
end
end
Flow diagram for component lookup cache behaviorflowchart TD
A[GetComponentAsync] --> B{Remote source using cache?}
B -->|No| C[GetIndexAsync]
B -->|Yes| D[TryReadFreshCache]
D --> E{Component in index?}
E -->|Yes| F[Fetch component document]
E -->|No| G[FetchAsync with refresh: true]
G --> H{Component in refreshed index?}
H -->|Yes| F
H -->|No| I[FileNotFoundException]
C --> J{Component in index?}
J -->|Yes| F
J -->|No| I
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs" line_range="84" />
<code_context>
.FirstOrDefault(e => string.Equals(e.Name, name, StringComparison.OrdinalIgnoreCase));
+ if (entry is null && usedCachedIndex)
+ {
+ entry = ParseIndex(await FetchAsync("llms.txt", ct, refresh: true))
+ .FirstOrDefault(e => string.Equals(e.Name, name, StringComparison.OrdinalIgnoreCase));
+ }
</code_context>
<issue_to_address>
**Stale indexes stay fresh**
When concurrent refreshes fetch different index revisions, `WriteContent` can overwrite a newer `llms.txt` body or pair an older body with newer metadata; a later 304 then treats that stale body as fresh for 24 hours, so `get` misses newly published components.
Serialize refreshes for each shared index and commit its body and metadata together, so concurrent responses cannot overwrite or mix revisions.
</issue_to_address>
### Comment 2
<location path="tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs" line_range="74-77" />
<code_context>
- var entry = ParseIndex(await GetIndexAsync(ct))
+ var index = "";
+ var usedCachedIndex = _useCache && !_refresh && TryReadFreshCache("llms.txt", out index);
+ if (!usedCachedIndex)
+ {
+ index = await GetIndexAsync(ct);
+ }
+
</code_context>
<issue_to_address>
**Concurrent cache update skips retry**
When another process writes a fresh index containing no requested component between the initial cache check and `GetIndexAsync`'s cache check, `GetIndexAsync` can read a newly written cache after the initial check misses, while `usedCachedIndex` remains false; if that index lacks the requested name, `GetComponentAsync` skips the automatic refresh and reports the component as not found.
Use the cache result and its provenance from a single lookup, or ensure that a miss on the initial lookup forces the subsequent index fetch to bypass cache.
</issue_to_address>| .FirstOrDefault(e => string.Equals(e.Name, name, StringComparison.OrdinalIgnoreCase)); | ||
| if (entry is null && usedCachedIndex) | ||
| { | ||
| entry = ParseIndex(await FetchAsync("llms.txt", ct, refresh: true)) |
There was a problem hiding this comment.
🟡 Medium · Stale indexes stay fresh
When concurrent refreshes fetch different index revisions, WriteContent can overwrite a newer llms.txt body or pair an older body with newer metadata; a later 304 then treats that stale body as fresh for 24 hours, so get misses newly published components.
Serialize refreshes for each shared index and commit its body and metadata together, so concurrent responses cannot overwrite or mix revisions.
Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs` at line 84:
**Stale indexes stay fresh**
When concurrent refreshes fetch different index revisions, `WriteContent` can overwrite a newer `llms.txt` body or pair an older body with newer metadata; a later 304 then treats that stale body as fresh for 24 hours, so `get` misses newly published components.
Serialize refreshes for each shared index and commit its body and metadata together, so concurrent responses cannot overwrite or mix revisions.| var usedCachedIndex = _useCache && !_refresh && TryReadFreshCache("llms.txt", out index); | ||
| if (!usedCachedIndex) | ||
| { | ||
| index = await GetIndexAsync(ct); |
There was a problem hiding this comment.
🟡 Medium · Concurrent cache update skips retry
When another process writes a fresh index containing no requested component between the initial cache check and GetIndexAsync's cache check, GetIndexAsync can read a newly written cache after the initial check misses, while usedCachedIndex remains false; if that index lacks the requested name, GetComponentAsync skips the automatic refresh and reports the component as not found.
Use the cache result and its provenance from a single lookup, or ensure that a miss on the initial lookup forces the subsequent index fetch to bypass cache.
Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs` at lines 74-77:
**Concurrent cache update skips retry**
When another process writes a fresh index containing no requested component between the initial cache check and `GetIndexAsync`'s cache check, `GetIndexAsync` can read a newly written cache after the initial check misses, while `usedCachedIndex` remains false; if that index lacks the requested name, `GetComponentAsync` skips the automatic refresh and reports the component as not found.
Use the cache result and its provenance from a single lookup, or ensure that a miss on the initial lookup forces the subsequent index fetch to bypass cache.
Link issues
fixes #1272
Summary By Copilot
Regression?
Risk
Verification
Packaging changes reviewed?
☑️ Self Check before Merge
Summary by Sourcery
Automatically retry component lookups against a refreshed index when cached index data is stale.
New Features:
Enhancements:
Build:
Documentation: