Phase 5c slice B. Three web write paths now pre-validate via the
itemwrite package before calling store.Create / Update / Reparent.
- handleDetailWrite: ValidateFormat + ValidateAgainstStore on (title,
slug, status, parent_ids) before the store.Update call.
- handleNewSubmit: same pair, scoped to a new item (no ID yet).
- handleReparent: format + DB-aware checks; validator catches
self-parent, unknown-parent, cycle. The existing
"parent_ids required" guard stays as a separate fast-fail.
- handleBulkApply: set_status pre-flight against the validator. Other
bulk actions (add_tag / set_mgmt / set_public / timeline_todos)
don't mutate validated fields so they pass through unchanged.
On ValidationError the handler responds 400 + a human banner keyed on
err.Kind via the new s.itemWriteFailure helper. itemWriteBannerCopy
centralises the Kind→copy mapping so web/server.go and web/bulk.go
share one phrasing.
No web test source touched — all web/*_test.go assert on observable
behaviour (HTTP status, response body) and the new validator path
preserves both for valid AND invalid inputs the SQL trigger would
have rejected anyway. Tests stay green unmodified.
Task: t-projax-5c-itemwrite