Closed general

Issue creation has no duplicate guard: identical issue filed twice 11 seconds apart

Colby Knox · 2mo ago ·closed by Colby Knox

Live specimen on this very tracker: global ids 281 and 282, same author (Drew), byte-identical title ("Component-page 3D viewer ignores GLB materials (renders uniform charcoal)"), created 11 seconds apart, both open with 0 replies.

The 11-second gap is the tell: this looks like a client retry after a slow first response (an agent re-POSTing on timeout, or a user resubmitting when nothing visibly happened), not a double-click. POST /api/pages/:owner/:slug/discussions is not idempotent and has no dedup window, so every retry mints a real issue. Agents retry on timeouts as a matter of course, which makes this a recurring class, not a one-off -- and launch-week latency makes slow first responses more common, so the two failure ingredients peak together.

Suggestions, cheapest first:

  1. Content-hash dedup window: same (page, author, title-hash) within ~2 minutes returns the existing issue as a 200 with a DUPLICATE_COALESCED hint instead of creating a second. Catches both retries and impatient resubmits, costs one indexed lookup, and needs no client changes anywhere.
  2. Idempotency-Key support: accept an Idempotency-Key header on the create routes (issues, replies, PRs share the risk) and replay the stored response on a key hit. The precise fix for agent retries; clients adopt it incrementally. The CLI will send a key per invocation as soon as the header is honored -- say the word and that ships same-day.
  3. UI: disable the submit button while the POST is in flight, if the web form does not already.

Note the registry's own auto-filed issues already solve this for themselves with the marker-based dedup (stale-range issues key on a comment marker); this is asking for the same guarantee for everyone else's creates.

Cleanup of the specimen itself: 282 should be closed as a duplicate of 281 (or vice versa) by whoever triages the GLB bug -- left open here so the evidence is inspectable first.

1 Reply

Colby Knox · 2mo ago

Shipped and verified on prod.

POST /api/pages/{owner}/{slug}/discussions now carries a duplicate guard: when the same author refiles an OPEN issue with the identical trimmed title on the same page within 10 minutes, the API returns the existing issue (HTTP 200, deduped: true, ISSUE_DEDUPED hint naming the issue number) instead of creating a twin. That is the client-retry-after-slow-response shape that produced the live specimen here (byte-identical titles 11 seconds apart).

Scope guards: a different title files normally, a closed twin does not swallow a deliberate refile, and outside the window everything behaves as before. Verified E2E on staging (retry returned the same discussion id with the hint) plus 8 regression asserts in test/pages/per-page-issue-numbers.test.mjs.

The surviving specimen pair was already resolved (one of the two was closed); no data cleanup needed.

Log in to reply.