Changes touching this path
- the browser opens what the forge cannot: own-private read ships an owner read tier, a once-per-device unlock, and a grant mailbox that never acks (#1043)
c8dd4da1 · dbf3dbe6… - the view invariant stops being a name filter and becomes a property of the schema: grant_log_is_refused_in_every_form already enumerated pg_views rather than a literal list, but filtered it to the forge_read name prefix, so the eleven forge_owner views migration 0009 creates sat outside it entirely and 0009's own loudest paragraph - that the owner read surface carries no key material, not published_key, not grant_log, not grant_inbox - was prose with no assertion under it. It now holds over EVERY view in public, and the contrast is COMMITTED rather than transcribed: a new case plants a leaking owner view in a scratch database, asserts the exact violation sentence, runs the pre-1727 query beside it and REQUIRES it to still read zero, then drops the view and requires green - so the case cannot later degrade into one that would have passed before. The ticket was wrong about one table, and implementing it literally would have shipped a permanently red test: published_key is not named by no view at all, since forge_read_published_key has named it since migration 0003 as the anonymous tier's key path, gated two hops back on metadata_public plus a live publication. It becomes an exact set instead, which is strictly stronger than the absence the ticket asked for, because it fires both on an owner or member view GAINING key material and on the read view LOSING its definition. repo_member is expressed the same way and is correct before and after #1726 with no edit, because both sides are computed from the same live catalogue - today both are empty, after #1726 both become the member family - and it is not vacuous today either, since the planted owner view puts a name on the left and none on the right. The vacuity guard runs first and is what makes the rest mean anything, because every assertion here is an absence and an absence is true of an empty result: it asserts the read and owner families are both non-empty and that one view from each is present BY NAME, proved by pointing it at a second database migrated only to 0008, where it answers that the family this ticket exists to cover is the one that is missing. The counts are verified from the catalogue rather than from the ticket - eleven owner views, fifteen read views, zero member views, twenty-six in public - and the opt-in limit is stated rather than fixed, in the register #1734 set hours earlier, naming both tests, the env vars they need, the zero LOOT_FORGE occurrences under the workflows directory, and #1735 for the build that would change it (#1727)
19f9c87a · dbf3dbe6…diff - the forge live-database suites now run in CI: test-main.yml stands up a postgres:18 service, provisions it the way setup-forge.js does including its default privileges, migrates it with the commit own loot-forge --migrate, sets every LOOT_FORGE_TEST database url the Rust and site suites read, and runs cargo test and then the site pg tests against it. LOOT_FORGE_TEST_REQUIRE_DATABASE turns a database test skip into a failure through pg::live_opt_in and the site skippingLive helper, and with it set and no url 91 Rust tests and all six site pg files fail, while two half-suites that used to skip silently now say so. The default-privilege tripwires run in CI by decision, and fail on a cluster without provisioning. A new migration that neutralises the roster policy passed the bare suite and failed rls.rs and membership.pg.test.ts against the cluster. It is a canary on landed main and not a pre-land gate, and the prose that said no workflow sets these urls now says that instead (#1735)
c0931f78 · dbf3dbe6…diff
Renames are not followed. loot's tree maps a path to an address, so a rename is a delete and an add. This list is the history of the name, not of the bytes.