Part of #2195.
Problem
Inside updateApiObjectsNoChild (src/components/Board/Board.actions.js:1000-1046), after createApiBoard succeeds and the local communicator has been mutated via replaceBoardCommunicator / replaceDefaultHomeBoardIfIsNescesary / upsertCommunicator, the cascade calls upsertApiCommunicator(comm) to persist the communicator to the server.
If that call fails:
- The newly created board has
syncMeta = SYNCED (set by CREATE_API_BOARD_SUCCESS).
- The local communicator already references the new board ID.
- The server-side communicator still references the old (local) board ID — or doesn't reference the board at all.
updateApiMarkedBoards() (the next step in the cascade) never runs.
The sync engine has no mechanism to retry the communicator push, because syncMeta only tracks boards, not communicators. The only recovery is an unrelated future create that runs the cascade again and happens to call upsertApiCommunicator for the same communicator.
Impact
- Other devices / sessions logged into the same account won't see the new board in the user's communicator until a future create accidentally pushes it.
- Cross-device drift, not detectable from the UI.
Proposed direction
- Track communicator dirtiness alongside
syncMeta (e.g. state.communicator.syncMeta[id]) or a simple pendingCommunicatorIds set.
- Mark the communicator PENDING when any local mutation happens.
- Add a dedicated step at the end of PUSH (Phase 2) that drains pending communicator pushes with retries.
- Stop calling
upsertApiCommunicator from inside updateApiObjectsNoChild — instead, mark and let the dedicated step handle it.
Acceptance criteria
- A simulated failure of
upsertApiCommunicator during a board create leaves the communicator in a PENDING state.
- The next
syncBoards() cycle retries the communicator push, regardless of whether any board needs to be created.
- Recovery requires no other create to happen.
Part of #2195.
Problem
Inside
updateApiObjectsNoChild(src/components/Board/Board.actions.js:1000-1046), aftercreateApiBoardsucceeds and the local communicator has been mutated viareplaceBoardCommunicator/replaceDefaultHomeBoardIfIsNescesary/upsertCommunicator, the cascade callsupsertApiCommunicator(comm)to persist the communicator to the server.If that call fails:
syncMeta = SYNCED(set byCREATE_API_BOARD_SUCCESS).updateApiMarkedBoards()(the next step in the cascade) never runs.The sync engine has no mechanism to retry the communicator push, because
syncMetaonly tracks boards, not communicators. The only recovery is an unrelated future create that runs the cascade again and happens to callupsertApiCommunicatorfor the same communicator.Impact
Proposed direction
syncMeta(e.g.state.communicator.syncMeta[id]) or a simplependingCommunicatorIdsset.upsertApiCommunicatorfrom insideupdateApiObjectsNoChild— instead, mark and let the dedicated step handle it.Acceptance criteria
upsertApiCommunicatorduring a board create leaves the communicator in aPENDINGstate.syncBoards()cycle retries the communicator push, regardless of whether any board needs to be created.