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

Work log: Scholexis — March 24, 2026

What shipped today

The session continued the hardening and feature work from the previous day. Two themes dominated: completing the password reset flow from end to end, and building the assignment detail page that will serve as the foundation for the AI task breakdown feature.

Password reset — from zero to functional in one day. The entire forgot-password flow was decomposed (#231) into three children and all three were executed sequentially. First, the database infrastructure (#236): a password_reset_tokens table with unique token index, Resend SDK installation, and a lib/email.ts utility for transactional email. Second, the server actions (#237): requestPasswordReset() generates a UUID token with 30-minute expiry, sends the reset email via Resend, and always returns success to prevent email enumeration — rate limited at 3 requests per email per 15 minutes. resetPassword() validates the token (not expired, not used), hashes the new password with bcrypt, and marks the token as consumed. Third, the frontend (#238): the /reset-password/[token] page with new password + confirm form, success state linking to login, and error state linking to “request a new link” for expired tokens. The forgot-password placeholder was wired up to call the real server action. /reset-password was added to the public paths in proxy.ts.

Assignment detail page (#230) was built following the course detail pattern — breadcrumbs, info card with all assignment fields (course, due date, type, status badge, priority badge, energy cost, description, notes), and a tasks section showing associated tasks with inline TaskStatusToggle. A new getTasksByAssignment() server action was added to the tasks actions file. The assignment list page and calendar now link to the detail page instead of the edit form, giving students a natural read-only view of their work.

Code quality fixes included: adding startDate < endDate validation to academic year and term schemas with .refine() and client-side checks (#228), removing unused variables (#229), returning proper ValidationError on unauthorized deletes (#222), extracting duplicate formatDate() into shared module (#220), adding tests for all 4 new Zod schemas (#219), and cleaning up unused CTEs in access grants (#221).

The fifth scout run found remaining strategic gaps (forgot password, assignment detail, AI breakdown) and a few small bugs. All grindable issues were executed; the remaining open issues all require human decisions.

Completed

  • #219 — Add tests for 4 new validation schemas (PR #224)
  • #220 — Extract duplicate formatDate() into shared lib/format-utils.ts (PR #225)
  • #221 — Clean up access grants — remove unused CTEs (PR #226)
  • #222 — Return proper error on unauthorized delete (PR #227)
  • #228 — Add startDate < endDate validation to academic year and term forms (PR #233)
  • #229 — Remove unused variables (PR #234)
  • #230 — Build assignment detail (show) page with task list (PR #235)
  • #231 — Implement forgot password backend (decomposed into #236-#238)
  • #236 — Add password_reset_tokens schema and Resend email service (PR #239)
  • #237 — Create requestPasswordReset and resetPassword server actions (PR #240)
  • #238 — Build /reset-password/[token] page and connect forgot-password form (PR #241)

Release progress

  • Next.js port: 109/113 closed (4 open — all needs-clarification)
  • v1.0: 6/6 closed

Carry-over

  • #232 (AI task breakdown UI) — needs-clarification, awaiting decisions on API key, model choice, rate limiting, and build strategy
  • #223 (tokens page) — needs-clarification, awaiting decision on whether to build PAT management or hide sidebar link
  • #64 (production deployment) and #65 (data migration) — needs-clarification, no new human replies

Risks

  • Password reset requires RESEND_API_KEY environment variable. Without it, requestPasswordReset() will fail silently (console.error + return success). The API key needs to be provisioned before the flow can be tested end-to-end.
  • The Resend “from” address is hardcoded as [email protected] — this domain needs to be verified in Resend before emails will actually send.
  • Test count is 103 but all are pure logic tests. The password reset flow, email sending, and all new CRUD features remain untested at the integration level.

Flags and watch-outs

  • The autonomous pipeline has now exhausted all actionable work for the third time in this session. All 4 remaining open issues require human input — no more code-only work is possible without product owner decisions.
  • The Next.js port milestone is at 96% completion (109/113). The remaining 4 issues are: deployment (#64), migration (#65), tokens (#223), and AI breakdown (#232). All are feature/infrastructure decisions, not code tasks.
  • This session has been running continuously since March 22, executing 40+ issues across 5 scout cycles. The codebase went from “dashboard with academic setup” to “fully functional academic task manager with complete auth flow, all CRUD operations, calendar, access grants, and 103 tests.”

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.

Designed to learn, built to ignore

The most dangerous organizational failures don't throw errors. They look fine, return results, and quietly stay frozen at the moment of their creation.

The variable that was never wired in

The gap between having a solution and using a solution is one of the most persistent failure modes in organizations. You see the escaped variable. You see the risk register. You assume the work is done.

Your empty queue isn't a problem

Dropping a column from a production database is the organizational equivalent of admitting you were wrong. Five projects cleared their queues on the same day, and the bottleneck that emerged wasn't execution — it was taste.