From c1dbb55ddf0cc48acf1884e007109e442033080b Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Fri, 6 Nov 2026 23:12:18 +0100 Subject: [PATCH 1/3] feat(common): add optional ClaimReader to the attempt journal An AttemptJournal may also implement ClaimReader so a provider client can ask which of a set of reservation IDs another token recorded as purchased. Found by type assertion; journals without it behave as before. Part of #700 Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + pkg/common/attempt_journal.go | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4caacb67..795cea3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). ### Added +- **`pkg`:** optional `common.ClaimReader` (`ClaimedByOthers(ctx, token, ids)`), which an `AttemptJournal` may implement so a provider can skip commitments another purchase recorded as bought (#700). - **`pkg`:** `common.Commitment.CostKnown` reports whether `Cost` holds a price the provider reported. The zero value means unknown, so a `Cost` of 0 without `CostKnown` must not be read as free. Producers set it in a follow-up (#74). - **`common`:** `AttemptJournal`, `AttemptRecord` and an optional `PurchaseOptions.AttemptJournal`, a caller-backed durable record of purchase attempts per idempotency token (#107). Nothing reads it yet. diff --git a/pkg/common/attempt_journal.go b/pkg/common/attempt_journal.go index 87e5c697..cdf49230 100644 --- a/pkg/common/attempt_journal.go +++ b/pkg/common/attempt_journal.go @@ -74,3 +74,15 @@ type AttemptJournal interface { PriorAttempts(ctx context.Context, token string) ([]AttemptRecord, error) RecordAttempt(ctx context.Context, rec AttemptRecord) error } + +// ClaimReader is an optional interface an AttemptJournal may also implement +// (go#700). A provider client finds it by type assertion on +// PurchaseOptions.AttemptJournal; a journal without it behaves as before. +// +// ClaimedByOthers returns the subset of ids that some attempt under a token +// other than token has recorded as purchased. An id that only the given token +// recorded is not returned, and an empty result excludes nothing. Any error +// means the claims are not known. +type ClaimReader interface { + ClaimedByOthers(ctx context.Context, token string, ids []string) ([]string, error) +} From 75a981020641d73f3ec0f935348dfa92b0fb6601 Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Fri, 6 Nov 2026 23:30:27 +0100 Subject: [PATCH 2/3] docs(common): mention ClaimReader on PurchaseOptions.AttemptJournal Part of #700 Co-Authored-By: Claude Opus 5.5 --- pkg/common/types.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/common/types.go b/pkg/common/types.go index 2ffb59e1..a8e92cf5 100644 --- a/pkg/common/types.go +++ b/pkg/common/types.go @@ -470,6 +470,8 @@ type PurchaseOptions struct { // Only Redshift reads it, honored by providers/aws from the follow-up // change onward; other providers ignore it. Used only with a non-empty // IdempotencyToken; see AttemptJournal for the caller contract. + // A journal that also implements the optional ClaimReader lets Redshift + // skip nodes another purchase recorded (go#700). AttemptJournal AttemptJournal // OfferingClass is the EC2 Reserved Instance offering class for this From cccc6ca15dccc9a7fb3d2a87ac5142554a1f4643 Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Sat, 7 Nov 2026 00:15:52 +0100 Subject: [PATCH 3/3] docs(common): say Redshift reads ClaimReader only from the follow-up Part of #700 Co-Authored-By: Claude Opus 5.5 --- pkg/common/types.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/common/types.go b/pkg/common/types.go index a8e92cf5..942f2f60 100644 --- a/pkg/common/types.go +++ b/pkg/common/types.go @@ -471,7 +471,8 @@ type PurchaseOptions struct { // change onward; other providers ignore it. Used only with a non-empty // IdempotencyToken; see AttemptJournal for the caller contract. // A journal that also implements the optional ClaimReader lets Redshift - // skip nodes another purchase recorded (go#700). + // skip nodes another purchase recorded, from the follow-up change to + // providers/aws onward (go#700). AttemptJournal AttemptJournal // OfferingClass is the EC2 Reserved Instance offering class for this