Summary
After #99 there are three separate content-list normalizers in crates/csp, two of which share a name while meaning different things:
| Location |
Signature |
What it does |
indexing/index.rs:102 |
pub(crate) fn normalize_content(Option<Vec<ContentType>>) -> Vec<ContentType> |
Substitutes DEFAULT_CONTENT when None. No dedup, no ordering. Used by CspIndex::from_path and cache_orchestrator. |
mcp.rs |
pub fn normalize_content(&[ContentType]) -> Vec<ContentType> |
Canonical form for the MCP session-cache key: dedup + enum (Ord) order via BTreeSet. |
indexing/cache.rs::resolve_cache_dir |
inline |
Sorts as_str() names alphabetically before hashing the on-disk cache key. |
The behaviours are all individually correct today (the on-disk key is order-independent because of the inline sort, and the MCP key is order-independent because of the BTreeSet), but the duplication is a trap: a reader grepping normalize_content finds two functions with different contracts, and a future caller that reaches for the index.rs one expecting dedup gets neither. The cache.rs sort also encodes a third ordering (alphabetical: code, config, docs) that differs from the enum order the MCP key uses, so the same selection renders in two different canonical orders depending on which key you look at.
Noted by the ocr review engine on #99 while validating the BTreeSet change.
Proposed change
- Add one canonical helper on the type, e.g.
ContentType::normalize(&[ContentType]) -> Vec<ContentType> in types.rs (dedup + Ord order, the mcp.rs semantics), and make mcp.rs delegate to it.
- Rename
index.rs::normalize_content to what it does (content_or_default) so the two contracts stop sharing a name.
- Have
resolve_cache_dir build its content key from the canonical helper instead of an ad-hoc alphabetical sort. This changes the hashed payload for any multi-type selection (["code","docs"] is unchanged since it is already alphabetical, but ["code","config"] / ["docs","config"] / all currently hash as ["code","config","docs"]). Bump INDEX_SCHEMA_VERSION or accept one rebuild of those cache entries, and say which in the PR.
Acceptance
Refs
Summary
After #99 there are three separate content-list normalizers in
crates/csp, two of which share a name while meaning different things:indexing/index.rs:102pub(crate) fn normalize_content(Option<Vec<ContentType>>) -> Vec<ContentType>DEFAULT_CONTENTwhenNone. No dedup, no ordering. Used byCspIndex::from_pathandcache_orchestrator.mcp.rspub fn normalize_content(&[ContentType]) -> Vec<ContentType>Ord) order viaBTreeSet.indexing/cache.rs::resolve_cache_diras_str()names alphabetically before hashing the on-disk cache key.The behaviours are all individually correct today (the on-disk key is order-independent because of the inline sort, and the MCP key is order-independent because of the
BTreeSet), but the duplication is a trap: a reader greppingnormalize_contentfinds two functions with different contracts, and a future caller that reaches for theindex.rsone expecting dedup gets neither. Thecache.rssort also encodes a third ordering (alphabetical:code, config, docs) that differs from the enum order the MCP key uses, so the same selection renders in two different canonical orders depending on which key you look at.Noted by the
ocrreview engine on #99 while validating theBTreeSetchange.Proposed change
ContentType::normalize(&[ContentType]) -> Vec<ContentType>intypes.rs(dedup +Ordorder, themcp.rssemantics), and makemcp.rsdelegate to it.index.rs::normalize_contentto what it does (content_or_default) so the two contracts stop sharing a name.resolve_cache_dirbuild itscontentkey from the canonical helper instead of an ad-hoc alphabetical sort. This changes the hashed payload for any multi-type selection (["code","docs"]is unchanged since it is already alphabetical, but["code","config"]/["docs","config"]/allcurrently hash as["code","config","docs"]). BumpINDEX_SCHEMA_VERSIONor accept one rebuild of those cache entries, and say which in the PR.Acceptance
normalize_contentwith different contracts.cache_keys_on_content,resolve_content_selection_*, thecache.rskey tests) pass, plus one test asserting the on-disk key is invariant under input order and duplicates.cargo fmt --all && cargo clippy --all-targets --all-features -- -D warnings && cargo test --workspacepass.Refs
contentparameter to search/find_related (semble#247) #99, parity(#247): add per-callcontentparameter to MCP search/find_related and key the session cache on it #85crates/csp/src/indexing/index.rs:102,crates/csp/src/mcp.rs(normalize_content),crates/csp/src/indexing/cache.rs(resolve_cache_dir)