Skip to content

refactor(content): one canonical ContentType normalizer for the MCP and disk cache keys #104

Description

@amondnet

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

  • Exactly one function in the crate produces the canonical content list, and both cache keys derive from it.
  • No two functions named normalize_content with different contracts.
  • Existing tests (cache_keys_on_content, resolve_content_selection_*, the cache.rs key 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 --workspace pass.

Refs

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    status:proposalProposal for discussiontype:refactorCode refactoring without behavior change

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions