# 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.