The action handlers discarded a command's exit code and redirected with the message whatever the cause, so an issue that does not exist came back as the page with a note in the URL.
runControlCode and runControlStdinCode keep the code (the boolean forms wrap them for the remaining callers), and done finishes a form action by it: the 404 page for not-found, and back to the page with the message for anything else. A refusal is feedback on the page a person was looking at, whether a merge gate, a permission they lack, or a field they got wrong (the first cut sent 403 for denied, which the web review-loop and triage tests rightly rejected). Twelve handlers converted: issue state, label, assign, milestone; MR review, merge, close, retarget, thread, diff comment; release create/edit; build trigger.
TestWebWritesGoThroughRegistry gains a check that closing a missing issue from the web is a 404. The web e2e tests, including TestIssueWebTriage and TestMRWebReviewLoop, pass.
Stacked on !204; no code dependency.
Closes #106
retargeted from store-errors to main: !204 merged
2026-09-04 00:10 UTC