learning_ai_notes/docs/COSMOS_QUERY_REVIEW.md

3.7 KiB

Cosmos Query Review

Date: 2026-05-05

This review covers current NoteLett repository access patterns against the Cosmos container registrations in backend/src/lib/cosmos-init.ts. All documents retain productId: "notelett" and all list routes include product/user/workspace scope filters before returning user data.

Container Partitions

Container Partition key Primary access pattern
notes, note_relationships, note_tasks, note_artifacts, note_agent_actions, note_shares, note_versions /workspaceId Workspace-scoped note surfaces and agent write audit trail
workspaces, saved_views, note_prompts, note_prompt_schedules, note_prompt_webhooks, note_intake_rules, note_intake_jobs /userId User-owned configuration, templates, and intake state
note_collaborators /sharedWithUserId Shared-with-me lookup; owner-side collaborator listing is note-scoped
palace_* /userId Per-user memory palace data and maintenance operations

Cross-Partition Or Count-Heavy Operations

Operation Why it can cross partitions Guardrails
notes.listNotes() without workspaceId notes is partitioned by /workspaceId, but dashboard/search surfaces can list across a user's workspaces. Always filters by userId and productId; paginated to caller limit. Workspace-specific calls include workspaceId.
note_agent_actions.listPendingActions() Pending review queue intentionally spans workspaces in the /workspaceId container. Filters by userId, productId, and state; performs two count queries plus two bounded reads.
note_shares.findShareByToken() Public share-token resolution starts from token/product instead of workspace. Filters by shareToken and productId, returns one record, and rejects expired shares before public note lookup revalidates note/user/product scope.
note_collaborators.listCollaboratorsForNote() The container is optimized for /sharedWithUserId; owner-side note collaborator listing starts from noteId. Filters by noteId and productId, limits to 100; route verifies the caller can access the note before listing.
palace search/maintenance scans Palace data is /userId partitioned, but some relevance, duplicate, KG, and maintenance jobs scan hundreds to thousands of user memories/triples. All scans include userId and productId; limits are explicit (500, 1000, or 5000) and remain single-user partition reads.
palace.getPalaceStats() Counts six Palace containers for a user. Counts are all scoped by userId and productId; suitable for diagnostics/dashboard use.
Prompt template builtin merge User templates and builtins live in separate /userId partitions. User partition and __builtin__ partition are queried separately, then merged in memory with limit bounds.

Regression Coverage

backend/src/modules/repository-scope.test.ts verifies scope isolation for:

  • Notes list and workspace counts across user, product, and workspace boundaries.
  • Agent action workspace lists and cross-workspace pending queues across user and product boundaries.
  • Share token, share list, note collaborator, and shared-with-me lookups across product, user, note, and workspace filters.

Follow-Up Notes

  • If dashboard global note search becomes high traffic, prefer a user-partitioned materialized search/index container or a dedicated search service over broad /workspaceId fan-out.
  • If pending review volume grows, consider a user-partitioned projection for draft/proposed agent actions to avoid two cross-workspace counts per queue load.
  • Public share tokens should remain high-entropy and globally unique; token lookup is intentionally cross-partition but bounded to one item.