Moves carry follows over; first DMs to Lemmy 0.19 and Mbin go as ChatMessage

Two owner decisions of 2026-10-05, both recorded in ROADMAP:
- After a verified Move the personas following the old account follow the new one, in the same lists, and a mute or
  block of the old account carries over, as Mastodon does it.
- A direct message to one account on a server whose NodeInfo names Lemmy before 1.0 or Mbin goes as a ChatMessage,
  the one place PrivaPub decides by a server's software (invariant 17). G-0008 is closed.

Mbin addresses its private messages to the recipient's profile page, so a Create addressed to a persona's /@name now
reaches the persona. Checked live: moves 8/8, Lemmy 0.19 30/30, Mbin 26/26 with messages both ways. The software
theory runs alone, since every test's peer shares 127.0.0.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-05 20:57:43 +02:00
1 parent f3e8cce2ed
commit 7b0377c85f
19 files changed
+309 -63

No files matched your search

+25 -18
View File
@@ -142,7 +142,7 @@ Priorities, used throughout:
| Polls (see §3 Misskey for vote shapes) | P1 | `Status.poll`, `/polls/:id`, `/polls/:id/votes`, `poll` notification |
| Custom emoji on posts, names, fields and poll options, proxied, refreshed by `updated` | P1 | `Status.emojis`, `Account.emojis` |
| Link attachments as the card source | P1 | `Status.card` |
| Inbound `Move` with Mastodon's checks (`target` re-fetched, its `alsoKnownAs` lists the old account, 7-day lock); move each persona's follow | P1 | `Account.moved` |
| Inbound `Move` with Mastodon's checks (`target` re-fetched, its `alsoKnownAs` lists the old account); move each persona's follow, lists, mutes and blocks (done 2026-10-05) | P1 | `Account.moved` |
| Re-run WebFinger when `preferredUsername` changes; key accounts on the actor id | P2 | `Account.acct` |
| Inbound `Block`: stop delivering, hide (**done** 2026-10-04) | P2 | `relationship.blocked_by` |
| `Add`/`Remove` featured (pins, tags) | P2 | `GET /accounts/:id/statuses?pinned=true` |
@@ -260,7 +260,9 @@ Such posts are then found in the member's conversations, never by a search on th
**Account moves (2026-10-05, `tools/pasture/scenarios/moves.sh`):** GoToSocial moves an account through its API (the new
one names the old in `alsoKnownAs` first, `/api/v1/accounts/alias`) and sends `Move{object: old, target: new}` to the
old one's followers. PrivaPub reads the new account again, finds the old one among its aliases and shows the old account
`moved`; 6 checks pass. PrivaPub dropped `Move` as an unknown type until then.
`moved`. Since the owner's decision of the same day it also moves alice's follow, as Mastodon does: a Follow to the new
account (locked by GoToSocial, which approves it) and an Undo to the old; 8 checks pass. PrivaPub dropped `Move` as an
unknown type until then.
### Misskey family: Misskey 2026.10.0, Sharkey 2025.4.7, Iceshrimp.NET 2026.1.2-beta, CherryPick 4.17
@@ -515,7 +517,7 @@ on a Page: pins live in `featured`, locks in `Lock`.
| Announces of activities other than Create (votes, moderation): trust the inner activity when the object's own group signed the Announce; refetching every vote does not scale. Keep the origin refetch for Create and Update. Votes and their undoing **done** 2026-10-04 (`AnnounceHandler.Relayed`: trusted from the community's own server or on its own posts, otherwise fetched from the voter's origin); moderation still open | P1 | — |
| Moderation state: removals (reason, by, at, cascade), locks, bans with `endTime`/`removeData`, featured, moderators, `Update{Group}` by a moderator | P1 | removed posts hidden plus `privapub.removed`; `privapub.locked` (replying answers 422); pins as `pinned=true` |
| Link posts: keep `Link.href`, the thumbnail `image` and alt text; build the card (Lemmy sends no title or description for the link) | P1 | `Status.card` |
| `ChatMessage` in and out (out to someone who writes to us that way, done 2026-10-05; a first message waits, G-0008) | P1 | `visibility: direct` |
| `ChatMessage` in and out (out to someone who writes to us that way, and to Lemmy 0.19 and Mbin by NodeInfo, done 2026-10-05) | P1 | `visibility: direct` |
| Outbound shape for Lemmy: both `to` and `cc`; the community in `to`; Public in the object, Create and Announce; votes and comments sent to the community inbox | P1 | — |
| Communities we host: pick `Announce(object)` per peer by NodeInfo (as PieFed does). Announcing to every follower instance, the author's included, is done and needed (pasture evidence below) | P1 | — |
| Flags from a `Service`-typed reporter actor with `to: [community]`; the reporter stays anonymous | P2 | — |
@@ -562,14 +564,14 @@ What it showed:
- 0.19's release trusts only the roots its rustls bundles, never Caddy's CA, so the pasture builds 0.19.20 from its tag
with reqwest's `rustls-tls-native-roots` added (`tools/pasture/images/lemmy19`) and runs it as `lemmy19.test`.
- **0.19 takes private messages only as `ChatMessage`** (`ChatMessageType` has no `Note`) and answers our direct
`Note` 400. Since 2026-10-05 a direct message to someone who writes to us as `ChatMessage`s goes out as one; the
first message to someone who never did is still a `Note` (G-0008). Most of the threadiverse runs 0.19, so this
matters more than Mbin's same rule.
- **Pasture evidence (2026-10-05, Lemmy 0.19.20, `tools/pasture/scenarios/lemmy19.sh`):** 29 checks pass and one gap is
expected (G-0008, a first direct message): communities both ways, threads with titles, comments both ways, votes up
and down both ways (relayed in the community's announces, as 1.0 does), its private message to alice and her answer
as a `ChatMessage` (another persona's too), a moderator's lock (replies then refused), unlock, ban and unban
(`blocked_by`) and removal, statistics.
`Note` 400. Its actors don't say so, so since 2026-10-05 (owner decision) a direct message to one account on a server
whose NodeInfo names Lemmy before 1.0 goes out as a `ChatMessage`, a first message too. Most of the threadiverse runs
0.19, so this matters more than Mbin's same rule.
- **Pasture evidence (2026-10-05, Lemmy 0.19.20, `tools/pasture/scenarios/lemmy19.sh`):** 30 checks pass: communities
both ways, threads with titles, comments both ways, votes up and down both ways (relayed in the community's announces,
as 1.0 does), its private message to alice and her answer as a `ChatMessage` (another persona's too), a first message
to an account that never wrote here, a moderator's lock (replies then refused), unlock, ban and unban (`blocked_by`)
and removal, statistics.
### PieFed 1.7.17 and Mbin 1.10.1
@@ -603,14 +605,19 @@ What it showed:
answers the thread gone.
- **Votes:** an upvote is an `Announce`, a favourite a `Like`. Downvotes stay on Mbin (no `Dislike`), and taking an
upvote back sends nothing (its vote listener announces only the upvote), so a boost counted here stays.
- **Private messages only as `ChatMessage`:** a direct `Note` is dropped ("PM: not implemented", G-0008), and Mbin's
actors say nothing that would let a sender choose; its API never starts a conversation with a remote account.
- **Private messages only as `ChatMessage`:** a direct `Note` is dropped ("PM: not implemented"), and Mbin's actors
say nothing that would let a sender choose, so PrivaPub sends a `ChatMessage` to a server whose NodeInfo names Mbin
(owner decision 2026-10-05). Its API never starts a conversation with a remote account.
- **Mbin addresses a private message to the recipient's profile page** (`apPublicUrl`, the actor's `url`), not to its
id. PrivaPub takes a persona's profile page as its address since 2026-10-05. Mbin also passes on a message it
received as though it were sending it, signed as its remote author; it has no key for that account, so the delivery
fails on Mbin's side and nothing leaves.
- Mbin names what it makes during a request after the request's host, port included.
- **Pasture evidence (2026-10-05, Mbin 1.10.1, `tools/pasture/scenarios/mbin.sh`):** 24 checks pass and one gap is
expected (G-0008): magazines both ways; an Mbin thread in our community arrives titled and ours reaches Mbin as a
thread; a magazine's thread reaches alice's home and her Note becomes a microblog post in it; comments both ways;
Mbin's favourite counts as a like and its upvote as a boost, alice's like and boost count there; a moderator's lock,
unlock and removal; the unfollow; statistics.
- **Pasture evidence (2026-10-05, Mbin 1.10.1, `tools/pasture/scenarios/mbin.sh`):** 26 checks pass: magazines both
ways; an Mbin thread in our community arrives titled and ours reaches Mbin as a thread; a magazine's thread reaches
alice's home and her Note becomes a microblog post in it; comments both ways; Mbin's favourite counts as a like and
its upvote as a boost, alice's like and boost count there; alice's first message and mbuser's answer; a moderator's
lock, unlock and removal; the unfollow; statistics.
- **Gaps:**
- **P1:** Lemmy's P1 set, W2, and tolerating `source` as a string.
- **P2:** galleries; post `Move`; `repliesEnabled`; `nsfl`; flairs; publish `likes`/`shares` totals.