Skip to main content
Paul Welty, PhD AI, WORK, AND STAYING HUMAN

2026-04-04

What shipped today

Massive hardening session — 12 issues closed across security, error handling, test coverage, UX, and performance. Three scout passes found progressively deeper issues as the surface-level problems got cleared.

The most consequential fix was an open redirect vulnerability in the auth callback (#370): the next query parameter was used without validation, allowing [email protected] to redirect users to external sites. Four lines of validation plus 5 parameterized test cases closed that gap.

Error handling got a systematic overhaul. Email notifications now use Promise.allSettled so one Brevo failure doesn’t kill remaining sends (#365). The cadence-nudge cron route had 4 Supabase queries silently ignoring errors — a failed votes query would trigger spurious reminders for everyone (#372). Two more forms (resolve plan, cadence settings) had try/finally without catch, swallowing errors silently (#375). Recipe create/edit forms got error display and pending states (#368). Input validation was added to family member notes, pantry categories, and settings timezone/dinnerTime (#373).

Performance improvements: unbounded recipe_history query on the history page capped at 1000 rows (#371), two composite indexes added for recipe_history and weekly_candidates (#374), and finalizePlan now parallelizes its two independent Supabase writes via Promise.all (#376).

UX polish: shopping list shows a green “all done” state when all items are checked (#369), plan builder delete button got an aria-label (#367), and the auth callback route now has 7 tests covering all 8 authentication paths (#366).

Test count grew from 327 → 341 (14 new tests). Zero failures throughout.

Completed

  • #365 Email notifications crash on single send failure
  • #366 Auth callback route has zero test coverage
  • #367 Plan builder delete button missing aria-label
  • #368 Recipe forms show no validation error messages
  • #369 Shopping list shows no empty state when all items checked
  • #370 Open redirect vulnerability in auth callback
  • #371 History page loads unbounded recipe_history query
  • #372 Cron cadence-nudge route ignores Supabase query errors
  • #373 Missing input validation on family member notes, pantry category, settings timezone
  • #374 Add composite indexes for recipe_history and weekly_candidates queries
  • #375 Resolve plan and cadence settings swallow errors silently
  • #376 finalizePlan: parallelize independent plan and cycle updates

Carry-over

  • #377 Replace select("*") with explicit column lists — moved to backlog, marginal payoff for the analysis required

Risks

None new. The open redirect was the only security-relevant finding and it’s patched.

Flags and watch-outs

  • Vercel deployment is now manual only (vercel or vercel --prod). No auto-deploy on push. Paul flagged high Vercel costs — deploy explicitly when a meaningful batch of changes is ready.
  • The @supabase/ssr 0.9→0.10 flag from 4/1 should be considered clear — auth flows tested today via the new callback route tests.

Next session

  1. Deploy to production — 12 commits since last deploy, including a security fix. Run vercel --prod from web/.
  2. Consider a scout run focused on feature gaps — the codebase hardening is largely done. “Repeat last week” is the biggest product gap remaining.
  3. All milestones are closed. May be time to plan the next phase.

Why customer tools are organized wrong

This article reveals a fundamental flaw in how customer support tools are designed—organizing by interaction type instead of by customer—and explains why this fragmentation wastes time and obscures the full picture you need to help users effectively.

Infrastructure shapes thought

The tools you build determine what kinds of thinking become possible. On infrastructure, friction, and building deliberately for thought rather than just throughput.

Server-side dashboard architecture: Why moving data fetching off the browser changes everything

How choosing server-side rendering solved security, CORS, and credential management problems I didn't know I had.

The work of being available now

A book on AI, judgment, and staying human at work.

The practice of work in progress

Practical essays on how work actually gets done.

The bottleneck moved and nobody noticed

When execution becomes nearly free, the bottleneck shifts from doing the work to deciding what work to do. Most organizations are optimized for the wrong constraint.

The inbox nobody reads is the one that matters

Every organization has a monitoring system that works perfectly and reports to nobody. The gap between having information and acting on it is where most failures actually live.

The best customers are the first ones you turn against

Every subscription makes a bet that most customers won't use what they're paying for. The customer who closes that gap becomes a problem to be managed.