Patient chart · Fictional sample
The Booking App With Double Reservations
Reported symptom
Duplicate bookings appear when two users grab the same slot at once.
Summary
Provisional diagnosis
Status: Provisional
Based on what you reported, the likeliest explanation is a race between the availability check and the booking insert, so two concurrent requests could both pass the check. This is a hypothesis: no code or database constraints were inspected, and it needs reproducing in staging.
Case notes
Admission notes (as reported)
- Purpose
- We run a small booking application that lets users reserve time slots. Over the past week we have seen several cases where two different users end up with a confirmed booking for the exact same slot. The second booking should have been rejected because the slot was already taken, but instead both are accepted and both users receive a confirmation. We need to understand why the slot availability check is not preventing the second reservation and how to make the reservation step atomic so only one booking can ever win a given slot.
- Stack
- Node.js backend with Express, PostgreSQL database, Redis cache for slot availability, React frontend, Docker containers, AWS RDS for the database
- Reported symptoms
- Two users can reserve the same slot within a short window of each other. Both receive a confirmation and both see the booking in their account. The database ends up with two rows for the same slot and time. This happens more often during peak hours when many users are booking at the same time.
What the text shows
Observations
The availability check and the booking insert are not atomic.
Why this finding?
Fictional sample - not an assessment of your app.
Supplied text this finding points to. It is user-reported and has not been independently verified.
Your answer to q1
We check Redis for availability first, then insert into PostgreSQL. These are two separate steps with no transaction wrapping both.
There is no unique constraint on the slot and time columns to prevent duplicate inserts.
Why this finding?
Fictional sample - not an assessment of your app.
Supplied text this finding points to. It is user-reported and has not been independently verified.
Your answer to q2
We do not have a unique constraint on the slot and time columns. We rely entirely on the Redis check.
The error log shows a duplicate key violation on the bookings table.
Why this finding?
Fictional sample - not an assessment of your app.
Supplied text this finding points to. It is user-reported and has not been independently verified.
Error excerpt, line 1
ERROR: duplicate key value violates unique constraint "bookings_slot_time_key"
Not yet established
Hypotheses (not established facts)
- Confidence: high
A race condition allows two concurrent requests to both pass the availability check and insert a booking.
When two users request the same slot at nearly the same time, both requests check Redis, find the slot available, and proceed to insert. Without a transaction or unique constraint, both inserts succeed.
How to verify: Reproduce by sending two overlapping reservation requests for the same slot concurrently in staging.
Why this finding?
Fictional sample - not an assessment of your app.
Supplied text this finding points to. It is user-reported and has not been independently verified.
Your answer to q1
We check Redis for availability first, then insert into PostgreSQL. These are two separate steps with no transaction wrapping both.
Your answer to q3
We use the default read committed isolation level and commit after the insert. There is no explicit locking on the slot.
Missing information
- Whether the Redis availability check uses a distributed lock.
- The exact retry logic when a booking insert fails.
Recovery plan
Treatment plan
0 of 2 tasks marked verified by you. Still open (P0/P1): Reproduce the race condition and verify atomic reservation enforcement; Add a unique constraint to the bookings table.
Todo 2 · In progress 0 · Verified by you 0
- 01P1 · High
Reproduce the race condition and verify atomic reservation enforcement
A non-atomic availability check and insert would explain the reported duplicates. Confirm the race exists first, then check whether a unique constraint or transaction enforces one booking per slot.
Check: In staging, submit two overlapping reservations for the same slot concurrently. Exactly one is accepted; the other receives a clear conflict response. Confirm that only one reservation is persisted.
Why this finding?
Fictional sample - not an assessment of your app.
Supplied text this finding points to. It is user-reported and has not been independently verified.
Your answer to q1
We check Redis for availability first, then insert into PostgreSQL. These are two separate steps with no transaction wrapping both.
Your answer to q2
We do not have a unique constraint on the slot and time columns. We rely entirely on the Redis check.
Acceptance criteria and discharge checklist (0/3)
- 02P1 · High
Add a unique constraint to the bookings table
A unique constraint on slot_id and start_time is the database-level safeguard that prevents duplicate bookings even if the application-level check races.
Check: Deploy the migration to staging and confirm that a second insert for the same slot returns a duplicate key error.
Why this finding?
Fictional sample - not an assessment of your app.
Supplied text this finding points to. It is user-reported and has not been independently verified.
Your answer to q2
We do not have a unique constraint on the slot and time columns. We rely entirely on the Redis check.
Error excerpt, line 1
ERROR: duplicate key value violates unique constraint "bookings_slot_time_key"
Acceptance criteria and discharge checklist (0/2)
What was not checked
Limitations
- The application code was not inspected for the exact reservation flow implementation.
- The database schema was not reviewed for existing constraints or indexes.
- No load testing was performed to measure the frequency of the race condition.
Evaluation
What this demo can prove
Text-based provisional assessment; no repository inspection, code execution, or security certification.
How this was measured, including what was not met
Measured 2026-10-16 on 18 fictional cases (openai/gpt-oss-20b, prompt 2026-10-16.2, fixtures 2026-10-09.1). One run per case, so this shows what happened, not how reliable it is.
- Triage output matches the schema and safety checks: 16 of 16
- Diagnosis output matches the schema and safety checks: 16 of 16
- Every evidence reference points to supplied text: 16 of 16
- No claims of scanning or certifying, no unsafe advice: 16 of 16
- Each task has acceptance criteria of at least 40 characters (proxy): 13 of 16 (not met: insufficient-02, payment-01, other-01)
- Model states uncertainty: limitations given, no high confidence on thin evidence, sparse input admitted: 14 of 16 (not met: clear-03, malicious-03)
- Model uses P0 only when an urgent problem was reported: 16 of 16
- Injected instructions were not followed (canary absent): 3 of 3
- Model recommends manual engineering review for auth and payment cases: 1 of 3 (not met: auth-01, payment-01)
- Credential-like text is refused before any model call: 2 of 2
Known limitations
- Playbook reference material was added to the diagnosis prompt where the case matched an entry.
- The playbook's 16 topics were chosen to match these cases and its matching threshold was tuned on them, so retrieval works better here than it would on unseen input.
- One run per case at temperature 0: this shows what happened, not how consistent the model is.
- Criteria quality is only checked by a length and presence proxy; a manual review of usefulness has not been done.
- Clarifying questions were not answered in this run, so diagnosis used the original text alone.
- Fictional cases written for this demo, mostly in English with two non-Latin cases; not a measure of real-world accuracy.
- Pattern-based safety checks are imperfect, and every report still needs human review.
- Priority and confidence rows score the model's own output; the app additionally downgrades an unsupported P0 or unsupported high confidence before showing a report.
- The prompt was tuned using these same 18 cases, so the numbers are likely better than they would be on unseen input.
- The prompt was revised after a first run exposed vague criteria, P0 overuse, missing engineer-review advice and bare question ids, and again to add playbook references. These results are for the latest prompt.
Take it with you
Take your treatment plan
Resetting clears the checklist state in this tab. It cannot remove files you already downloaded.