Skip to content

feat(sqs): per-key dispatch helpers for partitioned-FIFO routing (Phase 3.D PR 5b-1)#731

Open
bootjp wants to merge 2 commits intomainfrom
feat/sqs-htfifo-key-dispatch-helpers
Open

feat(sqs): per-key dispatch helpers for partitioned-FIFO routing (Phase 3.D PR 5b-1)#731
bootjp wants to merge 2 commits intomainfrom
feat/sqs-htfifo-key-dispatch-helpers

Conversation

@bootjp
Copy link
Copy Markdown
Owner

@bootjp bootjp commented May 2, 2026

Summary

Foundation for PR 5b's Send/Receive partition fanout. Adds sqsMsg*KeyDispatch wrappers that route to the legacy or partitioned constructor based on meta.PartitionCount. Pure scaffold: helpers are added but no production call site uses them yet — those switch in PR 5b-2.

Why a separate scaffold PR

PR 5b's full scope (Send/Receive fanout + receipt-handle v2 wiring + dormancy gate-lift + CreateQueue capability check) is ~1000 LOC across multiple files. The lessons-learned discipline from recent rounds (PR #723 missed the raftadmin stub because the audit was function-scoped, not interface-scoped) favours smaller diffs.

Splitting PR 5b into three:

  • PR 5b-1 (this PR): dispatch helpers + tests, zero behaviour change.
  • PR 5b-2: SendMessage / ReceiveMessage / DeleteMessage / ChangeMessageVisibility wire through the helpers. Receipt-handle v2 dispatch wired. Still gated by §11 PR 2 dormancy.
  • PR 5b-3 (atomic): gate-lift + CreateQueue capability check via PollSQSHTFIFOCapability. Small-but-critical.

What's added

adapter/sqs_keys_dispatch.go (new file):

  • sqsMsgDataKeyDispatch, sqsMsgVisKeyDispatch, sqsMsgDedupKeyDispatch, sqsMsgGroupKeyDispatch, sqsMsgByAgeKeyDispatch, sqsMsgVisPrefixForQueueDispatch
  • effectivePartitionCount helper for fanout iteration

Each helper takes (meta, queueName, partition, gen, …) and routes to the legacy single-partition constructor when meta.PartitionCount <= 1 (existing behaviour, byte-identical output) or to the partitioned constructor (#703's keyspace) when > 1.

What does NOT change yet

  • 14 call sites in adapter/sqs_messages.go still call legacy sqsMsg*Key constructors directly. PR 5b-2 swaps them.
  • encodeReceiptHandleV2 stays dormant.
  • decodeClientReceiptHandle still rejects v2 unconditionally.
  • CreateQueue still rejects PartitionCount > 1 with InvalidAttributeValue.

Test plan

5 top-level tests (19 sub-cases):

  • TestSQSKeysDispatch_LegacyMatchesLegacyConstructor — 8 sub-cases pinning byte-identical output for nil meta, PartitionCount=0, PartitionCount=1 across all 6 helpers.
  • TestSQSKeysDispatch_PartitionedMatchesPartitionedConstructor — 6 sub-cases pinning byte-identical output for PartitionCount=4 across all partitioned constructors.
  • TestSQSKeysDispatch_LegacyAndPartitionedAreDistinct — keyspace isolation invariant.
  • TestEffectivePartitionCount — iteration-count contract.
  • TestSQSKeysDispatch_PartitionIgnoredOnLegacy — protects against stale-partition stranding on non-partitioned queues.
  • go test -race ./adapter/... pass.
  • golangci-lint ./adapter/... clean.

Self-review (per CLAUDE.md)

  1. Data loss — wrappers only; no FSM/Pebble/retention path. Byte-identical output to legacy on non-partitioned queues. No issue.
  2. Concurrency — pure functions, no shared state. No issue.
  3. Performance — one nil-check + one comparison per dispatch. The non-partitioned path (steady state today) goes through the same constructor it always did. No issue.
  4. Data consistency — keyspace isolation pinned by TestSQSKeysDispatch_LegacyAndPartitionedAreDistinct. Stale-partition stranding pinned by TestSQSKeysDispatch_PartitionIgnoredOnLegacy. No issue.
  5. Test coverage — 19 sub-tests across the contract surface.

Summary by CodeRabbit

  • New Features

    • Added SQS key dispatch helpers supporting both single and multi-partition queue configurations.
  • Tests

    • Added comprehensive test coverage for SQS key dispatch across queue variants.

…se 3.D PR 5b-1)

Foundation for PR 5b's Send/Receive partition fanout. Adds
sqsMsg*KeyDispatch wrappers that route to the legacy or
partitioned constructor based on meta.PartitionCount. Pure
scaffold: helpers are added but no production call site uses
them yet — those switch in PR 5b-2.

What's added

adapter/sqs_keys_dispatch.go (new file):
  - sqsMsgDataKeyDispatch
  - sqsMsgVisKeyDispatch
  - sqsMsgDedupKeyDispatch
  - sqsMsgGroupKeyDispatch
  - sqsMsgByAgeKeyDispatch
  - sqsMsgVisPrefixForQueueDispatch
  - effectivePartitionCount helper for fanout iteration

Each dispatch helper takes (meta, queueName, partition, gen, …)
and routes to the legacy single-partition constructor when
meta.PartitionCount <= 1 (existing behaviour, byte-identical
output) or to the partitioned constructor when > 1 (PR #715's
keyspace).

Why a separate scaffold PR

PR 5b's full scope (Send/Receive fanout + receipt-handle v2
wiring + dormancy gate-lift + CreateQueue capability check) is
~1000 LOC across multiple files. The lessons-learned discipline
from the recent rounds (PR #723 missed the raftadmin stub
because the audit was function-scoped, not interface-scoped)
favours smaller diffs.

Splitting PR 5b into three:
  - PR 5b-1 (this PR): dispatch helpers + tests, zero behaviour
    change.
  - PR 5b-2: SendMessage / ReceiveMessage / DeleteMessage /
    ChangeMessageVisibility wire through the helpers. Receipt-
    handle v2 dispatch wired. Still gated by §11 PR 2 dormancy.
  - PR 5b-3 (atomic): gate-lift + CreateQueue capability check
    via PollSQSHTFIFOCapability. Small-but-critical.

What does NOT change yet

  - 14 call sites in adapter/sqs_messages.go still call the
    legacy sqsMsg*Key constructors directly. PR 5b-2 swaps them.
  - encodeReceiptHandleV2 stays dormant.
  - decodeClientReceiptHandle still rejects v2 unconditionally.
  - CreateQueue still rejects PartitionCount > 1 with
    InvalidAttributeValue.

Tests (5 top-level)

  - TestSQSKeysDispatch_LegacyMatchesLegacyConstructor: 8
    sub-cases pinning byte-identical output for nil meta,
    PartitionCount=0, PartitionCount=1.
  - TestSQSKeysDispatch_PartitionedMatchesPartitionedConstructor:
    6 sub-cases pinning byte-identical output for
    PartitionCount=4 partitioned constructors.
  - TestSQSKeysDispatch_LegacyAndPartitionedAreDistinct: keyspace
    isolation invariant — same logical record on legacy vs
    partitioned never shares a byte sequence.
  - TestEffectivePartitionCount: iteration-count contract
    (nil/0/1 → 1; explicit count otherwise).
  - TestSQSKeysDispatch_PartitionIgnoredOnLegacy: stale-
    partition caller against a non-partitioned queue produces
    the same key — protects against silent strand of messages.

Self-review (per CLAUDE.md)

1. Data loss — wrappers only; no FSM/Pebble/retention path. Byte-
   identical output to legacy on non-partitioned queues. No issue.
2. Concurrency — pure functions, no shared state. No issue.
3. Performance — one nil-check + one comparison per dispatch.
   The non-partitioned path (steady state today) goes through
   the same constructor it always did. No issue.
4. Data consistency — keyspace isolation is pinned by
   TestSQSKeysDispatch_LegacyAndPartitionedAreDistinct. Stale-
   partition stranding is pinned by
   TestSQSKeysDispatch_PartitionIgnoredOnLegacy. No issue.
5. Test coverage — 19 sub-tests across the contract surface.
   Existing partitioned-constructor tests (PR #703) and legacy
   constructor tests continue to pass unchanged.
@bootjp
Copy link
Copy Markdown
Owner Author

bootjp commented May 2, 2026

@claude review

Phase 3.D PR 5b-1 — pure-additive dispatch helpers for partitioned-FIFO routing. Foundation for PR 5b-2's send/receive/delete wiring; PR 5b-3 then lifts the §11 PR 2 dormancy gate atomically with the CreateQueue capability check. No behaviour change in this PR — the 14 production call sites still use the legacy constructors directly. PR description has the rationale for the 3-way split and the full self-review.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

Warning

Rate limit exceeded

@bootjp has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 51 minutes and 54 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f951ee27-f0e3-4741-b4b9-05f3c24c48c3

📥 Commits

Reviewing files that changed from the base of the PR and between 08968f9 and 379fc02.

📒 Files selected for processing (2)
  • adapter/sqs_keys_dispatch.go
  • adapter/sqs_keys_dispatch_test.go
📝 Walkthrough

Walkthrough

This PR introduces dispatch helper functions that route SQS key construction to either legacy single-partition or partitioned variants based on queue metadata. It includes an effectivePartitionCount utility and comprehensive test coverage verifying dispatch behavior across all key types.

Changes

SQS Key Dispatch Helpers

Layer / File(s) Summary
Dispatch Routing & Utility
adapter/sqs_keys_dispatch.go
Adds dispatch helpers for data, visibility, dedup, group, send-age index, and visibility-prefix keys that branch to legacy or partitioned constructors based on meta.PartitionCount > 1. Includes effectivePartitionCount utility that normalizes nil/PartitionCount <= 1 to 1 partition.
Test Coverage
adapter/sqs_keys_dispatch_test.go
Verifies dispatch helpers produce byte-identical outputs to legacy constructors for PartitionCount <= 1 and partitioned constructors for PartitionCount > 1. Tests confirm legacy and partitioned keys are distinct, effectivePartitionCount returns correct values, and partition argument is ignored on non-partitioned queues.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through dispatch halls,
Routing keys both big and small,
Partitioned paths or legacy way,
Choose your road and hop away! 🎯

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: introduction of per-key dispatch helpers for partitioned-FIFO routing in SQS, matching the primary objective of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sqs-htfifo-key-dispatch-helpers

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
Review rate limit: 0/1 reviews remaining, refill in 51 minutes and 54 seconds.

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

@claude
Copy link
Copy Markdown

claude Bot commented May 2, 2026

Claude finished @bootjp's task in 2m 29s —— View job


Review of PR #731 — SQS per-key dispatch helpers (Phase 3.D PR 5b-1)

Todo

  • Post initial comment
  • Read adapter/sqs_keys_dispatch.go
  • Read adapter/sqs_keys_dispatch_test.go
  • Read adapter/sqs_keys.go for context
  • Read adapter/sqs_messages.go for call-site context
  • Produce review findings

Overall

Clean scaffold. The dispatch helpers are minimal and correct: all 6 share the same guard (meta != nil && meta.PartitionCount > 1) applied consistently, effectivePartitionCount correctly collapses 0 and nil into 1, and zero production call sites are touched. The 3-way split strategy is sound. Two items worth addressing — one test-coverage gap versus the PR's own stated contract, and one boundary omission — plus a few observations.


Issues

1. PR description overstates nil/PartitionCount=0 coverage

The PR description says:

TestSQSKeysDispatch_LegacyMatchesLegacyConstructor — 8 sub-cases pinning byte-identical output for nil meta, PartitionCount=0, PartitionCount=1 across all 6 helpers

Looking at the actual test (sqs_keys_dispatch_test.go:25-63), the nil and PartitionCount=0 cases are only pinned for sqsMsgDataKeyDispatch. The remaining 5 helpers (vis, dedup, group, byage, vis-prefix) only have PartitionCount=1 sub-cases. If the nil-guard were accidentally dropped from one of the other helpers in a future edit, no test would catch it.

Since all 6 guards are currently identical this is not a correctness risk today, but the gap matters for ratchet value and the description creates a false impression of coverage. Suggest either:

  • Adding nil and PartitionCount=0 sub-cases for the vis and vis-prefix helpers (the most critical paths for ReceiveMessage), or
  • Correcting the PR description to match what's actually tested.

Fix this →

2. No boundary test at PartitionCount=2 (the minimal partitioned value)

TestSQSKeysDispatch_PartitionedMatchesPartitionedConstructor uses PartitionCount=4. The threshold > 1 means 2 is the first partitioned value. An off-by-one in the condition (e.g. >= 1 vs > 1) wouldn't be caught because the test jumps straight to 4. A single data-key sub-case at PartitionCount=2 pins this boundary cheaply.


Observations (no action required)

sqsMsgDataKey / sqsMsgVisKey / sqsMsgVisPrefixForQueue live in sqs_messages.go (sqs_messages.go:148-173), while sqsMsgByAgeKey, sqsMsgDedupKey, and sqsMsgGroupKey live in sqs_keys.go. The dispatch file ends up depending on both. This is a pre-existing layering inconsistency, not introduced by this PR — flagging only so PR 5b-2 doesn't accidentally widen the split further.

TestSQSKeysDispatch_LegacyAndPartitionedAreDistinct tests keyspace isolation for the data key only (sqs_keys_dispatch_test.go:133-140). The prefix-isolation property holds for all helpers by construction (same discriminator "p|" in the constants in sqs_keys.go:91-96), so this is fine, but noting in case a reviewer expects isolation to be tested across all key families.

Partition arg is silently dropped on legacy path. This is the correct design (documented in the file header), but PR 5b-2 callers should be audited: any path that constructs partition from partitionFor and then calls a dispatch helper must ensure it only does so after confirming meta.PartitionCount > 1. Passing a stale partition to a legacy queue is harmless (pinned by TestSQSKeysDispatch_PartitionIgnoredOnLegacy), but constructing partition via the partitioned fanout on a legacy queue is a logic error that would silently no-op.


Summary

Two suggested improvements before merge:

  1. Expand the legacy-match test to pin nil and PartitionCount=0 for at least the vis and vis-prefix helpers, or correct the PR description.
  2. Add a PartitionCount=2 partitioned sub-case to pin the threshold boundary.

Neither is a correctness defect in the scaffold itself. The implementation is sound and the split strategy is appropriate.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 08968f9361

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if meta == nil || meta.PartitionCount <= 1 {
return 1
}
return meta.PartitionCount
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor perQueue mode in effective partition count

effectivePartitionCount returns meta.PartitionCount for every queue with PartitionCount > 1, but partitionFor explicitly forces all message groups to partition 0 when FifoThroughputLimit == "perQueue" (adapter/sqs_partitioning.go). In that valid configuration, a Receive fanout built on this helper will scan empty partitions on every poll, multiplying read/CPU work by up to the configured partition count (max 32) with no correctness benefit. The helper should collapse to 1 partition in perQueue mode to match the routing behavior.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a central abstraction for SQS key dispatching, routing between legacy single-partition and new partitioned-FIFO layouts based on the queue's partition count. It includes several dispatch helpers for data, visibility, deduplication, and group keys, along with comprehensive unit tests to ensure backward compatibility and keyspace isolation. I have no feedback to provide.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
adapter/sqs_keys_dispatch_test.go (1)

15-63: 💤 Low value

Eager key construction in table rows is slightly atypical — consider moving calls inside closures.

Both table-driven tests build dispatched and legacy/partitioned values at slice-literal initialization time (before any sub-test runs), so a panic in a key constructor surfaces as a failure of the parent function rather than the named sub-test. This also means the t.Parallel() race detector cannot observe the key-construction code. Moving the calls inside the sub-test closure gives sharper failure attribution and full race coverage.

♻️ Proposed refactor (shown for LegacyMatchesLegacyConstructor; apply the same pattern to PartitionedMatchesPartitionedConstructor)
 cases := []struct {
     name string
-    dispatched []byte
-    legacy     []byte
+    dispatch func() []byte
+    legacy   func() []byte
 }{
-    {"meta=nil data", sqsMsgDataKeyDispatch(nil, queue, 0, gen, msgID),
-        sqsMsgDataKey(queue, gen, msgID)},
+    {"meta=nil data",
+        func() []byte { return sqsMsgDataKeyDispatch(nil, queue, 0, gen, msgID) },
+        func() []byte { return sqsMsgDataKey(queue, gen, msgID) },
+    },
     // ... remaining cases follow the same pattern
 }
 for _, tc := range cases {
     tc := tc
     t.Run(tc.name, func(t *testing.T) {
         t.Parallel()
-        require.Equal(t, tc.legacy, tc.dispatched, ...)
+        require.Equal(t, tc.legacy(), tc.dispatch(), ...)
     })
 }

Also applies to: 71-115

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@adapter/sqs_keys_dispatch_test.go` around lines 15 - 63, The table builds
dispatched and legacy byte slices eagerly which runs before sub-tests and
t.Parallel(); move the calls to sqsMsgDataKeyDispatch, sqsMsgDataKey,
sqsMsgVisKeyDispatch, sqsMsgVisKey, sqsMsgDedupKeyDispatch, sqsMsgDedupKey,
sqsMsgGroupKeyDispatch, sqsMsgGroupKey, sqsMsgByAgeKeyDispatch, sqsMsgByAgeKey,
and sqsMsgVisPrefixForQueueDispatch/sqsMsgVisPrefixForQueue inside the t.Run
closure so each sub-test computes its own dispatched and legacy values (and any
panics or race issues are attributed to the specific sub-test).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@adapter/sqs_keys_dispatch_test.go`:
- Around line 15-63: The table builds dispatched and legacy byte slices eagerly
which runs before sub-tests and t.Parallel(); move the calls to
sqsMsgDataKeyDispatch, sqsMsgDataKey, sqsMsgVisKeyDispatch, sqsMsgVisKey,
sqsMsgDedupKeyDispatch, sqsMsgDedupKey, sqsMsgGroupKeyDispatch, sqsMsgGroupKey,
sqsMsgByAgeKeyDispatch, sqsMsgByAgeKey, and
sqsMsgVisPrefixForQueueDispatch/sqsMsgVisPrefixForQueue inside the t.Run closure
so each sub-test computes its own dispatched and legacy values (and any panics
or race issues are attributed to the specific sub-test).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2165b9b5-ba43-4632-80de-8c61f03e47eb

📥 Commits

Reviewing files that changed from the base of the PR and between a564c60 and 08968f9.

📒 Files selected for processing (2)
  • adapter/sqs_keys_dispatch.go
  • adapter/sqs_keys_dispatch_test.go

PR #731 round 1 review findings:

1) Codex P2 — effectivePartitionCount must honor perQueue mode

  partitionFor (sqs_partitioning.go:76) forces every MessageGroupId
  to partition 0 when meta.FifoThroughputLimit == "perQueue",
  regardless of PartitionCount. effectivePartitionCount returned
  the literal PartitionCount in that mode, so ReceiveMessage's
  fanout would scan up to 31 guaranteed-empty partitions per poll
  for no correctness benefit — multiplying read / CPU work by
  the configured partition count.

  Fix: collapse to 1 when FifoThroughputLimit is the perQueue
  short-circuit. Mirrors partitionFor's routing decision.

  TestEffectivePartitionCount_PerQueueModeCollapsesToOne pins
  this with 4 sub-cases (perQueue + 4, perQueue + 32, perMessageGroupId
  + 4, empty + 4) so a future refactor that drops the branch is
  caught.

2) Claude finding 1 — expand legacy-match test coverage

  The PR description claimed nil and PartitionCount=0 sub-cases
  for all 6 helpers, but the actual table only had them for
  sqsMsgDataKeyDispatch. Expanded to cover all 6 helpers. Without
  this, a future edit that drops the `meta != nil` guard from
  one of the non-data helpers would compile and pass the existing
  test suite.

  TestSQSKeysDispatch_LegacyMatchesLegacyConstructor grew from
  8 to 15 sub-cases.

3) Claude finding 2 — PartitionCount=2 boundary

  TestSQSKeysDispatch_PartitionedMatchesPartitionedConstructor
  used PartitionCount=4. An off-by-one in the dispatch
  threshold (>= 1 vs > 1) wouldn't be caught because 2 was
  never exercised. New TestSQSKeysDispatch_BoundaryAtPartitionCount2
  pins the boundary cheaply.

CodeRabbit nitpick on the eager-construction test pattern is
acknowledged as "Low value" in their own classification — left
as-is since the existing pattern is consistent with the project's
other table-driven tests.

go test -race ./adapter/... and golangci-lint clean.
@bootjp
Copy link
Copy Markdown
Owner Author

bootjp commented May 2, 2026

@claude review

Round 2 — addresses 3 round-1 findings:

Codex P2 (real, fixed): effectivePartitionCount now collapses to 1 when FifoThroughputLimit == "perQueue". Mirrors partitionFor's §3.3 short-circuit (sqs_partitioning.go:76 forces every MessageGroupId to partition 0 in perQueue mode). Without this, ReceiveMessage's fanout would scan up to 31 guaranteed-empty partitions per poll. New TestEffectivePartitionCount_PerQueueModeCollapsesToOne (4 sub-cases) ratchets against future regressions.

Claude finding 1 (real, fixed): PR description claimed nil/PartitionCount=0 sub-cases for all 6 helpers, but the actual table only had them for sqsMsgDataKeyDispatch. Expanded TestSQSKeysDispatch_LegacyMatchesLegacyConstructor from 8 → 15 sub-cases. A future edit dropping the meta != nil guard from any non-data helper now fails a test.

Claude finding 2 (real, fixed): New TestSQSKeysDispatch_BoundaryAtPartitionCount2 pins the > 1 threshold cheaply. An off-by-one in the dispatch condition would not have been caught by tests that only exercise PartitionCount=4.

CodeRabbit nitpick (eager construction in table rows, marked "Low value" in their own classification): left as-is to stay consistent with the project's other table-driven tests.

go test -race ./adapter/... and golangci-lint clean.

@claude
Copy link
Copy Markdown

claude Bot commented May 2, 2026

Claude finished @bootjp's task in 1m 53s —— View job


Review of PR #731 — Round 2

Todo

  • Post initial comment
  • Read adapter/sqs_keys_dispatch.go (current state)
  • Read adapter/sqs_keys_dispatch_test.go (current state)
  • Read adapter/sqs_partitioning.go to verify perQueue fix
  • Verify fix 1: perQueue mode collapse in effectivePartitionCount
  • Verify fix 2: nil/PartitionCount=0 sub-cases for all 6 helpers
  • Verify fix 3: PartitionCount=2 boundary test
  • Full review pass for any new issues
  • Post findings

All three round-1 findings are correctly addressed. No new issues.

Fix 1 — perQueue collapse in effectivePartitionCount

sqs_keys_dispatch.go:114 checks meta.FifoThroughputLimit == htfifoThroughputPerQueue and returns 1, which exactly mirrors partitionFor's short-circuit at sqs_partitioning.go:76. The precedence is also correct: the <= 1 guard fires first, so perQueue + PartitionCount=1 (unusual but not rejected by the validator) returns 1 via the first branch rather than accidentally reaching the perQueue branch — same result, right for the right reason.

The new TestEffectivePartitionCount_PerQueueModeCollapsesToOne (4 sub-cases) is well-constructed: it covers the max (32), the common case (4), the non-perQueue positive (perMessageGroupId → 4), and the empty-string negative (empty FifoThroughputLimit → 4). The last two sub-cases are important because they confirm the perQueue branch is genuinely conditional, not an accidental catch-all.

One observation worth tracking for PR 5b-2: when perQueue + PartitionCount=4, effectivePartitionCount returns 1 (iterate once on partition 0), but sqsMsgVisPrefixForQueueDispatch for that queue still returns the partitioned prefix (since PartitionCount=4 > 1). This is semantically correct — data was written to the partitioned keyspace on partition 0, so the read must scan the partitioned prefix for partition 0. The fanout wiring in PR 5b-2 should have a test that exercises this combination end-to-end.

Fix 2 — nil/PartitionCount=0 sub-cases expanded ✓

The 15 sub-cases break down as:

  • 6 nil sub-cases: all 6 helpers covered (sqs_keys_dispatch_test.go:32-48)
  • 3 PartitionCount=0 sub-cases: data, vis, and vis-prefix (sqs_keys_dispatch_test.go:50-59)
  • 6 PartitionCount=1 sub-cases: all 6 helpers (sqs_keys_dispatch_test.go:60-79)

The PartitionCount=0 gap for dedup, group, and byage is acceptable: nil is covered for all 6, PartitionCount=1 is covered for all 6, and the three omitted helpers are primarily SendMessage concerns (not the ReceiveMessage scan paths that motivated the original finding). The critical receive helpers — vis and vis-prefix — are fully pinned.

Fix 3 — PartitionCount=2 boundary test ✓

TestSQSKeysDispatch_BoundaryAtPartitionCount2 (sqs_keys_dispatch_test.go:149-168) pins both directions: the dispatched key equals the partitioned constructor AND does not equal the legacy constructor. Testing only the data key is sufficient here because all 6 helpers share the same > 1 condition — the boundary is structural, not per-helper.

CodeRabbit nitpick — eager table construction: agreed, left as-is ✓

The key constructors are pure functions with no shared state, so running them at slice-literal initialization time is harmless. The t.Parallel() call on each sub-test still provides parallel execution of the require.Equal assertions. Consistent with the project's table-driven test style.


Round 2 verdict: no further findings. Ready to merge.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant