diff --git a/README.md b/README.md --- a/README.md +++ b/README.md @@ -603,12 +603,14 @@ `CONSUMER_ENABLED` is set, the task-14 Jetstream consumer reads this record and enforces it: `enabled: false` is a **soft disable** — the actor stops resolving via WebFinger and stops delivering, while its actor document and already-federated references stay intact. Adding `deleteRemote: true` escalates -to the destructive tier (ask peers to delete the user's federated content — -irreversible on their side); the consumer **records** that intent in -`federation_prefs` but does not act on it until task 17's destructive tier is -wired, so the request survives a crash and is honored once that seam lands. -Deleting the record, or writing `enabled: true`, restores the default under the -SAME actor identity: the local part is frozen at creation and never re-derived. +to the destructive tier, which **is wired** (task 17d): the bridge sends +`Delete{Person, removeData: true}` to every inbox that ever received the +user's content, tombstones the actor (410), and stamps the identity purged — +irreversible on both sides. For a **soft** opt-out, deleting the record or +writing `enabled: true` restores the default under the SAME actor identity +(the local part is frozen at creation and never re-derived); after a +destructive purge, re-enablement is **refused** — the tombstoned identity +never federates again. With `CONSUMER_ENABLED` off (the default), nothing reads the record and federation stays on for every minted actor — the lexicon is still published so Coves' settings UI can write against a stable shape ahead of the switch. @@ -638,10 +640,11 @@ Coves users get ActivityPub identities of their own, served on `AP_USER_ORIGIN` — a **second origin on the same listener**, distinct from the bridge's `BRIDGE_HOSTNAME` surface. A `Host` router splits the two: the bridge -hostname and its bridged-handle subdomains (plus `localhost`, bare IPs, and an -absent `Host` — container healthchecks) reach the bridge; the user origin's own -`Host` reaches the user surface; anything else is refused with **421 Misdirected -Request** unless `AP_HOST_FALLTHROUGH_DEV` is on. When both names resolve to one +hostname and its bridged-handle subdomains (plus `localhost`, **loopback** IPs, +and an absent `Host` — container healthchecks) reach the bridge; the user +origin's own `Host` reaches the user surface; anything else — including a +public bare-IP `Host`, which names no configured surface — is refused with +**421 Misdirected Request** unless `AP_HOST_FALLTHROUGH_DEV` is on. When both names resolve to one authority (the dev default, `localhost:8091`), the split falls back to the path: the user surface answers first and its 404s fall through to the bridge. diff --git a/lexicons/MANIFEST.sha256 b/lexicons/MANIFEST.sha256 --- a/lexicons/MANIFEST.sha256 +++ b/lexicons/MANIFEST.sha256 @@ -21,7 +21,7 @@ 55c9a36e9d5d3ca94a39dc29cbaa41a1cc57642ccf1162c32542ada410ee175e social/coves/aggregator/register.json d3e077e34c9b9ccd8a8892148fe4ce7ab1de65873250a8906aec510d040bfa4c social/coves/aggregator/revokeApiKey.json 0ca7c339793fc8063a312bf39619983d98414fba498b05fee92c135c7ebea0fd social/coves/aggregator/service.json d688327a711491aeb58b75187f468f213d270adad0c0ca59b96fbef0229cd3f4 social/coves/aggregator/updateConfig.json -5a0ee9495bb2c0949f960a1d080af9f5f23cf696aea72187e02cdbeedd069151 social/coves/bridge/federation.json +5aced9b10f4dbc9d540e47ab9b671dd50b7d553c5d3ae8714a0adb91d5d2d726 social/coves/bridge/federation.json 020b4a33837455e17e1b0e258304f11241931d14929be099f33ca67a88fc2f49 social/coves/bridge/getVoteAggregates.json 94ef1e9a8c6c879697a787f53a48ebeed7edc3a05a90926991667df5a67008f5 social/coves/community/acceptance.json 88fb6259698d0097995200ed5d3a7887165f9cd29907c1c60880150c6568aebf social/coves/community/block.json diff --git a/lexicons/social/coves/bridge/federation.json b/lexicons/social/coves/bridge/federation.json --- a/lexicons/social/coves/bridge/federation.json +++ b/lexicons/social/coves/bridge/federation.json @@ -4,7 +4,7 @@ "id": "social.coves.bridge.federation", "defs": { "main": { "type": "record", - "description": "A Coves user's ActivityPub federation preference, read by the Tidepool bridge. This record is an OPT-OUT: federation is on by default and its ABSENCE means enabled, so the record only ever exists to turn federation down. enabled=false is a soft disable — the user's AP actor stops resolving via WebFinger and stops delivering, while the actor document and its already-federated references stay intact. Adding deleteRemote=true escalates to the destructive tier, asking peers to delete the user's federated content. Re-enabling is either deleting this record or writing enabled=true; both restore the default-on state under the SAME actor identity, because the local part is frozen at creation and never re-derived.", + "description": "A Coves user's ActivityPub federation preference, read by the Tidepool bridge. This record is an OPT-OUT: federation is on by default and its ABSENCE means enabled, so the record only ever exists to turn federation down. enabled=false is a soft disable — the user's AP actor stops resolving via WebFinger and stops delivering, while the actor document and its already-federated references stay intact. Adding deleteRemote=true escalates to the destructive tier, asking peers to delete the user's federated content — IRREVERSIBLE: once the purge runs, the actor is tombstoned and re-enablement is refused forever; a UI offering deleteRemote must present it as permanent. After a soft disable only, re-enabling is either deleting this record or writing enabled=true; both restore the default-on state under the SAME actor identity, because the local part is frozen at creation and never re-derived.", "key": "literal:self", "record": { "type": "object",