fix(collab): stamp imported replays with the source's activity time - #655
Open
Harry19081 wants to merge 1 commit into
Open
fix(collab): stamp imported replays with the source's activity time#655Harry19081 wants to merge 1 commit into
Harry19081 wants to merge 1 commit into
Conversation
Clicking a cloud-org card in Kanban imports a local replay copy of the teammate's session, and the board then re-derives the card from that local row instead of the cloud row. The copy was stamped with the import moment, so Started / Last updated jumped to the click, the card read "Now", the row jumped to the top of List/Diary, and an old session was pulled back out of the auto-archived column. The copy now adopts the owner's `lastActivityAt` — the same value the pre-click cloud card renders — falling back to the import moment only for rows that carry none. `importedFrom.importedAt` still records now. `upsertSession` pins timestamps by policy, which meant an already- imported copy could never be corrected. Adds `applyImportedSessionTimestamps`, a fourth documented path in that policy, guarded to rows carrying `importedFrom`, so an imported mirror tracks its source while locally-owned sessions stay pinned. Reopening a previously-clicked card heals it in place. Pre-commit hook ran. Total eslint: 0, total circular: 0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Opening a cloud-org session from the Kanban board rewrote its Started and Last updated times to the moment of the click. The imported replay copy now carries the owner's activity time instead of the import moment, and copies already stamped with a click time heal on their next open.
Problem
Clicking a cloud-org card doesn't only open it —
replaySession→importRemoteSessionwrites a local imported copy of the teammate's session. The cloud row is then deduped out of the board (buildCloudRemoteKanbanProjectionskips rows that match a visible imported copy) and the card is re-derived from that local row.That local row was stamped with the import moment:
So before the click the card rendered the owner's
lastActivityAt; after the click it rendered the click. Visible fallout:Now, List shows Started / Last updated = the clickupdated_atWorse, it was permanent.
upsertSessiondeliberately pinscreated_at/updated_aton its update path (timestamp policy: a local reconcile must not make a multi-day-old session surface in the 6h window), so nothing — not a later delta import, not a reopen — could ever correct a copy once stamped.Solution
collabSessionImport.ts— the replay copy adopts the source's clock:readSourceActivityAt()takesremoteSession.lastActivityAt, the same value the pre-click cloud card renders. Cloud metadata carries no creation timestamp, so it feedscreated_at/updated_at/completed_atalike, exactly ascloudRemoteToKanbanTaskalready does. Falls back to the import moment only for rows carrying no activity time.resolveImportedCreatedAt()keeps the earlier of the existing and source times — a session cannot have been created after its own last activity, and the clamp heals rows stamped by the old behavior.importedFrom.importedAtstill recordsnow; that one really is about this device.mutations.ts— addsapplyImportedSessionTimestamps, a fourth documented path in the file's timestamp policy and the only mutation that writes someone else's clock. Guarded to rows carryingimportedFrom: an imported mirror tracks its source, locally-owned sessions stay pinned.Potential risks
getEffectiveAccessModeresolves to OFF for sessions created beforeshareSince. Moving an imported copy'screated_atearlier can only make that gate more restrictive, never less. Imported rows are excluded from push regardless (org2CloudSessionSync.metadata.tsreturns!session.importedFrom).prefersRightincanonicalSessionKey.tsresolves collaboration-replay rows beforeupdated_atis consulted, so lowering their timestamp cannot flip which copy survives.importedFromguard and covered by a test asserting a locally-owned row stays pinned.lastActivityAtis the owner's last activity, not their session's start. Until cloud metadata carries a creation timestamp,created_aton a fresh import is an approximation — the same one the cloud card already displays.Validation
npx tsc --noEmitclean; eslint clean on changed filesTeamCollaboration,Org2Cloud,TaskKanban,store/sessioncollabSyncEngineHelpers.test.ts: source-activity stamping on a fresh import, the no-lastActivityAtfallback, healing on a cursor-current reopen, and not regressing a genuinely-earliercreated_atmutations.test.ts: the override lands on an imported copy, a locally-owned row stays pinned, and a no-op returns the identical arrayRemaining
Not verified end-to-end against a live cloud org — that needs two instances. Per
.orgii/skills/dual-instance-verification, a 双机实测 pass is the gate before calling a sharing/sync change verified: