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

2026-03-29 — Authexis work log

What shipped today

Today was the single biggest hardening day in the project’s history — 50 issues closed across 43 commits, touching both the engine and web app. The work fell into four distinct themes.

Security and authorization fixes. Five high-severity issues were addressed: missing workspace membership checks on destructive settings actions (#1874), an IDOR vulnerability in OAuth callbacks where workspace_id from the state parameter was unverified (#1879), XSS risk from a permissive blog sanitizer allowing arbitrary iframes and style attributes (#1880), Stripe webhook handlers returning 200 on database write failures which prevented retries (#1876), and uncaught exceptions in OAuth token exchange and TTS fetch routes (#1857, #1858). These were all found by a scout security scan and fixed same-day.

Dependency upgrades and vulnerability remediation. A full dependency audit swept both the Python engine and Node web app. On the Python side: Pygments upgraded to fix CVE-2026-4539 (ReDoS), PyJWT and cryptography bumped for HIGH-severity CVEs, plus 6 minor dependency bumps (#1833, #1841, #1853). On the Node side: TypeScript 5→6, Stripe 20→21, lucide-react 0.x→1.7, @types/node 20→25, shadcn CLI 3→4, and 11 minor npm dependency bumps (#1837, #1848–1854). pip-audit was added to dev dependencies for ongoing vulnerability scanning (#1888).

Performance and error handling. The social queue’s N+1 update pattern was replaced with bulk Supabase RPCs for both position updates and scheduled_at changes (#1882–1884). The scheduler’s 9 remaining N+1 command inserts were batched with UNNEST (#1847), and the social post poller was similarly batched (#1843). Error handling was tightened: article_add now catches UniqueViolationError specifically instead of masking all errors (#1839), prospect_create handles duplicate slugs gracefully (#1855), track endpoints log failures instead of swallowing them (#1856), and the content_create NameError that was breaking production content creation was fixed (#1846).

Feature work and UX. The markdown blog import pipeline shipped end-to-end: server action for parsing (#1871), file upload UI (#1872), and Hugo/Jekyll/Astro frontmatter normalization (#1873). Markdown download for published content was added (#1867). The dashboard got an empty state for workspaces with no content (#1870), the calendar now highlights today and dims past days (#1881), and the ideas search clear button got an accessible name (#1869). Dead code cleanup removed unused components, exports, and lib files (#1860, #1864).

Sentry cleanup. A scout run identified 14 Sentry issues across both projects. Systematic analysis confirmed all were pre-fix (events predated the deployments containing their fixes). Eleven were bulk-resolved via sentry-cli (#1890), and engine deployment staleness was verified as a non-issue (#1889).

Completed

  • #1833 — bump PyJWT, cryptography, requests to fix HIGH-severity CVEs
  • #1835 — remove dead content_type references from contents creation paths
  • #1837 — bump 11 minor npm dependencies
  • #1839 — catch UniqueViolationError specifically in article_add
  • #1840 — fix StripeTier ReferenceError on billing page
  • #1841 — bump 6 minor Python engine dependencies
  • #1843 — batch command inserts in social post poller
  • #1844 — suppress ClientDisconnect noise on MCP /register endpoint
  • #1845 — fix duplicate test_social_fetch_metrics.py
  • #1846 — fix NameError in content_create event payload
  • #1847 — batch all scheduler N+1 command inserts with UNNEST
  • #1848 — upgrade @types/node from ^20 to ^25
  • #1849 — upgrade lucide-react from 0.x to ^1.7
  • #1851 — upgrade stripe from ^20 to ^21
  • #1852 — upgrade typescript from ^5 to ^6
  • #1853 — upgrade Pygments 2.19.2 → 2.20.0 to fix CVE-2026-4539
  • #1854 — upgrade shadcn CLI 3.8.4 → 4.1.1
  • #1855 — catch UniqueViolationError in prospect_create handler
  • #1856 — log errors in track endpoints instead of silently swallowing
  • #1857 — add try/catch around ElevenLabs TTS fetch
  • #1858 — add try/catch around OAuth token exchange fetches
  • #1859 — delete auth user before data in account deletion
  • #1860 — remove dead ScoreBadge component
  • #1861 — add composite index on contents(workspace_id, status)
  • #1863 — fix contents stage check constraint to include all active stages
  • #1864 — remove dead code: unused components, exports, and lib files
  • #1865 — fix StripeTier ReferenceError in billing server action
  • #1867 — add markdown download button for final content
  • #1869 — add aria-label to ideas search clear button
  • #1870 — add empty state to dashboard when pipeline has no content
  • #1871 — add server action for markdown content import
  • #1872 — add file upload UI for markdown content import
  • #1873 — normalize Hugo/Jekyll/Astro frontmatter in markdown import
  • #1874 — add workspace membership checks to 5 settings server actions
  • #1875 — fix scheduler payload cast from $N::text to $N::jsonb
  • #1876 — return 500 from Stripe webhook on DB write failure for retries
  • #1878 — wrap JSON.parse in updateField with try/catch for interview_qa
  • #1879 — add workspace membership check to OAuth callbacks
  • #1880 — tighten blog sanitizer: restrict iframe hosts, remove style attr
  • #1881 — highlight today and dim past days on calendar
  • #1882 — add bulk position update RPCs for social_posts and blog_queue
  • #1883 — add bulk_update_scheduled_at RPC for social_posts and blog_queue
  • #1884 — replace N+1 updates in social-queue.ts with bulk RPCs
  • #1885 — resolve Sentry JSONB type mismatch
  • #1886 — add explicit ::jsonb casts to all payload INSERT parameters
  • #1887 — resolve Sentry transcript JSON parsing error
  • #1888 — add pip-audit to engine dev dependencies
  • #1889 — verify engine deployment is current
  • #1890 — bulk-resolve 9 pre-fix Sentry issues

Release progress

  • v1.5: 1/50 open (1842 — needs GitHub PAT on Railway)
  • v2.0 — Product simplification: 0/25 closed
  • v2.1 — Content model refactor: 0/15 closed
  • v2.2 — Simplified pipeline: 0/3 closed

Carry-over

  • #1842 (needs-clarification): GitHub API 404 in changelog_generate — waiting on Paul to create a fine-grained PAT and set GITHUB_TOKEN on Railway
  • #1862 (backlog): Social queue page fetches all posts with no pagination

Risks

No new risks emerged. Several HIGH-severity risks were resolved today (security fixes, CVEs). Five open risks remain — see RISKS.md.

Flags and watch-outs

  • The blog import pipeline (#1871–1873) shipped but hasn’t been tested with real user data beyond the automated tests. Worth a manual test with a real Hugo export.
  • eslint ^9 → ^10 upgrade (#1850) was opened but not yet implemented — may require config migration.

Next session

  • Resolve #1842 if Paul has set the GITHUB_TOKEN on Railway — re-check and close
  • Consider pulling #1862 (social queue pagination) from backlog if queues are empty
  • Run /scout to find new work — today’s hardening pass likely cleared most low-hanging fruit, so scout may surface deeper issues
  • v1.5 milestone is 49/50 — closing #1842 completes it

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 headcount lie

The assumption that work scales with people is so embedded in how organizations think that questioning it feels like questioning gravity. But one operator just ran ten parallel operations in a single day. The unit of capacity isn't the person. It's the decision-maker.

AI and the Götterdämmerung of Work

Work is dead. And we have killed it. AI didn't defeat the myth that human value comes from reliable output — we built the systems that exposed it. What comes next isn't replacement. It's revaluation.

Everything pointed at ghosts

Most organizations are measuring work they stopped doing years ago. The dashboard is green. The reports are filed. Nobody realizes the entire apparatus is pointed at ghosts.