Public: anyone can read this; the crew can change it.

A proposer fixes a typo: the title and the paragraph, edited in the open and stamped #60

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`editProposal(db, who, {id, title, body})` lets a proposer correct the title and the paragraph of their own open proposal — the author only, so an admin who withdraws anybody's proposal still edits nobody's text — judged by the same two sentences `propose` uses, refused once the proposal is decided or withdrawn, and refusing the options out loud (`OPTIONS_LOCKED`) at every door rather than droppin…

shipped production is serving it deploy 2adbe7d

opened this

editProposal(db, who, {id, title, body}) lets a proposer correct the title and the paragraph of their own open proposal — the author only, so an admin who withdraws anybody's proposal still edits nobody's text — judged by the same two sentences propose uses, refused once the proposal is decided or withdrawn, and refusing the options out loud (OPTIONS_LOCKED) at every door rather than dropping them. editRefusal holds the who/state rules once, so the form, the terminal and the action all say the same thing; the line where a ballot check belongs when #5 lands is marked in the action, since nothing casts one yet.

The correction is shown rather than hidden, and this is the one place I deviated from the issue: the "edited" mark comes from a new edited_at column (migration 8, one ALTER TABLE ... ADD COLUMN) rather than from updated_at being later than created_at, because withdrawing a proposal and accepting a counter stamp updated_at too — comparing the two would have made every withdrawn proposal claim an edit nobody made. updated_at is still set by an edit. Saving the same words succeeds, stamps nothing and emits nothing.

Every door: an Edit link on /p/:id for the author, /p/:id/edit as a page of its own (the proposal is a live region, and a form inside one can be swapped out from under someone's hands), POST /proposals/:id/edit, PATCH or POST /api/proposals/:id, the edit_proposal MCP tool, and e at the terminal with both fields arriving already typed. An edit emits proposal.edited, which the proposal region now listens for; the thread is untouched.

To try it in the preview: open a proposal, follow Edit from /p/<id>, change the title to something with a < in it, and watch the byline gain "edited" with the time; then open the same page in a second window before saving to see it update in place. Tests: bun test is green (129), covering a non-author and an admin refused, a decided and a withdrawn proposal refused, the over-length title refused with exactly propose's sentence, a no-op edit leaving edited_at null, the page showing "edited" only after a real change and never after a withdrawal, escaping on the way out, and the event reaching an open page from a second process (that last one lives in live.test.ts beside its sibling, because server.test.ts starts a second server and the live store follows whichever database it saw last).

🤖 Generated with Claude Code

Closes #53

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs