A direct message answers in the form its recipient writes in
Lemmy 0.19 (most of the threadiverse) and Mbin take a private message only as a ChatMessage and refuse a direct Note. A direct message to one account elsewhere that writes to us as ChatMessages now goes out as one: to it alone, without a mention in its text, kept on the post (Post.AsChatMessage) so the served copy and an edit match. No software name decides it. Live against Lemmy 0.19: alice's answer to lemmyuser's private message and another persona's message to lemmyuser arrive (29 checks). A first message to an account that never wrote to anyone here is still a Note, which they refuse; G-0008 keeps that open for the owner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
a85ebd30c0
commit
f38ac73615
10 files changed
+90
-17
No files matched your search
@@ -551,7 +551,8 @@ tools/pasture/run.sh down # removes e
|
|||||||
rustls bundles, so `images/lemmy19` builds the tag with reqwest's `rustls-tls-native-roots` added (about ten minutes
|
rustls bundles, so `images/lemmy19` builds the tag with reqwest's `rustls-tls-native-roots` added (about ten minutes
|
||||||
the first time) and the pasture's bundle is mounted as the system's. Its config names the database as `uri` (1.0:
|
the first time) and the pasture's bundle is mounted as the system's. Its config names the database as `uri` (1.0:
|
||||||
`connection`) and its API is v3 (`/api/v3`, `sort=New`, `resolve_object` answering views). It takes private messages
|
`connection`) and its API is v3 (`/api/v3`, `sort=New`, `resolve_object` answering views). It takes private messages
|
||||||
only as `ChatMessage` (G-0008). `scenarios/lemmy19.sh`, 27 checks and that gap.
|
only as `ChatMessage`: a reply goes out as one, a first message cannot (G-0008). `scenarios/lemmy19.sh`, 29 checks
|
||||||
|
and that gap.
|
||||||
- **Hollo (0.9.19):** Fedify's microblog server on the shared Postgres, set up through its web form (which
|
- **Hollo (0.9.19):** Fedify's microblog server on the shared Postgres, set up through its web form (which
|
||||||
checks `Origin` against `Host`, so the request names `hollo.test` without the port). It needs a 44-character
|
checks `Origin` against `Host`, so the request names `hollo.test` without the port). It needs a 44-character
|
||||||
`SECRET_KEY`, a media directory and a `themeColor`; statuses and votes go as JSON. Town only, no scenario.
|
`SECRET_KEY`, a media directory and a `themeColor`; statuses and votes go as JSON. Town only, no scenario.
|
||||||
|
|||||||
@@ -158,6 +158,10 @@ persona's posts passed on to its followers. A deleted post answers 410 with a `T
|
|||||||
- **Blocks are sent.** A blocked remote account receives `Block` from the blocking account (and `Reject{Follow}` if it
|
- **Blocks are sent.** A blocked remote account receives `Block` from the blocking account (and `Reject{Follow}` if it
|
||||||
followed); an unblock sends `Undo{Block}`.
|
followed); an unblock sends `Undo{Block}`.
|
||||||
- **Reports** are sent as `Flag` by the instance actor, never by the reporting account.
|
- **Reports** are sent as `Flag` by the instance actor, never by the reporting account.
|
||||||
|
- **Direct messages** go out as a `Note` addressed to their recipients, except to someone who writes to us as
|
||||||
|
`ChatMessage`s (Pleroma's type, which Lemmy 0.19 and Mbin take as their only private messages): a message to that one
|
||||||
|
account alone goes out as a `ChatMessage`, to it alone, without a mention in its text. The first message to an
|
||||||
|
account that never wrote to anyone here is still a `Note`, which Lemmy 0.19 and Mbin refuse (G-0008).
|
||||||
- **Replies are passed on** (inbox forwarding; owner decision 2026-10-05). A public or unlisted reply from another server
|
- **Replies are passed on** (inbox forwarding; owner decision 2026-10-05). A public or unlisted reply from another server
|
||||||
to a persona's public, unlisted or followers-only post goes on to the persona's followers as its author's server sent
|
to a persona's public, unlisted or followers-only post goes on to the persona's followers as its author's server sent
|
||||||
and signed it, the way Mastodon forwards it: to every follower's server but the replier's own. Its `Update` and
|
and signed it, the way Mastodon forwards it: to every follower's server but the replier's own. Its `Update` and
|
||||||
|
|||||||
@@ -106,6 +106,49 @@ namespace PrivaPub.Tests.Federation
|
|||||||
Assert.NotNull(message.ConversationId);
|
Assert.NotNull(message.ConversationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lemmy 0.19 and Mbin take a private message only as a ChatMessage: someone who writes to us that way is answered in
|
||||||
|
// kind, anyone else with a Note
|
||||||
|
[Fact]
|
||||||
|
public async Task A_direct_message_answers_in_the_form_its_recipient_writes_in()
|
||||||
|
{
|
||||||
|
var token = TestContext.Current.CancellationToken;
|
||||||
|
var (_, alice) = await _harness.Persona("alice");
|
||||||
|
var lemmy = new RemoteActor(_harness.Peer, "pm");
|
||||||
|
var mastodon = new RemoteActor(_harness.Peer, "dm");
|
||||||
|
async Task<Post> Received(RemoteActor sender, string type)
|
||||||
|
{
|
||||||
|
var id = NewId(sender, "messages");
|
||||||
|
await _harness.Deliver(sender, "/human-centipede", new JsonObject
|
||||||
|
{
|
||||||
|
["id"] = NewId(sender, "activities/create"), ["type"] = "Create", ["actor"] = sender.Id, ["to"] = new JsonArray(alice.Uri),
|
||||||
|
["object"] = new JsonObject
|
||||||
|
{
|
||||||
|
["id"] = id, ["type"] = type, ["attributedTo"] = sender.Id, ["to"] = new JsonArray(alice.Uri),
|
||||||
|
["content"] = "<p>psst</p>", ["published"] = DateTime.UtcNow.ToString("O")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return await DB.Default.Find<Post>().Match(p => p.ObjectURI == id).ExecuteSingleAsync(token);
|
||||||
|
}
|
||||||
|
async Task<JsonObject> Answer(RemoteActor to, Post message)
|
||||||
|
{
|
||||||
|
var answer = await _harness.Statuses.Publish(alice, new PrivaPub.Domain.Statuses.StatusDraft
|
||||||
|
{
|
||||||
|
Text = "psst back", Visibility = PostVisibility.Direct, ConversationId = message.ConversationId
|
||||||
|
}, token);
|
||||||
|
Assert.True(answer.Ok, answer.Error);
|
||||||
|
return (JsonObject)(await _harness.Outgoing(to.Id + "/inbox")).Last(a => a["type"]!.GetValue<string>() == "Create")["object"]!;
|
||||||
|
}
|
||||||
|
|
||||||
|
var chat = await Answer(lemmy, await Received(lemmy, "ChatMessage"));
|
||||||
|
var note = await Answer(mastodon, await Received(mastodon, "Note"));
|
||||||
|
|
||||||
|
Assert.Equal("ChatMessage", chat["type"]!.GetValue<string>());
|
||||||
|
Assert.Equal(lemmy.Id, Assert.Single(chat["to"]!.AsArray())!.GetValue<string>());
|
||||||
|
Assert.Null(chat["cc"]);
|
||||||
|
Assert.DoesNotContain("h-card", chat["content"]!.GetValue<string>());
|
||||||
|
Assert.Equal("Note", note["type"]!.GetValue<string>());
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task An_unreachable_key_asks_the_sender_to_retry_instead_of_refusing()
|
public async Task An_unreachable_key_asks_the_sender_to_retry_instead_of_refusing()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -248,6 +248,9 @@ namespace PrivaPub.Domain.Statuses
|
|||||||
.Concat(post.Mentions)
|
.Concat(post.Mentions)
|
||||||
.DistinctBy(m => m.ActorURI)
|
.DistinctBy(m => m.ActorURI)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
// to someone who writes to us as ChatMessages (Lemmy 0.19 and Mbin take a private message no other way), in kind
|
||||||
|
post.AsChatMessage = recipients is [{ LocalId: null } recipient]
|
||||||
|
&& await _dbEntities.Posts.Match(p => p.ActorURI == recipient.Uri && p.IsFederatedCopy && p.ObjectType == "ChatMessage").ExecuteAnyAsync(token);
|
||||||
var note = ActivityPubRenderer.DirectNote(post, author, recipients.Select(r => (r.Uri, r.Handle)).ToList(), dmGroup.ConversationURI);
|
var note = ActivityPubRenderer.DirectNote(post, author, recipients.Select(r => (r.Uri, r.Handle)).ToList(), dmGroup.ConversationURI);
|
||||||
create = ActivityPubRenderer.Create(author, note, $"create-{post.ID}");
|
create = ActivityPubRenderer.Create(author, note, $"create-{post.ID}");
|
||||||
post.To = Strings(note["to"]);
|
post.To = Strings(note["to"]);
|
||||||
|
|||||||
@@ -183,7 +183,14 @@ namespace PrivaPub.Federation.Rendering
|
|||||||
foreach (var recipient in recipients.Where(r => !named.Contains(r.Uri)))
|
foreach (var recipient in recipients.Where(r => !named.Contains(r.Uri)))
|
||||||
tags.Add(new JsonObject { ["type"] = "Mention", ["href"] = recipient.Uri, ["name"] = "@" + recipient.Handle });
|
tags.Add(new JsonObject { ["type"] = "Mention", ["href"] = recipient.Uri, ["name"] = "@" + recipient.Handle });
|
||||||
var unmentioned = recipients.Where(r => !named.Contains(r.Uri)).ToList();
|
var unmentioned = recipients.Where(r => !named.Contains(r.Uri)).ToList();
|
||||||
if (unmentioned.Count > 0)
|
// a ChatMessage (Pleroma's, which Lemmy 0.19 and Mbin take as their private messages) has one recipient and no
|
||||||
|
// mention of them in its text
|
||||||
|
if (post.AsChatMessage)
|
||||||
|
{
|
||||||
|
note["type"] = "ChatMessage";
|
||||||
|
note.Remove("cc");
|
||||||
|
}
|
||||||
|
else if (unmentioned.Count > 0)
|
||||||
note["content"] = "<p>" + string.Join(" ", unmentioned.Select(r =>
|
note["content"] = "<p>" + string.Join(" ", unmentioned.Select(r =>
|
||||||
$"<span class=\"h-card\" translate=\"no\"><a href=\"{WebUtility.HtmlEncode(r.Uri)}\" class=\"u-url mention\">@<span>{WebUtility.HtmlEncode(r.Handle.Split('@')[0])}</span></a></span>"))
|
$"<span class=\"h-card\" translate=\"no\"><a href=\"{WebUtility.HtmlEncode(r.Uri)}\" class=\"u-url mention\">@<span>{WebUtility.HtmlEncode(r.Handle.Split('@')[0])}</span></a></span>"))
|
||||||
+ "</p>" + note["content"]!.GetValue<string>();
|
+ "</p>" + note["content"]!.GetValue<string>();
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ namespace PrivaPub.Models.Post
|
|||||||
public bool IsFederatedCopy { get; set; }
|
public bool IsFederatedCopy { get; set; }
|
||||||
public string ObjectURI { get; set; }//the Note's id
|
public string ObjectURI { get; set; }//the Note's id
|
||||||
public string ObjectType { get; set; }//the remote object's type: Note, Article, Page, Video, Event…; null for local posts
|
public string ObjectType { get; set; }//the remote object's type: Note, Article, Page, Video, Event…; null for local posts
|
||||||
|
public bool AsChatMessage { get; set; }//a local direct message sent as a ChatMessage: its one recipient writes to us that way
|
||||||
public string ActivityURI { get; set; }//the Create's id
|
public string ActivityURI { get; set; }//the Create's id
|
||||||
public string ActorURI { get; set; }//attributedTo
|
public string ActorURI { get; set; }//attributedTo
|
||||||
public string Url { get; set; }
|
public string Url { get; set; }
|
||||||
|
|||||||
+9
-7
@@ -510,7 +510,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 | — |
|
| 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` |
|
| 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` |
|
| 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 only to Lemmy < 1.0 and Mbin; `Note` to everyone else) | P1 | `visibility: direct` |
|
| `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` |
|
||||||
| 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 | — |
|
| 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 | — |
|
| 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 | — |
|
| Flags from a `Service`-typed reporter actor with `to: [community]`; the reporter stays anonymous | P2 | — |
|
||||||
@@ -557,12 +557,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
|
- 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`.
|
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
|
- **0.19 takes private messages only as `ChatMessage`** (`ChatMessageType` has no `Note`) and answers our direct
|
||||||
`Note` 400. Most of the threadiverse runs 0.19, so this matters more than Mbin's same rule (G-0008).
|
`Note` 400. Since 2026-10-05 a direct message to someone who writes to us as `ChatMessage`s goes out as one; the
|
||||||
- **Pasture evidence (2026-10-05, Lemmy 0.19.20, `tools/pasture/scenarios/lemmy19.sh`):** 27 checks pass and one gap is
|
first message to someone who never did is still a `Note` (G-0008). Most of the threadiverse runs 0.19, so this
|
||||||
expected (G-0008, direct messages to it), with no change to PrivaPub: communities both ways, threads with titles,
|
matters more than Mbin's same rule.
|
||||||
comments both ways, votes up and down both ways (relayed in the community's announces, as 1.0 does), its private
|
- **Pasture evidence (2026-10-05, Lemmy 0.19.20, `tools/pasture/scenarios/lemmy19.sh`):** 29 checks pass and one gap is
|
||||||
message to alice, a moderator's lock (replies then refused), unlock, ban and unban (`blocked_by`) and removal,
|
expected (G-0008, a first direct message): communities both ways, threads with titles, comments both ways, votes up
|
||||||
statistics.
|
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.
|
||||||
|
|
||||||
### PieFed 1.7.17 and Mbin 1.10.1
|
### PieFed 1.7.17 and Mbin 1.10.1
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -72,8 +72,9 @@ Written 2026-10-01 from the original 2023 code, the decePubClient UI, a federati
|
|||||||
- wave 2, under way: PieFed, Mbin, NodeBB and Lemmy 0.19 in the pasture with scenarios (2026-10-05). What they showed and was fixed: the
|
- wave 2, under way: PieFed, Mbin, NodeBB and Lemmy 0.19 in the pasture with scenarios (2026-10-05). What they showed and was fixed: the
|
||||||
instance actor answers at the server's root, where PieFed looks for the inbox it announces to; a community's removal
|
instance actor answers at the server's root, where PieFed looks for the inbox it announces to; a community's removal
|
||||||
of a post on its own server is believed at once; a followed group's post its own server sends without announcing
|
of a post on its own server is believed at once; a followed group's post its own server sends without announcing
|
||||||
it is kept, and a bare `Lock` from the post's server is taken (Mbin). Open: direct messages to Lemmy 0.19 and Mbin,
|
it is kept, and a bare `Lock` from the post's server is taken (Mbin). A direct message to someone who writes to us as
|
||||||
which take them only as `ChatMessage` (G-0008, waits for the owner).
|
`ChatMessage`s goes out as one (Lemmy 0.19, Mbin). Open: a first message to such an account (G-0008, waits for the
|
||||||
|
owner).
|
||||||
- [ ] P7 Threads, communities, moderation, the social graph
|
- [ ] P7 Threads, communities, moderation, the social graph
|
||||||
- [ ] P8 Signatures, discovery, the long tail
|
- [ ] P8 Signatures, discovery, the long tail
|
||||||
- [x] P9 Reading at volume (owner decision 2026-10-04, back from "Cut"): lists, server-side filters, scheduled posts,
|
- [x] P9 Reading at volume (owner decision 2026-10-04, back from "Cut"): lists, server-side filters, scheduled posts,
|
||||||
|
|||||||
@@ -87,10 +87,21 @@ echo " private messages"
|
|||||||
alice_on_lm=$(lm GET "resolve_object?q=@alice_lemmy19@privapub.test" | j "print(d['person']['person']['id'])")
|
alice_on_lm=$(lm GET "resolve_object?q=@alice_lemmy19@privapub.test" | j "print(d['person']['person']['id'])")
|
||||||
lm POST private_message "{\"content\":\"a secret from Lemmy 0.19\",\"recipient_id\":$alice_on_lm}" >/dev/null
|
lm POST private_message "{\"content\":\"a secret from Lemmy 0.19\",\"recipient_id\":$alice_on_lm}" >/dev/null
|
||||||
until_true 45 'curl -s -H "$LAH" "$P/api/v1/conversations" | grep -q "a secret from Lemmy 0.19"' && ok "Lemmy 0.19's private message arrives as a DM" || ko "Lemmy 0.19's private message missing on PrivaPub"
|
until_true 45 'curl -s -H "$LAH" "$P/api/v1/conversations" | grep -q "a secret from Lemmy 0.19"' && ok "Lemmy 0.19's private message arrives as a DM" || ko "Lemmy 0.19's private message missing on PrivaPub"
|
||||||
# (0.19 takes a private message only as a ChatMessage and answers alice's direct Note 400, G-0008; 1.0 takes a Note)
|
# lemmyuser wrote as a ChatMessage, so alice's answer goes out as one
|
||||||
curl -s -o /dev/null -X POST -H "$LAH" $P/api/v1/statuses -d 'status=@lemmyuser@lemmy19.test a secret from PrivaPub&visibility=direct'
|
curl -s -o /dev/null -X POST -H "$LAH" $P/api/v1/statuses -d "status=@lemmyuser@lemmy19.test an answer from PrivaPub $run&visibility=direct"
|
||||||
until_true 30 'lm GET "private_message/list?limit=50" | grep -q "a secret from PrivaPub"' && ok "alice's DM arrives as a Lemmy 0.19 private message" \
|
until_true 45 'lm GET "private_message/list?limit=50" | grep -q "an answer from PrivaPub $run"' && ok "alice's answer reaches Lemmy 0.19 as a ChatMessage" || ko "alice's answer never reached Lemmy 0.19"
|
||||||
|| xf "alice's DM never reaches Lemmy 0.19, which takes private messages only as ChatMessage (G-0008)"
|
# another persona writing to lemmyuser, who writes to us as ChatMessages, does so in kind too
|
||||||
|
LBT=$(privapub_token bob_lemmy19)
|
||||||
|
curl -s -o /dev/null -X POST -H "Authorization: Bearer $LBT" $P/api/v1/statuses -d "status=@lemmyuser@lemmy19.test a word from bob $run&visibility=direct"
|
||||||
|
until_true 45 'lm GET "private_message/list?limit=50" | grep -q "a word from bob $run"' && ok "bob's DM to lemmyuser goes as a ChatMessage too" || ko "bob's DM never reached Lemmy 0.19"
|
||||||
|
# (0.19 takes a private message only as a ChatMessage and answers a direct Note 400: a first message to someone who
|
||||||
|
# never wrote to anyone here is a Note, G-0008. 1.0 takes a Note)
|
||||||
|
quiet="quiet$run"
|
||||||
|
QT=$(site lemmy19.test -s -X POST "$LM/api/v3/user/register" -H 'Content-Type: application/json' \
|
||||||
|
-d "{\"username\":\"$quiet\",\"password\":\"Lemmy-Pasture-Pass-1\",\"password_verify\":\"Lemmy-Pasture-Pass-1\",\"show_nsfw\":false}" | j "print(d['jwt'])")
|
||||||
|
curl -s -o /dev/null -X POST -H "$LAH" $P/api/v1/statuses -d "status=@$quiet@lemmy19.test a first word from PrivaPub $run&visibility=direct"
|
||||||
|
until_true 30 'site lemmy19.test -s "$LM/api/v3/private_message/list?limit=50" -H "Authorization: Bearer $QT" | grep -q "a first word from PrivaPub $run"' \
|
||||||
|
&& ok "alice's first DM to someone there arrives" || xf "alice's first DM to someone there never arrives, a Note Lemmy 0.19 refuses (G-0008)"
|
||||||
|
|
||||||
echo " moderation"
|
echo " moderation"
|
||||||
p_locked() { curl -s -H "$LAH" "$P/api/v1/statuses/$lm_cats_on_p" | j "print((d.get('privapub') or {}).get('locked'))"; }
|
p_locked() { curl -s -H "$LAH" "$P/api/v1/statuses/$lm_cats_on_p" | j "print((d.get('privapub') or {}).get('locked'))"; }
|
||||||
|
|||||||
@@ -110,7 +110,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "G-0008",
|
"id": "G-0008",
|
||||||
"title": "A direct message to a Lemmy 0.19 or Mbin account never arrives: both take a private message only as a ChatMessage",
|
"title": "A first direct message to a Lemmy 0.19 or Mbin account never arrives: both take a private message only as a ChatMessage",
|
||||||
"match": {
|
"match": {
|
||||||
"feature": "deliver\\.direct",
|
"feature": "deliver\\.direct",
|
||||||
"observer": "(mbin|lemmy19)"
|
"observer": "(mbin|lemmy19)"
|
||||||
@@ -120,6 +120,6 @@
|
|||||||
"code": "lemmy 0.19.20 crates/apub/src/protocol/objects/chat_message.rs: ChatMessageType has ChatMessage alone, so a Create{Note} to a person answers 400 (Lemmy 1.0 takes a Note); mbin 1.10.1 src/Service/ActivityPub/ActivityPubContent.php getVisibility(): a Note neither public nor to the author's followers throws 'PM: not implemented'",
|
"code": "lemmy 0.19.20 crates/apub/src/protocol/objects/chat_message.rs: ChatMessageType has ChatMessage alone, so a Create{Note} to a person answers 400 (Lemmy 1.0 takes a Note); mbin 1.10.1 src/Service/ActivityPub/ActivityPubContent.php getVisibility(): a Note neither public nor to the author's followers throws 'PM: not implemented'",
|
||||||
"opened": "2026-10-05",
|
"opened": "2026-10-05",
|
||||||
"status": "open",
|
"status": "open",
|
||||||
"note": "Neither server's actors say so, and PrivaPub never decides by a server's software name, so choosing ChatMessage for a recipient waits for the owner. Pleroma and Akkoma file a ChatMessage as a chat apart from direct messages, so sending both would show them twice. Mbin's API also never starts a conversation with an account elsewhere."
|
"note": "Since 2026-10-05 a direct message to someone who writes to us as ChatMessages goes out as one (Post.AsChatMessage), so answers arrive. A first message to someone who never wrote to anyone here is still a Note: neither server's actors say what they take, and PrivaPub never decides by a server's software name, so that waits for the owner. Pleroma and Akkoma file a ChatMessage as a chat apart from direct messages, so sending both would show them twice. Mbin's API never starts a conversation with an account elsewhere."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
Reference in new issue
Block a user