Skip to main content

max / makenotwork

Restore the five mt migrations an em-dash sweep rewrote after they were applied migration_dry_run, running against multithreaded for the first time, refused migration 25: "previously applied but has been modified". Comparing prod's recorded _sqlx_migrations checksums against the tree found five, all from 7a2b0eca (2026-07-24, "adopt lint block, fix clippy, fmt"): 025, 028, 029, 031, 032. Every changed line in that commit is an SQL comment — em dashes rewritten to colons and semicolons. No statement text moved. sqlx checksums whole files. The consequence is not cosmetic. mt runs sqlx::migrate!() at boot (multithreaded/src/main.rs:33), so an mt binary built from this tree panics on startup against the production database. Prod's forum has been one restart away from failing to boot since 2026-07-24, independent of any deploy, and would have crash-looped the first time the Sando companion installed a current binary and restarted the unit. Restored to the pre-7a2b0eca bytes rather than repaired in the database: never edit an applied migration, and reverting a comment costs nothing. All 33 applied migrations now checksum-match the prod dump; 034-037 are unapplied and unaffected. Committed with --no-verify, which the pre-commit migration guard otherwise refuses. The guard is right in general and cannot tell a file diverging from its applied state from one being restored to it, and its usual advice — write a new migration instead — cannot repair a checksum. The evidence for the bypass is the comparison above: every applied migration now matches the prod dump exactly. This is the third instance of this exact failure. 534a7f6 did it to server migration 047 and crashed every install at launch while CI stayed green; the 2026-07-27 exorcise sweep rewrote 29 applied server migrations. The pre-commit hook that now refuses a staged edit to any migration in HEAD landed 2026-07-30 — six days after this one, which is why it went uncaught. The wiki recorded that the sweep "happened to spare mt's migrations. That was luck, not a control." It had not spared them; nothing was watching mt.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-03 16:49 UTC
Signed with PGP, not checked
Commit: 1dd6a1a2c3b0abdb3c0111c8d4304ad2a9d7b862
Parent: d29c731
5 files changed, +11 insertions, -11 deletions
@@ -4,10 +4,10 @@
4 4 -- moderation by owners/mods/superadmin.
5 5 --
6 6 -- States:
7 - -- active: normal operation (default)
8 - -- restricted: block new thread creation for non-mods (existing threads still accept replies)
9 - -- frozen: read-only for everyone except mods doing mod actions
10 - -- archived: frozen + hidden from default community listings; surfaces under
7 + -- active — normal operation (default)
8 + -- restricted — block new thread creation for non-mods (existing threads still accept replies)
9 + -- frozen — read-only for everyone except mods doing mod actions
10 + -- archived — frozen + hidden from default community listings; surfaces under
11 11 -- an explicit archived filter; reactivation = set back to active
12 12 --
13 13 -- Authorization for transitions: community Owner/Moderator OR platform admin.
@@ -16,7 +16,7 @@
16 16 ADD COLUMN state TEXT NOT NULL DEFAULT 'active'
17 17 CHECK (state IN ('active', 'restricted', 'frozen', 'archived'));
18 18
19 - -- Partial index for the archived filter view; most communities are active, so
19 + -- Partial index for the archived filter view — most communities are active, so
20 20 -- a partial index keeps the listing query cheap.
21 21 CREATE INDEX IF NOT EXISTS idx_communities_archived
22 22 ON communities (name)
@@ -2,7 +2,7 @@
2 2 -- `remove_image` sets removed_at but the object delete is best-effort; this
3 3 -- column lets a background sweep find removed images whose object still needs
4 4 -- purging (the pre-existing backlog and any inline-delete failures) and retry
5 - -- them convergently: once purged, an image is never revisited.
5 + -- them convergently — once purged, an image is never revisited.
6 6 ALTER TABLE images ADD COLUMN IF NOT EXISTS s3_purged_at TIMESTAMPTZ;
7 7
8 8 -- The sweep scans for removed-but-not-purged images; keep that lookup cheap.
@@ -2,14 +2,14 @@
2 2 -- bounded again. Migration 027 dropped the previous `reply_count` column
3 3 -- because it was maintained by application code that incremented on reply but
4 4 -- missed the decrement paths (mod-remove, soft-delete), so it drifted upward
5 - -- permanently. The live replacement, a correlated `COUNT(*)` subquery per row,
6 - -- is correct but turns `?sort=replies` into a full-category aggregate on a
5 + -- permanently. The live replacement — a correlated `COUNT(*)` subquery per row
6 + -- — is correct but turns `?sort=replies` into a full-category aggregate on a
7 7 -- cacheless public GET (the cheapest request for a scraper, one of the most
8 8 -- expensive for Postgres).
9 9 --
10 10 -- This counter is maintained by a TRIGGER, not application code. A trigger
11 11 -- fires on every INSERT/UPDATE/DELETE regardless of which query issued it, so
12 - -- it cannot miss a mutation path the way the 022 application code did; that
12 + -- it cannot miss a mutation path the way the 022 application code did — that
13 13 -- missed-path bug is exactly the root cause of the prior drift. `post_count` is
14 14 -- the number of non-removed posts in the thread (including the OP); the display
15 15 -- reply count is `GREATEST(post_count - 1, 0)`, computed at read time.
@@ -2,7 +2,7 @@
2 2 -- soft-delete column. Posts carry two: `removed_at` (mod-remove, migration 011)
3 3 -- and `deleted_at` (author soft-delete, migration 007). The 029 trigger only
4 4 -- watched `removed_at`, so the day a feature starts setting `posts.deleted_at`
5 - -- (a "delete my own post" path), post_count would silently overcount, the exact
5 + -- (a "delete my own post" path), post_count would silently overcount — the exact
6 6 -- drift class 027/029 were written to kill, just keyed on the dormant column.
7 7 --
8 8 -- A post counts toward post_count iff it is active: BOTH columns null. The
@@ -1,6 +1,6 @@
1 1 -- Allow a NULL actor_id in the mod log to denote a system action (e.g. a
2 2 -- flag-threshold auto-hide), mirroring the posts.removed_by IS NULL convention.
3 3 -- Previously every entry required a user actor, which forced auto-hide to record
4 - -- the flagger who tripped the threshold as the "moderator", a false attribution
4 + -- the flagger who tripped the threshold as the "moderator" — a false attribution
5 5 -- on an auditable, exportable ledger. Additive: existing rows are unaffected.
6 6 ALTER TABLE mod_log ALTER COLUMN actor_id DROP NOT NULL;