# Design note — editing a post

**Dated 2026-08-04. Written before the code, per the provenance practice in
[ROADMAP.md](../../ROADMAP.md#proving-independence).**

Not a roadmap phase. This closes a gap carried since phase 2: the `posts` table
has `edited_at`, `edited_by` and `edit_count`, the topic view already renders
"Edited N times", and there has never been a way to edit anything.

A forum where you cannot fix a typo is broken in a way no advanced feature
makes up for, so this comes before phase 6.

---

## The job to be done

Somebody posts, spots a mistake, and fixes it. A moderator corrects something
that should not stay as written. Both leave a trace, because a post that can
change silently is a post nobody can quote safely.

## Decision 1 — who may edit, in one function

Three rules, in order:

1. **A moderator may edit any post**, including in a locked topic. Locking is
   how moderation stops a conversation; it should not stop moderation.
2. **An author may edit their own post**, if the topic is not locked and the
   post is not hidden or deleted.
3. **Nobody else, ever.**

A hidden post is deliberately excluded from author editing: it has been
actioned by a moderator, and letting the author rewrite it afterwards makes
the moderation record meaningless. A moderator can still edit it.

## Decision 2 — a time window, off by default

An admin setting, `post_edit_window`, in minutes. **Zero means no limit, and
that is the default**, because a forum that silently stops you correcting
yourself after ten minutes is a forum people complain about, and an
administrator who wants that limit knows they want it.

The window applies to authors only. A moderator is not editing their own
mistake; they are moderating, and that has no clock.

## Decision 3 — editing the first post edits the topic title

The first post *is* the topic in every forum anyone has used, so its edit form
carries the title. Editing any other post does not.

Changing the title does **not** change the slug. The URL is
`/topic/12-old-title`, the id is what resolves it, and links people have
already shared should not rot because a typo was fixed. That is a deliberate
trade: the URL can end up saying something slightly stale, which is much
cheaper than breaking every link to it.

## Decision 4 — the trace is a count and a timestamp, not a diff

`edit_count` increments, `edited_at` is stamped, `edited_by` records who. The
topic view already renders this; the only change is that it now says who when
it was not the author.

**No revision history for posts.** Themes have it because a theme is one small
document. A forum keeping every draft of every post is a storage decision, a
moderation-policy decision and a privacy decision all at once — somebody
deleting personal information from their own post reasonably expects it gone.
That deserves its own note if it is ever wanted.

An edit inside a short grace period does not bump the count. Fixing a typo
three seconds after posting is not "edited", and marking it as such trains
people to ignore the marker.

## Decision 5 — attachments and mentions behave as they do on a reply

The same editor, the same renderer, the same attachment binding, the same
mention linkifying. Anything else would mean an edited post could render
differently from how it was posted, which is worse than not being able to edit
at all.

**Mention notifications are not re-sent.** Somebody edited into a post is not
notified, because otherwise editing a post repeatedly is a way to notify
somebody repeatedly. Named in the docs so it is a decision rather than a bug.

## Decision 6 — a `PostEdited` event, which the docs already promised to want

`docs/extensions/events.md` currently says there is no event for post edits.
There is now, and that line goes.

## What this does not do

- **No revision history.** See above.
- **No edit reason.** A field nobody fills in honestly is worse than nothing;
  if it is wanted it should be required, which is a policy decision.
- **No editing another member's post as a non-moderator**, however trusted.
