iOS app, simulator, Xcode, Swift crash, .ips crash log, Capacitor shell misbehaving, WKWebView rendering wrong (e.g. border-radius not clipping a composited img), in-app sign-in bounced to Safari, app stuck on splash / OTA rollback, webview UA flagged as in-app browser, Clerk/Apple/Google social sign-in failing in a Capacitor app — authorization_invalid / native_api_disabled / origin_authorization_headers_conflict / oauth_token_apple / "native social login won't work in the app", OR a passkey/WebAuthn ceremony failing in the webview — "passkey registration was cancelled or timed out", webcredentials, associated domains, AASA 404 | iOS App Symptoms — route to the /ios skill (dev/debug loop, axiom crash/build/perf agents, webview driving via axe, simulator streaming/eyes + taps + :3100/ax a11y tree via the /serve-sim skill, AIVA Capacitor traps incl. clerk-js allowedRedirectProtocols, notifyAppReady rollback, WKWebView clip bug). Any in-webview auth/credential ceremony fails with a GENERIC error until the app↔domain binding exists — read /ios trap #12's binding matrix and PROBE FIRST: social-OAuth Apple → trap #4 (allowNavigation); Google → policy-blocked, hide it; clerk-js scheme → allowedRedirectProtocols; passkey "cancelled or timed out" → curl <domain>/.well-known/apple-app-site-association + grep entitlements for webcredentials (improvebayarea dadfdf3). Don't debug the JS ceremony before the 30-sec probe. | /ios skill (~/.claude/skills/ios/SKILL.md) |
| catch-all, generic error, wrong status code, misleading error | Catch-All Error Masking (#1) | error-handling-patterns.md |
| SF311 save 500, Verint save 500, Improve AI resubmit, category changed 500, request_type_id 500 | External Municipal Form Category Hard-500 (#15) | error-handling-patterns.md |
| ticket description truncated, navFooter dropped, map links missing, address missing on filed ticket, description ends abruptly, external form truncation, Verint dform Request_description, bracket truncation, square bracket strip | External Form Description Truncation by Character (#19) | error-handling-patterns.md |
| 311 ticket missing Location box, Open311 address null, mobile311 viewer shows description but no Location dt/dd, "one ticket has location another doesn't", sf_full_address dropped, Location_description ignored, structured location empty, lat/long null in Open311, address only in description body not the actual location field, scf location_details, address forwarding broken, coord-string in structured slot, "hardening 311 address forwarding", multi-city address never break | 311 Structured-Location Dropped by Long-Form / Coord-String Address (#21, backend-agnostic) | error-handling-patterns.md |
| DBI complaint reported as validation but city has it, "DBI re-rendered the form (validation rejected the submission)" but DataSF shows the case, third-party form rejected but actually recorded, form echoed back on success, parser says failure but the agency received it, external form 200 OK we classified as failure, complaintNumber undefined but submission worked, dform/Verint/aspx false-negative on success, success-detection heuristic matches both success AND failure pages, lblError success vs failure span, signal-extraction tests use synthetic HTML, every IBA-submitted DBI complaint fails | Third-party signal-extractor false-negative due to synthetic fixtures (#23) | error-handling-patterns.md + ~/.claude/skills/shared/third-party-signal-fixtures.md |
| CI false positive, grep wrong, CI still fails | CI False Positives (#11) | error-handling-patterns.md |
| admin 403, requireAdmin, metadata-only | Admin Auth Missing DB Fallback (#14) | error-handling-patterns.md |
| admin 500 instead of 403 | Admin Route Wrong Status | error-handling-patterns.md |
| react undefined, scope bug, not defined | React Scope Bug (#2) | react-patterns.md |
| silent startup, blank page, no console errors, module-level throw | Silent React Startup (#3) | react-patterns.md |
| useEffect, renders twice, state lags, derived state | useEffect Abuse (#15) | react-patterns.md |
| localStorage, preference lost, resets on refresh | Preference Lost on Reload (#13) | react-patterns.md |
| double click, duplicate API call, async button | Async Button Double-Click | react-patterns.md |
chat/support widget gone after SSR, cookie banner missing on SSR page, ?support=open/deep-link does nothing, global widget vanished after Hono/Astro/RSC conversion, "worked on every page before SSR", floating launcher dead, analytics/exit-intent dropped on SSR route | Global App.tsx Component Vanishes After SPA→SSR Conversion (#24) | react-patterns.md |
invisible text after SSR, white headings on light/gray bg, page background wrong color after conversion, "colors got messed up on conversion", body background overridden, SSR design clobbered by Tailwind/island CSS, text disappeared but HTML is there, computed bg ≠ design token, low contrast only on SSR pages, island/global CSS leaks body styles | Bundled Island/Global CSS Clobbers SSR Inline Design — Invisible Text (#25) | react-patterns.md |
| auth guard, unauthenticated error, no redirect | Missing Frontend Auth Guard | react-patterns.md |
renders undefined, shows NaN, "Invalid Date", "[object Object]", toggle/section/control disappeared or silently vanished, "make sure nothing is undefined", Cannot read properties of undefined, is not iterable, null-gate hides UI, useState<T|null> gates a render, .map/property access on possibly-undefined API data, admin/dashboard renders garbage, optional chaining missing | Undefined / Null-Render Safety (9-pattern catalog + live DOM grep for undefined/NaN/[object Object]) — also re-sweeps the adjacent admin blind-spot class (default-LIMIT truncation, NULL-aggregate sort burial, count-source mismatch, inner-JOIN row drop, admin-auth DB fallback) | ~/.claude/skills/shared/undefined-null-render-safety.md |
generic isRecord/isObject guard, as unknown as T, (x as any).field, repetitive type-guard boilerplate, "vibe coding" / AI-slop TypeScript, loose unknown-everywhere, no schema validation at boundary, Record<string, unknown> everywhere | Anti-Slop TypeScript — replace generic guards/casts with named types, discriminated unions, or Zod (z.infer); detector: ~/.claude/skills/carmack/tools/detect-ts-slop.sh | ~/.claude/skills/shared/anti-slop-typescript.md |
| text overflow, min-w-0, flex escape, card boundary | Text Overflow Flex+Grid (#12) | css-layout-patterns.md |
| grid mobile, grid-cols, responsive breakpoint | Fixed Grid Breaks Mobile | css-layout-patterns.md |
| iOS Safari, blank iPhone, PDF iframe, vh units | iOS Safari Rendering | css-layout-patterns.md |
| og image, twitter card, social cache, stale card | Social Card Cache (#5) | csp-cache-patterns.md |
| CSP, embed blank, frame-src, img-src, broken icons | CSP Blocking (#9) | csp-cache-patterns.md |
YouTube "Error 153", "Video player configuration error", embed shows gray panel / "Watch video on YouTube", Vimeo/Spotify/SoundCloud embed won't load, video plays on youtube.com but not on my site, embed broke after adding security headers / secureHeaders() / Hono | Embed Dies With No Referer (#27) — NOT CSP, NOT the video. The page sends Referrer-Policy: no-referrer (Hono secureHeaders() default; also .htaccess / WP security plugins / ad blockers). YouTube has refused Referer-less embeds since late 2025. Probe FIRST, 30s: curl -sI https://<site>/ | grep -i referrer-policy (→ no-referrer = confirmed) and curl -s -o /dev/null -w "%{http_code}" "https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=<ID>&format=json" (200 = video is fine; 401 = embed disabled; 404 = dead). Fix = referrerpolicy="strict-origin-when-cross-origin" on the iframe — never weaken the global header. Verify on the DEPLOYED artifact (hono/jsx vs React attribute casing can drop it) + a real browser screenshot; allow >30s for Worker propagation before concluding. Sweep the repo for the sibling bugs: rendered hrefs containing whitespace (renderer swallowed prose into the URL) and bare URLs rendering as dead text. | csp-cache-patterns.md (Pattern 27) |
| Cloudflare security alert, Security Insights CSV, security.txt missing, /.well-known/security.txt 404, securityheaders.com low score, observatory grade D, missing HSTS/CSP/COOP/CORP, CAA records, DNSSEC, RFC 9116, sitemap.xml 404, robots.txt advertises sitemap that doesn't exist | Site Security Baseline (#16) | ~/.claude/skills/shared/site-security-defaults.md |
CF Security Insights flags: "Dangling A/AAAA", "Unproxied CNAME", "DMARC Record Error", "Bot Fight Mode not enabled" — DO NOT blindly apply CF's recommended fix; ~16% are false positives that break Clerk/SaaS CNAMEs, delete live Google-forwarding DNS, or duplicate valid DMARC. dig/curl-verify the OFTEN-FALSE classes first. Apply only the 3 safe fixes (security.txt + block AI bots + AI Labyrinth). | CF Security Insights triage map | ~/.claude/skills/shared/site-security-defaults.md (triage section) + ~/.claude/skills/carmack/tools/cf-security-insights.sh |
DMARC failing from a sender IP, custom-domain mail bouncing / landing in spam, "send-as alias DMARC fail", Gmail "Send mail as", p=reject rejecting my OWN mail, "SPF passes but DMARC fails", "can't send from my domain", forwarded mail failing DMARC, a DMARC aggregate (RUA) report flags a source — this is OUTBOUND auth alignment, NOT broken records. Records are usually fine; the sending path is wrong (Gmail send-as / a relay signs as the wrong domain → no aligned identifier → DMARC fail). dig the real SPF/DMARC/DKIM/MX FIRST; adding the relay's IP to SPF usually does NOTHING (SPF aligns on the envelope domain). Check the platform's CURRENT native send capability before recommending a 3rd-party — verify live, not from memory: a Cloudflare domain can now SEND via Email Sending (wrangler email sending list/settings; smtp.mx.cloudflare.net:465, user api_token, pwd = CF token w/ Email Sending Write). Fix = route the From-domain's sending through a DKIM-aligned sender; verify with a REAL send (gog send --from <alias> → grep dmarc=pass). | Email Deliverability / DMARC Alignment | ~/.claude/skills/shared/email-deliverability-dmarc.md |
provider swap, replace Resend/Auth0/Stripe/S3/Twilio with X, migrate email/auth/payments provider, "switch from X to Y", removed the old SDK, deleted the old API key, feature silently stopped after swapping providers, if (!env.OLD_KEY) gate, legacy ids unresolvable, old provider ids in DB | Provider Migration Safety — four silent breakages, none of which throw: (1) feature gates still testing the OLD provider's env var (incl. CRITICAL_ENV_VARS) → feature disabled forever once the secret is deleted; (2) persisted legacy identifiers the new API can't resolve → zero rows → a confident wrong status; (3) the new SDK returns {data,error} instead of throwing → every failure reads as success; (4) the local emulator (wrangler dev) doesn't enforce the new provider's server-side rules → local green ≠ prod accepted. Run the 7-item checklist. Never decommission the old account off one repo's grep — another project may hold a live key on the same verified domain. | ~/.claude/skills/shared/provider-migration-safety.md |
status chip says "expired"/"not found" on rows that are fine, freshly-created record reads as missing, a uniform block of rows all show the same scary status, status derived from analytics/GraphQL/search backend, zero rows treated as a reason, retention_expired on brand-new data | Absent Data Reported As A Confident Wrong State (#29) — rows.length === 0 has ≥4 causes (ingestion lag, wrong id namespace/provider, real retention expiry, never created, query failed) and they need different words. Discriminate on identifier SHAPE before querying (free), use the system of record's created_at vs the backend's ingestion grace window to separate lag from expiry, model reasons as a union, and never render a raw enum in the UI. | error-handling-patterns.md (Pattern 29) |
third-party submit "worked" (200 + id, no error) but the ticket/record never went live — never got a public number, never opened, never associated, openedAt: null, publicId: null, submittedTickets: 0; guest/anonymous create dead-ends silently; A/B-tested a flag/category/field and the symptom stayed IDENTICAL; "why does spotmobile/guest submit never get a case number"; freshly-minted guest token; shadow-limited actor; "is it the payload or something else" | False-Positive Success — async lifecycle is the real signal + IDENTITY is the hidden variable (#30) — a synchronous 200+id is a pending state, not done; gate success on the lifecycle transition (public number / opened / row in public dataset), polled, against a known-good baseline. When fix-A/fix-B/fix-C leave the symptom byte-identical, STOP editing the request — the actor/identity/account you held constant is the variable; re-run the SAME payload under a known-good established identity FIRST. Prove the working backend by RUNNING THE REAL FUNCTION LIVE (repro harness → real id), never from old code or a "Verified" comment. | error-handling-patterns.md (Pattern 30) |
"the deploy broke prod", Failed to load module script ... MIME type "text/html", SPA won't mount after deploy, only SEO fallback text renders, ERR_BLOCKED_BY_CLIENT, page worked 5 min ago, verifying a deploy in a :9222/clone browser | Your Verification Browser Is Stale — False "Prod Is Broken" (#28) — a cached HTML shell references pre-deploy asset hashes; the SPA fallback serves index.html for the missing .js; the browser refuses HTML as a module script. Production is fine; only your tab is broken. NEVER conclude a bad deploy from a browser alone: curl the live HTML for its asset refs, confirm each returns 200 text/javascript (not text/html), and grep the deployed chunk for a string only your new code has. location.reload(true) is a no-op; use navigate_page {ignoreCache:true} or a cache-busting query param. ERR_BLOCKED_BY_CLIENT = ad blocker, not your code. | csp-cache-patterns.md (Pattern 28) |
npm install fails with "Socket npm exiting due to risks", socket blocks install, SOCKET_CLI_VIEW_ALL_RISKS=1 prints nothing, "socket won't let me install", install works with SOCKET_CLI_ACCEPT_RISKS=1 but not without, deps missing after a "successful" npm ci, Cannot find type definition file for '@cloudflare/workers-types' right after install, vitest/tsc missing though they're in package.json | Socket CLI fails CLOSED when it has no API token (verified 2026-07-23) — it aborts the install AND cannot name the risk, because naming it requires the API the missing token would authenticate. The failure LOOKS like a security finding; it is a config gap. Diagnose in one command: ~/.claude/skills/shared/tools/socket-health-check.sh --live (exit 1 = BLIND, 2 = DISARMED, 0 = OK). ⚠️ The install is only PARTIAL — node_modules may be half-populated, so the next symptom is a missing type package or a missing test runner, which sends you debugging the wrong thing. Fix the token, then re-run a full install. Do NOT reach for SOCKET_CLI_ACCEPT_RISKS=1 (permanent blanket disarm — the pre-bash-socket-disarm-guard.sh hook blocks persisting it); use ~/tools/npm-real for a scoped bypass. | ~/.claude/skills/shared/tools/socket-health-check.sh |
dependabot alert, npm audit, CVE, GHSA-xxxx, "vulnerable dependency", transitive vuln, "fix the security/dependabot page", overrides, esbuild/tar/minimatch/ws/vite/uuid vuln, npm install fails on override version | Dependency Vulnerability Audit & Fix (7-step: BOTH dependabot-api + per-manifest npm-audit, scan EVERY lockfile, scoped overrides for multi-major packages, verify patched version is published, never blind npm audit fix --force, verify build with project's real build) | ~/.claude/skills/shared/dependency-audit.md |
| www redirect, cookies lost, auth break | WWW Redirect Auth Break (#4) | csp-cache-patterns.md |
| deploy logout, chunk hash, preloadError | Deploy Logs Users Out | csp-cache-patterns.md |
| stale version, failed deploy, CF Pages | CF Pages Stale Deploy | csp-cache-patterns.md |
| terraform destroy, infra deleted, catastrophic | AI Agent Destroys Infra (#6) | infrastructure-patterns.md |
| prod auth, pk_test, accounts.dev, Clerk production, Wrangler binding, wrong auth instance | Production Auth Instance Drift (#12) | infrastructure-patterns.md |
| prime-rhino, clerk.example.com missing, live HTML/CSP differs from dist, prod integration fails | AIVA Live Artifact/Auth Drift (#12a) | infrastructure-patterns.md |
| wrangler secret put binding already in use, plaintext Worker var, secret_text missing, BREVO_API_KEY in vars | Worker Secret Binding Drift (#12b) | infrastructure-patterns.md |
D1 route 500s with generic "Internal Server Error", no such column/no such table, D1_ERROR, intake/any-write save fails for everyone, migration file exists but column missing in prod, wrangler tail shows outcome Ok + empty exceptions, schema drift, migration not applied to remote | D1 Schema Drift — migration-file-exists-but-not-applied-to-prod (#26). Detect: wrangler tail --format json → grep logs for D1_ERROR/no such column (it's in logs[], not exceptions[]); confirm with PRAGMA table_info(<t>) on --remote (the file/local-D1 are NOT proof). Fix: additive ALTER … ADD COLUMN/CREATE … IF NOT EXISTS on remote, then INSERT OR IGNORE the filename into d1_migrations — NEVER bulk migrations apply (re-runs non-idempotent data migrations → corruption). Gate: ~/.claude/skills/shared/tools/d1-schema-drift-check.sh <repo>. | ~/.claude/skills/shared/d1-schema-drift.md |
| rust clippy, cross-platform, cfg, unused_mut | Rust Cross-Platform Lint (#7) | infrastructure-patterns.md |
| homebrew, keg-only, launchd, cron PATH | Homebrew Keg-Only PATH (#8) | infrastructure-patterns.md |
launchd/cron watchdog false alerts, "job-not-loaded" but service is up, gateway DOWN alert spam, bootstrap rc=5, launchctl list empty in launchd context, health-check passes interactively but fails on schedule, watchdog restarting a healthy service | launchd-Context Health-Check False Positive (#19) | infrastructure-patterns.md |
| serde, deny_unknown_fields, config crash | Serde Config Crash (#10) | infrastructure-patterns.md |
| innerHTML, XSS, dangerouslySetInnerHTML | XSS via innerHTML | infrastructure-patterns.md |
| JSON-LD, script breakout | JSON-LD Breakout | infrastructure-patterns.md |
Python SIGABRT / "Abort trap: 6" at finalization, parent sshd-session, _enter_buffered_busy, Py_Finalize/_io_TextIOWrapper_close in the stack, a Thread blocked in read(), recurring Python-*.ips, "crash over SSH", MCP bridge/server crashes on disconnect, cross-device ssh host python …, crash survives swapping the python interpreter | Python finalization SIGABRT over SSH — daemon-thread-blocked-in-read SCRIPT bug, usually a cross-device MCP stdio server (NOT the interpreter; NOT scheduled — on-demand). Forensic capture via ~/.zshenv SSH-cmd logger + WatchPaths crash-watcher correlated by parentPid. Fix: run the MCP server locally where the resource lives + os._exit(0) after the work loop (#22) | infrastructure-patterns.md |
| cannot find module, postinstall, npm install broke, every update breaks | File Extension Mismatch / Broken Postinstall (#17/#18) | infrastructure-patterns.md |
| npm-cli.js, shell script, SyntaxError unexpected string | npm-cli.js Shell Script Corruption (#17) | infrastructure-patterns.md |
| installing deps one by one, each reveals another missing | Non-Fatal Postinstall Cascade (#18) | infrastructure-patterns.md |
| stale data, admin user sync, visibilitychange | Data Stale Admin/User (#16) | debugging-discipline.md |
| slow page, slow route, slow dashboard, 8M rows, COUNT(*) on every request, full table scan, why is X so slow, route reads wrong cache, cron warms wrong KV key, prewarm warms wrong thing, 24h/last-N window empty, lagged data source, requested_datetime lag | Hot-Path Data-Volume & Cache-Topology (#20) | debugging-discipline.md |
| systematic, 4-phase, root cause, discipline | Debugging Discipline | debugging-discipline.md |
| lint, biome, npm audit, security cleanup | Lint & Security Cleanup | debugging-discipline.md |
Workers Cache leak / wrong data after enabling cache.enabled — user A sees user B's data, authed JSON route returns someone else's response, cf-cache-status: HIT on a per-user route, stale per-user data exactly ~2h old, data leak after enabling the new CF Workers Cache, cache flag "not doing anything" (wrangler <4.69 silently ignores it), Unexpected fields found in top-level field: "cache" | Workers Cache heuristic-caching cross-user leak — a 200 with NO Cache-Control is heuristically cached 2h; cookie auth (Clerk __session) does NOT auto-bypass. Fix: fail-safe default private, no-store + explicit public opt-ins; verify with ~/.claude/skills/ship/tools/workers-cache-check.sh <repo> + live curl -sI | grep -i cf-cache-status. Wrangler must be ≥4.69 in the repo's node_modules or the flag is inert. | ~/.claude/skills/shared/workers-cache-safety.md |
Sitewide redirect loop / site down right after enabling Workers Cache — ERR_TOO_MANY_REDIRECTS, every path 301s to its own URL, all UAs affected, Location: equals the requested URL, 301s explode in zone analytics right after a cache-enable deploy, HSTS header disappeared, worker logs show http:// in request.url while cf-visitor says {"scheme":"https"}, "I disabled the flag and it didn't fix it" (checked within seconds) | Workers Cache scheme-presentation class (2026-07-06 exampleapp ~25-min outage): the cache front-layer hands the Worker http:// for HTTPS visitors → any url.protocol === "http:" canonicalize middleware 301-loops the whole site, and url.protocol === "https:"-gated HSTS silently never fires. Diagnose in ONE probe: wrangler tail --format json → event.request.url scheme for a live HTTPS request. Fix: derive the client scheme from cf-visitor (authoritative) — visitorIsHttps() pattern, AIVA src/worker/middleware/securityHeaders.ts; url.protocol only as local-dev fallback. Triage rules: disable/rollback propagates in >30s — a <60s check is NOT evidence (a 3s check false-negatived during the incident and caused an unneeded rollback; verify over ≥60s); zone SSL mode, Page Rules, and Config Rules are red herrings (the presentation comes from the cache layer itself). | ~/.claude/skills/shared/workers-cache-safety.md |
| error too vague to act on, ambiguous error message, "can't tell what failed", same error fires 100s of times, log noise / superfluous log entries, no log at the failure point, silent failure, "why are these errors so unclear", add debug attributes, clean up the logs, assess the logs, improve log output | Observability / Log Hygiene — make ambiguous errors actionable (what was attempted + actual values + likely cause/branch + disambiguation: a vague error is usually two root causes sharing one string — split them), reduce noise by downgrading level (never delete), add the one attribute that names the failure. For a proactive scheduled pass over a window of logs, use the /log-hygiene skill instead. | ~/.claude/skills/shared/observability-instrumentation.md (+ /log-hygiene skill) |