Make every service function shard-aware, without cutting over shard assignment yet - #125
Conversation
…hard assignment yet (#120) Every service function that used to call resolveWorkspaceContext() bare now resolves its actual target shard via new catalog primitives (resolveShardForParent/resolveShardForRecord), falling back to the default context when untracked. createCollection still assigns shardId: 'default' deliberately — this proves the resolution mechanism correct for a genuinely separate shard (tests manually construct one, same pattern as the holds eviction-wiring fix) without changing where content actually lives yet, so production behavior is unchanged and no client/attach-ws changes are needed in this slice. - catalog.ts: reserveRecordLocator/releaseRecordLocator (row-level, closes the gap where write_record/delete_record/hold_records only ever receive a bare recordId), resolveShardForParent/resolveShardForRecord. - permissions.ts: resolveParentWorkspaceContext/resolveRecordWorkspaceContext/ groupRecordIdsByShard — shared resolution helpers; requireAccessibleRecord is now itself shard-aware, which every existing caller already goes through. - records.ts: createRecord reserves a row locator when its parent is a Collection; writeRecord/deleteRecord/getRecord resolve via the record's own locator. - collections.ts: queryCollection/updateCollectionTitle/deleteCollection resolve the collection's real shard. - holds.ts: hold_records/release_records group recordIds by resolved shard and operate against each shard's own Awareness (a cross-document agent batch is a stated acceptance criterion — see collaboration.md). - search.ts: Collections are enumerated via the catalog first (resolving each one's real shard, including its own meta entry — not just its rows), with a fallback pass over the default doc for uncataloged (direct-Yjs- written) Collections the catalog loop can't see. No MCP tool schema changes needed — every tool already carries enough of an id for server-side shard resolution. 661/661 tests passing (13 new). Refs #120. Branched off feat/workspace-catalog-113-phase-a (PR #119, not yet merged) since this depends on its catalog.ts.
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
agentClocks/agentTtlTimers were keyed only by the synthetic clientId (deterministic per access token, regardless of which shard's Awareness it's operating against). A cross-shard agent hold batch under the same token now legitimately holds on two different Awareness instances at once (#125 made hold_records capable of this) — the second shard's scheduleTtl() call was silently cancelling the first shard's timer via the shared clientId key, so that hold never auto-expired. Both maps are now Map<Awareness, Map<number, T>>, with get-or-create helpers threaded through writeRemoteState/scheduleTtl/clearTtl. 635/635 tests passing (2 new, proving independent TTL expiry across two Awareness instances under the same clientId). Refs #120
…re-service-resolution-120 # Conflicts: # src/lib/server/catalog.test.ts # src/lib/server/db/schema.ts
Summary
Stacks on #119 (Phase A catalog) — base branch is
feat/workspace-catalog-113-phase-a, notmain, so this diff only shows what's new here. Merge #119 first, then retarget/merge this one.Every service function that used to call
resolveWorkspaceContext()bare now resolves its actual target shard via new catalog primitives, falling back to the default context when untracked.createCollectionstill deliberately assignsshardId: 'default'— this PR proves the resolution mechanism correct for a genuinely separate shard (tests manually construct one, the same pattern as the holds eviction-wiring fix in #124) without changing where content actually lives yet. Production behavior is unchanged; no client orattach-ws.tschanges are needed in this slice, since the browser's live sync path is never affected.catalog.ts:reserveRecordLocator/releaseRecordLocator(row-level — closes the gap wherewrite_record/delete_record/hold_recordsonly ever receive a barerecordId, no parent hint),resolveShardForParent/resolveShardForRecord.permissions.ts:resolveParentWorkspaceContext/resolveRecordWorkspaceContext/groupRecordIdsByShard— shared resolution helpers.requireAccessibleRecordis now itself shard-aware, which every existing caller already goes through.records.ts:createRecordreserves a row locator when its parent is a Collection;writeRecord/deleteRecord/getRecordresolve via the record's own locator.collections.ts:queryCollection/updateCollectionTitle/deleteCollectionresolve the collection's real shard.holds.ts:hold_records/release_recordsgrouprecordIdsby resolved shard and operate against each shard's own Awareness (a cross-document agent batch is a stated acceptance criterion — seecollaboration.md).search.ts: Collections are enumerated via the catalog first (resolving each one's real shard, including its own meta entry — not just its rows), with a fallback pass over the default doc for uncataloged (direct-Yjs-written) Collections the catalog loop can't see.No MCP tool schema changes — every tool already carries enough of an id for server-side shard resolution.
Test plan
npm run test— 661/661 passing (13 new)npm run lint/npm run check— cleancreateCollection's always-'default'behavior) and assertqueryCollection,createRecord,writeRecord,getRecord,deleteRecord,holdRecords/releaseRecords, andsearchWorkspaceall correctly reach into that shard rather than the default docRefs #120 (not closing — the shard-assignment cutover itself and Document sharding remain)
🤖 Generated with Claude Code