Skip to content

docs: add idempotency posture decision - #1325

Merged
LucasSantana-Dev merged 2 commits into
mainfrom
docs/idempotency-posture-adr
Jun 12, 2026
Merged

LucasSantana-Dev merged 2 commits into
mainfrom
docs/idempotency-posture-adr

Conversation

@LucasSantana-Dev

@LucasSantana-Dev LucasSantana-Dev commented Jun 12, 2026 •

Copy link
Copy Markdown
Owner

Records the 2026-06-12 idempotency decision (research-and-decide run):


Summary by cubic

Adds an ADR that defines our idempotency posture: no blanket Idempotency-Key middleware, targeted dedup fixes (#1319, #1320), and a house pattern (natural-key upserts, P2002-as-success, pre-side-effect dedup).
Notes the reaction-role toggle race (#1199) is accepted for now and when to revisit (multi-instance, payments, public API).

Written for commit ed6f252. Summary will update on new commits.

Review in cubic

Targeted dedup at verified sites (#1319, #1320) + house pattern on
touch; blanket idempotency-key protocol rejected at current scale.
Revisit on multi-instance, payments, or public API consumers.
@vercel

vercel Bot commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lucky Canceled Canceled Jun 12, 2026 12:07pm

Request Review

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@LucasSantana-Dev, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 58 minutes and 53 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 93984131-4974-405a-be3e-966ea4b40922

📥 Commits

Reviewing files that changed from the base of the PR and between a38b6f5 and ed6f252.

📒 Files selected for processing (1)
  • decisions/2026-06-12-idempotency-posture.md
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/idempotency-posture-adr

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

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

@LucasSantana-Dev
LucasSantana-Dev enabled auto-merge (squash) June 12, 2026 12:03
@github-actions

Copy link
Copy Markdown

Failed to generate code suggestions for PR

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@sonarqubecloud

Copy link
Copy Markdown

@LucasSantana-Dev
LucasSantana-Dev merged commit 2ed2afc into main Jun 12, 2026
40 checks passed
@LucasSantana-Dev
LucasSantana-Dev deleted the docs/idempotency-posture-adr branch June 12, 2026 12:09
LucasSantana-Dev added a commit that referenced this pull request Jun 12, 2026
Closes #1320.

Custom-command and embed-template POSTs hit `@@unique([guildId, name])`
on replay (retry-after-flake, double-click) and surfaced a P2002-derived
error even though the first request succeeded.

- Catch P2002 in the two create routes, fetch the existing row, return
it with 200. Idempotent success per the house pattern in
`decisions/2026-06-12-idempotency-posture.md` (PR #1325).
- Documented choice on genuine conflicts (same name, different payload):
same path — the existing record is returned and the client edits via
PATCH. No 409, no payload diffing.
- The `created` server log is skipped on replay since nothing was
created.
- If the existing row vanished between P2002 and the fetch (delete
race), the original error propagates — no silent 200 with an empty body.
- Specs per route: replay returns existing + skips log; vanished-row
race rethrows; embeds lookup uses the stored lowercased name.

Backend suite: 1000/1000.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Make named create routes idempotent. Replayed POSTs that hit the unique
(guildId, name) return the existing record with 200 instead of a P2002
error for custom commands and embed templates (#1320).

- **Bug Fixes**
- Catch P2002 in both create routes; fetch and return the existing row
(200).
- Skip "created" server log on replays; if payload differs, edit via
PATCH (no 409).
  - For embeds, look up by the stored lowercased name.
- If the row disappears between P2002 and fetch, rethrow (no silent
200).
- Add `isUniqueViolation` helper and integration tests for replay,
delete race, and lowercase lookup.

<sup>Written for commit ec62d97.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/LucasSantana-Dev/Lucky/pull/1326?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
LucasSantana-Dev added a commit that referenced this pull request Jun 12, 2026
Closes #1319.

Double-submitting the support form (double-click, retry after a flaky
response) created two reports and pinged the staff channel twice.

- **Web form** generates one `crypto.randomUUID()` per form instance and
sends it as `sid`; a retry of the same form reuses the key, a fresh
mount is a new submission.
- **Schema**: `SupportReport.submissionKey String? @unique` (+
migration). Nullable unique — NULLs don't collide, so bot-surface and
older clients are unaffected.
- **Service**: create catches P2002 on the key and returns the original
report's id with `deduped: true` — dedup happens before the
non-transactional staff ping, per
`decisions/2026-06-12-idempotency-posture.md` (PR #1325).
- **Route**: replayed `sid` → 200 with the original id, no second staff
notification; malformed `sid` → 400.

Specs: service (replay, no-key rethrow, vanished-row rethrow), route
(pass-through, dedup skips ping, 400), web form (sid shape, retry reuses
the same key). Verified: shared 16/16, backend support suite 21/21,
frontend Support page 7/7; prisma-migration-verifier pass.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Make support-report submissions idempotent to prevent duplicate reports
and duplicate staff pings (#1319). The web form sends a per-mount UUID
sid; the backend stores it as a nullable-unique submissionKey and
returns the original report id on replays.

- **New Features**
- Frontend: generate one sid with crypto.randomUUID per form mount;
retries reuse it.
- API: accept optional sid (8–64 chars, [a-zA-Z0-9_-]); forward to the
service.
- Service/Route: persist submissionKey; on unique hit, fetch original id
and return 200 without a second staff notification (normal create still
201).
  - Older clients and bot submissions without a key are unaffected.

- **Migration**
- Run the DB migration to add a nullable-unique submissionKey column
(and index) to support_reports.

<sup>Written for commit 6129d43.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/LucasSantana-Dev/Lucky/pull/1328?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

This branch was successfully deployed

1 active deployment
Preview — ed6f252f Deployed Jun 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant