refactor(schema): stop auto-fencing new tables in desired-state bootstrap (#8620)

### Why?

This is a cleanup that brings the schema bootstrap in line with how the
codebase works today, as asked for by
[`docs/database.md`](dc25198d53/docs/database.md (L103-L124))
(#8273). Writes are now blocked during community deletion by application
admission (`begin_community_write_transaction`), and that doc's Rule 1
says new tables must not add triggers. But
`schema/community_write_fence.sql` still looped over every table with a
`community_id` column and attached the old fence trigger to it. That
meant a new table got a trigger on a fresh database and none on a
migrated one, so the two schema paths disagreed and new tenant tables
were blocked. The doc says this bootstrap change must land "before the
feature, or as the feature's first PR."

### What?

Deletes the blanket fence loop and its `\i` from `schema/schema.sql`.
Existing legacy tables keep their fences through their explicit
`schema/triggers/` files, so no current table loses its fence and
runtime behavior is unchanged. Adds a test that a new `community_id`
table stays unfenced while `events` and `users` stay fenced, and updates
`docs/database.md` and `ARCHITECTURE.md` to match. It stands on its own;
the media-sharing PRs (#8451, #8444) are the first to rely on it.

buzz-review-completed

---------

Signed-off-by: Nikolaj Goodger <ngoodger@squareup.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ngoodger-block
2026-10-28 09:26:41 +11:00
committed by GitHub
parent d4a07063c8
commit f33ebaafa1
7 changed files with 60 additions and 51 deletions

View File

@@ -100,7 +100,7 @@ writer of a fenced table already goes through admission. The remaining
fence-retirement work drops the fence triggers and functions, and MUST also
update ARCHITECTURE.md § *Dual enforcement*.
**Today this blocks new tenant-owned tables.** Startup and deletion validation
**New tenant-owned tables use application admission.** Startup and deletion validation
no longer require a fence on any table; they pass with every universal fence
object dropped (`migration_schema_fence_objects_are_optional_for_serving_and_deletion`
in `crates/buzz-db/src/store/deletion.rs`). Two things still matter:
@@ -110,21 +110,19 @@ in `crates/buzz-db/src/store/deletion.rs`). Two things still matter:
(`community deletion catalog drift (missing=…, unknown=…)`), and deletion
fails closed for every community, not only the new table's. Listing the
table is enough to pass.
- Desired-state bootstraps run `schema/community_write_fence.sql`, which
attaches a fence trigger to every `community_id` table not excluded by
`community_write_fence_excluded_table`. A fresh desired-state database would
put a trigger on the new table and a migrated one would not, so the two
schema paths would diverge.
- Desired-state bootstraps install only the legacy fences explicitly listed
under `schema/triggers/`. They do not discover and fence new tables.
Keep those existing backstops until their own retirement is verified;
new tables receive no fence in either schema path.
So before a feature can add a tenant-owned `community_id` table, the
desired-state bootstrap must stop attaching fence triggers. That change belongs
to the fence-retirement work. Land it before the feature, or as the feature's
first PR. Do not work around it with a trigger, or with an entry in
The blanket desired-state fence attachment has been removed. A feature may
add a tenant-owned `community_id` table when it follows the checklist below.
Do not add a trigger, or an entry in
`community_write_fence_excluded_table` for a table the community owns.
#### Checklist: adding a tenant-owned `community_id` table
After the desired-state change above has landed, all in the same PR:
All in the same PR:
- [ ] Every writer of the table goes through community admission
(`begin_community_write_transaction` or another constructor that returns