---
title: "Patch Turn"
method: PATCH
path: "/internal/runs/{run_id}/turn"
tags: ["internal"]
---

# Patch Turn

`PATCH /internal/runs/{run_id}/turn`

Turn-status PATCH: the entrypoint reports how the turn ended, and (turn 1)
the captured sdk_session_id. Terminal statuses release the session lock by
construction (the partial unique index only covers pending/running).

Race shape (final review, three iterations): a finalize request carries
its resume-key mutation INSIDE the transition statement (one atomic CTE)
— the mutation applies iff that request wins the active→terminal
transition, and both commit together, so there is no window between the
key landing/withdrawing and the lock releasing, and a swept zombie's
finalize applies nothing. Bare mutations (the init-time background
PATCH) are terminal-fenced with a fresh status read, and their set is
additionally guarded on the run still being active inside the UPDATE —
a stalled bare set racing the atomic finalize either lands before it
(an owning clear overwrites it; an owning set finds the slot taken —
first-writer-wins, same key) or after it (guard fails, no-op).

## Path parameters

- `run_id` string, uuid, required

## Request body

- TurnPatchRequest
  - `status` 'completed' | 'failed' | 'interrupted', nullable
  - `error_message` string, nullable
  - `sdk_session_id` string, nullable
  - `clear_sdk_session_id` boolean

## Response `200`

Successful Response

- TurnControlResponse — Alpha payload: {interrupt}. One route shaped to carry later signals (e.g. next_message for warm sandbox reuse) without a new surface.
  - `interrupt` boolean

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/nanocorp/apis/nanocorp-api.md) · [All operations](https://skmtc.dev/nanocorp/apis/nanocorp-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/nanocorp/nanocorp-api/revisions/04b208d3215b/schema)
