Repository navigation
Cloud: a hold answered on the phone is known from the feed push, not a poll (#32354) - #32368
Conversation
…not fail the create (#32354) Red first: answered on the phone, then yes in the Mac sheet before the next watch check. The approved op still reads pending, its feed item is closed, so the answer finds no open item and the create fails with the closed-item mismatch. A hold of another team must still fail.
…h, not a poll (#32354) The person answers a Cloud create's approval hold on the phone; the approve item in their FeedDO closes in that commit, and the owner pushes the event to the Mac's feed mirror at once. The feed decode dropped the item's approval reference, so the create flow could not use it and waited for its same-key watch (1 to 8 s). A yes in the sheet before that check answered the hold again and failed with the closed-item mismatch. - CmuxNextFeed keeps the approve action's hold ({request, team}) and FeedItem.cloudHoldRequest reads it only for the team's Cloud owner's cloud item. - CloudApprovalHolds (CmuxNextCloud) records each closed hold from the feed mirror; CloudApprovalSheet (moved out of the App flow) ends the sheet on the push, the click or the watch, whichever comes first, and reads a yes against the hold's state. - CloudApprovalAnswer: when no open item carries the request, the same team's closed item means answered elsewhere (.answered); another team's item still fails with the mismatch. App lines: +24 -34.
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Default changesThis pull request changes 2 defaults at
Signed off on this commit by Merge receipt: merged as Regenerate the snapshot with Shipped in:
|
|
Review (claude review subagent): SHIP at eb85e7e I read the code only. I did not compile or run tests. eb85e7e is 6e02d93 plus What I checked:
Non-blocking notes:
|
…doc comments name the answered case
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Review (claude review subagent): SHIP at fd6359c My earlier review at eb85e7e still holds. I read only the change from eb85e7e to fd6359c. I did not compile or run tests.
The non-blocking notes in my earlier comment still apply: a closed item counts as answered whatever its close reason, and |
…race # Conflicts: # Packages/macOS/CmuxNext/Sources/CmuxNextApp/Cloud/CloudMachineCreateFlow.swift # Packages/macOS/CmuxNext/Sources/CmuxNextApp/Cloud/CloudService+AppServer.swift
…closed item mean answered; another team's still fails (#32354) After merging #32270 (no sheet for a person's create; every closed-item mismatch went to the same-key retries): - CloudApprovalAnswer answers .answered(request) for this team's closed item and for a hold the feed push already shows answered (no lookup, no answer); another team's item stays the closed-item mismatch. - The flow's answered-elsewhere path takes only .answered, so a true team mismatch fails at once again instead of retrying into stillPending. - alreadyAnswered/answeredElsewhere move to CloudApprovalAnswer.Failure (CmuxNextDaemonService); CloudApprovalSheet goes (no sheet to race).
…c closure default)
…'s own team (review on #32368) CloudApprovalHolds keeps each closed hold's team, FeedItem.cloudHold carries it, and CloudApprovalAnswer's feed predicate takes the create's team: another team's closed hold on the phone still ends in the closed-item mismatch. Test: anotherTeamsHoldTheFeedShowsAnsweredStillFailsAtOnce.
|
Review (claude review subagent): SHIP at 4cca854 I read the whole PR at this head, which merges feat and keeps #32270's flow with no create sheet. I also read the fix commit since ce2f694. I did not compile or run tests.
Non-blocking: |
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
Fixes #32354. Follow-up to #32271, #32300, #32336 and #32270.
Cause
The person answers a Cloud create's approval hold on the phone. The backend closes the approve item in the person's
FeedDOin that commit, and the feed owner pushes the event to the Mac's feed mirror at once. ButFeedWireDecodedropped the item'saction.input.approval, so the Mac could not link the closed item to its create. When this Mac then answered the hold, the approved op still read pending, no open item carried the request, and the reply was.mismatch(reason: "feed item or team"). That reply also means "this item belongs to another team".#32270 (landed while this PR was open) removed the sheet for a person's create, and now sends every closed-item mismatch to the same-key retries. That keeps the phone case going, but it also excuses a true team mismatch: such a create retries into
stillPendinginstead of failing with the mismatch. The issue asked for exactly that difference.Fix (Mac only, no server change)
Approve.Action.hold: request, team).FeedItem.cloudHoldRequestreads it only for a cloud item that its team's Cloud owner (system:cloud:<team>) posted, which is the backend'sapprovalOfrule.CloudApprovalHoldsrecords every closed Cloud hold (request and team) that the feed mirror sees (snapshot and events,FeedService.observe). The push is how the Mac learns of the phone's answer: no poll and no timer.CloudApprovalAnswer(CmuxNextDaemonService):.answered(request:)when the feed already shows the create's own team's item for the request closed (no lookup, no answer). Another team's closed hold on the feed counts for nothing here, so the normal checks run..answeredwhen no open item carries the request but this team's closed item does (same op, digest, team, poster scope). This covers an answer that comes before the push..mismatch(reason: "feed item or team")..answeredto cmux NEXT Cloud: a person's own Cloud send creates the machine with no second approval prompt #32270's answered-elsewhere path (same-key retries, nothing recorded). A true team mismatch fails at once again. The two judgments (alreadyAnswered,answeredElsewhere) moved fromCloudMachineCreateFlowtoCloudApprovalAnswer.Failure.App lines: -12 (
arch-ratchet.py --base <merge-base> --head HEAD).Tests
CloudApprovalHoldRaceTests(no sleeps; it drives the realCloudApprovalAnswerover a fake session backend):aHoldAnsweredOnThePhoneFirstGoesOnWithTheOpsAnswer: the create goes on with the op's answer, answers nothing, and records nothing.aHoldOfAnotherTeamFailsAtOnce(answered or not): the create fails with the mismatch. On feat it retries intostillPending: this is the red.aHoldTheFeedShowsAnsweredIsNotAskedAboutAgain: after the push, no session call is made.anotherTeamsHoldTheFeedShowsAnsweredStillFailsAtOnce: the feed shows team_b's hold answered, and the create is team_a's. The create still fails with the mismatch, after the normal lookup (review finding at ce2f694).theFeedKeepsTheCloudHoldOfItsOwnTeamsItemOnly: the decode and the poster-scope rule.CloudPersonCreateApprovalTests(#32270): its answered-elsewhere fixture now throws.answered, which is whatCloudApprovalAnswerreturns for that case.CloudCreateRetryKeyTests: it now calls the moved judgments and has two new cases (this team's closed item versus another team's).Command:
cmux-ci run --class light --script scripts/ci/package-test-lane.sh --ref SHA --arg=suite --arg=Packages/macOS/CmuxNext --arg=SUITEScloud-hold-race-red2(f28f673 = the feat merge base 2f1caeb plus the two tests that compile on feat): job 77b23e7ba2106602adbcd526 failed as expected.aHoldOfAnotherTeamFailsAtOncegets the wrong error (stillPending) when the hold is not answered, and no error at all when it is answered on the phone.aHoldAnsweredOnThePhoneFirstGoesOnWithTheOpsAnswerpasses on feat.cloud-hold-race-red3(9b8753c = ce2f694 plus the new test, written against the old API), job 5e3c32a2cd7decf27a48df85.anotherTeamsHoldTheFeedShowsAnsweredStillFailsAtOncefails: no error is thrown, and sessionCalls is 0.prepush-gate.py: no new violations. Arch ratchet: app_lines -12.Observed / Not run
Changelog
No capture: there is no UI change.