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

Work log: Authexis - March 11, 2026

What shipped today

Today was a hardening day — fixing production bugs surfaced by Sentry, closing security gaps found by scout, and getting the pipeline infrastructure more resilient. Six PRs merged across security, reliability, and correctness.

Security hardening

Two auth-related fixes shipped. The Supabase listUsers admin API was hitting the 1,000-user limit silently across five different files (#983) — extracted shared paginated helpers into admin-helpers.ts and wired them in everywhere. The /api/feeds/validate endpoint (#1035) was an unauthenticated SSRF vector — it fetched arbitrary URLs without checking who was asking. Added cookie-based auth and full SSRF protection (private IP blocking, scheme validation, port restriction). The sister endpoint /api/feeds/discover was found to have the same issue during today’s scout sweep — tracked as #1048 for next session.

Production reliability

Three engine fixes: the email signature path (#1038) was hard-coded to a local filesystem path that doesn’t exist in Railway containers — made it configurable via EMAIL_SIG_HTML_PATH env var with a warning log when missing. The blog publish handler (#985) was making bare HTTP calls to GitHub’s API with no retry — wrapped it with the existing retry_api_call decorator from http_retry.py for automatic retry on transient errors. And the Sentry AttributeError (#1021) where triple-encoded JSON payloads caused .get() on a string — replaced the fragile double-decode in the poller with a robust loop that handles any encoding depth, with warnings for anomalous levels.

Cleanup

Removed Fastmail draft creation from the engine (#1024) since draft management moved to paulos. Closed the false-positive dead code issue (#1037) — _assemble_post_text() is called at line 289, scout got it wrong.

Scout findings

A scout sweep created 5 new issues: two auth bypass bugs (#1047 switch-workspace, #1048 feed/discover), three scheduler functions that are fully implemented but never registered with APScheduler (#1049), the 2,720-line content-detail component (#1050), and the near-zero test coverage in the engine (#1051).

Completed

  • #983 — Fix listUsers pagination across all auth user lookups
  • #1035 — Add auth and SSRF protection to feed validate endpoint
  • #1038 — Make email signature path configurable via env var
  • #985 — Add retry logic for GitHub API calls in blog publish handler
  • #1021 — Fix multi-encoded JSON payload decoding in command poller
  • #1037 — Closed as invalid (not dead code)

Release progress

  • v1.5: 4/5 closed (1 open)
  • v2: 20/20 closed
  • v1-outbound: 19/19 closed

Carry-over

  • #1043 / #1046 — Railway deploy failures on the last two commits. These need investigation — the code looks correct (imports exist, syntax valid) but Railway builds are failing. May be a build cache or dependency issue.
  • Two new auth bypass issues (#1047, #1048) are grindable and high priority — same class as the feed/validate SSRF we just fixed.

Risks

  • Engine may not be deploying. #1043 and #1046 are both Railway deploy failures. The fixes from today (#985, #1021) may not be live yet. Need to check Railway dashboard and potentially investigate build logs.
  • Three scheduler functions (#1049) are silently not running. Onboarding nudges, wizard reminders, and re-engagement drip are fully implemented but never fire. This means lifecycle emails aren’t going out.

Flags and watch-outs

  • Scout false positives: #1037 was wrong about dead code. Worth sanity-checking scout findings before grinding them.
  • The v1.5 milestone has 1 issue remaining (#967, needs-decompose). Once that’s broken down, v1.5 could close.

Next session

  1. Investigate Railway deploy failures (#1043, #1046) — check Railway build logs, determine if it’s a code issue or infrastructure issue. This is blocking all engine fixes from going live.
  2. Grind auth bypass issues (#1047, #1048) — both are ready-for-dev, concrete, ~10 min each. Same pattern as the feed/validate fix.
  3. Grind scheduler registration (#1049) — ready-for-dev, just needs three add_job() calls.
  4. Prep remaining issues (#1039 race condition, #1036 rate limiter, #1032 blog idea).

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 machine is eating faster than you can feed it

Sixty-three issues closed across thirteen projects in one day. Four milestones completed. And the hardest problem wasn't building — it was keeping up with what you've already built.

The proxy problem

Every organization has this problem: knowledge locked inside one person's head. Today I accidentally designed a solution — and it has nothing to do with documentation.

True 1-to-1 outreach is finally possible with AI

The 1-to-1 personalization promise is thirty years old. It never worked because understanding each person was too expensive. AI changed the economics.