Repository navigation
feat(purchase): make notified real and pin the scheduler claim to the gated snapshot - #827
Conversation
… gated snapshot Refs #631 (PR2b-2a). Nothing attaches recommendations to plan steps yet. - RotatePendingApprovalToken now also promotes pending to notified in the same statement, so the status only changes after the notification email went out; a failed send leaves the row pending and the scheduler refuses it. - claimAndExecute claims with TransitionExecutionStatusPinned, which requires the row's recommendations to still be empty (or non-empty) as the gate saw them. A lost pin is a benign skip on the cron and SQS paths. - A claimed pending/notified row re-runs CheckStepCommitmentCap against the current plan and fails with the beforeSubmission class so suppressions release; approved and web rows are unchanged. - planstep.Precheck / checkStoredSPCount fail closed on Include*/Exclude*/ MinCount filters, an immediate ramp with percent_per_step != 100 and a Savings Plans stored row with count != 1; Resolve calls them first. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Gate verdict: APPROVE (money path, scheduler auto-purchase)Reviewed SHA: Checks
Local evidenceRun from
Fails-before (fix reverted, tests kept):
The gate ran no mutation sweep. The author's capped run (17 mutants) stands per the owner policy. Non-blocking follow-ups (must be closed before PR2b-2b turns attach on)Rows now become
The email Cancel link and session cancel still accept Size: about 190 production lines including the mock. Everything above 400 lines is tests. CI: 26/26 checks pass at |
Refs #631 (PR2b-2a of the plan-step attach work; PR2b-2b does the wiring and must not merge before this).
What this does
notifiedbecomes real.RotatePendingApprovalTokennow setsstatus = 'notified'in the same UPDATE that stores the token hash, and it still runs only after the email succeeds. A failed send leaves the rowpending, and the feat(purchase): per-plan step commitment cap, auto-purchase kill switch and notified veto #825 gate refuses a rec-bearingpendingrow.TransitionExecutionStatusPinnedaddsAND (recommendations IN ('[]','null')) = $gateSawEmptyto the claim CAS.claimAndExecute(cronprocessOneExecutionand the SQShandleExecutePurchase) passes what the gate saw; a lost pin is a benign skip and the next tick gates again. For pending/notified rows it then re-runsCheckStepCommitmentCapagainst the freshly read plan and fails the claimed row withbeforeSubmission, so suppressions release. Approved, web-token and direct purchases are unchanged (tested).planstep.Precheckrefuses any Include*/Exclude*/MinCount on a ServiceConfig and an immediate ramp withpercent_per_step != 100;checkStoredSPCountrefuses an SP stored row withCount != 1.Resolvecalls both first.PurchasePlan.Validateis deliberately NOT changed: rejecting those plans at save time would break saving existing plans that never attach anything, and the attach path is the only caller that needs the refusal (PR2b-2b). One existing SP fixture used a stored count of 3 and was changed to 1.What is NOT wired
Nothing attaches recommendations to a plan step.
planstep.Resolvestill has no scheduler caller;getOrCreateExecutionstill fails rec-less steps; no schedule, email content or UI message changes. The only behavior change on today's data: a notified plan row is nownotifiedinstead of stayingpendingafter its email.Current state
Kill switch
auto_purchase_enabledstays default OFF andmax_step_commitmentstays NULL, so the scheduler still refuses every rec-bearing row. Nothing to flip.Evidence
-tags integration, Docker helper temporarily overridden and reverted before commit): pinned CAS and the notified transition at the store level; manager-level notified transition; a real attach injected between gate and claim leaves the rownotifiedwith its recommendations.MinCountboundary) got assertions and now fail.Not run: macOS real-account verification (no attach exists to exercise); no real DB or cloud was touched.
🤖 Generated with Claude Code
Summary by CodeRabbit