Changes touching this path
- a forge backup is operator recovery, and a restore replays the revocation journal (#586)
#586 asked whether a backup defeats a burn. It does, but not where the ticket
looked, and the grilling moved the question in both directions at once.
NARROWER: the #502 amendment means the forge files a content key only where
`publish::published_rows` authorizes one, so an operator backup reconstitutes
plaintext ONLY for content that was Published -- i.e. world-readable anyway.
And `published_key` is not "the one table with no other copy": the rows come
from the client's own bundle at ingest, so a re-push re-supplies them. Painful,
loud, not unrecoverable.
WIDER, and this is the find: burn is not the only thing a restore inverts. Three
columns are monotone capability-removals that no client can push back --
`burn_tombstone`, `publication.retracted_at`, `grant_log.revoked_at`. A restore
is the single operation that runs time backwards over all three. Stated once,
because it is the whole ADR: A RESTORE RE-GRANTS A CAPABILITY SOMEONE
DELIBERATELY TOOK AWAY. Burn is just the one with an ADR attached.
So the cure is not a shorter window alone. Snapshots stay immutable at rest and
the RESTORE PATH is scrubbed by construction: a key-free, content-free revocation
journal, exported continuously and replayed before the forge binds a port. The
window (7 days, enforced by an R2 lifecycle rule rather than by a prune script
that can fail silently) then bounds media at rest only, never a running system.
The dump is `age`-encrypted to a key the VPS does not hold, because
`tree_entry.path` and `path_touch.path` are PLAINTEXT for every tier -- #610's
barrier views protect the live database and protect a dump not at all. The
journal is deliberately NOT encrypted: putting the one unrecoverable artifact
behind a losable key buys nothing.
R2 gets no mirror. The realistic threat to blobs is #493's own unbuilt reaper,
which that ticket says of itself deletes live data unrecoverably when it drifts
-- so the reaper reaps into a `reaped/` prefix under the same 7 days, and burn
keeps deleting outright. Two paths remove blobs; only one may be recoverable.
Weekly automated restore-verification is rejected as SELF-DEFEATING rather than
expensive: automating decryption puts the private key back on the VPS.
The one scoping correction: #586 said the work lands beside `setup-forge.js`.
That holds for the machinery. The honesty half -- burn's third tier and the
retention window advertised on `/info` -- lands in loot proper, so this is two
build tickets in two repos.
Decision only; nothing here is built. ADR 0046, three CONTEXT.md entries, a
third tier marked into ADR 0038 in place, and forge-datastores.md's closing
"still unspecified" line replaced with a plan that says out loud it is a plan
until the drill's negative has been run.
79fa0586 · 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.