feat(exchange): scope pending-exchange cancellation by origin + ladder plumbing (L3) - #1368
Conversation
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 49 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (18)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
…e dry-run (G10 / #1348) RunAutoExchange previously called CancelAllPendingExchanges (store-wide), so the standalone ri_exchange_reshape task would silently cancel pending reshapes created by ladder runs and vice versa. Three sub-goals addressed: 1. SCOPE the cancellation: replace CancelAllPendingExchanges in RunAutoExchange with CancelPendingExchangesByOrigin(ctx, ladderScoped). - ladderScoped=false (standalone): WHERE ladder_run_id IS NULL - ladderScoped=true (ladder): WHERE ladder_run_id IS NOT NULL Keep CancelAllPendingExchanges on the interface for compat. 2. LADDER_RUN_ID plumbing: add LadderRunID *string to ExchangeRecord, RunAutoExchangeParams, and config.RIExchangeRecord; write it in SaveRIExchangeRecord ($21 param) and read it in all SELECT queries / queryRIExchangeRecords Scan; propagate through the adapter converters. The DB column already existed (migration 000080). 3. TRUE DRY-RUN: RunAutoExchangeParams.DryRun=true skips cancellation, SaveRIExchangeRecord, and Execute; returns outcomes tagged Simulated=true. No live approval tokens issued. ReshapeBuffer's DryRun rejection comment updated to reflect that the pkg/exchange layer now supports it (end-to-end wiring deferred to L16). Also: extract nullPtrFromNullString helper in store_postgres.go to reduce queryRIExchangeRecords cyclomatic complexity back below 10; add ExchangeOrigin typed enum (ExchangeOriginStandalone / ExchangeOriginLadder). Tests added: - TestRunAutoExchange_StandaloneDoesNotCancelLadderPendings (regression for G10) - TestRunAutoExchange_LadderDoesNotCancelStandalonePendings - TestRunAutoExchange_DryRun_ManualMode_ZeroMutations (mock.AssertExpectations) - TestRunAutoExchange_DryRun_AutoMode_ZeroMutations - TestRunAutoExchange_LadderRunID_StampedOnRecords (round-trip) - TestRunAutoExchange_NoLadderRunID_RecordHasNilLadderRunID - TestPGXMock_CancelPendingExchangesByOrigin_{Standalone,Ladder} - TestPostgresStore_CancelPendingExchangesByOrigin_NilDB
…m (L3 review) Address Fable FIX-THEN-SHIP findings on the L3 diff: 1. [HIGH] Make ladder-side scoping reachable and honest. Widen the exchangeRunner.RunAutoExchange seam to carry (ladderRunID *string, dryRun bool) as explicit params, add BufferReshapeConfig.LadderRunID, and have ReshapeBuffer forward both. The concrete runner (L16) is now FORCED to thread LadderRunID, so it cannot default to nil and cancel standalone pendings (the G10 bug). Correct the reshape.go comments: standalone scoping is active now; ladder-side scoping activates when the runner is wired (L16). Remove the stale "dry-run not supported" rejection; DryRun is forwarded. 3. [MEDIUM] Replace the bare `ladderScoped bool` with a typed common.ExchangeOrigin enum end-to-end (exchange.RIExchangeStore, config.StoreInterface, PostgresStore, adapter, all mocks). The enum moves to pkg/common (no heavy SDK deps) so internal/config can import it. PostgresStore validates the origin and fails loud on an unknown value. 2. [MEDIUM] Document the deliberate coarse IS NOT NULL partition (cancels all ladder-linked pendings, not per-run) with a TODO(#1367) at the SQL. 4. [MEDIUM] Tighten the pgxmock branch tests to match `ladder_run_id IS NULL` vs `IS NOT NULL` (mutually exclusive regexes) so a branch mix-up fails; add an unknown-origin fail-loud test and a 21-arg SaveRIExchangeRecord INSERT column-alignment test. 5. [LOW] Document the FK ON DELETE SET NULL reclassification (deleting a ladder run makes its still-pending reshape standalone-cancellable) as known/acceptable. 6. [NIT] Touch updated_at in the scoped cancel queries for parity. Verified fail-before/pass-after: swapping the two WHERE clauses fails both TestPGXMock_CancelPendingExchangesByOrigin_{Standalone,Ladder}; correct SQL passes.
5079701 to
5b9a8e5
Compare
|
Rebased onto post-#1362 main (
No semantic conflict: main's Union gates on the rebased head
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
Merged to main after: two Fable review rounds (typed ExchangeOrigin enum, correct-by-construction ladder seam forcing LadderRunID/DryRun through, pgxmock WHERE-clause + 21-arg INSERT alignment tests), CodeRabbit clean, rebase onto post-#1362 main (4 import-union conflicts), and a local union re-verify against post-#1365 main (build/vet/ladder tests all exit 0) since both PRs touched providers/aws/ladder/interfaces.go. Standalone and ladder pending-exchange cancellation are now origin-scoped and cannot cross-cancel; per-run scoping before ladder reshapes create pendings is tracked in #1367 (needed with L16). |
What
Work item L3 of the auto-laddering full-automation plan (closes gap G10 / issue #1348). Prevents the standalone
ri_exchange_reshapetask and ladder runs from silently cancelling each other's pending exchanges, and adds the plumbing the ladder write path needs.Today
RunAutoExchangebegins by cancelling all pending exchanges store-wide. Once laddering creates pending reshapes, the standalone task (its own 6h schedule) would silently cancel a ladder run's awaiting-approval reshapes.Changes
CancelPendingExchangesByOrigin(ctx, origin common.ExchangeOrigin)replaces the store-wide cancel.ExchangeOriginStandalonecancels onlyladder_run_id IS NULLrows;ExchangeOriginLaddercancels onlyIS NOT NULL. The origin is a validated typed enum (pkg/common, fails loud on an unknown value) — not a bare bool.LadderRunIDplumbing: added to the exchange record type and theri_exchange_history.ladder_run_idcolumn is now written/read (INSERT is 21 columns/args, all 5 SELECT/RETURNING + Scan aligned; an alignment regression test guards it). Ladder-originated exchanges are tagged; standalone rows stay NULL.DryRun=trueperforms zero mutations (no cancel, no save, noExecute, no token generation) and returnsSimulated=true.exchangeRunner.RunAutoExchangeis widened to(ctx, cfg, ladderRunID *string, dryRun bool)so the concrete runner (wired in L16) is structurally forced to threadLadderRunID— it cannot compile while defaulting to nil and re-introducing the cross-task-cancel bug.Scope / current state
Standalone-side scoping is active now (a single-source deployment behaves exactly as before). Ladder-side scoping activates when the write path's concrete runner is wired (L16); until then the ladder reshape path returns
errWriteNotWired. TheIS NOT NULLpartition is deliberately coarse (is-ladder, not per-run); a per-run/per-config scoping key is tracked in #1367 for before ladder reshapes create pendings.Verification (exit 0)
go build ./...,go vet ./...clean.pkggo test ./exchange/...100 pass;go test ./internal/server/... ./internal/config/...1010 pass; integration (real PG/pgxmock) 733 pass;providers/awsladder 115 pass;gocyclo -over 10clean.mock.AssertExpectations, no sleeps);LadderRunIDround-trips (nil forwarded as nil, no fabricated value); unknown origin fails loud with no query issued; 21-arg INSERT column alignment.Part of #1336. Tracker #1333. Addresses #1348.