@@ -19,9 +19,6 @@ import type { HunkSessionBrokerClient, LiveComment } from "../hunk-session/types
1919import { App } from "./App" ;
2020import { useStartupUpdateNotice } from "./hooks/useStartupUpdateNotice" ;
2121
22- /** Sentinel review key used when no commit cursor is present. */
23- const DEFAULT_REVIEW_KEY = "" ;
24-
2522/** Result returned by `onMoveCommit` so the caller can detect blocked moves. */
2623export type MoveCommitResult =
2724 | { kind : "moved" ; index : number }
@@ -53,9 +50,9 @@ export function AppHost({
5350 // survive the App remount that fires on every commit-cursor move. App's view-state
5451 // reset on commit nav is intentional for selection / scroll / filter (they don't
5552 // translate across commits), but the user's metadata-visibility preference and the
56- // notes they've left should follow them. Live comments are bucketed by commit sha so
57- // each commit keeps its own annotation set; switching back to a previously visited
58- // commit restores its notes.
53+ // notes they've left should follow them. Live comments are bucketed by the active
54+ // changeset's id so each commit (or each non-commit-review canvas) keeps its own
55+ // annotation set; switching back to a previously visited commit restores its notes.
5956 const [ commitDetailsMode , setCommitDetailsMode ] = useState < CommitDetailsMode > (
6057 bootstrap . initialCommitDetailsMode ?? "full" ,
6158 ) ;
@@ -64,31 +61,35 @@ export function AppHost({
6461 current === "full" ? "compact" : current === "compact" ? "hidden" : "full" ,
6562 ) ;
6663 } , [ ] ) ;
67- const [ liveCommentsBySha , setLiveCommentsBySha ] = useState <
64+ const [ liveCommentsByReviewKey , setLiveCommentsByReviewKey ] = useState <
6865 Record < string , Record < string , LiveComment [ ] > >
6966 > ( { } ) ;
70- const currentReviewKey = activeBootstrap . currentCommit ?. sha ?? DEFAULT_REVIEW_KEY ;
67+ // Bucket key is the active changeset's id rather than the commit sha. The producer
68+ // already builds it as `commit:<sha>` for normal commits and `commit:anonymous:N`
69+ // for commits with no parsed sha, so anonymous commits each get their own bucket
70+ // instead of colliding on an empty-string key.
71+ const currentReviewKey = activeBootstrap . changeset . id ;
7172 const liveCommentsByFileId = useMemo < Record < string , LiveComment [ ] > > (
72- ( ) => liveCommentsBySha [ currentReviewKey ] ?? { } ,
73- [ liveCommentsBySha , currentReviewKey ] ,
73+ ( ) => liveCommentsByReviewKey [ currentReviewKey ] ?? { } ,
74+ [ liveCommentsByReviewKey , currentReviewKey ] ,
7475 ) ;
7576 // Updater scoped to the current review's slice. Forwarding an updater here keeps the
7677 // controlled-hook pattern in useReviewController (functional and value setters both
77- // work) while AppHost decides which sha bucket the writes land in.
78+ // work) while AppHost decides which review-key bucket the writes land in.
7879 const setLiveCommentsByFileId = useCallback <
7980 Dispatch < SetStateAction < Record < string , LiveComment [ ] > > >
8081 > (
8182 ( action ) => {
82- setLiveCommentsBySha ( ( bySha ) => {
83- const currentSlice = bySha [ currentReviewKey ] ?? { } ;
83+ setLiveCommentsByReviewKey ( ( byKey ) => {
84+ const currentSlice = byKey [ currentReviewKey ] ?? { } ;
8485 const nextSlice =
8586 typeof action === "function"
8687 ? ( action as ( prev : Record < string , LiveComment [ ] > ) => Record < string , LiveComment [ ] > ) (
8788 currentSlice ,
8889 )
8990 : action ;
90- if ( nextSlice === currentSlice ) return bySha ;
91- return { ...bySha , [ currentReviewKey ] : nextSlice } ;
91+ if ( nextSlice === currentSlice ) return byKey ;
92+ return { ...byKey , [ currentReviewKey ] : nextSlice } ;
9293 } ) ;
9394 } ,
9495 [ currentReviewKey ] ,
@@ -266,9 +267,9 @@ export function AppHost({
266267
267268 setActiveBootstrap ( nextBootstrap ) ;
268269 if ( options ?. resetApp !== false ) {
269- // A full reload is a fresh review canvas — drop any cached per-sha comments
270+ // A full reload is a fresh review canvas — drop any cached per-review comments
270271 // since the file IDs and content no longer correspond to the new bootstrap.
271- setLiveCommentsBySha ( { } ) ;
272+ setLiveCommentsByReviewKey ( { } ) ;
272273 setAppVersion ( ( current ) => current + 1 ) ;
273274 }
274275
0 commit comments