The forum shipped in 0.8.57 with the hard part already finished — a read model
that carries its visibility rules as SQL, so nothing leaks even from an endpoint
that forgot to filter. What was missing was everything between "the API is
correct" and "a stranger arrives from Hacker News and stays".
ILIKE + trigram GINtsvector: the tests run on SQLite, and a query the tests cannotQAPage with an acceptedAnswer.limit/offset; no page ever read one, socontext=community; /login never forwarded it, so thePlus a social card per thread, an RSS feed, and the directory in the sitemap and
the site's own navigation.
Four shapes that lay out channels, seed first threads, and set participation
defaults. Idempotent by channel slug, so a second click reports what it skipped
rather than leaving you with help and help-a1b2c3. Publishing stays a
separate decision, and a template's participation settings are defaults —
written on first setup only, so re-applying one to add a channel cannot re-open
replies on a forum whose owner deliberately closed them.
A Service Desk ticket's answer, or a document, can become a public thread. Two
independent per-workspace switches, because a workspace may well want its docs
public and its customer ticket traffic emphatically not.
Nothing is published as it arrived: the composer is pre-filled and a person edits
it, because a customer's email contains the customer and no redaction heuristic
is good enough to run that unattended. A document gets an intro rather than a
copy of itself — a document is edited after publishing, and a stale copy on a
public page is worse than none.
Driven against the live stack, not just tests: migration applied, a community
seeded, then asked a question, replied, reacted, marked an answer, searched,
viewed a profile, checked RSS and both sitemaps, and mobile. The opt-in gates
confirmed empty→populated as each switch flipped. The anonymity guarantee
confirmed to remove the name, the handle and the profile page together. Search
confirmed to return 200 up to its budget and then 429.
972 backend tests, 638 frontend tests, tsc clean, 0 lint errors, the six
community backend modules mypy-clean, and the production build compiles all
nine new routes.
The three commits are worth reading in order — the second and third are a
self-review of the first and say plainly what was shipped broken:
09174063 the feature38d7e83f six gaps found reviewing it, including a docs link that had ab9a214b5 the remaining hardening — search budget, shadowed slugs, typedmigrate_2026_08_25_community_launch.sql andmigrate_2026_08_25_community_reserved_slugs.sql. The second is separateschema_migrations