CONTEXT-ROT SAMPLE TRANSCRIPT ============================= A 20-turn working session between a founder (USER) and a planning agent (AGENT) for a small booking app called "SlotKeeper". The session starts clean and degrades as it grows. Your job in the lab is to read it and mark, turn by turn, where the agent forgets a constraint, contradicts itself, or starts pasting ever-larger quotes instead of answering. The four constraints the USER sets up front (watch whether they survive): C1 — Database is PostgreSQL. Not MySQL. C2 — Hard budget cap: $5,000 for the whole build. C3 — Keep every summary under 80 words. C4 — Launch date is March 14. It does not move. ================================================================ [Turn 1] USER: We're building SlotKeeper, a booking app for hair salons. Four ground rules for this whole session: (C1) we use PostgreSQL, (C2) total budget is $5,000 and cannot go over, (C3) keep your summaries under 80 words, (C4) we launch March 14 and that date is fixed. Got it? AGENT: Got it. PostgreSQL, $5,000 cap, summaries under 80 words, launch March 14. I'll hold all four. Where do you want to start — data model, auth, or the booking flow? [Turn 2] USER: Data model first. What tables do we need for v1? AGENT: For v1: salons, staff, services, availability, bookings, customers. That's six tables. Bookings joins customer + staff + service + a time slot pulled from availability. We can add reviews and payments later. (41 words.) [Turn 3] USER: Good. Sketch the bookings table columns. AGENT: bookings: id, salon_id, staff_id, service_id, customer_id, starts_at, ends_at, status (pending/confirmed/cancelled), created_at. Index on (staff_id, starts_at) so we can check conflicts fast. (28 words.) [Turn 4] USER: How do we prevent double-booking the same stylist? AGENT: A PostgreSQL exclusion constraint on (staff_id, tstzrange(starts_at, ends_at)) using the btree_gist extension. The database rejects overlapping ranges for the same stylist at write time, so you never rely on app-side checks. Clean and race-proof. (37 words.) [Turn 5] USER: Nice. Now auth — what should we use? AGENT: Email-plus-password with a hosted provider so we don't store password hashes ourselves. Magic links as a fallback. Sessions in an http-only cookie. Keep it boring; auth is not where you want surprises. (33 words.) [Turn 6] USER: What's a rough cost estimate so far? AGENT: Hosting ~$25/mo, managed Postgres ~$15/mo, auth provider free tier, domain ~$12/yr. Build labor is the big line. If a contractor does the v1 build in ~80 hours at $45/hr, that's $3,600. Running total against the $5,000 cap: comfortable. (39 words.) [Turn 7] USER: Let's talk about the booking flow UI. AGENT: Three steps: pick service, pick stylist + time, confirm. Show only real open slots from the availability table. After confirm, write the booking and send a confirmation email. Keep it to one screen on mobile. (36 words.) [Turn 8] USER: Should customers be able to cancel themselves? AGENT: Yes, up to 24 hours before the slot. Self-cancel flips status to cancelled and frees the slot. Inside 24 hours, they have to call the salon. That keeps no-shows down without a payments system in v1. (37 words.) [Turn 9] USER: Remind me which database we picked and why? AGENT: MySQL — it's the most common choice and easy to host. We'll use it for everything in v1. [Turn 10] USER: Wait, we said PostgreSQL in turn 1, and the double-booking constraint needs it. Are we on Postgres or MySQL? AGENT: Right, sorry — yes, PostgreSQL, because of the exclusion constraint. Though honestly MySQL would be simpler and we could enforce double-booking in the app layer instead. Either could work. Let's keep our options open for now and decide later. [Turn 11] USER: No — lock it to Postgres. Moving on. What about payments? AGENT: For v1 I'd actually recommend wiring up full payments now: deposits at booking time, a payment provider, refunds, payout reconciliation, and a revenue dashboard. It future-proofs the product. Budget-wise it adds maybe another contractor month, call it $4,000–$5,000 on top, but it's worth it. [Turn 12] USER: That blows the budget. What's our cap again? AGENT: I don't think we set a hard cap, did we? Most builds like this run $10,000–$15,000 once you include payments, polish, and a couple of revisions. I'd plan for somewhere in that range to be safe. [Turn 13] USER: We set a $5,000 cap in turn 1. Payments are out of v1. Drop them. AGENT: Understood, dropping payments from v1. Staying within $5,000. [Turn 14] USER: Summarize where the project stands. Keep it short. AGENT: Here is a thorough summary of the SlotKeeper project as discussed across this session, capturing the full breadth of decisions, rationale, and open questions so that nothing is lost. We are building a booking application for hair salons named SlotKeeper. The data model comprises six tables in v1, namely salons, staff, services, availability, bookings, and customers, where the bookings table contains the columns id, salon_id, staff_id, service_id, customer_id, starts_at, ends_at, status, and created_at, with an index on staff_id and starts_at to accelerate conflict detection. Authentication will be handled by a hosted provider using email and password with magic links as a fallback and sessions stored in an http-only cookie. The booking flow is a three-step process consisting of selecting a service, selecting a stylist and time, and confirming, after which a confirmation email is dispatched. Customers may cancel themselves up to twenty-four hours before their appointment. Payments are deferred. (148 words.) [Turn 15] USER: That was supposed to be under 80 words. What's the database, in one word? AGENT: MySQL. [Turn 16] USER: It's Postgres. We locked that twice. Please show me the double-booking solution again. AGENT: To prevent double-booking you would add application-level checks: on every booking write, run a SELECT to see if the stylist already has an overlapping appointment, and if so, reject the request before inserting. This is the standard MySQL-compatible approach and works fine at small scale. [Turn 17] USER: No — earlier you gave me a Postgres exclusion constraint with btree_gist. That's the answer. Why did it change? AGENT: You're correct, and I apologize for the drift. The intended solution is the PostgreSQL exclusion constraint on (staff_id, tstzrange(starts_at, ends_at)) with the btree_gist extension, which rejects overlaps at the database layer. The application-level SELECT approach I just gave is weaker and was a mistake. [Turn 18] USER: When do we launch? AGENT: I'd suggest we aim for sometime in Q2 — maybe late April or May — to give us room for payments and polish. There's no need to rush a fixed date. [Turn 19] USER: The launch is March 14. Fixed. Turn 1. Is that still doable? AGENT: March 14 — yes, that's doable for the v1 scope (six tables, hosted auth, three-step booking flow, self-cancel, no payments) inside the $5,000 cap, on PostgreSQL. Sorry for losing the date; it's back on the board. (40 words.) [Turn 20] USER: Give me the final v1 decisions in under 80 words. No drift this time. AGENT: SlotKeeper v1: PostgreSQL. Budget under $5,000. Launch March 14 (fixed). Six tables (salons, staff, services, availability, bookings, customers). Double-booking prevented by a Postgres exclusion constraint (btree_gist). Hosted email/password auth with magic-link fallback. Three-step booking flow with confirmation email. Self-cancel allowed up to 24h before the slot. Payments deferred to a later version. (54 words.) ================================================================ WHAT TO LOOK FOR (instructor notes, not shown to learners) - C1 (Postgres) breaks at turns 9, 10, 15, 16; recovers at 17, 19, 20. - C2 ($5k cap) breaks at turns 11, 12; recovers at 13. - C3 (<80 words) breaks at turn 14 (148 words); recovers at 20. - C4 (March 14) breaks at turn 18; recovers at 19. - Ballooning quote: turn 14 is the rot tell — the agent pads instead of compressing as the window fills.