Operant Studio
OPER-208

Fix CreateTask 500 on full-payload POST (retire narrow-POST-then-PATCH workaround)

Suggested
Justin Cooke

Body

---
feature_id: FEAT-studio-planning-validation
---

## Context

Every ticket-filing session for the past three weeks (2026.08.26, 2026.09.08, 2026.09.10, 2026.09.13) has used a narrow-POST-then-PATCH workaround: POST with only `{title, body, priority}`, then PATCH `{size, module, writeSets, verificationCmd}`. The reason: POST with the full payload returns HTTP 500 with an opaque error.

This has cost roughly 2 extra API calls per ticket + additional latency on every filing session. Total waste at ~20 tickets/week: 40 extra calls/week for weeks.

Root cause hypothesis (unverified until this ticket ships): the POST handler at `apps/web/src/app/api/studio/[team]/tasks/route.ts` runs classification/planner logic in the same transaction as the create, and the classifier fails on partial input, cascading to a 500 that swallows the classifier error. The PATCH path succeeds because classifier does not re-run on PATCH.

## What

Diagnose and fix the POST-500-on-full-payload path. Three-step:

1. **Reproduce**: write a failing integration test at `apps/web/src/app/api/studio/[team]/tasks/route.test.ts` that POSTs `{title, body, priority, size, module, writeSets, verificationCmd}` and asserts HTTP 201.
2. **Diagnose**: capture the 500 stack trace via a temporary Sentry-style trace + log the classifier input at time of failure.
3. **Fix**: either (a) make the classifier resilient to fully-populated intake, or (b) separate the create-then-classify path into two sequential transactions in the handler with the classifier failure NOT rolling back the create. Prefer (b) — the ticket should always land even if classifier fails; classifier can retry async.

Add regression test that asserts POST with the full payload returns 201, is admitted, and (if band-classifiable) is classified within one tick.

## Acceptance Criteria

- [ ] Failing integration test reproduces the 500 in CI
- [ ] Root cause identified and documented in the ticket comment thread
- [ ] Fix lands (either classifier resilience or create-then-classify separation)
- [ ] Regression test asserts POST with full payload returns 201
- [ ] Regression test asserts classifier still fires within one tick when payload is full
- [ ] Documentation update: `docs/task-state-machine.md` notes the fix and removes the narrow-POST-then-PATCH workaround guidance

## Blocked-by

None.

## Size / Band

M / assurance (touches POST handler, classifier, adds regression tests; potentially touches transaction boundary — the reason it is M and not S is the diagnosis unknown-cost).

## Discovered by

Weekly filing workaround since at least 2026.08.26. Documented in session summary 2026.09.10 as `CreateTaskBody-500-On-Full-Payload` failure class candidate. Not filed until 2026.09.13.

## Verification

Ships when full-payload POST works and the workaround is removed from ticket-filing scripts, and the regression test guards it.

Attachments

Loading attachments…

Comments

Loading comments…