Skip to content

fix(config): use the earliest row when purchase_history duplicates a purchase_id - #1103

Merged
cristim merged 4 commits into
LeanerCloud:mainfrom
IAmJSD:fix/issue-267
Oct 25, 2026
Merged

cristim merged 4 commits into
LeanerCloud:mainfrom
IAmJSD:fix/issue-267

Conversation

@IAmJSD

@IAmJSD IAmJSD commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

What was still broken

Most of #267 was already handled by earlier merges, so this PR covers only what was left:

Rows saved before 000108 can still share a purchase_id. Deleting them is a pending owner decision (cristim on #704), so this PR deletes no rows and adds no migration. With such rows, main still gets these wrong:

  1. GetPurchaseHistoryByPurchaseID uses LIMIT 1 with no ORDER BY, so it returns whichever duplicate the planner finds first. The marketplace-list and revoke handlers read listing state, offering class and account from that row.
  2. ClaimMarketplaceListingSlot joins prev to the target on purchase_id, so every duplicate is joined to every other one. When the duplicates' listing state has diverged (for example the earliest row is active and a later twin was saved without it):
    • the claim succeeds on the twin, so the handler can send a second CreateReservedInstancesListing for an RI that is already listed
    • the returned PriorState and ListingID can come from a different row than the one claimed, and the release later writes that PriorState back

Fix (internal/config/store_postgres.go)

  • GetPurchaseHistoryByPurchaseID orders by created_at, id, so it always returns the earliest row. That is the row fix(purchase): save purchase history once per commitment #776's "first row wins" kept.
  • ClaimMarketplaceListingSlot:
    • prev locks only the earliest row (ORDER BY created_at, id LIMIT 1 FOR UPDATE), and the update joins on id. The claim, its prior state and its listing id all belong to that one row.
    • A NOT EXISTS refuses the claim while any duplicate records an active listing.
    • The other writers (UpdatePurchaseHistoryListing, ReleaseMarketplaceListingClaim, revocation) still match on purchase_id, so a recorded listing covers every duplicate. The release only matches rows that are pending with the caller's token, which now means only the earliest row.

Concurrency: concurrent claims all lock the same earliest row first. created_at and id never change, so the row prev picks stays the same while a claim waits. The claim holds one row lock and only reads the twin rows, so it adds no new lock-order deadlock with the all-rows UPDATEs. One race is the same as on main: if a claim and UpdatePurchaseHistoryListing interleave, the update overwrites the claim's pending state.

Verification

All evidence is local integration evidence against real Postgres (testcontainers, -tags integration, which CI runs). Since merging main, the new test takes its database from testhelpers.RequireMigratedDatabase, the package's shared container (#1165), like the other internal/config integration tests. Nothing touched real AWS. All tests ran with AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/null, because this machine's default AWS profile is invalid.

The new test TestPurchaseHistoryLegacyDuplicates_Postgres (internal/config/store_postgres_purchase_duplicates_integration_test.go) seeds a legacy duplicate with created_at before the index cutoff. The earliest row is stored second on disk, so an unordered lookup returns the later row.

go test -tags integration -run 'TestPurchaseHistoryLegacyDuplicates_Postgres|TestMarketplaceListingClaim_PostgresSemantics' -count=1 -v ./internal/config/
Subtest origin/main store code this PR
LookupReturnsEarliestRow FAIL PASS
ClaimRefusedWhenEarliestRowIsListed FAIL (claims, leaves a row pending) PASS
ClaimRefusedWhenAnyDuplicateIsListed FAIL (claims, PriorState active taken from the twin) PASS
ClaimReportsEarliestRowState FAIL (wrong prior state/listing id; release overwrites) PASS
ClaimReleaseReclaimDoesNotWedge PASS (the wedge was already fixed by #525) PASS
ConcurrentClaimWaitsAndResumes FAIL* PASS
ParallelClaimsShareOneAttempt (8 goroutines) PASS PASS
existing TestMarketplaceListingClaim_PostgresSemantics PASS PASS

* ConcurrentClaimWaitsAndResumes holds an open transaction that marks only the earliest row pending, which is the shape of the new claim. Its failure on main is not evidence of a race on main, because on main a real claim marks every duplicate. It is here to check the new locking.

Mutation probes (each reverted afterwards). Each one fails at least one subtest:

Mutation Failing subtests
Drop the twin NOT EXISTS ClaimRefusedWhenAnyDuplicateIsListed
Drop the lookup ORDER BY LookupReturnsEarliestRow
ORDER BY created_at DESC in prev ClaimReportsEarliestRowState, ConcurrentClaimWaitsAndResumes
Drop LIMIT 1 in prev, so every duplicate is claimed ClaimReportsEarliestRowState

Other checks

  • go test -tags integration ./internal/config/ -count=1: ok (340.9s)
  • go test ./internal/config/ ./internal/mocks/ -count=1: ok
  • go build ./..., go vet ./internal/config/ and go vet -tags integration ./internal/config/: clean
  • golangci-lint v2.10.1 run --build-tags integration ./internal/config/...: 0 issues
  • gocyclo -over 10 -ignore "_test\.go" internal/config/store_postgres.go: silent
  • scripts/gosec-hook.sh on the changed files: exit 0
  • git-secrets: full scan in an isolated fresh repo with the repo's patterns is clean, and scripts/test-git-secrets-allowlist.sh gives 42 PASS, 0 FAIL
  • git diff --check: clean

Not covered: I did not run against a deployed database or a real AWS Marketplace listing, and I don't know how many legacy duplicates production holds.

Out of scope / left for a decision

  • The issue suggests a full unique index on purchase_history(purchase_id) after a dedupe migration. That needs the legacy duplicates removed or rewritten, which is the pending owner decision on fix(purchase): skip duplicate purchase_history insert on re-drive and add a unique index #704, so this PR adds no migration.
  • MarkPurchaseRevoked, FlipPurchaseRevocationInFlight, ClearRevocationInFlight, UpdatePurchaseHistoryListing and StampOfferingClass still match every row with the purchase_id. The duplicates describe the same commitment, so stamping all of them keeps them consistent. MarkPurchaseRevoked only touches rows with revoked_at IS NULL.
  • The 000108 key is (provider, account_id, purchase_id), while these single-row helpers key on purchase_id alone. AWS RI IDs and Azure reservation IDs are globally unique, so I did not change that.
  • Legacy duplicates still double count spend and savings in history and YTD views (noted in fix(purchase): save purchase history once per commitment #776).
  • While a claim is pending, only the earliest row shows pending; its twins keep their old listing state until the next all-rows update. This only affects how history and list views show those twins.
  • The marketplace cancel handler checks only the earliest row's listing state, while the claim also refuses when any twin is active. No current writer leaves only a twin active (the listing update and the release write every duplicate together), so this is theoretical; it belongs with the dedupe decision on fix(purchase): skip duplicate purchase_history insert on re-drive and add a unique index #704.

Note for whoever merges: this repo's squash message lists the commit messages, and the first commit's message (53b3c03) ends with a closing keyword for issue 267. Please delete that line from the squash message (or merge with an explicit message), because this PR only partly fixes that issue and it should stay open.

Maintainer: please mirror the issue's triage labels onto this PR: priority/p2, severity/medium, triaged, urgency/this-quarter, impact/few, effort/m, type/bug.

Refs #267 (partial: the full purchase_id unique index and duplicate cleanup wait on the owner decision on #704)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Purchase history lookups and listing claims now consistently use the earliest record when multiple records exist for a purchase.
    • A listing claim is refused if another record for the same purchase already has an active listing.
    • Releasing a claim preserves the state of the other purchase records, and eligible claims can be retried.

…purchase_id

Rows saved before migration 000108 can still share a purchase_id, and
deleting them is a pending owner decision. GetPurchaseHistoryByPurchaseID
returned whichever duplicate the planner found first, and
ClaimMarketplaceListingSlot joined every duplicate to every other, so with
duplicates whose listing state diverged it could claim an RI that already
had an active listing and report another row's prior state and listing id.

The lookup now orders by (created_at, id), and the claim locks and updates
only that earliest row, refusing while any duplicate records an active
listing.

Closes LeanerCloud#267

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@IAmJSD IAmJSD added priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged urgency/this-quarter Within the quarter impact/few Limited audience effort/m Days type/bug Defect labels Oct 19, 2026
@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Caution

Review failed

The pull request is closed.

Walkthrough

The PostgreSQL store now selects the earliest purchase-history row for duplicate purchase IDs during lookup and marketplace claims. Claims are refused when another row for that purchase ID has an active listing. Integration tests cover lookup, claim state, release, retry, and concurrent claims.

Changes: Duplicate Purchase History Claims

Layer / File(s) Summary
Select the earliest row for lookup and claims
internal/config/store_postgres.go, internal/config/store_postgres_purchase_duplicates_integration_test.go
Claims target the earliest matching history row, ordered by created_at and then id. A claim is refused if another row for the purchase ID has an active listing. Lookups use the same ordering. Integration tests cover duplicate-row setup, lookup, and active-listing refusal.
Verify claim release and concurrency
internal/config/store_postgres_purchase_duplicates_integration_test.go
Integration tests verify prior-state restoration, release and retry behavior, and concurrent claims that resume with the same token.

Priority: Not assessed

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Suggested reviewers: cristim

Merge Risk: Minimal · up to 7921c

The reviewed change can merge with normal checks; no unresolved issue in the lookup or claim behavior was established.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@cristim

cristim commented Oct 20, 2026

Copy link
Copy Markdown
Member

VERDICT: APPROVE 53b3c03

Reviewed: full diff origin/main...53b3c03 (1 commit, 2 files, +298/-6). Rebase check: git merge-tree against origin/main b6a0649 is clean; every test below ran on the merged tree (973f447f).

Findings (none blocking):

Attacked:

  • SQL ordering and tie-break: created_at is TIMESTAMPTZ NOT NULL and id is the UUID PK (000001_initial_schema.up.sql:102,119), so ORDER BY created_at, id is total and deterministic, and no NULLS LAST case applies. prev and the lookup use the same key (store_postgres.go:2401, 2859), so the handler validates the same row it claims.
  • Concurrency: prev locks one row, the twin NOT EXISTS is a plain read, and the all-rows writers must take the earliest-row lock, so no new lock cycle appears. If UpdatePurchaseHistoryListing commits first, the EPQ recheck sees the earliest row as active and refuses the claim.
  • Readers of purchase_history by purchase_id: GetPurchaseHistoryByPurchaseID callers (handler_marketplace.go:199,362, handler_purchases_revoke.go:180,596), plus the release, revoke and in-flight writers. They all match every duplicate, so state stays uniform.
  • Transitional rows left pending by the old claim (all duplicates carrying the same token): the new claim resumes on the earliest row, and the release still matches every pending row with that token.
  • Mutation probes (fresh scratch export, real Postgres; each change was reverted and the restore checked with cmp):
    • dropped the lookup ORDER BY: LookupReturnsEarliestRow FAILS
    • dropped the twin NOT EXISTS: ClaimRefusedWhenAnyDuplicateIsListed FAILS
    • prev ORDER BY created_at DESC: ClaimReportsEarliestRowState and ConcurrentClaimWaitsAndResumes FAIL

Local results on the merged tree:

  • go vet -tags integration ./internal/config/: clean
  • go test -tags integration -run 'TestPurchaseHistoryLegacyDuplicates_Postgres|TestMarketplaceListingClaim_PostgresSemantics|PurchaseHistory|Marketplace' ./internal/config/ (testcontainers Postgres): ok (27s)

@cristim

cristim commented Oct 20, 2026

Copy link
Copy Markdown
Member

Independent review 2 (claude-fleet, cold): APPROVE 53b3c03

Findings (none blocking):

Attacked:

  • Root cause: the claim's prev joined on purchase_id, which joined every duplicate to every other one. The fix:
    • locks only the earliest row (store_postgres.go:2397-2403);
    • updates by p.id = prev.id (:2411);
    • refuses when any twin is active (:2414-2418);
    • makes the lookup use ORDER BY created_at, id (:2859), the same row SavePurchaseHistory's "first wins" keeps.
  • Lock order: the claim locks one row and only reads the twins, so it cannot form a cycle with the all-rows UPDATEs. created_at and id are immutable, so the earliest row cannot change while a claim waits.
  • Mixed-version deploy:
    • An old instance's claim stamps every row with token A.
    • New code resumes A on the earliest row.
    • Release (purchase_id + token) clears all rows.
  • Callers:
    • handler_marketplace_attempt.go:120 (claim).
    • Lookups at handler_marketplace.go:199 and :362, and handler_purchases_revoke.go:180 and :596.
    • mocks/stores.go. There are no other implementers.
  • Mutation probes on a scratch copy, each restored and confirmed identical with cmp. All were caught:
    • M1, the twin NOT EXISTS dropped: ClaimRefusedWhenAnyDuplicateIsListed FAILS.
    • M2, the lookup ORDER BY dropped: LookupReturnsEarliestRow FAILS.
    • M3, join on p.purchase_id = $2: ClaimReportsEarliestRowState and ConcurrentClaimWaitsAndResumes FAIL.
    • M4, FOR UPDATE dropped in prev: ConcurrentClaimWaitsAndResumes FAILS.
    • M5, ORDER BY created_at DESC in prev: ClaimReportsEarliestRowState and ConcurrentClaimWaitsAndResumes FAIL.
  • Main drift: merge-tree with origin/main is clean, and store_postgres.go has not changed on main since the base. Main added migrations 000131-000133, and 000133 touches purchase_history, so I also ran the tests on a merged export.
  • No migration added. The highest on main is 000133.

Verified locally, on git archive exports with no cloud credentials, under the heavy lock:

  • Head:
    • gofmt -l on both changed files: clean.
    • go build ./...: ok.
    • go vet on config and mocks, and with -tags integration on config: ok.
    • go test -count=1 ./internal/config/ ./internal/mocks/ ./internal/api/: ok.
    • go test -tags integration -count=1 -run 'TestPurchaseHistoryLegacyDuplicates_Postgres|TestMarketplaceListingClaim_PostgresSemantics' ./internal/config/: all 7 subtests and the existing claim test PASS.
  • Fail-before, with the new test file on base:
  • Merged export: build and vet ok, config and mocks unit tests ok, and the same integration run passes.
  • Not run: the full -tags integration ./internal/config/ package.

Reviewed by an independent agent with no author context (second reviewer). Review only: nothing was pushed, and the GitHub review state is unchanged.

IAmJSD and others added 2 commits October 23, 2026 03:01
…ed container

Main's LeanerCloud#1165 moved internal/config's integration tests onto one shared
PostgreSQL container, and TestIntegrationTestsShareOnePostgresContainer
fails on any test that starts its own. TestPurchaseHistoryLegacyDuplicates_Postgres
now gets a freshly migrated database of its own from
testhelpers.RequireMigratedDatabase, like setupTestContainerDB does.

Refs LeanerCloud#267

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@IAmJSD

IAmJSD commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up to VERDICT: APPROVE and Independent review 2 (both on 53b3c03). New head: 1dcdc2d.

Main merged in (merge commit, no rebase), no conflicts. After merging, main's TestIntegrationTestsShareOnePostgresContainer (#1165) failed on this PR's new test because it started its own container (store_postgres_purchase_duplicates_integration_test.go:29: testhelpers.RequirePostgresContainer).

  • Fixed in internal/config/store_postgres_purchase_duplicates_integration_test.go:28-33. The test now gets its own migrated database from testhelpers.RequireMigratedDatabase(ctx, t, getTestMigrationsPath()), the same way setupTestContainerDB does, and it no longer imports migrations or runs a cleanup of its own. The test logic is unchanged.

Findings

Verification on the merged tree (1dcdc2d), with AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/null:

  • go build ./..., go vet ./internal/config/ and go vet -tags integration ./internal/config/: clean. gofmt -l: clean.
  • TestIntegrationTestsShareOnePostgresContainer FAILS on the bare merge (the offender above) and PASSES with the fix.
  • go test -tags integration -run 'TestPurchaseHistoryLegacyDuplicates_Postgres|TestMarketplaceListingClaim_PostgresSemantics|TestIntegrationTestsShareOnePostgresContainer' ./internal/config/: all 7 subtests and both other tests PASS.
  • Mutation probe on the shared DB (I dropped the lookup's ORDER BY, then restored it and checked with cmp): LookupReturnsEarliestRow FAILS.
  • Full go test -tags integration -timeout 20m -count=1 ./internal/config/, skipping TestPostgresStoreDB_ResolveStaleRIExchange_ValidatesCloudCheck (a known failure on main, fixed in fix(config): compare resolve checked_at at the database's microsecond precision #1252): ok (282s). The first attempt hit a 60s template-creation timeout while the host was under load (environmental); the rerun was clean.
  • go test ./internal/config/ ./internal/mocks/ -count=1: ok.
  • golangci-lint v2.10.1 on ./internal/config/..., with and without --build-tags integration: 0 issues. gocyclo -over 10 on store_postgres.go: silent. git diff --check: clean.
  • git-secrets: I ran the repo's setup in an isolated fresh repo with both changed files tracked: clean. A planted fake key was flagged. scripts/test-git-secrets-allowlist.sh: 137 PASS, 0 FAIL.

The PR stays a draft. The govulncheck failures (GO-2026-6809) aren't related to this PR and are covered by #1236.

🤖 Generated with Claude Code

@cristim

cristim commented Oct 25, 2026

Copy link
Copy Markdown
Member

VERDICT: APPROVE 1dcdc2d

Re-review of #1103 (closes #267). Old head 53b3c03, new head 1dcdc2d. origin/main is 00a3f40, merge-tree 82a3e777, clean.

Delta: the production SQL is identical to the old head (only hunk offsets moved). The changes are:

Full PR, internal/config/store_postgres.go:

  • ClaimMarketplaceListingSlot (~2424-2443): prev locks the earliest row (ORDER BY created_at, id LIMIT 1 FOR UPDATE). The UPDATE targets that row by id. A NOT EXISTS check refuses the claim while any duplicate is active.
  • GetPurchaseHistoryByPurchaseID (~2884): uses the same ORDER BY, so the lookup and the claim agree on the row.
  • Fixes the issue's wedge: the claim touches one row, so RowsAffected is 1 and the release can match.

Checked and fine:

  • Downstream UpdatePurchaseHistoryListing stamps every duplicate, so the twin-active guard then holds.
  • Release only touches the token-owning pending row (the earliest one).
  • A pending twin left by the old code does not block; it resumes.
  • created_at and id never change, so the earliest row is stable while a claim waits on the lock.

Findings: none blocking.

  • nit, pre-existing and outside this diff: MarkPurchaseRevoked, FlipPurchaseRevocationInFlight, ClearRevocationInFlight and StampOfferingClass still match every duplicate. The issue names MarkPurchaseRevoked. These writes are idempotent multi-row stamps, not a wedge. Consider a follow-up issue.
  • nit: the keying is purchase_id only, while 000108's unique key is (provider, account_id, purchase_id). This matches the existing APIs.
  • nit: the branch updates main by merge commits, not by rebasing.

Results on the merged tree:

  • go build and go vet (unit + integration tags): ok.
  • go test for config and api: 4968 passed.
  • -tags integration for LegacyDuplicates, Marketplace, ListingSlot, ListingClaim, PurchaseHistoryByPurchaseID and ResolveStaleRIExchange_ValidatesCloudCheck: ok.

Mutation probes (all reverted, restore verified with cmp):

  • Remove the claim's ORDER BY: ClaimReportsEarliestRowState and ConcurrentClaimWaitsAndResumes FAIL.
  • Make the claim's ORDER BY DESC: same two FAIL.
  • Drop the twin NOT EXISTS: ClaimRefusedWhenAnyDuplicateIsListed FAIL.
  • Remove the lookup's ORDER BY: LookupReturnsEarliestRow FAIL.

CI on 1dcdc2d (run 39894693449, old base):

  • Integration Tests fail in the same unrelated ResolveStaleRIExchange_ValidatesCloudCheck subtests, which pass locally on the merged tree.
  • Security Scanning fails: go1.26.9 govulncheck, fixed on main in 52edcf5.
  • Docker amd64/arm64 fail: image advisory.
  • None of the failures is caused by the PR; they come from the old base. Main CI is green at 00a3f40. A rebase or re-run is needed before merge.

@IAmJSD CI on this head is red only from the old merge base (govulncheck on go1.26.9, fixed on main by #1236; a Docker image advisory; and TestPostgresStoreDB_ResolveStaleRIExchange_ValidatesCloudCheck, which passes on the merged tree). Please merge or rebase onto current main so CI runs on a fresh merge ref.

Brings in main's CI fixes (LeanerCloud#1236, LeanerCloud#1252) and CI changes since, so this PR gets a fresh CI run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cristim

cristim commented Oct 25, 2026

Copy link
Copy Markdown
Member

VERDICT: APPROVE 7921c3b

Delta re-review after the refresh onto main (previously approved at 1dcdc2d).

  • Only new commit: 7921c3b, a merge of origin/main (503eb2e) into 1dcdc2d. git show --remerge-diff is empty: no conflicts and no hand edits.
  • The PR diff against its merge base is identical to the approved one apart from hunk offsets: the ClaimMarketplaceListingSlot earliest-row CTE plus the NOT EXISTS twin guard, and ORDER BY created_at, id in GetPurchaseHistoryByPurchaseID.
  • Semantic overlap: main's feat(api): scope-aware SQL totals for the History summary cards #1200 changed store_postgres.go (it extracted purchaseHistoryFilterWhere and historyExecutionsPredicate). Those are different functions from the ones this PR edits. Neither function this PR edits is used by the new aggregate.
  • Tests on the new head (fresh archive): go build ./... passes and go test ./internal/config/ passes. The -tags integration -run 'PurchaseHistory|Marketplace|Listing|Revoke|HistorySummary' ./internal/config/ run passes, with all 7 TestPurchaseHistoryLegacyDuplicates_Postgres subtests green.
  • Mutation probe: removing the NOT EXISTS twin guard makes ClaimRefusedWhenAnyDuplicateIsListed fail. The file was restored and verified identical.
  • CI: gh pr checks reports 33 pass and 1 skipping. mergeStateStatus is CLEAN. The PR is still a draft.
  • Note: main has since moved to 2ded648. Those commits do not touch internal/config.

@cristim

cristim commented Oct 25, 2026

Copy link
Copy Markdown
Member

Independent review 2 (claude-fleet, cold), re-review: APPROVE 7921c3b

Delta (53b3c03..7921c3b, first-parent): 6c65690 merge (remerge-diff empty), 1dcdc2d test-only (+5/-6), 7921c3b merge (remerge-diff empty). The production change in internal/config/store_postgres.go is byte-identical to the approved head, and the head and merged-with-main copies of both PR files are identical.

Findings: none.

  • [non-blocking, not a defect] internal/config/store_postgres_purchase_duplicates_integration_test.go:224 counts lock waiters in pg_stat_activity, which is server-wide, so on the shared server another database's backend would also count. No internal/config integration test calls t.Parallel, so nothing else runs while this test runs. main's store_postgres_marketplace_claim_integration_test.go:67 uses the same query.

Attacked:

  • Vacuous pass: RequireMigratedDatabase (testhelpers/shared.go:61) skips only when the Docker provider is unhealthy, the same skip rule as the RequirePostgresContainer call it replaces. A start or migration failure fails the test through require.NoError. No SKIP lines in any run.
  • Collision: each test gets its own CREATE DATABASE clone (cudly_test_N) of the migrated template, which is dropped at cleanup. The 8-worker parallel claim fits inside the 10-connection pool, as it did before.
  • Same assertions: the diff touches only setup (container and migrations replaced by RequireMigratedDatabase). All 7 subtests and their assertions are unchanged.
  • Probes on the merged export, each restored and checked with cmp:
    • M1 (drop the twin NOT EXISTS): ClaimRefusedWhenAnyDuplicateIsListed FAILS.
    • M3 (p.purchase_id = $2 instead of p.id = prev.id): ClaimReportsEarliestRowState and ConcurrentClaimWaitsAndResumes FAIL.
    • M4 (drop FOR UPDATE): ConcurrentClaimWaitsAndResumes FAILS.

Verified locally (merged tree 6c5cd5d, GOTOOLCHAIN=go1.26.10, no credentials, heavy lock):

  • gofmt -l: clean.
  • go build ./... and go vet -tags integration ./internal/config/: rc=0.
  • go test ./internal/config/: ok.
  • TestIntegrationTestsShareOnePostgresContainer: PASS. The old head would have failed this guard.
  • go test -tags integration -count=3 -run 'TestPurchaseHistoryLegacyDuplicates_Postgres|TestMarketplaceListingClaim_PostgresSemantics': PASS in all 3 runs, including both concurrent-claim subtests.

Reviewed by an independent agent with no author context (second reviewer). Review only: nothing was pushed, and the GitHub review state is unchanged.

@cristim

cristim commented Oct 25, 2026

Copy link
Copy Markdown
Member

Local verification at 7921c3b6834c9ac99ccb3692e23e0c8468d07414 merged onto current main (2033cb89; merge-tree 4985dd05; macOS):

  • go build ./..., go vet -tags integration ./... and go test -race -short ./... pass (full suite).
  • Nothing was applied to any cloud.

@cristim

cristim commented Oct 25, 2026

Copy link
Copy Markdown
Member

Marked ready and merged by the owner's agent after 2 independent reviews and local verification (see the review and verification comments above, all at 7921c3b6834c9ac99ccb3692e23e0c8468d07414).

@cristim
cristim marked this pull request as ready for review October 25, 2026 17:56
@cristim
cristim merged commit 7cde88e into LeanerCloud:main Oct 25, 2026
33 of 34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/m Days impact/few Limited audience priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged type/bug Defect urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants