@@ -206,40 +206,41 @@ export const syncAll = internalAction({
206206 return undefined ;
207207 }
208208
209- // Upsert each task
210- const results = await Promise . all (
211- linearIssues . map ( async ( issue ) => {
212- // Try to match assignee by name
213- let assigneeId : Id < "agents" > | undefined = undefined ;
214- if ( issue . assigneeName ) {
215- const matchedAgent = agents . find (
216- ( a : { name : string ; _id : Id < "agents" > } ) => a . name . toLowerCase ( ) === issue . assigneeName ?. toLowerCase ( )
217- ) ;
218- assigneeId = matchedAgent ?. _id ;
219- }
209+ // Upsert each task sequentially to avoid write conflicts on tasks table
210+ // (Promise.all caused ~80 OCC conflicts per sync cycle)
211+ const results : Array < { created : boolean } > = [ ] ;
212+ for ( const issue of linearIssues ) {
213+ // Try to match assignee by name
214+ let assigneeId : Id < "agents" > | undefined = undefined ;
215+ if ( issue . assigneeName ) {
216+ const matchedAgent = agents . find (
217+ ( a : { name : string ; _id : Id < "agents" > } ) => a . name . toLowerCase ( ) === issue . assigneeName ?. toLowerCase ( )
218+ ) ;
219+ assigneeId = matchedAgent ?. _id ;
220+ }
220221
221- // AGT-142: Parse agent from description first, fallback to "max" (PM owns unassigned)
222- const parsedAgent = parseAgentFromDescription ( issue . description ) ;
223- const taskAgentName = parsedAgent ?? "max" ;
224-
225- // AGT-175: Use taskAgentName for activity attribution (not hardcoded "max")
226- return await ctx . runMutation ( api . tasks . upsertByLinearId , {
227- agentName : taskAgentName ,
228- taskAgentName,
229- projectId : evoxProject . _id ,
230- linearId : issue . linearId ,
231- linearIdentifier : issue . linearIdentifier ,
232- linearUrl : issue . linearUrl ,
233- title : issue . title ,
234- description : issue . description ,
235- status : issue . status ,
236- priority : issue . priority ,
237- assignee : assigneeId ,
238- createdAt : issue . createdAt ,
239- updatedAt : issue . updatedAt ,
240- } ) ;
241- } )
242- ) ;
222+ // AGT-142: Parse agent from description first, fallback to "max" (PM owns unassigned)
223+ const parsedAgent = parseAgentFromDescription ( issue . description ) ;
224+ const taskAgentName = parsedAgent ?? "max" ;
225+
226+ // AGT-175: Use taskAgentName for activity attribution (not hardcoded "max")
227+ const result = await ctx . runMutation ( api . tasks . upsertByLinearId , {
228+ agentName : taskAgentName ,
229+ taskAgentName,
230+ projectId : evoxProject . _id ,
231+ linearId : issue . linearId ,
232+ linearIdentifier : issue . linearIdentifier ,
233+ linearUrl : issue . linearUrl ,
234+ title : issue . title ,
235+ description : issue . description ,
236+ status : issue . status ,
237+ priority : issue . priority ,
238+ assignee : assigneeId ,
239+ createdAt : issue . createdAt ,
240+ updatedAt : issue . updatedAt ,
241+ } ) ;
242+ results . push ( result ) ;
243+ }
243244
244245 const created = results . filter ( ( r : { created : boolean } ) => r . created ) . length ;
245246 const updated = results . filter ( ( r : { created : boolean } ) => ! r . created ) . length ;
0 commit comments