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

2026-03-22

What shipped today

Today was a comprehensive quality and hardening sprint — 15 issues closed across two full scout cycles, plus a marketing onboarding questionnaire filled out for the Synaxis agency engagement.

The session started with a scout run that surfaced issues across security, error handling, performance, test coverage, and feature gaps. The most impactful findings were: XSS vectors in briefing and blog pages rendering unsanitized HTML (now sanitized via DOMPurify), the Stripe webhook returning 200 on database failures (silently losing subscription updates), and per-row database inserts in rss_scan that should have been batched. All three were fixed immediately. A user-facing feature also shipped — learned preferences (the AI’s evolving understanding of what the user cares about) are now visible in the settings page, addressing the “show your work” product principle.

Test coverage was the other major theme. The parent issue (#393) was decomposed into 4 child issues covering the 5 critical untested handlers: article_add, briefing_generate, google_search_scan, newsletter_process, and daily_pipeline. All four were prepped and executed in sequence, adding 28 new test cases and bringing the suite from 135 to 163 tests. Every handler now has coverage for its core paths — dedup, scoring, error handling, and downstream command routing.

A second scout run found a critical NameError in website_scan (variable undefined, should have been feed_rows), plus website_scan’s per-link Claude calls (1 per link instead of batched like rss/google). Both were fixed — website scanning now works and uses batch scoring matching the pattern in all other scan handlers. The session also added security headers to Next.js, error handling to the bookmarks page, and consolidated two ratings queries into one in user_context.

Completed

  • #389 — Sanitize HTML in briefing and blog pages with DOMPurify
  • #390 — Stripe webhook returns 500 on database update failures
  • #391 — Batch article and processed_post inserts in rss_scan
  • #392 — Surface learned preferences to users in settings page
  • #393 — Add test coverage for critical untested engine handlers (decomposed)
  • #398 — Add tests for article_add handler (7 tests)
  • #399 — Add tests for briefing_generate handler (6 tests)
  • #400 — Add tests for google_search_scan handler (6 tests)
  • #401 — Add tests for newsletter_process and daily_pipeline handlers (9 tests)
  • #406 — Fix NameError in website_scan: feeds vs feed_rows
  • #407 — Batch link scoring in website_scan to match rss/google patterns
  • #408 — Add error handling and loading states to bookmarks page
  • #409 — Add security headers to Next.js config
  • #410 — Consolidate two ratings queries into one in user_context

Carry-over

  • Verify PostHog and Sentry are configured correctly (env vars added previously, need to confirm events firing and errors captured in production)
  • Confirm security headers are present on production responses after next Vercel deploy
  • Marketing onboarding questionnaire filled out for Synaxis agency — awaiting Paul’s review and brief approval
  • Pre-existing build error in admin users page (type mismatch on feeds name vs title) — not blocking but should be cleaned up

Risks

  • None identified. All milestones are closed. The open backlog is 4 items, all parked.

Flags and watch-outs

  • website_scan had TWO NameError bugs (lines 67 and 86) — the handler was completely broken for website feeds. Fixed now but worth verifying in production that website scans complete successfully.
  • The isomorphic-dompurify dependency was added for HTML sanitization — first deploy will pull this new package.
  • Security headers added via next.config.ts headers() — no CSP header included (would break shadcn inline styles). CSP is a separate, more complex effort if needed.
  • Test suite is now 163 tests, up from 135 at session start. All passing.

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.

When your agents start breaking each other's code

Two agents modified the same file independently and created database locks. The fleet hit 135 issues in one day — and the coordination problem that comes with it.

The removal tax

The most productive thing you can do with a product is take features away. Eighty-nine issues closed across eight projects, and the hardest lesson came from a pipeline that ran perfectly and produced nothing.

The product changed its mind

A product pivoted its entire philosophy mid-session — from 'here's your list' to 'here's your next thing.' The code shipped in the same conversation as the idea. That's not iteration. That's something else.