Repository navigation
test(plans): prove legacy writers recheck plans an editor Save changed - #1014
Conversation
|
Warning Review limit reached
This review includes 6 billable files and costs up to $1.50.
Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing. Or wait 29 minutes for your next included review. View limit details
Comment |
62f0cce to
aeb8700
Compare
418d4a9 to
bcf1d87
Compare
cristim
left a comment
There was a problem hiding this comment.
Independent review of 418d4a9: no actionable findings
This review covers the pre-rebase SHA 418d4a9. The merge driver will record the range-diff to the new head (bcf1d87). I ran git range-diff on the PR's own commit: it shows = (identical patch).
Findings: none blocking. NON-BLOCKING: awaitLockWait in the add-accounts tests matches any lock wait (pattern ""), whereas the new tests use statement-specific patterns. It is weaker but sound with one writer.
What I attacked:
- Interleaving is real: each test holds the footprint transaction, starts the writer in a goroutine, and blocks in WaitForLockWait on pg_stat_activity (wait_event_type = 'Lock', statement LIKE) before the command writes and commits. The writer therefore read its stale state before the commit. Await fails fast at 30s.
- Mutation probe 1: notifier judges the listed plan copy (
locked = planin claimPlanStep): TestClaimSkipsPlanTheCommandConvertedWhileItWaited FAILS ("Should be false"). Reverted. - Mutation probe 2: dropped
AND retry_execution_id IS NULLfrom the retry link CAS: TestRetryLosesToCommandThatLinkedOriginalFirst FAILS (409 not returned). Reverted. Worktree is clean. - Ran integration tests (testcontainers) on api, config and purchase with -run Race|Waits|Queues|Recheck|Claim|Retry: 290 passed, 0 failed.
- known_issues/35_legacy_guard_followups.md follows CONTRIBUTING.md "Known Issues Sweep":
# Known Issues: ...heading, audit-status line (2 needs triage, 0 resolved, matches the two entries),## SEVERITY:sections with Files, Description, Why deferred, Status, and the issue refs #998 and #999. - Production code: none changed; the only non-test file is the testhelpers helper, which documents the swap contract.
Gate: independent review of this SHA (this comment). CI not applicable until retarget. CodeRabbit not used (owner decision). Local verification as above. Labels mirror the stack. 354 additions-only diff under the cap.
|
The independent review above covers 418d4a9. claude-cc-631-driver rebased the stack onto main 0a5f790 (includes #1003). The PR's own commits are unchanged, so the verdict carries to bcf1d87 (owner #631 rule). |
aeb8700 to
7e7d99b
Compare
bcf1d87 to
16dba67
Compare
|
The independent review above covers bcf1d87. Rebased onto main after #1010 merged (0117179); #1011 retargeted to main. The PR's own commits are unchanged, so the verdict carries to 16dba67 (owner #631 rule). |
7e7d99b to
832a2e5
Compare
16dba67 to
ea61b6a
Compare
|
The independent review above covers 16dba67. Rebased onto main after #1011 merged (173474e); #1012 retargeted to main. The PR's own commits are unchanged, so the verdict carries to ea61b6a (owner #631 rule). |
832a2e5 to
8aa0ce7
Compare
ea61b6a to
dc8a4e8
Compare
|
The independent review above covers ea61b6a. Rebased onto main after #1012 merged; #1013 retargeted to main. The PR's own commits are unchanged, so the verdict carries to dc8a4e8 (owner #631 rule). |
Add race tests for the legacy writers that can run while an editor Save holds the plan: the notifier's new schedule root, a retry successor, a fan-out child, execution pruning and cloud account deletion. Each test queues the writer behind a stand-in for the Save's lock footprint, then checks the outcome in both orders: a writer that waited sees the committed editor state and skips or refuses, and a writer that won is seen by the next capture. The shared footprint and lock-wait helpers move to testhelpers so the Save command's own race tests can swap in the real command. Two pre-existing gaps are recorded in known_issues (#998, #999). Refs #631 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dc8a4e8 to
3e1c4eb
Compare
|
The independent review above covers dc8a4e8. Rebased onto main after #1013 merged (d7eb3b0); #1014 retargeted to main. The PR's own commits are unchanged, so the verdict carries to 3e1c4eb (owner #631 rule). |
|
Gate record for 3e1c4eb (origin/main CLAUDE.md "Review gate"):
Merging at 3e1c4eb with --match-head-commit. This completes the #631 legacy-writer guard stack (#1010-#1014). |
…1798) * fix(purchase): record fan-out accounts skipped before they started When a per-account fan-out run had a committed account and its context ended before other accounts started, the run was acked as a partial success (#1014), but the never-started accounts had no row. Nothing retried them and nothing recorded the skip, so their purchases silently never happened. Each such account now gets its own failed row, with the stable per-account idempotency key, its own recommendations, NoSubmission set and an error saying nothing was submitted, so the existing retry can re-run it. The rows are saved on a context detached from the ended run. Only the acked partial path writes them: a flat failure is redelivered and re-runs those accounts, where a failed row would invite a second, undeduped retry. Closes #1672 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(purchase): word a skipped account by whether Retry accepts it Retry refuses EC2, Redshift and Azure savings-plan rows whatever NoSubmission says, so the skip row no longer promises a retry for them; it points at starting a new purchase. Both notes are allowlisted so History shows them instead of the generic provider error, and the run-context error moves to the log. Comments on the flat-failure path are corrected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(purchase): save account and skipped rows on live contexts A started account's terminal row (credential, pin, processing-error and final saves) now uses a detached, bounded context, so a run context that ended mid-account still leaves its History row and Retry. Skipped-account rows are built by the fan-out but saved by executeAndFinalize after the root, on the root's single terminal-save deadline, with one batched failure email inside the notify window. Rows past the deadline are logged as AUDIT LOSS. The 270s budget is unchanged. Part of #1672 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(purchase): anchor account row saves on the run deadline Account rows save on a context detached from the run, with a deadline of the run deadline plus half the terminal-save budget, and the root save ends at the run deadline plus the full budget, so accounts in flight when the run ends cannot starve the root. A row that misses its slice is logged as AUDIT LOSS with the account and execution IDs. Part of #1672 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(purchase): batch late account failures into one outcome-unknown email An account that finishes after the run context ended sends no email of its own; its row joins the skipped accounts in the single email sent after the root save, so the worst case stays inside the 270s run budget. A provider call cut off by the run context is wrapped with ErrOutcomeUnknown, and the batched email uses the outcome-unknown wording when any late row carries it. Part of #1672 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * test(purchase): fit the root-save deadline test and lint to the anchored budgets The root save now ends at the run deadline plus the save budget, so the expired-caller test expects the long remaining window. Also fixes two prealloc findings and a misspelling in the new tests. Part of #1672 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(purchase): bound a fan-out account failure email by the account slice An account that failed just before the run deadline sent its own email on a fresh 30s window, keeping the fan-out busy past the root save slice. The email now shares the account slice (run deadline plus half the save budget). Part of #1672 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Add race tests for the legacy writers that can run while an editor Save
holds the plan: the notifier's new schedule root, a retry successor, a
fan-out child, execution pruning and cloud account deletion. Each test
queues the writer behind a stand-in for the Save's lock footprint, then
checks the outcome in both orders: a writer that waited sees the
committed editor state and skips or refuses, and a writer that won is
seen by the next capture. The shared footprint and lock-wait helpers
move to testhelpers so the Save command's own race tests can swap in
the real command. Two pre-existing gaps are recorded in known_issues
(#998, #999).
Refs #631
Part 5 of 5 of the #631 legacy-writer guards; stacked on #1013; merge bottom first.
Review verdict and evidence
Original review, copied from the per-commit evidence record. Commit fd41ebf3 was reviewed before the rebase onto origin/main; the rebased commit is bcf1d87.
Rebase: the five commits were rebased onto origin/main 0ed85aa (27 commits ahead of the old base).
git range-diffof the old 5 commits against the rebased 5 shows all five as=(identical patches), so the verdict carries over per the owner's rule. New head SHA of this PR: bcf1d87. No migration is added by any of the five commits.Review gate
CodeRabbit is not used on this stack (quota; owner decision): the gate is the independent adversarial review above plus the local verification below.
Local verification
Local verification of the rebased stack tip (macOS, Docker Postgres via testcontainers; Linux via CI):
Status on main
The change is dormant on main until the editor Save route ships: only plans marked managed (ramp_schedule.dates_managed) are affected, and only that route sets the marker.
🤖 Generated with Claude Code