feat(google): queue group binding reconciliation - #133
Conversation
BK1031
commented
Sep 10, 2026
- Persist Google group binding mutations as pending operations before accepting them
- Return 202 responses with prefixed operation IDs while reconciliation runs in the background
- Resume and retry pending sync operations across process restarts
- Surface pending status and sync failures through the binding API and web client
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 271d398005
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if exists && binding.TargetGoogleGroupID != "" && group.Id != binding.TargetGoogleGroupID { | ||
| return ErrGoogleGroupStateChanged |
There was a problem hiding this comment.
Reject groups that appear after preflight
When preflight found the requested address unused, TargetGoogleGroupID is persisted as empty. If another administrator creates a Workspace group at that address before the queued sweep runs, exists is true and this condition does not reject it, so reconciliation proceeds without the overwrite confirmation and may delete that unrelated group's MEMBERs. Treat an existing group with an empty recorded target ID as a state change, while separately handling recovery after this operation's own creation.
Useful? React with 👍 / 👎.
| if !exists { | ||
| if binding.TargetGoogleGroupID != "" { | ||
| return ErrGoogleGroupStateChanged |
There was a problem hiding this comment.
Make state-changed operations recoverable
If a target that existed during preflight is deleted or renamed before reconciliation, this branch returns a permanent state-change error. ReconcileAll only records that error while leaving the row pending, every later sweep repeats the same failure, and QueueGoogleBinding rejects every edit or deletion of pending bindings. The binding therefore becomes permanently locked through the API; transition it to a recoverable failed/previous state or otherwise allow an administrator to supersede the operation.
Useful? React with 👍 / 👎.
| toast.success( | ||
| preflight?.binding_changed | ||
| ? "Group updated. Google sync started." | ||
| : "Group updated", | ||
| ) |
There was a problem hiding this comment.
Surface asynchronous sync failures in the UI
When the worker fails after the PUT has returned 202—for example because a member operation fails or the Google group changes—this path still shows a success toast and navigates away. Although the client type now includes status and last_sync_error, the inspected GoogleSyncCard receives only the email and syncing flag, and there is no polling or rendering of either field, so administrators cannot tell that the requested binding or deletion never completed. Display and refresh the persisted operation status/error rather than treating acceptance as the end of the user-visible flow.
Useful? React with 👍 / 👎.