Replace a single section of a workspace's doc body, identified by its heading text. The targeted edit complement to `update_doc` (full replacement) and `append_doc_section` (append-only at the end). Use this when the agent maintains a recurring section (e.g., a 'Status' block in a launch-prep doc, an 'Outcomes' block in a meeting note) and only needs to refresh that one piece. Without it, agents are forced into 'GET → splice → PUT' which costs tokens, costs latency, and races against any concurrent human edit elsewhere in the doc (last-write-wins clobbers). Section semantics: the FIRST heading whose plain text matches `heading` exactly (case-sensitive on trimmed text) is found, and everything from that heading up to the next heading at the same OR shallower level is replaced. So a `## Outcomes` section ends at the next `## …` or `# …`; nested `### …` subsections stay part of the replaced range. Returns 404 when no matching heading exists; strict by design so a misremembered heading fails loudly. `markdown` is the FULL replacement, INCLUDING the heading line: pass it back as-is to keep the heading, change it to rename or rewrite the heading, change the heading level, or omit the heading entirely (collapses the section into the prior one). Empty `markdown` deletes the section. Same markdown surface as update_doc / append_doc_section (CommonMark + GFM + `` images + lone-URL videos (mp4/webm/mov/mkv/m4v) + Mermaid + KaTeX + callouts + SVG + details + cross-refs + @-mentions + URL embeds). Identity / attribution / events / doc-guard all flow through the same writeDocBody path as the other doc endpoints, so @-mentions in the new section fire `doc.mention_added` for newly-added mentions just like update_doc does. Requires editor role. Multi-surface workspaces optionally accept `surface_slug` to target a specific doc surface. WARNING — a section runs to the next heading of the SAME OR SHALLOWER level, so targeting the LAST heading (or a lone H1) means its section extends to the END OF THE DOCUMENT and this call replaces everything below it. That has silently destroyed a doc twice (#8196), both times returning success. Call `get_doc` first and check which headings follow the one you are targeting. Agent writes that would drop most of the doc's blocks are now REFUSED with both block counts. So are writes that would delete a heading inside the replaced range (a nested subsection, content below a trailing heading, or the target heading itself when you send only body text), drop a callout / quote / code block / table / image / embed in the range, or most of the section's own blocks; the refusal lists `removedHeadings` and `removedBlocks`. A block counts as carried back only when one top-level block of your markdown has exactly its text (whitespace aside); rewording a callout, or folding its text into a larger block, counts as removing it. Carry back what you mean to keep, or pass `allowBlockLoss: true` to confirm an intended deletion. Edited or deleted paragraphs and lists are allowed but reported: `replacedSection.removedBlockCount` and `removedBlocks`. CONCURRENCY: concurrent writes to other sections are merged, never overwritten. But if you rebuild a section from an earlier read (someone may have written since), pass the `updatedAt` from your `get_doc` as `if_unmodified_since`, or pass the `sectionHash` from your previous update_doc_section response as `if_section_hash` (guards only this section). Without a precondition the write wins even over an edit you never saw. Every success returns `prior` (the replaced range's `updatedBy`, `updatedAt`, `blockCount`, `contentHash`: who and what you overwrote), `sectionHash` (the section as it now stands, the value for your next `if_section_hash`; null if your markdown left no heading), and the new `updatedAt` to chain into your next `if_unmodified_since`. Heed `warning` (`section_recently_changed_by_other`): your unguarded write landed right after another principal's; `updatedBy` on the doc names only the latest writer, so re-read and restore their edit if your body predates it.