Changes touching this path
- tenant_blob counts what a tenant references, and the account tier it belongs to stays unwritten on purpose
#612 asked what `tenant_blob.bytes` counts before anything counts it, and said
the dedup question decides whether the producer belongs at the blob `put`
"where dedup is visible" or at `ingest` "where tenancy is". Both halves resolve,
and neither the way the ticket framed them.
`bytes` is REFERENCED FOOTPRINT. What settles it is #482's own accepted cost --
deleting a tenant is "refcount-decrement-and-delete-if-zero, because a fork
legitimately holds the same object". A decrement presupposes many tenants
holding a row for one oid, which is the reference reading; under the origination
reading there is one row per oid forever and nothing to decrement.
The shorter argument -- that the primary key forces it -- is tempting and does
not work, so the comment says so rather than leaving the next reader to try it.
`(tenant_id, object_oid)` does settle the ticket's other half, running total vs
append-only ledger, because a set whose `bytes` is a property of the oid cannot
accumulate. It does not separate reference from origination: "one row per oid,
for the tenant that introduced it" is equally a set with that key.
Origination is already recorded and is not this table's: `object.introduced_by`
(#501) is first-write-wins on the address, keyed by PUBKEY, not tenant_id. What
it lacks is a byte count, so billing on origination is a column on `object`.
The put-vs-ingest question dissolves rather than being answered by the dedup
verdict. Dedup is not visible at `put` at all -- `BlobStore::put` returns no
novelty bit, and an `exists`-then-`put` is a race between concurrent pushes --
and a set-membership upsert never needs to know. So: ingest, where tenancy is.
The reason nothing counted anything is bigger than this table, and is the find
worth keeping: `tenant` HAS NO PRODUCER EITHER. #504 resolved "first push
auto-creates the `tenant` and `repo` rows"; only `repo` was built, correctly,
because `repo` is keyed by owner_pubkey and has no tenant_id at all. `tenant`,
`account_key`, `repo_member` and `tenant_blob` are one unbuilt ACCOUNT TIER --
#487 decided its shape and is closed, #753 is the build. So tenant_blob was
never a missing producer; it is a member of a tier held whole, flagged alone
because #482 named it by table. Its consumer is behind the same door: quotas
arrive with #504's open multi-tenant push.
No producer is built, and no migration is added. The record goes in the schema
comment, which is legitimate because migration 0001 IS docs/sql/forge-schema.sql
and comment-only edits are the #720-enforced exception to append-only --
`released_migration_statements_are_pinned_by_checksum` proves no statement token
moved. Per-tenant export, the third consumer, is recorded as deferred rather
than answered: it needs #493's reachability walk, which a byte count is not.
tests/account_tier.rs is the tripwire that keeps the absence from re-opening
silently, and it is written to be deletable when #753 arrives. Its own first cut
failed open twice -- on a `\` line continuation (the house SQL style) and a
quoted identifier (`INSERT INTO "ref"` is real) -- so the scan now normalises
both, plus schema qualifiers and Rust escapes, and covers the migrations
directory rather than only src/. Every spelling it claims to catch is pinned by
a positive control, because a scan that has quietly stopped matching reproduces
the exact silence #612 was filed about, inside its own guard.
Two claims in the first draft were corrected by review before landing: the
primary-key argument above, and pointing the reader at #487 (closed) rather than
#753. #690's allowlist is also named as what it is -- a deployment setting, not
a code closure, since an empty list means open and the binary only warns.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
a0106e52 · dbf3dbe6…
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.