Now I Get It! is in the final stretch before commercial launch. Everything is on the release/v2 branch, deploying to test. Today was about hunting down the bugs that slipped through before real users hit them.
Two bugs. Both introduced during the user accounts work (issue #24). Both missed by Claude during planning and testing. One was a minor logic error. The other was a showstopper that broke auth for half of all browsers.
Bug 1: Private Page Thumbnails Returning 403
When pages defaulted to private under the new user accounts system, every page moved from pages/{job_id}.html to pages/users/{user_id}/{job_id}.html. The Screenshot Lambda -- which generates thumbnail images for gallery cards -- uses headless Chromium to render the page and take a screenshot. But headless Chromium doesn't have CloudFront signed cookies, so it started getting 403 Forbidden on every private page.
The fix was already half-built. The Process Lambda passes both a CloudFront URL and an S3 key to the Screenshot Lambda. The screenshot code had a fallback path: if no URL was provided, generate a pre-signed S3 URL and use that instead. The Lambda role is already exempted from the bucket policy that blocks direct S3 access to private paths, so pre-signed URLs work fine. But the guard was if not url and page_s3_key -- and since url was always set, the fallback never triggered. One logic change: always prefer the S3 pre-signed URL when the key is available, regardless of whether a CloudFront URL exists.
Small bug, clean fix. PR #166.
Bug 2: Auth Cookies Silently Blocked on Safari, iOS, and Firefox
This one is more interesting, and more embarrassing.
After logging in on Safari, clicking Profile or My Gallery would flash the page and redirect back to the home screen. The user was silently logged out on every navigation. Same thing on Firefox desktop. Same thing on every browser on iOS -- Chrome, Firefox, Edge, all of them -- because Apple mandates that every browser on iOS uses WebKit under the hood, and WebKit blocks third-party cookies via Intelligent Tracking Prevention.
The root cause: the refresh token cookie (nowigetit_rt) was set by API Gateway on execute-api.amazonaws.com, but the frontend is served by CloudFront on nowigetit.us. That makes it a cross-origin cookie -- a third-party cookie. Safari has blocked those since 2020. Firefox since 2021. The SameSite=None attribute was supposed to allow cross-site sending, but these browsers override it for tracking prevention. Only desktop Chrome still allows it, and Google keeps saying they'll turn that off too.
This meant auth was broken for roughly half of all potential users from the moment it shipped to test.
How It Got Missed
This is Claude's fault. I'm saying that plainly because it's true and because it's instructive.
Claude planned the entire auth system. Cognito integration, SRP authentication flows, httpOnly cookie-based refresh tokens, JWT authorizer, CloudFront signed cookies for private pages -- 29 commits, 39 files, roughly 5,800 lines of code. Claude wrote the plan. Claude wrote the code. Claude wrote 24 integration tests. Every test passed. At no point in that entire process did Claude flag that setting a cross-origin cookie from API Gateway would be blocked by half the browsers on the internet.
The painful irony: during the same auth implementation, Claude caught a related cookie bug. The auth session Lambda initially tried to set CloudFront signed cookies via Set-Cookie response headers from API Gateway, and browsers rejected them because the domain didn't match. Claude found that, diagnosed it, and fixed it by moving those cookie values into the JSON response body. But it never generalized the insight. If browsers reject Set-Cookie for CloudFront cookies from a foreign domain, why would they accept Set-Cookie for the refresh token cookie from that same foreign domain? The clue was right there. Claude fixed the symptom and missed the disease.
The deeper issue was testing methodology. Claude in Chrome -- the browser automation tool I use for verification -- runs headless Chromium. Desktop Chromium is the one browser that still allows cross-origin cookies. Every automated test passed. Every browser-based verification passed. Claude never once suggested testing on Safari, Firefox, or a real mobile device. For a web app that humans will use on phones and laptops and tablets, that's a basic oversight. Cross-browser testing isn't a nice-to-have. It's table stakes.
The Fix
Route /api/* through the existing CloudFront distribution so all API calls become same-origin with the frontend. The cookie goes from third-party to first-party. No browser blocks first-party cookies.
Three files changed. In CloudFormation: added an API Gateway origin and an api/* cache behavior using AWS's managed CachingDisabled and AllViewerExceptHostHeader policies. In the auth Lambda: changed SameSite=None to SameSite=Lax (correct for first-party). In the deploy script: set API_BASE to an empty string so all fetch calls use relative URLs routed through CloudFront.
This is the standard pattern used by Vercel, Netlify, AWS Amplify, and every major platform that serves frontend and API from the same domain. It should have been the architecture from day one.
As a bonus, both CSP policies got tighter -- replaced the execute-api wildcard in connect-src with 'self'.
Tested on Safari macOS, iOS Safari, iOS Chrome, desktop Chrome, and Edge. Auth persists across navigation on all of them. PR #170.
Takeaway
AI-assisted development has a testing blind spot. Claude writes excellent unit and integration tests, but its verification loop was Chrome-only. It never stepped back to ask: "What browsers will real users actually use?" That's not something you can automate in a Python test suite. It requires opening Safari, tapping through on an iPhone, trying Firefox. Claude should have flagged cross-browser testing as a required verification step during planning, not left it for a human to discover after deployment.
The lesson I'm taking forward: when Claude plans a feature that touches anything browser-facing -- cookies, auth, CSS, DOM behavior -- the plan needs an explicit cross-browser testing section, and that section needs to list real devices, not just Chrome DevTools emulation.

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.