Skip to main content

max / makenotwork

Close out chat: owner settings, wipe-now, mention highlight, entry point Multithreaded chat had its crate, storage, trait impls, routes and client island but no way in and no way for an owner to shape it. Four things: The community page links to the room. Nothing did, so /p/{slug}/chat was reachable only by typing it. The link resolves through room_state rather than reading chat_policy, so it appears exactly when the route does not 404 and a read-only room still links. The settings screen writes chat_policy and both retention bounds, owner only, generated from ChatPolicy::ALL so a fifth variant needs no template edit. Both bounds are validated against the crate ceilings before the write, leaving migration 039's CHECKs as the backstop they were meant to be. Saving calls recompute_chat_expiry, which had no caller: expiry is stamped at insert, so a shortened window that does not reach back applies only to future messages. Wipe-now is a new ChatEvent::Wipe rather than a fan of Delete or Purge frames, since a wipe is not addressed at anyone and the client just empties the log. Owner-only through a separate flag on MtChatModeration: moderators moderate people, and emptying the room is not that. Logged as ModAction::ChatWipe on the same transaction as the deletion. Mentions highlight in-room and notify nobody. Matched against docengine's username rule on the rendered body, since render_chat deliberately leaves @name as plain text. Code spans and tag interiors are excluded, and a name markup splits stays split, so the client and the forum agree on what counts as naming someone. Also: button.danger had no CSS, so the admin clean-slate button rendered as an ordinary one.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-09 19:00 UTC
Signed with PGP, not checked
Commit: 2f81be8cb1225bf06ea89393cdf5a20542ce303d
Parent: 5ef6b5b
27 files changed, +1266 insertions, -34 deletions
@@ -4862,14 +4862,6 @@
4862 4862 source = "registry+https://github.com/rust-lang/crates.io-index"
4863 4863 checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
4864 4864
4865 - [[patch.unused]]
4866 - name = "synckit-client"
4867 - version = "0.8.0"
4868 -
4869 - [[patch.unused]]
4870 - name = "synckit-config"
4871 - version = "0.2.0"
4872 -
4873 4865 [[patch.unused]]
4874 4866 name = "kberg"
4875 4867 version = "0.1.0"
@@ -4877,3 +4869,35 @@
4877 4869 [[patch.unused]]
4878 4870 name = "painhours"
4879 4871 version = "0.1.0"
4872 +
4873 + [[patch.unused]]
4874 + name = "quasi-axum"
4875 + version = "0.1.0"
4876 +
4877 + [[patch.unused]]
4878 + name = "quasi-http"
4879 + version = "0.1.0"
4880 +
4881 + [[patch.unused]]
4882 + name = "quasi-router"
4883 + version = "0.1.0"
4884 +
4885 + [[patch.unused]]
4886 + name = "quasi-store"
4887 + version = "0.1.0"
4888 +
4889 + [[patch.unused]]
4890 + name = "quasi-tauri"
4891 + version = "0.1.0"
4892 +
4893 + [[patch.unused]]
4894 + name = "quasi-webview"
4895 + version = "0.1.0"
4896 +
4897 + [[patch.unused]]
4898 + name = "synckit-client"
4899 + version = "0.8.0"
4900 +
4901 + [[patch.unused]]
4902 + name = "synckit-config"
4903 + version = "0.2.0"
@@ -266,6 +266,24 @@
266 266 opacity: 0.8;
267 267 }
268 268
269 + /* Irreversible actions. The class was in the markup before it was in here (the
270 + admin clean-slate button, the chat wipe), rendering as an ordinary button,
271 + which is the one thing a destructive control must not look like. */
272 + button.danger {
273 + background: var(--danger);
274 + color: var(--primary-light);
275 + border: none;
276 + padding: 0.5rem 1rem;
277 + font-family: inherit;
278 + font-size: 0.85rem;
279 + cursor: pointer;
280 + transition: opacity 0.2s ease;
281 + }
282 +
283 + button.danger:hover {
284 + opacity: 0.8;
285 + }
286 +
269 287 /* FORMS */
270 288
271 289 form {
@@ -1669,6 +1687,14 @@
1669 1687 border-left: 2px solid var(--danger);
1670 1688 }
1671 1689
1690 + /* Someone named this reader. A tint and a rule rather than anything louder:
1691 + chat scrolls, the highlight has to survive being one of forty messages, and
1692 + there is deliberately no notification behind it. */
1693 + .chat-message.is-mention {
1694 + background: var(--surface-alt);
1695 + border-left: 2px solid var(--highlight);
1696 + }
1697 +
1672 1698 .chat-error {
1673 1699 color: var(--danger);
1674 1700 font-size: 0.85rem;