# QA: Edit title and slug, revision protection (backend) Backend only. Go tests in test/, black-box. No design states. ## Automated, no server (task test) 1. UpdateArticle use case over fakes and a fake Transactor, table-driven over title boundaries, explicit slug edits and revision-raising fields. Assert article.ErrInvalidTitle, ErrInvalidSlug, ErrSlugTaken and the new revision-conflict sentinel with errors.Is. The revision compare-and-set and the write run in the same transaction. content_revision rises only for the listed fields. 2. HTTP via NewHandler, a chi router mirroring api/router.go, validator.InitValidator(), httptest and a jwt cookie. A PATCH with "title" present but empty must be 400 (guard against omitempty on a *string skipping validation). Assert body strings, X-Current-Revision, X-Slug-Suggestion, and "revision" in the read, list, POST, PATCH, publish and unpublish JSON, with old keys unchanged. 3. Two goroutines with the same if_revision: exactly one answers 200. 4. Regression: article_title_rules, article_publishing, SEO and pagination tests stay untouched, except the updated pair text. ## Automated, SQLite file (task test) 5. The migration adds edit_revision with default 1 for existing rows; a second Migrate changes nothing. 6. The compare-and-set is one UPDATE ... WHERE edit_revision = ? (or equivalent). With concurrent writers, one wins. ## Automated, real databases (task test:mysql, task test:postgres) 7. Repeat 5-6 on MySQL 8.4, MariaDB 11 and PostgreSQL. Record NOT RUN if the daemon is down, or use the podman shim (see memory). ## Build and lint 8. task test, task lint:go and CGO_ENABLED=0 go build -tags nofrontend ./... pass. No comments in the added Go files. task mutate scoped via MUTATE_FILES to the revision and title code. 9. docs/api/articles.md gains title, slug, revision, if_revision and X-Current-Revision. ## Manual None.