Skip to content

fix(purchase): refuse two identical Redshift recs in one execution - #1895

Merged
cristim merged 1 commit into
mainfrom
fix/redshift-duplicate-tuple-refusal
Nov 9, 2026
Merged

cristim merged 1 commit into
mainfrom
fix/redshift-duplicate-tuple-refusal

Conversation

@cristim

@cristim cristim commented Nov 9, 2026

Copy link
Copy Markdown
Member

Summary

One execution that selects two Redshift recs with an identical tuple (region, node type, term, payment, count) and account bought one node: the go client adopts the node found for the same offering and count, so the second call reported success and bought nothing. preExecutionRefusal now refuses such a selection before submission (no_submission) with a fixed, allowlisted text (redshiftDuplicateTupleRefusal). Count 1+1 versus a single count 2, different accounts, unselected recs and non-Redshift twins are not duplicates. A rec with no account of its own uses the execution account.

Closes #1809

Verification

  • New tests in redshift_duplicate_tuple_test.go plus both sanitizer allowlist tests; go test ./internal/purchase/ passes, golangci-lint 0 issues (none new vs base).
  • Mutation probes (drop the call, drop the account from the key, drop the Selected filter, drop the account fallback, drop the allowlist entry, drop the beforeSubmission wrapper) each fail a test.
  • Two adversarial review passes by one cold reviewer: no actionable findings. Every entry to the Redshift dispatch (approve, scheduled fire, reaper, re-drive) runs the check before any provider call.
  • known_issues/39_redshift_dedupe_window.md updated.

A legacy parked plan row that already holds duplicates will now fail with no_submission; its plan then stalls like any other before-submission refusal (#1785).

🤖 Generated with Claude Code

The go client adopts a node it already finds for the same offering and
count, so the second of two identical-tuple recs bought nothing while
both reported success. preExecutionRefusal now refuses the selection
before submission with a fixed, allowlisted text.

Closes #1809

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@cristim cristim added priority/p2 Backlog-worthy type/bug Defect labels Nov 9, 2026
@coderabbitai

coderabbitai Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 31 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between a163385 and 67cea7c.

Files selected for processing: 6

  • internal/purchase/errnotes.go
  • internal/purchase/errnotes_test.go
  • internal/purchase/manager.go
  • internal/purchase/redshift_duplicate_tuple_test.go
  • internal/purchase/redshift_lineage.go
  • known_issues/39_redshift_dedupe_window.md
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@cristim

cristim commented Nov 9, 2026

Copy link
Copy Markdown
Member Author

APPROVE @ 67cea7c by claude-nibblets

Cold review of #1895 (closes #1809, +163/-3, money path; 0 behind main): one execution that selects two Redshift recs with an identical tuple and account bought one node, because the go client adopts the node it finds for the same offering and count, so the second call reported success and bought nothing.

Read: hasDuplicateRedshiftTuple (internal/purchase/redshift_lineage.go) takes redshiftTuples(exec) (selected Redshift recs only), keys each by region, node type, term, payment and count plus the rec's account (its own, else the execution's, else empty) and refuses on the first repeat. Count 1+1 versus a single count 2, different accounts, unselected recs and non-Redshift twins are not duplicates. It runs in preExecutionRefusal (internal/purchase/manager.go) as a beforeSubmission error with the fixed note redshiftDuplicateTupleRefusal, which is on the stored-error allowlist (errnotes.go), so the row ends no_submission before any provider call; a retry of such an execution is attempt 1 or more, so #1870's attempt-0 rule keeps its Retry locked. The key compares exact strings, like the existing RedshiftTuple.LockKey, so a case or whitespace variant of the same node type would not be caught; the same limitation as the existing gate, not new. A legacy parked row that already holds duplicates now fails with no_submission, as the PR says.

Scoped probes (go test -run RedshiftDuplicate|DuplicateTuple|ErrNote|ServerNote|PreExecution|Redshift|Sanitiz in internal/purchase, scratch worktree at this head, baseline ok), each killed: check not called (TestRedshiftDuplicateTuple_Detection, _RefusedBeforeSubmission, _UnscopedRecUsesTheExecutionAccount); account dropped from the key (TestExecuteAndFinalize_RedshiftFanOutAccountsShareRootStamp, _Detection, _UnscopedRecUsesTheExecutionAccount; my first version did not compile and was redone); count dropped from the key (_Detection); unselected recs counted (TestRedshiftDispatchGate_QueriesOnlySelectedRedshiftTuples, _Detection); execution-account fallback dropped (_UnscopedRecUsesTheExecutionAccount); allowlist entry dropped (TestSanitizeStoredError_AllowlistedNotesPassThroughVerbatim, _RedshiftGateRefusalsAreClosed); not a beforeSubmission error (_Detection, _RefusedBeforeSubmission).

CI at this head: all 41 checks pass (Unit Tests, Lint Code, Integration Tests (purchase), CI Success); 1 skipping (CodeRabbit).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority/p2 Backlog-worthy type/bug Defect

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Redshift: two identical-tuple recommendations in one execution buy one node

1 participant