Verify libtacky bugs from the AI interop runs (v1.2.0-rc2, 71 found) #1

Open
opened 2026-11-07 17:28:33 +00:00 by asxpi · 7 comments
Member

Status as of libtacky v1.2.1 (8919dc12), 2026-11-08. Of the 73 bugs (71 plus C3.1 and C34): 16 fixed in v1.2.0, 44 fixed in v1.2.1, 5 partly fixed (S3, C8, M18, M23, M25), 2 not fixed (C3.1, C34), 6 not a bug or left as a decision (C12, M9, M12, M17, M20, M24). The Upstream column and lines below are rechecked against the code at v1.2.1. "ours verbatim": same git patch-id as our fix/<ID> branch; "ours, reworded": same code, comments or tests rewritten; "upstream's own": different code. The text further down describes v1.2.0-rc2.

Summary

The AI interop runs of 2026-11-04 to 2026-11-07 tested libtacky v1.2.0-rc2 (tackyd-json) against slixmpp on Prosody, ejabberd and anotherim-server. They found 71 distinct libtacky bugs: 13 security/privacy, 33 correctness and 25 minor/SHOULD. Upstream v1.2.0 (1dae0a6c, develop HEAD) fixes 16 of them, partly fixes 1 and probably fixes 1. The other 53 are not fixed upstream or have an unclear status. Duplicates across servers and runs are merged below.

How to verify a bug: open each linked run dir, read notes and bug in run.toml, then find the stanza in client.log (libtacky's wire). client-events.log holds the API events and client-debug.log the debug log. peer-slixmpp.log and server.log show the other side. Source refs are file:line at tag v1.2.0-rc2. "Checked" means the code at 1dae0a6c was compared. "Commit log only" means no matching upstream commit was found but the code was not re-read. Tick the box once a human has seen it. Bugs marked Needs live check can only be settled against a live server (the three test servers are being restarted); they say what to check.

Links: runs https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/<dir>, commits https://dev.another.im/another-im/libtacky/commit/<sha>.

Contents

# Bug Severity Upstream
S1 Call invites and meeting messages bypass OMEMO security/privacy fixed in v1.2.1, upstream's own (7559ecfc, 9b1e961b)
S2 Chat state, receipt request and markable in clear beside OMEMO 2 (XEP-0420) security/privacy fixed in v1.2.1, ours verbatim (810c609e)
S3 SIMS file metadata in clear beside legacy OMEMO ciphertext security/privacy partly fixed: opt-out setting, default unchanged (801f9533)
S4 Fake room join at a contact's bare JID turns off 1:1 OMEMO for good security/privacy fixed in v1.2.1, ours verbatim (065b273b)
S5 CAPTCHA inline BoB data not hash/size/type checked security/privacy fixed in v1.2.1, ours verbatim (03b0c666)
S6 spans-0 fallback strip hides arbitrary text security/privacy fixed in v1.2.1, ours verbatim (0b3f2385)
S7 XEP-0100: a user JID posing as a gateway gets into the roster security/privacy fixed in v1.2.1, ours verbatim (c9c3ae27)
S8 geoloc stop overtaken by a stale republish security/privacy fixed in v1.2.1, ours verbatim (ba1f07cf)
S9 OTR ssid/fingerprint mangled by Tcl expr (Inf) security/privacy fixed in v1.2.1, ours verbatim (10ca7f9f)
S10 parse_uri splits a decoded ? (link spoofing), accepts ports security/privacy fixed in v1.2.1, ours verbatim (e706c4ad)
S11 XEP-0227 export: every PEP node open; vcard-temp as a PEP node security/privacy fixed in v1.2.0 (0213e2ea)
S12 Peer can choose our stanza-id (forged by= own account) security/privacy fixed in v1.2.0 (267e5bc4)
S13 Secrets in host-facing output (sm <Ack>, XML console) security/privacy fixed in v1.2.1, ours verbatim (fd8de84e)
C1 Invalid jinglepub from throws, message lost correctness fixed in v1.2.1, ours verbatim (7efc7c82)
C2 IBB error: no <close/>, 60 s stall (callback arity) correctness fixed in v1.2.1, ours, reworded (01f262a2)
C3 Mention offsets not shifted after XmlText strips chars correctness fixed in v1.2.1, ours verbatim (67d627cf)
C4 Subject-only reply fallback treated as whole-body; reply dropped correctness fixed in v1.2.1, ours verbatim (77ea7932)
C5 service-0 notices raise notify <Notify> correctness fixed in v1.2.1, ours narrowed (659997ee)
C6 Room caption folded by origin-id instead of stanza-id correctness fixed in v1.2.1, ours verbatim (8de65a15)
C7 XEP-0482 reject uses the wrong ids correctness fixed in v1.2.1, ours without the invite-id change (6f004395)
C8 XEP-0492 <advanced/> dropped on rewrite correctness partly fixed, ours verbatim (e576b749)
C9 Geoloc on Prosody: own node <delete/> stops sharing for good correctness fixed in v1.2.1, ours, reworded (0df268dd)
C10 XEP-0470 attachments node made without max_items (own reaction evicted) correctness fixed in v1.2.1, ours, reworded (707ddaf2)
C11 pubsub publish/create ids through expr (1E…→Inf) correctness fixed in v1.2.1, upstream's own (4a00f894)
C12 XEP-0153 photo hash advertised before own vCard fetched correctness not changed: documented deviation (bc534bf0)
C13 SIMS <file/> lacks <hash/> and <desc/> correctness fixed in v1.2.1, ours, reworded (5a194a64)
C14 send_album source messages lack sfs fallback marker correctness fixed in v1.2.1, ours, reworded (84347d15)
C15 Outgoing inline thumbnails have no size cap correctness fixed in v1.2.1, ours, reworded (3c58decb)
C16 disco#info lacks urn:ietf:params:xml:ns:vcard-4.0 correctness fixed in v1.2.1, ours, reworded (6dd6be8f)
C17 disco#info lacks urn:xmpp:eme:0; name= on listed EME ns correctness fixed in v1.2.1, ours, reworded (fca586fb)
C18 microblog publish leaves pubsub#notify_retract false correctness fixed in v1.2.1, ours, reworded (d2c3a50d)
C19 messagestore IsDuplicate merges different messages correctness fixed in v1.2.1, upstream's own (752e4825)
C20 Forged XEP-0425 moderation stored as a message correctness fixed: rooms in v1.2.0 (292016a5), 1:1 in v1.2.1 (95ef9888)
C21 Stream-error replay loop with no backoff correctness fixed in v1.2.0 (dc48ac80)
C22 Post-auth features ignored on SASL2/Bind 2 (roster ver, pre-approval) correctness fixed in v1.2.0 (8b25b7d3)
C23 message send neither validates nor prepares JIDs correctness fixed in v1.2.0 (246a66fe)
C24 Stale vCard4 retry wipes the name (Prosody) correctness fixed in v1.2.0 (6b9bac06)
C25 account unregister never answers on ejabberd; redial loop correctness fixed in v1.2.0 (1dff6016)
C26 Forwarded <message/> in urn:xmpp:forward:0 namespace correctness fixed in v1.2.0 (86ccda9a)
C27 XEP-0440 rules 4/5 not enforced on SASL2 correctness fixed in v1.2.0 (c186eaa7)
C28 Over-limit IQ answer dropped instead of policy-violation correctness fixed in v1.2.0 (70aae84e)
C29 iap / happy_eyeballs settings never reach the connection correctness fixed in v1.2.0 (5a87d4ec)
C30 MUC decline sent to the room, not the occupant inviter correctness fixed in v1.2.0 (616beba4)
C31 Jingle sender refuses peer's session-terminate correctness fixed in v1.2.0 (4d485589)
C32 XEP-0424: @id retraction ignored; refused ones stored as messages correctness fixed in v1.2.0 (64378ebe)
C33 XEP-0444 reaction set not reverted on error correctness fixed in v1.2.0 (5bdefcae)
C3.1 Draft with a character XML cannot carry never synced (bgerror) correctness not fixed (upstream says 1.2.2, unreleased)
C34 Destroyed room recreated by autojoin on next sign-in correctness not fixed (libtacky#26, PR #27)
M1 Host slot APIs request slots for empty files minor fixed in v1.2.0 (f396065d)
M2 adhoc list keeps foreign command nodes minor/SHOULD fixed in v1.2.1, ours, reworded (81f4ace7)
M3 thread_parent == thread accepted minor fixed in v1.2.1, upstream's own (6e8203ce)
M4 Foreign-namespace <attachments> read as attachments minor fixed in v1.2.1, ours, reworded (40640d58)
M5 get_invoice without disco minor/SHOULD fixed in v1.2.1, upstream's own (6d620727)
M6 XEP-0472 side issues minor fixed in v1.2.1, upstream's own (2d82b42d)
M7 XEP-0501 entry lacks atom:author minor fixed in v1.2.1, ours, reworded (5e8b4565)
M8 Forged roster push gets no IQ reply minor fixed in v1.2.1, upstream's own (4ac96afd)
M9 <r/> unanswered ~50 min without declaring the stream dead minor not reproduced, no change
M10 XEP-0410 self-pings rooms already left minor fixed in v1.2.1, upstream's own (7a177c07)
M11 RSM <count> hidden minor fixed in v1.2.1, upstream's own (6b9ba1fc)
M12 untrust_certificate for a registration domain fails minor not reproduced, no change
M13 tackyd-json build unstamped (version 0.1, caps node tacky.example) minor fixed in v1.2.1, upstream's own (761c0bb0)
M14 OTR whitespace tag kept in stored body minor fixed in v1.2.1, upstream's own (60daed8b)
M15 Duplicate vCard gets for MUC avatars minor fixed in v1.2.1, upstream's own (7e939060)
M16 Republishing another device's bookmark adds <nick> minor fixed in v1.2.1, ours, reworded (318f210b)
M17 Stale store state after server-side deletes minor not changed (design; roster part is S7)
M18 Replayed sealed items dropped with no debug line minor partly fixed, upstream's own (86b86680)
M19 Own call-invite row says joined with no call minor fixed in v1.2.1, upstream's own (c24cddf6)
M20 tls-server-end-point computed for Ed25519 certs minor not a bug: documented (625d4462)
M21 PIE import oddities minor fixed in v1.2.1, ours, reworded (ddde3fc9)
M22 Refused accept_invite leaves its autojoin bookmark minor fixed in v1.2.1, upstream's own (da2984cc)
M23 OMEMO list/store hygiene minor partly fixed, upstream's own (d99bcf28)
M24 XEP-0377 report stanza-id by= (untested) minor not changed (decision)
M25 INFO-level oddities (live-location, pep-expiry, poll, MUC/Sub, XEP-0511) minor partly fixed, upstream's own (3dad47ab, c4d00bc9, e364005c, e9379baf, 2336d35a)

Security / privacy

S1. Call invites (XEP-0482) and meeting messages (XEP-0483) bypass OMEMO

  • verified by a human
  • Spec: XEP-0483 §8 (the meeting URL is a bearer secret); libtacky's omemo set_enabled doc says "a send fails closed rather than going out in the clear".
  • Seen: anotherim-server 162349-XEP-0483. Call invites were noted during the XEP-0482 runs (093754 ejabberd, 094412 prosody).
  • What happens: OMEMO was on for ai3b (explicit:true). meetings invite/accept/reject/retract/leave each wrote a plain <message type='chat'> with no <encrypted/>. Example from client.log line 144: <message id='meet-…' to='ai3b@…' type='chat'><invite xmlns='urn:xmpp:call-invites:0'><external uri='https://meet.example.invalid/…'/>…<body>You are invited to join … at https://…</body>. Muji call invites likewise put the room JID in the clear.
  • Expected: encrypted, or refused (as webxdc send_update does under OMEMO).
  • Root cause: tacky/xmpp/modules/meetings.tcl:273-284 Send calls $client write. tacky/xmpp/modules/groupcall.tcl:1910-1925 SendToChat calls $client write. Both bypass the message/OMEMO send path.
  • Fix: route both through the message module's encrypted send (OMEMO 2 envelope with the <invite/> inside), or refuse when omemo chat_state is enabled and the payload cannot be sealed.
  • Upstream: fixed in v1.2.1 by 7559ecfc (groupcall) and 9b1e961b (meetings), upstream's own change. Meeting messages in an OMEMO chat are refused ({MEETINGS ENCRYPTED}), as our patch did. Group-call invites and answers are not refused but sealed: groupcall Deliver puts them in an OMEMO 2 envelope (omemo encrypt_envelope, new) with only the EME marker and <store/> outside, and withholds them ({TACKY GROUPCALL ENCRYPTED}, or a <Warning> for an answer) when no OMEMO 2 device can read them. So an OMEMO 0.3-only peer (Dino today) gets no call invite in an OMEMO chat.

S2. Chat state, receipt request and markable in clear beside OMEMO 2 ciphertext

  • verified by a human
  • Spec: XEP-0420 §9 says non-server-processed elements "MUST NOT be available in plaintext outside the <envelope/>". libtacky's features.md row says "an encrypted message's outer elements are only the server's".
  • Seen: ejabberd 040316, anotherim 040943, prosody 040944, prosody 035747.
  • What happens: …<encrypted xmlns='urn:xmpp:omemo:2'>…</encrypted><body>I sent you an OMEMO encrypted message…</body><encryption xmlns='urn:xmpp:eme:0' …/><store/><active xmlns='http://jabber.org/protocol/chatstates'/><request xmlns='urn:xmpp:receipts'/><markable xmlns='urn:xmpp:chat-markers:0'/></message>. The same happens on replies and corrections. Receipts, displayed markers, reactions and retractions also go out in the clear (INFO R19).
  • Expected: these elements inside the SCE <content/>, or not sent. Only Table 2 elements and the fallback body belong outside.
  • Root cause: tacky/xmpp/modules/message.tcl:3443-3451 (BuildMessageStanza) appends active/request/markable unconditionally, outside the encrypted payload.
  • Fix: when encWire is set, put these into the envelope's extras (as is done for reply pointers), or omit them. Then do the same for receipts, markers, reactions and retractions.
  • Upstream: fixed in v1.2.1 by 810c609e (our patch verbatim). BuildMessageStanza hands <active/>, <request/> and <markable/> to encrypt_message with the pointers, so they ride inside the :2 envelope. They stay outside only when a 0.3 element is written. Bodyless signals sent on their own (receipts, displayed markers, chat states, reactions, retractions) are still in the clear; features.md now says so.

S3. File name, size and type in clear beside legacy OMEMO ciphertext

  • verified by a human
  • Spec: XEP-0420 §9 (by analogy) and XEP-0384 privacy. Also notes "Security (CONFIRMED)".
  • Seen: all three servers: anotherim 081706 (client.log:580), ejabberd 074324, prosody 082145.
  • What happens: an upload sent to a peer with a legacy (0.3) device goes out as …</encrypted><body>…</body><encryption …/><store/><reference xmlns='urn:xmpp:reference:0' type='data'><media-sharing xmlns='urn:xmpp:sims:1'><file …><media-type>application/octet-stream</media-type><name>f-87e2cf27.bin</name><size>2000</size></file></media-sharing></reference>….
  • Expected: no plaintext metadata. At most a generic body.
  • Root cause: this is deliberate in the code (legacyOutside, message.tcl:3288-3299, :3340, :3416-3421, LegacySimsNode ~:3500) so that legacy readers see it. It is not stated in features.md or HANDBOOK.
  • Fix: drop LegacySimsNode beside ciphertext. If the legacy UX matters, gate it behind a setting and document the leak.
  • Upstream: partly fixed in v1.2.1 by 801f9533 (upstream's own change). Upstream kept the leak and added the installation setting legacy_file_metadata: 0 drops the SIMS metadata beside a 0.3 ciphertext, but unset means on, so by default the file name, size and type still go out in the clear. Our patch removed LegacySimsNode beside ciphertext outright. The leak is now documented (features.md, HANDBOOK).

S4. A "room join" at a contact's bare JID silently downgrades the 1:1 chat to plaintext

  • verified by a human
  • Spec: libtacky's OMEMO rules (an explicit choice always wins).
  • Seen: anotherim-server after the XEP-0463 fake-join (132727, 132902). This comes from the night notes, not run.toml. The store rows were since repaired by hand.
  • What happens: joining aiNb@… as a room left module_state muc_features/<contact> = "-". From then on omemo chat_state for that contact says enabled:false reason room_not_eligible, overriding the user's explicit ON. This persists, and there is no API to forget it.
  • Expected: a failed or fake join of a non-room JID records nothing. The 1:1 OMEMO choice stays.
  • Root cause: tacky/xmpp/modules/omemo.tcl:5188-5195 IsRoom trusts muc PrivacyOf "known" (muc.tcl:718), which reads the stale muc_features row.
  • Fix: write muc_features only after disco#info shows a conference identity. In IsRoom, prefer roster/contact evidence. Add a forget call.
  • Upstream: fixed in v1.2.1 by 065b273b (our patch verbatim).

S5. CAPTCHA inline BoB data taken without hash, size or type check

  • verified by a human
  • Spec: XEP-0231 §2, XEP-0221 §2, XEP-0158 §3.1.2/§6.3. libtacky's rows: "<data/> taken only when its bytes hash to its cid".
  • Seen: XEP-0221 on ejabberd 050619, prosody 051534, anotherim 051737. XEP-0158 on anotherim 121814, prosody 122509, ejabberd 123409.
  • What happens: <uri>cid:sha1+40ecc4…@bob.xmpp.org</uri> and <data cid='sha1+40ecc4…'> hold bytes hashing to 0aebef…. captcha <Challenge> still carries media.ocr with those bytes. The ad-hoc path in the same run logs adhoc: <data cid=…> dropped: the data does not hash to its cid. The notes add that unbounded size and image/svg+xml with onload also pass, which is an XSS risk if a host renders SVG. Challenges for stanzas never sent, and from a foreign from, also reach the host (SHOULD ignore).
  • Root cause: tacky/xmpp/modules/captcha.tcl:224-238 only base64-decodes the data. Compare adhoc.tcl:312, which uses ::tacky::bob::check $cid … $MEDIA_MAX plus a raster-only type filter.
  • Fix: apply the same bob::check and raster allowlist as adhoc.tcl:312-319. Drop challenges whose referenced stanza id we never sent.
  • Upstream: fixed in v1.2.1 by 03b0c666 (our patch verbatim).

S6. spans-0: any range marked as fallback is stripped, so a sender can hide text

  • verified by a human
  • Spec: urn:tacky:spans-0 (libtacky's own docs/protocol). Recorded as INFO, not as a doc violation.
  • Seen: prosody 110023.
  • What happens: a <fallback for='urn:tacky:spans:0'> range is removed without checking that it is (href). Text such as "PS: wire the money…" is shown by other clients but hidden from libtacky users. A range past the body end is clipped. A childless <fallback for=spans/> drops the whole message. Forwards and quotes lose the hidden URL.
  • Root cause: tacky/xmpp/modules/message.tcl:8864-8867 (fallback ranges for spans) and :9521-9522.
  • Fix: strip only an exact (<href>) directly after a link span. Ignore other ranges and a childless spans fallback.
  • Upstream: fixed in v1.2.1 by 0b3f2385 (our patch verbatim).

S7. XEP-0100: a user's full JID claiming gateway identity gets added to the roster

  • verified by a human
  • Spec: XEP-0100 §6.1 (a gateway address SHOULD be a hostname only). libtacky's own GatewayTarget rule.
  • Seen: prosody 114621, ejabberd 115158. It was not run on anotherim on purpose.
  • What happens: after adhoc execute node=register at ai2b@ejabberd.asxp.io/gw-… (disco identity gateway/legacy), libtacky sent <iq type='set'><query xmlns='jabber:iq:roster'><item jid='ai2b@…/gw-…'/></query></iq> plus <presence type='subscribe'/>. On ejabberd this replaced the existing bare contact (subscription both became to, losing from). Where pre-approval is used, it also gives our presence away.
  • Root cause: tacky/xmpp/modules/adhoc.tcl:340-345 GatewayRegistered, then search Linked (search.tcl:675), then roster.tcl:600 IfGateway. None of them checks that the JID has no node or resource.
  • Fix: in GatewayRegistered/IfGateway, return early unless jid username and jid resource are both empty, as gateway register already refuses ("is not a remote service").
  • Upstream: fixed in v1.2.1 by c9c3ae27 (our patch verbatim).

S8. geoloc stop overtaken by a stale republish after set_allowed

  • verified by a human
  • Spec: XEP-0080 §4.1 (stop = empty <geoloc/>), §8 (access control).
  • Seen: ejabberd 113228, anotherim 113802. First seen in 112745.
  • What happens: the calls set_allowed [], set_allowed [peer] and stop were made back to back. iq 78 publishes the empty <geoloc/> and is acked. Then iq 80 sets the peer as member, and iq 81 publishes <item id='current'><geoloc>…<lat>12.3456</lat>…</geoloc></item> again. The peer reads the location, and geoloc get says active true.
  • Expected: the stop is the last word.
  • Root cause (suspected): tacky/xmpp/modules/geoloc.tcl:257-266 AfterListChange republishes Stored own loc for added members without checking that sharing is still active. The refill of Stored was not traced.
  • Fix: in AfterListChange, return if the own state is stopped/inactive. Serialise stop after pending list changes.
  • Needs live check: on ejabberd/anotherim, run set_allowed [], set_allowed [peer], stop back to back; read the geoloc node as the peer 8 s later (must be empty) — on rc2 and on 1dae0a6c.
  • Upstream: fixed in v1.2.1 by ba1f07cf (our patch verbatim); rig case d5ecda72.

S9. OTR ssid and fingerprint mangled by Tcl expr

  • verified by a human
  • Spec: OTR v3 AKE (the ssid is shown for out-of-band comparison).
  • Seen: ejabberd 130347. The other servers did not hit it (the ssid is random).
  • What happens: the ssid 02802368162e5437 was reported as "ssid": "Inf" in otr <State> (client-events.log:89).
  • Root cause: tacky/xmpp/otr.tcl:277-278 builds fingerprint and ssid inside expr {… ? "" : [hex …]}. Tcl canonicalises numeric-looking results (…e… becomes Inf; all digits lose leading zeros).
  • Fix: if {$x eq ""} {set s ""} else {set s [string tolower [binary encode hex $x]]}, not expr. Same class as C11.
  • Upstream: fixed in v1.2.1 by 10ca7f9f (our patch verbatim).
  • verified by a human
  • Spec: RFC 5122 §2.8.1 (separate the query before decoding; the address must conform), §5.2. XEP-0147.
  • Seen: prosody 121127, ejabberd 122029, anotherim 122401.
  • What happens: xmpp:x%3Fy…@example.invalid?subscribe gives jid x, so xmpp:target.example%3Fz@innocent.example?subscribe subscribes to target.example. ?invite;jid=a%3Fb@… gives a. xmpp:ai1b@prosody.asxp.io:5222?message is accepted with the port in the domain.
  • Root cause: in tacky/xmpp/jid.tcl, the rc2 pattern refused ? in a localpart, so jid bare split at it. Used from account.tcl:1791 LinkUri. jid valid does not refuse : in a domain.
  • Fix: the ? split is fixed upstream. Also refuse a :port (and ?) in the decoded domain, and add URI tables to test_link.tcl.
  • Needs live check: re-run XEP-0147.py R7 against libtacky 1dae0a6c (local parse only, any server): %3F link now names x?y@…; does …:5222?message still parse?
  • Upstream: fixed in v1.2.1 by e706c4ad (our patch verbatim): a port or a decoded query in the address is refused. The ? split was fixed in v1.2.0 by cd3e39c5.

S11. XEP-0227 export: every PEP node exported as open; own vcard-temp written as a PEP node

  • verified by a human
  • Spec: XEP-0227 §4.7.
  • Seen: anotherim 030802, ejabberd 031202, prosody 031526.
  • What happens: <user> holds <pubsub#owner><configure node='vcard-temp'> (access open) plus items, and no <vCard xmlns='vcard-temp'/> child. On Prosody the urn:xmpp:vcard4 node is exported as open although the server has it as presence. An importing server would publish the vCard to everyone.
  • Root cause: tacky/xmpp/modules/backup.tcl:584 hard-codes open except for bookmarks. WriteUser exports the vcard-temp pseudo-node (vcard.tcl Keep).
  • Upstream: fixed in v1.2.0 by 0213e2ea (commit).

S12. A peer can choose the stanza-id of its own message (forged by= our account)

  • verified by a human
  • Spec: XEP-0359 §3. The server part (Prosody keeps the forged element) is listed under server-side issues.
  • Seen: prosody 222405.
  • What happens: <stanza-id by=ai1a id=forged-me-…/> came before Prosody's own, and libtacky stored server_id=forged-me-… even after MAM catch-up. Replies, retractions and markers then name the peer's choice.
  • Root cause: tacky/xmpp/modules/message.tcl:9474 ArchiveStanzaId takes the first element with by= our account.
  • Upstream: fixed in v1.2.0 by 267e5bc4 (commit).

S13. Secrets reach host-facing output

  • verified by a human
  • Spec: none (hygiene).
  • Seen: night notes, around the XEP-0077 runs (prosody 001423) and XEP-0401 runs (prosody 010250).
  • What happens: (a) sm <Ack> hands the host the raw acked stanzas, including change_password's new password (it reached client-events.log; the scenario redacts it). (b) The XML console logs the invite form URI with its preauth token unredacted, because redact::uriParams is used only by jlog.
  • Fix: strip jabber:iq:register <password/> and SASL/FAST data from <Ack> payloads. Run redact::uriParams on debugtap output.
  • Upstream: fixed in v1.2.1 by fd8de84e (our patch verbatim).

Correctness

C1. Invalid <jinglepub from> throws; the whole message is lost (and fails again on every MAM catch-up)

  • verified by a human
  • Spec: XEP-0358 §2.1.
  • Seen: anotherim 124106, ejabberd 125512, prosody 130302.
  • What happens: <jinglepub from='@@@/evil-….invalid@@' …> causes client-debug.log bgerror: Invalid JID: @@@/evil-….invalid@@. No row and no <New> is created. Any contact can make a message vanish.
  • Root cause: tacky/xmpp/modules/message.tcl:11132 (ExtractSfsAttachments: jid norm [jid bare $pubFrom] with no catch).
  • Fix: if {[catch {jid norm [jid bare $pubFrom]} b]} { continue }, which drops that source and keeps the message.
  • Upstream: fixed in v1.2.1 by 7efc7c82 (our patch verbatim).

C2. IBB: a data error never closes the bytestream (callback arity), 60 s stall

  • verified by a human
  • Spec: XEP-0047 §2.2 (sender MUST close on error; recipient MUST close on bad seq). XEP-0261.
  • Seen: prosody 112315, anotherim 112907, ejabberd 113720.
  • What happens: <data seq='1'> is answered <unexpected-request/>, then client-debug.log shows ibb callback failed: wrong # args: should be "...jinglefile OnIbbSent sid n result". No <close/> is sent, and the session ends only after the 60 s stall timer. As receiver, an out-of-sequence block terminates the Jingle session but sends no IBB <close/>.
  • Root cause: tacky/xmpp/modules/ibb.tcl:94,126 calls Callback $cmd err <text> (two args). jinglefile.tcl:2711 OnIbbOpened {sid result} and :2741 OnIbbSent {sid n result} take one.
  • Fix: have ibb.tcl pass one list ([list err $text]), or change the jinglefile methods to {sid n status args}. On error, send <close/> before unsetting Out(sid). Send <close/> on the receiver's bad-seq path.
  • Upstream: fixed in v1.2.1 by 01f262a2 (our patch; only a comment rewrapped).

C3. Mention offsets point at the wrong text after XML-forbidden characters are stripped

  • verified by a human
  • Spec: XEP-0426 §2.
  • Seen: anotherim 131221, prosody 132640, ejabberd 153155.
  • What happens: the body '… ctl\x01 nonchar￾ lone\uD83D @Bee end' with mention 30..34 goes out with U+0001 and U+FFFE removed, but <reference begin='30' end='34'/> now covers ee e.
  • Root cause: tacky/xmpp/modules/message.tcl:3798-3800: XmlText runs, then CheckMentions uses the cleaned body without shifting offsets. Edits and captions behave the same.
  • Fix: compute the index map while stripping and shift mention offsets, or refuse the send when stripping touches a mentioned range.
  • Upstream: fixed in v1.2.1 by 67d627cf (our patch verbatim, libtacky#25). Also covers the second symptom (a mention at the end of the body pushed past it, so the send was refused). See C3.1 for drafts.

C4. A reply fallback naming only <subject/> is read as covering the whole body, and the reply is dropped

  • verified by a human
  • Spec: XEP-0428 §2.2 (only a childless <fallback/> covers everything).
  • Seen: anotherim 064613, ejabberd 065302, prosody 065529.
  • What happens: for <fallback for='urn:xmpp:reply:0'><subject start='0' end='3'/></fallback> no row and no <New> are created. The same reply without <fallback/> is stored.
  • Root cause: tacky/xmpp/modules/reply.tcl:51-55: if {[llength $bodies] == 0} { lappend ranges [list 0 $len] }.
  • Fix: apply the whole-body range only when [llength [dict get $fb children]] == 0.
  • Upstream: fixed in v1.2.1 by 77ea7932 (our patch verbatim).

C5. service-0 notices raise notify <Notify>

  • verified by a human
  • Spec: libtacky docs/protocol/service-0.md §4 ("never unread, never notified").
  • Seen: anotherim 110355, prosody 110829, ejabberd 111044.
  • What happens: for all 11 service rows (pin, ttl, screenshot…), events like notify <Notify> {"id": "svc-pin-…", "body": "Peer did pin …"} are raised. The unread count stays correct.
  • Root cause: tacky/xmpp/modules/notify.tcl:287-293 OnNew skips only content types call and omemo_session.
  • Fix: also skip service (and any other notice content types).
  • Upstream: fixed in v1.2.1 by 659997ee (our patch, narrowed). OnNew skips content type service beside omemo_session; ours skipped every notice row. Timer, ttl and screenshot notices still raise <Notify>, by upstream's choice.

C6. In a room, a caption is folded by origin-id rather than the room's stanza-id

  • verified by a human
  • Spec: XEP-0367 §4.1, §5.
  • Seen: ejabberd 071802, anotherim 072110, prosody 072653.
  • What happens: a groupchat <attach-to id='go2-…'/> naming the file's origin-id is folded (message <Edited> content.caption …) instead of being shown as a normal message. The author check still applies, so there is no spoofing.
  • Root cause: tacky/xmpp/modules/message.tcl:9224 FoldCaption, then messagestore.tcl:2448 rowsByTarget, which matches server_id, own_id and origin_id in rooms too.
  • Fix: for ?join chats, match attach-to against server_id only.
  • Upstream: fixed in v1.2.1 by 8de65a15 (our patch verbatim).

C7. XEP-0482 reject uses the wrong ids

  • verified by a human
  • Spec: XEP-0482 0.1.0 §3.1.
  • Seen: ejabberd 093754, prosody 094412, anotherim 094906.
  • What happens: (1) A 1:1 invite without Dino's <invite id> is declined locally, but no <reject/> is sent. The expected answer is <reject id='<origin-id>'/>. (2) In a room, the decline sends <reject id='ci7-…'/> (the invite@id) instead of the room's stanza-id. libtacky's own invites have a message id that differs from invite@id and no origin-id, so 0.1.0-only peers never match.
  • Root cause: tacky/xmpp/modules/groupcall.tcl:376-391 decline uses only invite id.
  • Fix: keep invite@id (for Dino), falling back to origin-id, then message id, and in rooms to stanza-id. Accept answers naming any of them. Set origin-id equal to invite@id on our own invites.
  • Upstream: fixed in v1.2.1 by 6f004395 (our patch minus one part). decline falls back to CallInviteRef (stanza-id in a room, else origin-id, own id, wire id) and answers are matched the same way (CallInvitesByRef). Upstream did not set origin-id = invite@id on our own invites (re-invites share one <invite id/>); a 0.1.0 peer's answer naming our random message id is matched by own_id instead.

C8. XEP-0492: <advanced/> dropped when the attribute-free element is rewritten

  • verified by a human
  • Spec: XEP-0492 0.2.0 §3 (MUST NOT delete or alter <advanced/>; SHOULD add a fallback).
  • Seen: ejabberd 091607, prosody 092506, anotherim 092531.
  • What happens: <notify><always><advanced><rule…/></advanced></always>…</notify> passed through set_notification -value on-mention becomes …<on-mention/></notify> with no <advanced/>. Two more problems: (a) a scoped write with no setting adds no attribute-free fallback (SHOULD); (b) notify get answers {muted: 0, mentions: 1} regardless of the bookmark setting, while <Notify> alerts do follow it.
  • Root cause: tacky/xmpp/modules/bookmarks.tcl:841-890 NotifyMerge, around 867/882: the matching element is skipped and the new one gets children {}.
  • Fix: carry the old element's <advanced/> children over to the new one. Add the fallback on scoped writes. Make notify get read the bookmark.
  • Upstream: partly fixed in v1.2.1 by e576b749 (our patch verbatim): NotifyMerge carries <advanced/> over. Not done: (a) the attribute-free fallback on a scoped write (SHOULD). (b) upstream says notify get already reads the bookmark once a ?join chat is in scope (not a bug).

C9. Geoloc on Prosody: the owner's node <delete/> event ends sharing; set_allowed after item-not-found is marked synced

  • verified by a human
  • Spec: XEP-0080 §4.1/§8. libtacky's row ("deleting the node and publishing afresh"; members set before the item).
  • Seen: prosody 113745.
  • What happens: set_allowed [] sends iq 41 <delete node=geoloc/>. Prosody pushes the owner <delete/> event, after which geoloc <Changed> active false fires and the node is never republished. set_allowed [ai1b] then reads affiliations, gets item-not-found, and sets geoloc_allowed_dirty 0. stop publishes under a whitelist without making ai1b a member, so ai1b reads <forbidden/>. Nothing leaks.
  • Root cause: tacky/xmpp/modules/geoloc.tcl:445-451 OnNotification treats our own delete as a stop. :372 clears the dirty flag after an error-ish sync.
  • Fix: ignore our own delete events while a delete-and-republish is in flight. Keep the dirty flag when the affiliations read fails. Set members before every publish.
  • Needs live check: on prosody.asxp.io, set_allowed [] then set_allowed [peer]: does the owner get its own <delete/> event, and does a peer read item-not-found/forbidden afterwards.
  • Upstream: fixed in v1.2.1 by 0df268dd (our patch, same code; upstream added an integration case).

C10. XEP-0470 attachments node made without pubsub#max_items (Prosody keeps 1, so our own reaction is evicted)

  • verified by a human
  • Spec: XEP-0470 §4.1/§4.2 (one item per JID).
  • Seen: prosody 132847.
  • What happens: after our reaction (item id='ai1a@…') and the peer's, the node holds only ai1b.
  • Root cause: tacky/xmpp/modules/microblog.tcl:688-690 OnPostPublished creates the node with access_model/publish_model/persist_items only.
  • Fix: add pubsub#max_items max (as create_feed does at :1140-1143).
  • Upstream: fixed in v1.2.1 by 707ddaf2 (our patch, same code; comments and an integration case added).

C11. pubsub publish/create return a numeric-looking id altered (1E…→Inf, 0x10→16)

  • verified by a human
  • Spec: XEP-0060 §3, §7.1.2.
  • Seen: anotherim 042352, ejabberd 043115, prosody 043422. ejabberd's own hex ids hit this too (70262E937439→Inf).
  • Root cause: tacky/xmpp/modules/pubsub.tcl:1044 expr {$made eq "" ? $node : $made} and :1158 Done $command [expr {$given ne "" ? $given : $id}].
  • Fix: use if/else. Also grep for other expr {… ? $str : $str} on ids (see S9).
  • Upstream: fixed in v1.2.1 by 4a00f894 (upstream's own change, broader). Every id/text picked with expr ?: across 13 modules now uses if; ours touched pubsub.tcl only. Left: the create error text (pubsub.tcl:1072, Could not create [expr {...? "a node" : $node}]) still goes through expr (cosmetic).

C12. XEP-0153: the kept photo hash is advertised before the own vCard is downloaded

  • verified by a human
  • Spec: XEP-0153 §4.2 (MUST NOT).
  • Seen: ejabberd 044317, anotherim 044833, prosody 044857.
  • What happens: the first presence after sign-in carries <x xmlns='vcard-temp:x:update'><photo>74f5…</photo></x>, and the own <vCard/> get goes out after it.
  • Root cause: tacky/xmpp/modules/presencemod.tcl:155-169 (PhotoKnown/LoadPhoto, deliberately, for an Android cold start).
  • Fix: send an empty <x/> until the vCard is fetched, or document the deviation in the row.
  • Upstream: not changed, by decision: bc534bf0 documents the deviation (photo hash advertised at bind for an Android cold start) in features.md. Our branch fix/C12-photo-hash-before-vcard (empty <x/> until the vCard is fetched) was not taken.

C13. SIMS <file/> lacks <hash/> and <desc/>

  • verified by a human
  • Spec: XEP-0385 §4.1 (MUST), §4.2.
  • Seen: anotherim 065654, ejabberd 070001, prosody 070606. Also noted for XEP-0491 on ejabberd.
  • What happens: <media-sharing><file><media-type/><name/><size/><thumbnail/></file>… has no hash, while the XEP-0447 <file/> beside it has the sha-256 and desc.
  • Root cause: tacky/xmpp/modules/message.tcl:3462 ShareNodes.
  • Fix: reuse the SFS file's <hash xmlns='urn:xmpp:hashes:2'/> and <desc/> in the SIMS file.
  • Upstream: fixed in v1.2.1 by 5a194a64 (our patch, same code reordered).

C14. send_album source messages carry a url body without the sfs fallback marker

  • verified by a human
  • Spec: XEP-0447 §3.3 (MUST add <fallback for='urn:xmpp:sfs:0'>).
  • Seen: ejabberd 031219, prosody 034725, anotherim 035238.
  • Root cause: tacky/xmpp/modules/message.tcl:4683 SourceWrite.
  • Fix: add j fallback -ns urn:xmpp:fallback:0 -for urn:xmpp:sfs:0 { j body }, as send_file does.
  • Upstream: fixed in v1.2.1 by 84347d15 (our patch, comment reworded).

C15. Outgoing inline thumbnails have no size cap (a 70 KB thumb gives a ~95 KB stanza)

  • verified by a human
  • Spec: XEP-0264 §5. libtacky's row ("≤ 160 px, 64 KiB").
  • Seen: ejabberd 052434, prosody 063013, anotherim 063101.
  • Root cause: tacky/xmpp/modules/file.tcl:2763 thumb_data_parts checks only syntax and type. thumb_data_uri (:2756) does check thumb_max_bytes.
  • Fix: in thumb_data_parts, return "" when the decoded size is over [thumb_max_bytes].
  • Upstream: fixed in v1.2.1 by 3c58decb (our patch, same check in thumb_data_parts; comment and test reworded).

C16. disco#info lacks urn:ietf:params:xml:ns:vcard-4.0

  • verified by a human
  • Spec: XEP-0292 §7 (MUST).
  • Seen: anotherim 052450, prosody 052758, ejabberd 062115.
  • Root cause: tacky/xmpp/modules/vcard.tcl:783 adds only ${NODE4}+notify.
  • Fix: also $client caps addFeature urn:ietf:params:xml:ns:vcard-4.0.
  • Upstream: fixed in v1.2.1 by 6dd6be8f (our patch, comment reworded; our doc rows left out).

C17. disco#info lacks urn:xmpp:eme:0; name= sent for listed protocols

  • verified by a human
  • Spec: XEP-0380 §3.3 (MUST); §3.2/§4 (SHOULD NOT send name for listed ns).
  • Seen: ejabberd 063100, anotherim 063509, prosody 064133.
  • Root cause: no module calls caps addFeature urn:xmpp:eme:0. message.tcl:3375 puts -name OMEMO on the urn:xmpp:omemo:2 hint.
  • Fix: add the feature (in the omemo or message module). Drop name for listed namespaces.
  • Upstream: fixed in v1.2.1 by fca586fb (our patch, same code; comments and tests reworded).

C18. microblog publish leaves pubsub#notify_retract false on a fresh node

  • verified by a human
  • Spec: XEP-0277 §4.1 (MUST be true; send_last_published_item never, SHOULD).
  • Seen: ejabberd 123051, anotherim 125031.
  • Root cause: tacky/xmpp/modules/microblog.tcl:671-675 pubOptions (access_model, persist_items, max_items only).
  • Fix: add pubsub#notify_retract true pubsub#send_last_published_item never. The notes also say <script> content in html entries is passed to the host verbatim; check that the HANDBOOK warns hosts.
  • Upstream: fixed in v1.2.1 by d2c3a50d (our patch, same options in another order; our two commits squashed).

C19. messagestore IsDuplicate merges two different messages (different @id, no stanza-id, same body/sender/second)

  • verified by a human
  • Spec: none (data loss).
  • Seen: anotherim 052745 (two direct MUC invitations).
  • Root cause: tacky/xmpp/modules/messagestore.tcl:511 IsDuplicate.
  • Fix: never treat rows whose wire @ids differ as duplicates.
  • Needs live check: on anotherim-server, send two direct MUC invitations with the same body in the same second (different @id); expect two rows on 1dae0a6c.
  • Upstream: fixed in v1.2.1 by 752e4825 (upstream's own change). IsDuplicate treats two stanzas that each name an id and share none as two messages, matching origin-id and @id across each other; ours compared wire_id with wire_id only.

C20. Forged XEP-0425 moderation from an occupant stored as a message showing its fallback

  • verified by a human
  • Spec: XEP-0425 §5/§6 (MUST discard non-service moderation). XEP-0424 §5.
  • Seen: ejabberd 064423, anotherim 064909.
  • What happens: the target was rightly untouched, but both the :1 <retract><moderated/> form and the legacy apply-to form became rows (message <New> 'mod-… forged fallback occupant 1').
  • Needs live check: re-run XEP-0425.py on ejabberd/anotherim with libtacky 1dae0a6c; expect no message <New> for the forged :1 and :0 forms.
  • Upstream: fixed. Room-relayed notices in v1.2.0 by 292016a5; the remaining 1:1 legacy :0 notice in v1.2.1 by 95ef9888 (upstream's own change; no branch of ours): a :0 moderation outside a room is dropped.

C21. Stream-error replay loop: the stanza that killed the stream is replayed on every new stream, with no backoff

  • verified by a human
  • Spec: RFC 6120 §4.9, §3.3. XEP-0198 §4 (count stanzas only).
  • Seen: ejabberd 215429, anotherim 215659. There were 24 <invalid-from/> errors and reconnects in 45 s, always retry_in 1000 attempt 1.
  • Upstream: fixed in v1.2.0 by dc48ac80 (commit), 5f5b8c3e (commit) and 198f4438 (commit).

C22. On SASL2/Bind 2, post-auth stream features are ignored (no roster ver, preapprove refused, no pre-approval)

C23. message send neither validates nor prepares JIDs (forbidden chars accepted; AI1B@…, fullwidth or final-dot JIDs become separate chats; sends stuck pending)

  • verified by a human
  • Spec: RFC 7622 §3.2-3.4.
  • Seen: prosody 230844, anotherim 233631, ejabberd 233948. The bad chats persist in the ai1a/ai2a/ai3a stores (later runs still query OMEMO lists for ai2b@ejabberd.asxp.io.), so a store cleanup is needed.
  • Upstream: fixed in v1.2.0 by 246a66fe (commit, every jid argument normalised) and bc454657 (commit, invalid ones refused at the door). Issue #19 is still open.

C24. Prosody: a vCard4 publish refused with precondition-not-met is retried unchanged after a newer one, wiping the name

  • verified by a human
  • Spec: XEP-0054/XEP-0292/XEP-0398.
  • Seen: prosody 234725 (client.log iq 58 then 64).
  • Upstream: fixed in v1.2.0 by 6b9bac06 (commit).

C25. account unregister never answers on ejabberd-family servers and the removed account redials

  • verified by a human
  • Spec: XEP-0077 §3.2. RFC 6120 §8.1.2.1.
  • Seen: anotherim 000550.
  • What happens: the result comes from the user's own full JID and is dropped by iq.tcl:151-165. The following <conflict/> "User removed" is read as a resource clash, leading to a not-authorized loop. Minor: <remove/> carried to=domain (SHOULD NOT).
  • Upstream: fixed in v1.2.0 by 1dff6016 (commit) and 5f8c84cf (commit). The latter also drops the to.

C26. Forwarded inner <message/> has no xmlns='jabber:client'

  • verified by a human
  • Spec: XEP-0297 §3.2.
  • Seen: anotherim 003420, prosody 004939, ejabberd 005842.
  • Root cause: message.tcl:7018 ForwardNodes. Minor: message forward returns "" although the HANDBOOK says it returns a string. Its upstream status is unclear.
  • Upstream: fixed in v1.2.0 by 86ccda9a (commit).

C27. XEP-0440 rules 4/5 not enforced on SASL2

C28. An IQ result over the XEP-0478 limit is dropped instead of answered with policy-violation

C29. The iap (XEP-0509) and happy_eyeballs (XEP-0495) installation settings never reach the connection

C30. A MUC decline is sent to the room itself when the room names the inviter by occupant JID

  • verified by a human
  • Spec: XEP-0045 §7.8.2.
  • Seen: prosody 021513.
  • Root cause: message.tcl:10739-10747 ParseInvite takes the bare JID. Note: the scenario's R14 check should accept the inviter as given.
  • Upstream: fixed in v1.2.0 by 616beba4 (commit).

C31. The Jingle file sender tears down on <received/> and refuses the receiver's session-terminate (unknown-session)

C32. XEP-0424: a retraction naming the @id is ignored when origin-id differs; refused retractions are stored as messages with the fallback body

C33. XEP-0444: the reaction set is not reverted on a not-acceptable error

  • verified by a human
  • Spec: XEP-0444 §3.3 (MUST revert).
  • Seen: prosody 025420, anotherim 025944, ejabberd 030024.
  • Root cause: message.tcl:7306 SetReactions (stores the set optimistically, with no error path).
  • Upstream: fixed in v1.2.0 by 5bdefcae (commit) for 1:1 and ecfd1682 (commit) for rooms.

C3.1. A draft holding a character XML cannot carry is never synced

  • verified by a human
  • Seen: by hand in anotherim-js (009c9884, libtacky 56d29734) on anotherim-server, 2026-11-08: paste hi\x01\x02 into the composer (comment).
  • What happens: chats draft keeps the text locally, then PublishDraft fails: bgerror: text contains U+0001, which XML cannot carry. The draft never reaches the other devices (urn:tacky:drafts:0 / sealed:1), and the error escapes the module.
  • Root cause: tacky/xmpp/modules/chatsync.tcl:972-985 PublishDraft writes <draft><body> through ::tacky::core::xml::write without XmlText, unlike message send.
  • Fix: clean the text with XmlText before PublishDraft, or catch and log the write error. Test with U+0001.
  • Upstream: not fixed in v1.2.1 (chatsync.tcl:983 PublishDraft writes the text as is). Upstream says 7dddfd32 for 1.2.2; not on the forge yet.

C34. A destroyed room comes back on the next sign-in

  • verified by a human
  • Spec: XEP-0045 §10.9, XEP-0402 (autojoin).
  • Seen: by hand in anotherim-js (009c9884, libtacky 56d29734 + C3/S2) on anotherim-server, 2026-11-08 (comment). Playbook: fixes/C34/.
  • What happens: the owner's muc destroy_room succeeds, but the XEP-0402 bookmark keeps autojoin='true'. On the next sign-in disco#info answers item-not-found, libtacky joins anyway, and the server creates a new room (status 201/110, owner): empty, default config, same address.
  • Root cause: tacky/xmpp/modules/muc.tcl:2290 destroy_room only sends the iq; nothing acts on <Destroyed> (muc.tcl:3058, :3941); autojoin ignores a disco#info item-not-found.
  • Fix: never autojoin a bookmarked room whose disco#info says item-not-found (report it), and clear autojoin after a successful destroy_room. Host side (anotherim-js ui/src/state/muc-room.ts:204): show the row as destroyed and offer Remove.
  • Upstream: not fixed in v1.2.1. Issue libtacky#26, our PR libtacky#27 (fix/C34-destroyed-room-autojoin).

Minor / SHOULD

M1. file slot / message upload_slot request slots for empty files (OMEMO adds the 16-byte tag first)

M2. adhoc list returns command nodes whose jid is not the responder's

  • verified by a human
  • Spec: XEP-0050 §5 (SHOULD ignore).
  • Seen: prosody 042022, ejabberd 042705, anotherim 044651.
  • Root cause: adhoc.tcl:214-216.
  • Fix: if {$ij ne "" && [jid norm $ij] ne [jid norm $service]} continue.
  • Upstream: fixed in v1.2.1 by 81f4ace7 (our patch, jid compared for jid norm, no debug line).

M3. message send accepts thread_parent == thread

  • verified by a human
  • Spec: RFC 6121 §5.2.5 (MUST differ). XEP-0201.
  • Seen: ejabberd 121739, anotherim 122558, prosody 122700.
  • Root cause: message.tcl:3271-3275 (and send at :3814).
  • Fix: refuse the call (or drop the parent) when they are equal.
  • Upstream: fixed in v1.2.1 by 6e8203ce (upstream's own change). CheckThreadParent refuses thread_parent == thread in send, send_file and send_album, and the builder never writes such a parent; unlike ours it does not refuse a parent without a thread.

M4. <attachments> in a foreign namespace is read as an attachment

  • verified by a human
  • Spec: XEP-0470 §4.1.1/§4.5.
  • Seen: ejabberd 131801, anotherim 153239.
  • Root cause: microblog.tcl:1009 (and :925) checks only tag eq "attachments".
  • Fix: also require xmlns eq $NS_ATTACH.
  • Upstream: fixed in v1.2.1 by 40640d58 (our patch, dict getdef for the namespace).

M5. payment get_invoice sends <get-invoice/> without a disco check

  • verified by a human
  • Spec: XEP-0518 §4.4 (SHOULD). The HANDBOOK says it sends only to an entity advertising #invoice-request.
  • Seen: ejabberd 161842, prosody 162650.
  • Root cause: payment.tcl:508.
  • Upstream: fixed in v1.2.1 by 6d620727 (upstream's own change; triage had it as a decision): get_invoice asks disco#info first and sends only to an entity advertising #invoice-request.

M6. XEP-0472 side issues

  • verified by a human
  • Seen: ejabberd 132926, prosody 153205, anotherim 153635.
  • What happens:
    • An open feed's attachments node gets access_model=presence (XEP-0470 §4.1.1 SHOULD match).
    • Comments nodes lack itemreply=publisher.
    • A hostile post's comments/reply_to http:// URLs surface in <Post>.
    • An edit re-creates the attachments node (logged as "no attachments node").
  • Upstream: fixed in v1.2.1 by 2d82b42d (upstream's own change, broader than ours): all four points, including the attachments node's access model and the re-create on edit that triage left as decisions.

M7. XEP-0501 story entry lacks atom:author

  • verified by a human
  • Spec: RFC 4287 §4.1.2.
  • Seen: anotherim 160304.
  • Upstream: fixed in v1.2.1 by 5e8b4565 (our patch, same code).

M8. A forged roster push gets no IQ reply

  • verified by a human
  • Spec: RFC 6120 §8.2.3. RFC 6121 §2.1.6 (should be answered with an error).
  • Seen: XEP-0100 runs (prosody 114621).
  • Upstream: fixed in v1.2.1 by 4ac96afd (upstream's own change; triage had it as not a bug): a push from anyone but our server is answered service-unavailable, nothing stored.

M9. XEP-0198 <r/> unanswered for ~50 min (network outage 05:31-06:20 UTC) without the stream being declared dead

  • verified by a human
  • Seen: night notes, during the 2026-11-07 outage. This is only a possible bug.
  • Needs live check: hold a session through a network cut (drop packets to the server) and see whether libtacky declares the stream dead after its <r/> timeout.
  • Upstream: not reproduced on v1.2.0 (ejabberd 175338: dead 60 s after <r/>); no change in v1.2.1.

M10. XEP-0410 self-pings rooms already left, during the resume replay (Prosody ordering)

  • verified by a human
  • Seen: prosody 010924.
  • Upstream: fixed in v1.2.1 by 7a177c07 (upstream's own change; triage had it as not a bug): self-pings after a resume wait for the replay and skip rooms left or leaving.

M11. mam query hides RSM <count>; disco Truncated count is empty although page 1 had <count>

  • verified by a human
  • Seen: XEP-0059 on ejabberd 235156, prosody 235904, anotherim 001123.
  • Upstream: fixed in v1.2.1 by 6b9ba1fc (upstream's own change): mam query answers count from ::tacky::rsm::parse ("" when absent; ours left the key out), disco <Truncated> keeps page 1's count.

M12. account untrust_certificate -acc <registration domain> fails with "Account doesn't exist" (trust works; HANDBOOK CERTPIN names both)

  • verified by a human
  • Seen: night notes (run not named).
  • Needs live check: account trust_certificate then untrust_certificate with -acc <registration domain> during an IBR flow, on 1dae0a6c.
  • Upstream: not reproduced on v1.2.0 (ejabberd 175154: works while the registration session is open); no change in v1.2.1.

M13. tackyd-json v1.2.0-rc2 build: ::tacky::version unset

  • verified by a human
  • What happens: software version reads 0.1 and the caps node is https://tacky.example.
  • Seen: XEP-0115 on anotherim 221514, prosody 221754.
  • Fix: check the build stamping in the tackyd-json packaging.
  • Upstream: fixed in v1.2.1 by 761c0bb0 (upstream's own change; triage had it as a decision): ::tacky::LibraryVersion answered, caps node is the DOAP home.

M14. OTR whitespace tag kept in the stored plaintext body

  • verified by a human
  • Spec: OTR v3 says to strip it before display.
  • Seen: prosody 125746, ejabberd 130347, anotherim 132541.
  • Upstream: fixed in v1.2.1 by 60daed8b (upstream's own change): only a tag that ends the body is cut, so no offset moves; ours cut it anywhere and moved mentions after it. A mid-body tag stays.

M15. Duplicate vCard gets for a MUC avatar (after 104 + x:update, and on join)

  • verified by a human
  • Seen: XEP-0486 on prosody 090404, ejabberd 090905.
  • Upstream: fixed in v1.2.1 by 7e939060 (upstream's own change): avatar FetchVCard keeps one get in flight per JID and hash; a 104 and our own set ask regardless (-force).

M16. Republishing another device's bookmark adds a <nick> it lacked

M17. Stale store state after server-side deletes

  • verified by a human
  • What happens:
    • A contact PEP item deleted by node delete without notice (ejabberd notify_delete false) stays in the store for good.
    • The stored roster kept the XEP-0100 full-JID item until a full roster fetch.
  • Seen: ejabberd 115158 and the night notes.
  • Upstream: not changed, by decision: a PEP item deleted with its node and no notice cannot be told from no item without a re-read; the stale full-JID roster item is S7's and no longer created.

M18. Replayed or equal-stamp sealed items are dropped without a debug line (other drops are logged)

  • verified by a human
  • Seen: sealed-1 runs (prosody 093734).
  • Upstream: partly fixed in v1.2.1 by 86b86680 (upstream's own change): chatsync's list path and pte_seal now log older and equal-stamp drops. The draft path (chatsync.tcl:1128, :1131, the Drafts/Cleared checks) still returns silently; our branch logged those too.

M19. The own call-invite row reads state joined although no call started (no media backend)

  • verified by a human
  • Seen: ejabberd 093754.
  • Upstream: fixed in v1.2.1 by c24cddf6 (upstream's own change; triage had it as a decision): our invite reads joined only while this device is in the call, pending otherwise, elsewhere for another device's.

M20. tls-server-end-point is computed for Ed25519 certificates, where RFC 5929 leaves it undefined

  • verified by a human
  • Seen: XEP-0440 runs (anotherim 011841).
  • Upstream: not a bug: SHA-256 for Ed25519/Ed448, as other XMPP stacks; the RFC 5929 row says so since 625d4462.

M21. PIE import oddities

  • verified by a human
  • What happens:
    • A restored custom tag appears only after a restart.
    • An imported enabled account connects during the import.
    • pie-0.md lacks <quick/>.
  • Seen: anotherim 025824.
  • Upstream: fixed in v1.2.1 by ddde3fc9 (our patch, comments reworded): tags reload after import; pie-0.md lists every <row/> facet. An enabled account coming up during the import is by design.

M22. A refused muc accept_invite leaves its autojoin bookmark

  • verified by a human
  • Seen: XEP-0249 runs (prosody 052252).
  • Upstream: fixed in v1.2.1 by da2984cc (upstream's own change; triage had it as a decision): a terminal refusal restores the room's previous bookmark (or removes it); wait-type errors keep it.

M23. OMEMO list and store hygiene

  • verified by a human
  • What happens:
    • publish_list drops OMEMO 2 label attributes on republish.
    • forget_inactive is unsafe when contacts have older inactive rows; a per-device forget is needed.
    • trust_list active reads false for devices on current lists (check the meaning in the HANDBOOK).
    • Fresh-store runs keep adding own devices (ai3a has ~46).
  • Seen: XEP-0384 runs (prosody 024328) and XEP-0450 runs (prosody 084617).
  • Upstream: partly fixed in v1.2.1 by d99bcf28 (upstream's own change): unsigned OMEMO 2 labels are kept on republish; trust_list active is documented (listed on a list read on this connection). Left as decisions: a per-device forget, own-device rows piling up on fresh stores.

M24. XEP-0377 report: the row says stanza-id by= is the reported JID, but §6 says to copy the received <stanza-id/>

  • verified by a human
  • Seen: XEP-0377 untestable on all three servers (ejabberd 125134). It needs Prosody mod_spam_reporting or a fake.
  • Upstream: not changed, by decision: XEP-0377's text and its example disagree; left to the maintainer or the XEP author.

M25. INFO-level oddities

  • verified by a human
  • What happens:
    • live-location (ejabberd 110656): the own device's correction of a peer's share is stored as an outgoing live row. An out-of-range correction becomes a text edit with body ≠ place. live_stopped is not set at expiry, although the HANDBOOK suggests it is.
    • pep-expiry: the writer accepts year 10000, which its own reader treats as no expiry. A replaced item's expiry stays pending until the next sign-in.
    • poll-fluux: <fallback for=urn:fluux:poll:0/> has no <body/>, unlike libtacky's own poll-fluux-0.md §3.1.
    • MUC/Sub: in a semi-anonymous room, subscriber rows without a jid give subscribers [] and no SubscriberChanged.
    • XEP-0511: the rdf:about-in-body check is a substring match (untested).
  • Upstream: partly fixed in v1.2.1 (upstream's own changes; ours covered the first three): poll-fluux <body/> 3dad47ab, XEP-0511 whole-link check c4d00bc9, pep-expiry year bound and replaced-item pending e364005c, live-location bad move dropped and live_stopped doc e9379baf, MUC/Sub nick-only subscribers 2336d35a. Left: the own device's correction of a peer's share still stored as an outgoing live row.

Server-side issues (not libtacky)

  • ejabberd / anotherim-server, XEP-0191 §3.3: the bounce for a blocked JID lacks <blocked xmlns='urn:xmpp:blocking:errors'/>. Runs: anotherim 221228, ejabberd 221627.
  • Prosody, XEP-0359 §3: delivers a sender-forged <stanza-id by=recipient/> ahead of its own and keeps it in MAM. libtacky is hardened (S12). Run: prosody 222405.
  • ejabberd / anotherim-server, RFC 7395 + RFC 5802 §6: WebSocket offers SCRAM without -PLUS, then refuses gs2 y ("Invalid channel binding"). libtacky works around it with n (20f0aecc, commit). Runs: ejabberd 230523, anotherim 233905.
  • ejabberd, XEP-0163 §4.3: no PEP notifications to a contact whose subscription was redone during the publisher's session. Runs: 000849, 001339.
  • ejabberd / anotherim-server, XEP-0045 §7.2.6: a non-member is admitted to a members-only moderated room (mod_muc_room.erl get_occupant_initial_role → stored role). Report to ProcessOne. Runs: ejabberd 014838, anotherim 015135.
  • Prosody 13.0.7 mod_proxy65: relays only the first 4096 bytes of a larger single write, then stalls. Reproduced without libtacky. The run is recorded fail although libtacky passed R1-R10; relabel it, or make the scenario chunk writes. Run: prosody 113200.
  • ejabberd test config: mod_proxy65 advertises streamhost 127.0.0.2:7777, and public port 7777 accepts then closes. This is a config fix and the user's decision.
    Needs live check: disco#info of proxy65 on ejabberd.asxp.io and a connect to public :7777.
  • Prosody: advertises only tls-exporter (XEP-0440 says servers MUST advertise tls-server-end-point). Maybe a config or version matter; not checked.
    Needs live check: read the stream features on prosody.asxp.io (no sign-in needed) and the channel-binding config.
  • Prosody: stopped routing ai1b's c2s stanzas after a 20.8 KB share (mod_limits?). Run: prosody 063013. Check the config.
    Needs live check: Prosody limits/c2s_stanza_size_limit config and a 20 KB stanza from a test account.
  • Prosody: an attribute newline sent as &#10; arrives as a space (INFO). Run: contact-0 prosody 104729.
  • ejabberd, XEP-0503 §4: lacks the MUST meta-data feature and leaves the owner's own private-space subscription pending. Run: 161316.
  • Peer library (slixmpp 1.17, for the harness): xep_0202 cannot answer time queries (set_tzo ValueError). The xep_0080 timestamp is broken. Iterating pubsub_event items in a handler hangs at 100% CPU.

Harness / scenario issues already fixed in the interop repo

  • peer.py: each Peer's wire log now holds only its own stream (commit "ai: keep each Peer's wire log to its own stream"). Runs before ~11:15 UTC on 2026-11-07 still have mixed peer-slixmpp*.log.
  • common.wire(): splitlines() broke on raw U+0085 in libtacky JSON lines. Fixed in 2633218. Other scenarios with their own splitlines() loops carry the same latent bug.
  • nix/https443.nix redirected container egress on port 443 too. Fixed, so a fresh anotherim server can build its image.
  • nix develop .#ai copied the repo into the store on every tree change, which filled the disk. Fixed with tools/ai/aish (pinned rev). Old copies are still in /nix/store.
  • XEP-0420 scenario: peer signals outside the envelope are now a FAIL (R7), and Prosody was re-run.
  • Redaction now covers XEP-0379 pre-approval tokens, and two 2026-11-04 RFC 5122 runs were redacted. The tokens are still in git history: revoke them (roster revoke_invite) and decide whether to rewrite history.
  • interop-log rotated-files fix: deployed to ejabberd only (Prosody and anotherim were not redeployed).
  • Store repair: stale muc_features/ai{1,2,3}b rows deleted (see S4). Backups are in the scratchpad store-bak/.

Not bugs: documented deviations or judgement calls

  • XEP-0379: accept_invite sends no server pre-approval; it approves on arrival (upstream ce96d4c5, row updated).
  • XEP-0333: <received/> marker kept beside the XEP-0184 receipt (upstream 2dd5a78f documents why).
  • XEP-0466: expired ephemeral text kept under preserve_history (default). <ephemeral/> in clear beside OMEMO 0.3. Documented. The OMEMO 2 case was fixed in d78fd98c (#17).
  • XEP-0396 R1: peer devices on the OMEMO 2 list are excluded from 0.3 key transport per libtacky's row. A strict §3 reading differs; the user decides.
  • XEP-0448: tagless aes-gcm uploads are refused (§4 only RECOMMENDS the tag). The OMEMO 2 envelope's aesgcm:// body has no XEP-0428 fallback mark.
  • XEP-0491: update/realtime refused under OMEMO (documented). The upload slot request names the filename and application/webxdc+zip in clear, as XEP-0363 requires.
  • XEP-0501: pubsub#type and item_expire unset (the row says so).
  • XEP-0420: envelopes without rpad/from are refused (INFO, stricter than the spec).
  • SASL: SCRAM-SHA-256-PLUS is preferred over SHA-512-PLUS (a preference question).
  • XEP-0077: the register form does not set legacy for legacy-field forms (INFO).
  • sealed:1: which Ed25519 conversion verifies seal signatures varies per device (XEdDSA sign bit?). A person should judge this against sealed-1.md.
  • Not covered by any run: XEP-0431 (no full-text MAM), XEP-0114 (no component listener), XEP-0377 (no server support), XEP-0317 R3/R5/R7 on ejabberd-family servers, XEP-0398 R4 (only ejabberd or a fake), XEP-0452 R1/R3 (needs mod_muc_mention_notifications on Prosody), XEP-0507 and other call paths (no media backend).
  • libtacky docs out of date (not bugs in code):
    • RFC 5929 and XEP-0440 rows (upstream 38bcfa35 rewrote XEP-0440's).
    • HANDBOOK fast_token needs token-mechanism + user-agent-id.
    • HANDBOOK mam intro says XEP-0441 prefs are unimplemented.
    • XEP-0493 row says the issuer is not checked.
    • XEP-0450 row and the omemo.tcl ATM comment (~7532) say trust messages go to every usable device, but the code sends to authenticated devices only.
    • HANDBOOK says a MUC invite password never reaches the host, but <Invite> and the stored row carry it.
    • The XEP-0292 row's reason for no vcard-temp copy.
    • message forward's documented return value.

6 comments

> **Status as of libtacky v1.2.1 ([8919dc12](https://dev.another.im/another-im/libtacky/commit/8919dc1271cca948849fef776547d847c70005aa)), 2026-11-08.** Of the 73 bugs (71 plus C3.1 and C34): 16 fixed in v1.2.0, 44 fixed in v1.2.1, 5 partly fixed (S3, C8, M18, M23, M25), 2 not fixed (C3.1, C34), 6 not a bug or left as a decision (C12, M9, M12, M17, M20, M24). The Upstream column and lines below are rechecked against the code at v1.2.1. "ours verbatim": same `git patch-id` as our `fix/<ID>` branch; "ours, reworded": same code, comments or tests rewritten; "upstream's own": different code. The text further down describes v1.2.0-rc2. ## Summary The AI interop runs of 2026-11-04 to 2026-11-07 tested libtacky **v1.2.0-rc2** (tackyd-json) against slixmpp on Prosody, ejabberd and anotherim-server. They found **71 distinct libtacky bugs**: **13 security/privacy**, **33 correctness** and **25 minor/SHOULD**. Upstream **v1.2.0** (`1dae0a6c`, develop HEAD) **fixes 16 of them**, **partly fixes 1** and **probably fixes 1**. The other 53 are not fixed upstream or have an unclear status. Duplicates across servers and runs are merged below. **How to verify a bug:** open each linked run dir, read `notes` and `bug` in `run.toml`, then find the stanza in `client.log` (libtacky's wire). `client-events.log` holds the API events and `client-debug.log` the debug log. `peer-slixmpp.log` and `server.log` show the other side. Source refs are `file:line` at tag `v1.2.0-rc2`. "Checked" means the code at `1dae0a6c` was compared. "Commit log only" means no matching upstream commit was found but the code was not re-read. Tick the box once a human has seen it. Bugs marked **Needs live check** can only be settled against a live server (the three test servers are being restarted); they say what to check. Links: runs `https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/<dir>`, commits `https://dev.another.im/another-im/libtacky/commit/<sha>`. ## Contents | # | Bug | Severity | Upstream | |---|-----|----------|----------| | S1 | Call invites and meeting messages bypass OMEMO | security/privacy | fixed in v1.2.1, upstream's own ([7559ecfc](https://dev.another.im/another-im/libtacky/commit/7559ecfc3a5f2682934b668267381e2aca77d8af), [9b1e961b](https://dev.another.im/another-im/libtacky/commit/9b1e961b6bba6c2d24242eca5e17f63d3ba5905e)) | | S2 | Chat state, receipt request and markable in clear beside OMEMO 2 (XEP-0420) | security/privacy | fixed in v1.2.1, ours verbatim ([810c609e](https://dev.another.im/another-im/libtacky/commit/810c609e5339c8d19b51b2b97809626b8cb13550)) | | S3 | SIMS file metadata in clear beside legacy OMEMO ciphertext | security/privacy | partly fixed: opt-out setting, default unchanged ([801f9533](https://dev.another.im/another-im/libtacky/commit/801f9533fed1a4b744b4bc2bad1dafdfca61e65d)) | | S4 | Fake room join at a contact's bare JID turns off 1:1 OMEMO for good | security/privacy | fixed in v1.2.1, ours verbatim ([065b273b](https://dev.another.im/another-im/libtacky/commit/065b273b9e93f84402c91ba50befa55bf34cb71c)) | | S5 | CAPTCHA inline BoB data not hash/size/type checked | security/privacy | fixed in v1.2.1, ours verbatim ([03b0c666](https://dev.another.im/another-im/libtacky/commit/03b0c666e626514a9a9dd305cef3cfc31aeeeb60)) | | S6 | spans-0 fallback strip hides arbitrary text | security/privacy | fixed in v1.2.1, ours verbatim ([0b3f2385](https://dev.another.im/another-im/libtacky/commit/0b3f2385ddbf351c0589ce5c5a22bccfe3d46501)) | | S7 | XEP-0100: a user JID posing as a gateway gets into the roster | security/privacy | fixed in v1.2.1, ours verbatim ([c9c3ae27](https://dev.another.im/another-im/libtacky/commit/c9c3ae276f40dc456ffb529821e6763e2ecae2e0)) | | S8 | `geoloc stop` overtaken by a stale republish | security/privacy | fixed in v1.2.1, ours verbatim ([ba1f07cf](https://dev.another.im/another-im/libtacky/commit/ba1f07cfa28177be1c52b0246d978cb8ae918d75)) | | S9 | OTR ssid/fingerprint mangled by Tcl `expr` (`Inf`) | security/privacy | fixed in v1.2.1, ours verbatim ([10ca7f9f](https://dev.another.im/another-im/libtacky/commit/10ca7f9f7f981d518ccfafbb34e7419b76de457b)) | | S10 | `parse_uri` splits a decoded `?` (link spoofing), accepts ports | security/privacy | fixed in v1.2.1, ours verbatim ([e706c4ad](https://dev.another.im/another-im/libtacky/commit/e706c4ad7a24775d051c6d3413bcbfcffbfd1505)) | | S11 | XEP-0227 export: every PEP node open; vcard-temp as a PEP node | security/privacy | fixed in v1.2.0 ([0213e2ea](https://dev.another.im/another-im/libtacky/commit/0213e2eafc6ba94aed38caff9c5e5a2c6b674f4d)) | | S12 | Peer can choose our stanza-id (forged `by=` own account) | security/privacy | fixed in v1.2.0 ([267e5bc4](https://dev.another.im/another-im/libtacky/commit/267e5bc43557fe0d33058a15115dcfbbb38f29af)) | | S13 | Secrets in host-facing output (sm `<Ack>`, XML console) | security/privacy | fixed in v1.2.1, ours verbatim ([fd8de84e](https://dev.another.im/another-im/libtacky/commit/fd8de84e543c2783e653a877353637332a4fd492)) | | C1 | Invalid jinglepub `from` throws, message lost | correctness | fixed in v1.2.1, ours verbatim ([7efc7c82](https://dev.another.im/another-im/libtacky/commit/7efc7c8273d516dab5100d4c9d4a9430abfbc538)) | | C2 | IBB error: no `<close/>`, 60 s stall (callback arity) | correctness | fixed in v1.2.1, ours, reworded ([01f262a2](https://dev.another.im/another-im/libtacky/commit/01f262a25952cce93342f8f2ea457058d1a7aea9)) | | C3 | Mention offsets not shifted after XmlText strips chars | correctness | fixed in v1.2.1, ours verbatim ([67d627cf](https://dev.another.im/another-im/libtacky/commit/67d627cf78a6b488f703615d89a495a13eae88ed)) | | C4 | Subject-only reply fallback treated as whole-body; reply dropped | correctness | fixed in v1.2.1, ours verbatim ([77ea7932](https://dev.another.im/another-im/libtacky/commit/77ea793237cdc95b56981ec9d35464623ee19b04)) | | C5 | service-0 notices raise `notify <Notify>` | correctness | fixed in v1.2.1, ours narrowed ([659997ee](https://dev.another.im/another-im/libtacky/commit/659997ee53dbab10f7fe6658e2f440fbf5c6aaaf)) | | C6 | Room caption folded by origin-id instead of stanza-id | correctness | fixed in v1.2.1, ours verbatim ([8de65a15](https://dev.another.im/another-im/libtacky/commit/8de65a15f618808b83af3fcc202015acfb17b92c)) | | C7 | XEP-0482 reject uses the wrong ids | correctness | fixed in v1.2.1, ours without the invite-id change ([6f004395](https://dev.another.im/another-im/libtacky/commit/6f0043957278d104575714c31edddef748b5f93d)) | | C8 | XEP-0492 `<advanced/>` dropped on rewrite | correctness | partly fixed, ours verbatim ([e576b749](https://dev.another.im/another-im/libtacky/commit/e576b749d995636451bbcbfab18836d200ee2a63)) | | C9 | Geoloc on Prosody: own node `<delete/>` stops sharing for good | correctness | fixed in v1.2.1, ours, reworded ([0df268dd](https://dev.another.im/another-im/libtacky/commit/0df268ddee3346d29a5b5270c01ca4e12d21fd6a)) | | C10 | XEP-0470 attachments node made without max_items (own reaction evicted) | correctness | fixed in v1.2.1, ours, reworded ([707ddaf2](https://dev.another.im/another-im/libtacky/commit/707ddaf2246db2940b7ff27665b6d53ef56d4922)) | | C11 | pubsub publish/create ids through `expr` (`1E…`→`Inf`) | correctness | fixed in v1.2.1, upstream's own ([4a00f894](https://dev.another.im/another-im/libtacky/commit/4a00f894c4b948d4f3b065d6b5e9cee418edb757)) | | C12 | XEP-0153 photo hash advertised before own vCard fetched | correctness | not changed: documented deviation ([bc534bf0](https://dev.another.im/another-im/libtacky/commit/bc534bf04da78eb42fe5142ac00eada9fba9664f)) | | C13 | SIMS `<file/>` lacks `<hash/>` and `<desc/>` | correctness | fixed in v1.2.1, ours, reworded ([5a194a64](https://dev.another.im/another-im/libtacky/commit/5a194a643011af548243633f1755bc92fd17222b)) | | C14 | send_album source messages lack sfs fallback marker | correctness | fixed in v1.2.1, ours, reworded ([84347d15](https://dev.another.im/another-im/libtacky/commit/84347d154566fa1bcfa8b629dc2f75570b0bf1bb)) | | C15 | Outgoing inline thumbnails have no size cap | correctness | fixed in v1.2.1, ours, reworded ([3c58decb](https://dev.another.im/another-im/libtacky/commit/3c58decbde288536ecc89fecd8319c56a599ca8e)) | | C16 | disco#info lacks `urn:ietf:params:xml:ns:vcard-4.0` | correctness | fixed in v1.2.1, ours, reworded ([6dd6be8f](https://dev.another.im/another-im/libtacky/commit/6dd6be8f5e32c9000b027494241be0d72d3c3303)) | | C17 | disco#info lacks `urn:xmpp:eme:0`; `name=` on listed EME ns | correctness | fixed in v1.2.1, ours, reworded ([fca586fb](https://dev.another.im/another-im/libtacky/commit/fca586fb50cd3f8611e9ecf5702f3540825c05ae)) | | C18 | microblog publish leaves `pubsub#notify_retract` false | correctness | fixed in v1.2.1, ours, reworded ([d2c3a50d](https://dev.another.im/another-im/libtacky/commit/d2c3a50d1f92a2f75a02e831e5dad4c87cf35496)) | | C19 | messagestore IsDuplicate merges different messages | correctness | fixed in v1.2.1, upstream's own ([752e4825](https://dev.another.im/another-im/libtacky/commit/752e4825b00a4cc3739fab591d8557f3c03fcead)) | | C20 | Forged XEP-0425 moderation stored as a message | correctness | fixed: rooms in v1.2.0 ([292016a5](https://dev.another.im/another-im/libtacky/commit/292016a5f536d04f0a93c70da6c0ae5038ec875e)), 1:1 in v1.2.1 ([95ef9888](https://dev.another.im/another-im/libtacky/commit/95ef9888afff6f74923872f1dd5d36d590872912)) | | C21 | Stream-error replay loop with no backoff | correctness | fixed in v1.2.0 ([dc48ac80](https://dev.another.im/another-im/libtacky/commit/dc48ac80eaabb0e699a82eed0f563305c9885486)) | | C22 | Post-auth features ignored on SASL2/Bind 2 (roster ver, pre-approval) | correctness | fixed in v1.2.0 ([8b25b7d3](https://dev.another.im/another-im/libtacky/commit/8b25b7d35f25411bb5ff428e7988b7645e89bfbf)) | | C23 | `message send` neither validates nor prepares JIDs | correctness | fixed in v1.2.0 ([246a66fe](https://dev.another.im/another-im/libtacky/commit/246a66fee0ba2464735a1696ed1b68727e5f17b3)) | | C24 | Stale vCard4 retry wipes the name (Prosody) | correctness | fixed in v1.2.0 ([6b9bac06](https://dev.another.im/another-im/libtacky/commit/6b9bac06e7a418e93426c6cedf59f155c1e12f98)) | | C25 | `account unregister` never answers on ejabberd; redial loop | correctness | fixed in v1.2.0 ([1dff6016](https://dev.another.im/another-im/libtacky/commit/1dff601618468e4b8a87a66da7c9141ed7dab8e8)) | | C26 | Forwarded `<message/>` in urn:xmpp:forward:0 namespace | correctness | fixed in v1.2.0 ([86ccda9a](https://dev.another.im/another-im/libtacky/commit/86ccda9a69a51b1b27d6505b344be75384b7e4b8)) | | C27 | XEP-0440 rules 4/5 not enforced on SASL2 | correctness | fixed in v1.2.0 ([c186eaa7](https://dev.another.im/another-im/libtacky/commit/c186eaa7524baf109f828ec72dfb163695b61030)) | | C28 | Over-limit IQ answer dropped instead of policy-violation | correctness | fixed in v1.2.0 ([70aae84e](https://dev.another.im/another-im/libtacky/commit/70aae84ed61a974e0878a1c7c7d760054ff5effe)) | | C29 | `iap` / `happy_eyeballs` settings never reach the connection | correctness | fixed in v1.2.0 ([5a87d4ec](https://dev.another.im/another-im/libtacky/commit/5a87d4ec40de5e96698ac7229e074fd191c0cd0e)) | | C30 | MUC decline sent to the room, not the occupant inviter | correctness | fixed in v1.2.0 ([616beba4](https://dev.another.im/another-im/libtacky/commit/616beba4dd6d69eedf746ff8a61b0aaf8982238f)) | | C31 | Jingle sender refuses peer's session-terminate | correctness | fixed in v1.2.0 ([4d485589](https://dev.another.im/another-im/libtacky/commit/4d4855899137ccd0d53ce478d346dbd717e91f2f)) | | C32 | XEP-0424: @id retraction ignored; refused ones stored as messages | correctness | fixed in v1.2.0 ([64378ebe](https://dev.another.im/another-im/libtacky/commit/64378ebe1d675c20e9b438d007b9f1e8b7cf5e2e)) | | C33 | XEP-0444 reaction set not reverted on error | correctness | fixed in v1.2.0 ([5bdefcae](https://dev.another.im/another-im/libtacky/commit/5bdefcae3879db1b40831bdf1317839e2971ab32)) | | C3.1 | Draft with a character XML cannot carry never synced (`bgerror`) | correctness | not fixed (upstream says 1.2.2, unreleased) | | C34 | Destroyed room recreated by autojoin on next sign-in | correctness | not fixed ([libtacky#26](https://dev.another.im/another-im/libtacky/issues/26), PR [#27](https://dev.another.im/another-im/libtacky/pulls/27)) | | M1 | Host slot APIs request slots for empty files | minor | fixed in v1.2.0 ([f396065d](https://dev.another.im/another-im/libtacky/commit/f396065d18d5b98334ffa0c9cec7fd27dcee8f91)) | | M2 | `adhoc list` keeps foreign command nodes | minor/SHOULD | fixed in v1.2.1, ours, reworded ([81f4ace7](https://dev.another.im/another-im/libtacky/commit/81f4ace7b5eac6abe978ac9ef69e98c2b34181bb)) | | M3 | `thread_parent == thread` accepted | minor | fixed in v1.2.1, upstream's own ([6e8203ce](https://dev.another.im/another-im/libtacky/commit/6e8203ce99a8c78b107a863bc99a6d9626800441)) | | M4 | Foreign-namespace `<attachments>` read as attachments | minor | fixed in v1.2.1, ours, reworded ([40640d58](https://dev.another.im/another-im/libtacky/commit/40640d5891b36cd863e0eb0c135b52dbcb2692c0)) | | M5 | `get_invoice` without disco | minor/SHOULD | fixed in v1.2.1, upstream's own ([6d620727](https://dev.another.im/another-im/libtacky/commit/6d620727e74a44d5cd8efb65e73461436fc819aa)) | | M6 | XEP-0472 side issues | minor | fixed in v1.2.1, upstream's own ([2d82b42d](https://dev.another.im/another-im/libtacky/commit/2d82b42db6112c98fbab3ecbe5a25e7661ab8588)) | | M7 | XEP-0501 entry lacks atom:author | minor | fixed in v1.2.1, ours, reworded ([5e8b4565](https://dev.another.im/another-im/libtacky/commit/5e8b45652760840265cc92fee9de266f7b418053)) | | M8 | Forged roster push gets no IQ reply | minor | fixed in v1.2.1, upstream's own ([4ac96afd](https://dev.another.im/another-im/libtacky/commit/4ac96afd0abfcceec2fcb7ddfee308b3f25b3156)) | | M9 | `<r/>` unanswered ~50 min without declaring the stream dead | minor | not reproduced, no change | | M10 | XEP-0410 self-pings rooms already left | minor | fixed in v1.2.1, upstream's own ([7a177c07](https://dev.another.im/another-im/libtacky/commit/7a177c0735c25ae65960f37ee35f0f570a9c15a0)) | | M11 | RSM `<count>` hidden | minor | fixed in v1.2.1, upstream's own ([6b9ba1fc](https://dev.another.im/another-im/libtacky/commit/6b9ba1fc2ef58fe93d2ed6008280ebd355a1821d)) | | M12 | `untrust_certificate` for a registration domain fails | minor | not reproduced, no change | | M13 | tackyd-json build unstamped (version 0.1, caps node tacky.example) | minor | fixed in v1.2.1, upstream's own ([761c0bb0](https://dev.another.im/another-im/libtacky/commit/761c0bb0c567fe5a675582766d9cd7c4b35e73ff)) | | M14 | OTR whitespace tag kept in stored body | minor | fixed in v1.2.1, upstream's own ([60daed8b](https://dev.another.im/another-im/libtacky/commit/60daed8b71d95339ed2cc1ebdce6ea7e1551d877)) | | M15 | Duplicate vCard gets for MUC avatars | minor | fixed in v1.2.1, upstream's own ([7e939060](https://dev.another.im/another-im/libtacky/commit/7e939060af2d7805d9b59718126a9d223d6e906a)) | | M16 | Republishing another device's bookmark adds `<nick>` | minor | fixed in v1.2.1, ours, reworded ([318f210b](https://dev.another.im/another-im/libtacky/commit/318f210b83e735fe4c3617fbaecdfa9d10b5ce11)) | | M17 | Stale store state after server-side deletes | minor | not changed (design; roster part is S7) | | M18 | Replayed sealed items dropped with no debug line | minor | partly fixed, upstream's own ([86b86680](https://dev.another.im/another-im/libtacky/commit/86b866802e0cd11eafbe11920ac470c9fbf56a91)) | | M19 | Own call-invite row says joined with no call | minor | fixed in v1.2.1, upstream's own ([c24cddf6](https://dev.another.im/another-im/libtacky/commit/c24cddf6a15f1243ca9e0d50307bc42efd8bbebe)) | | M20 | tls-server-end-point computed for Ed25519 certs | minor | not a bug: documented ([625d4462](https://dev.another.im/another-im/libtacky/commit/625d4462f55ed11b538dd81a4290ba820a78eb0a)) | | M21 | PIE import oddities | minor | fixed in v1.2.1, ours, reworded ([ddde3fc9](https://dev.another.im/another-im/libtacky/commit/ddde3fc9c37bb192aab8b912d1375e4a9de54ed6)) | | M22 | Refused `accept_invite` leaves its autojoin bookmark | minor | fixed in v1.2.1, upstream's own ([da2984cc](https://dev.another.im/another-im/libtacky/commit/da2984ccbabe722efd7cdd16d4e1c8cd02ee51bc)) | | M23 | OMEMO list/store hygiene | minor | partly fixed, upstream's own ([d99bcf28](https://dev.another.im/another-im/libtacky/commit/d99bcf28d19fcb3d04f2f59fb04dddbc6d907ae1)) | | M24 | XEP-0377 report `stanza-id by=` (untested) | minor | not changed (decision) | | M25 | INFO-level oddities (live-location, pep-expiry, poll, MUC/Sub, XEP-0511) | minor | partly fixed, upstream's own ([3dad47ab](https://dev.another.im/another-im/libtacky/commit/3dad47aba847480b7515ca5170a754d374914b15), [c4d00bc9](https://dev.another.im/another-im/libtacky/commit/c4d00bc915ea0cda5ad3d2a73bd43349c103183d), [e364005c](https://dev.another.im/another-im/libtacky/commit/e364005c57925f7efaf9ca5cc0142d73b5f49b48), [e9379baf](https://dev.another.im/another-im/libtacky/commit/e9379baf15dbbe1dbc3cd95e49bb6b4a8b7955b8), [2336d35a](https://dev.another.im/another-im/libtacky/commit/2336d35a2f889f4520e5cd26efb2d771281abc91)) | --- ## Security / privacy ### S1. Call invites (XEP-0482) and meeting messages (XEP-0483) bypass OMEMO - [ ] verified by a human - **Spec:** XEP-0483 §8 (the meeting URL is a bearer secret); libtacky's `omemo set_enabled` doc says "a send fails closed rather than going out in the clear". - **Seen:** anotherim-server [162349-XEP-0483](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-162349-XEP-0483-slixmpp-anotherim-server). Call invites were noted during the XEP-0482 runs ([093754 ejabberd](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-093754-XEP-0482-slixmpp-ejabberd), [094412 prosody](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-094412-XEP-0482-slixmpp-prosody)). - **What happens:** OMEMO was on for ai3b (`explicit:true`). `meetings invite/accept/reject/retract/leave` each wrote a plain `<message type='chat'>` with no `<encrypted/>`. Example from client.log line 144: `<message id='meet-…' to='ai3b@…' type='chat'><invite xmlns='urn:xmpp:call-invites:0'><external uri='https://meet.example.invalid/…'/>…<body>You are invited to join … at https://…</body>`. Muji call invites likewise put the room JID in the clear. - **Expected:** encrypted, or refused (as webxdc `send_update` does under OMEMO). - **Root cause:** `tacky/xmpp/modules/meetings.tcl:273-284` `Send` calls `$client write`. `tacky/xmpp/modules/groupcall.tcl:1910-1925` `SendToChat` calls `$client write`. Both bypass the message/OMEMO send path. - **Fix:** route both through the message module's encrypted send (OMEMO 2 envelope with the `<invite/>` inside), or refuse when `omemo chat_state` is enabled and the payload cannot be sealed. - **Upstream:** fixed in v1.2.1 by [7559ecfc](https://dev.another.im/another-im/libtacky/commit/7559ecfc3a5f2682934b668267381e2aca77d8af) (groupcall) and [9b1e961b](https://dev.another.im/another-im/libtacky/commit/9b1e961b6bba6c2d24242eca5e17f63d3ba5905e) (meetings), upstream's own change. Meeting messages in an OMEMO chat are refused (`{MEETINGS ENCRYPTED}`), as our patch did. Group-call invites and answers are not refused but sealed: `groupcall Deliver` puts them in an OMEMO 2 envelope (`omemo encrypt_envelope`, new) with only the EME marker and `<store/>` outside, and withholds them (`{TACKY GROUPCALL ENCRYPTED}`, or a `<Warning>` for an answer) when no OMEMO 2 device can read them. So an OMEMO 0.3-only peer (Dino today) gets no call invite in an OMEMO chat. ### S2. Chat state, receipt request and markable in clear beside OMEMO 2 ciphertext - [x] verified by a human - **Spec:** XEP-0420 §9 says non-server-processed elements "MUST NOT be available in plaintext outside the `<envelope/>`". libtacky's features.md row says "an encrypted message's outer elements are only the server's". - **Seen:** [ejabberd 040316](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-040316-XEP-0420-slixmpp-ejabberd), [anotherim 040943](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-040943-XEP-0420-slixmpp-anotherim-server), [prosody 040944](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-040944-XEP-0420-slixmpp-prosody), [prosody 035747](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-035747-XEP-0420-slixmpp-prosody). - **What happens:** `…<encrypted xmlns='urn:xmpp:omemo:2'>…</encrypted><body>I sent you an OMEMO encrypted message…</body><encryption xmlns='urn:xmpp:eme:0' …/><store/><active xmlns='http://jabber.org/protocol/chatstates'/><request xmlns='urn:xmpp:receipts'/><markable xmlns='urn:xmpp:chat-markers:0'/></message>`. The same happens on replies and corrections. Receipts, displayed markers, reactions and retractions also go out in the clear (INFO R19). - **Expected:** these elements inside the SCE `<content/>`, or not sent. Only Table 2 elements and the fallback body belong outside. - **Root cause:** `tacky/xmpp/modules/message.tcl:3443-3451` (BuildMessageStanza) appends `active`/`request`/`markable` unconditionally, outside the encrypted payload. - **Fix:** when `encWire` is set, put these into the envelope's extras (as is done for reply pointers), or omit them. Then do the same for receipts, markers, reactions and retractions. - **Upstream:** fixed in v1.2.1 by [810c609e](https://dev.another.im/another-im/libtacky/commit/810c609e5339c8d19b51b2b97809626b8cb13550) (our patch verbatim). `BuildMessageStanza` hands `<active/>`, `<request/>` and `<markable/>` to `encrypt_message` with the pointers, so they ride inside the :2 envelope. They stay outside only when a 0.3 element is written. Bodyless signals sent on their own (receipts, displayed markers, chat states, reactions, retractions) are still in the clear; features.md now says so. ### S3. File name, size and type in clear beside legacy OMEMO ciphertext - [ ] verified by a human - **Spec:** XEP-0420 §9 (by analogy) and XEP-0384 privacy. Also notes "Security (CONFIRMED)". - **Seen:** all three servers: [anotherim 081706](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-081706-XEP-0391-slixmpp-anotherim-server) (client.log:580), [ejabberd 074324](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-074324-XEP-0391-slixmpp-ejabberd), [prosody 082145](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-082145-XEP-0391-slixmpp-prosody). - **What happens:** an upload sent to a peer with a legacy (0.3) device goes out as `…</encrypted><body>…</body><encryption …/><store/><reference xmlns='urn:xmpp:reference:0' type='data'><media-sharing xmlns='urn:xmpp:sims:1'><file …><media-type>application/octet-stream</media-type><name>f-87e2cf27.bin</name><size>2000</size></file></media-sharing></reference>…`. - **Expected:** no plaintext metadata. At most a generic body. - **Root cause:** this is deliberate in the code (`legacyOutside`, `message.tcl:3288-3299`, `:3340`, `:3416-3421`, `LegacySimsNode` ~`:3500`) so that legacy readers see it. It is not stated in features.md or HANDBOOK. - **Fix:** drop `LegacySimsNode` beside ciphertext. If the legacy UX matters, gate it behind a setting and document the leak. - **Upstream:** partly fixed in v1.2.1 by [801f9533](https://dev.another.im/another-im/libtacky/commit/801f9533fed1a4b744b4bc2bad1dafdfca61e65d) (upstream's own change). Upstream kept the leak and added the installation setting `legacy_file_metadata`: `0` drops the SIMS metadata beside a 0.3 ciphertext, but unset means on, so by default the file name, size and type still go out in the clear. Our patch removed `LegacySimsNode` beside ciphertext outright. The leak is now documented (features.md, HANDBOOK). ### S4. A "room join" at a contact's bare JID silently downgrades the 1:1 chat to plaintext - [ ] verified by a human - **Spec:** libtacky's OMEMO rules (an explicit choice always wins). - **Seen:** anotherim-server after the XEP-0463 fake-join ([132727](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-132727-XEP-0463-slixmpp-anotherim-server), [132902](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-132902-XEP-0463-slixmpp-anotherim-server)). This comes from the night notes, not `run.toml`. The store rows were since repaired by hand. - **What happens:** joining `aiNb@…` as a room left `module_state muc_features/<contact> = "-"`. From then on `omemo chat_state` for that contact says `enabled:false reason room_not_eligible`, overriding the user's explicit ON. This persists, and there is no API to forget it. - **Expected:** a failed or fake join of a non-room JID records nothing. The 1:1 OMEMO choice stays. - **Root cause:** `tacky/xmpp/modules/omemo.tcl:5188-5195` `IsRoom` trusts `muc PrivacyOf` "known" (`muc.tcl:718`), which reads the stale `muc_features` row. - **Fix:** write `muc_features` only after disco#info shows a `conference` identity. In `IsRoom`, prefer roster/contact evidence. Add a forget call. - **Upstream:** fixed in v1.2.1 by [065b273b](https://dev.another.im/another-im/libtacky/commit/065b273b9e93f84402c91ba50befa55bf34cb71c) (our patch verbatim). ### S5. CAPTCHA inline BoB data taken without hash, size or type check - [ ] verified by a human - **Spec:** XEP-0231 §2, XEP-0221 §2, XEP-0158 §3.1.2/§6.3. libtacky's rows: "`<data/>` taken only when its bytes hash to its cid". - **Seen:** XEP-0221 on [ejabberd 050619](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-050619-XEP-0221-slixmpp-ejabberd), [prosody 051534](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-051534-XEP-0221-slixmpp-prosody), [anotherim 051737](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-051737-XEP-0221-slixmpp-anotherim-server). XEP-0158 on [anotherim 121814](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-121814-XEP-0158-slixmpp-anotherim-server), [prosody 122509](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-122509-XEP-0158-slixmpp-prosody), [ejabberd 123409](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-123409-XEP-0158-slixmpp-ejabberd). - **What happens:** `<uri>cid:sha1+40ecc4…@bob.xmpp.org</uri>` and `<data cid='sha1+40ecc4…'>` hold bytes hashing to `0aebef…`. `captcha <Challenge>` still carries `media.ocr` with those bytes. The ad-hoc path in the same run logs `adhoc: <data cid=…> dropped: the data does not hash to its cid`. The notes add that unbounded size and `image/svg+xml` with `onload` also pass, which is an XSS risk if a host renders SVG. Challenges for stanzas never sent, and from a foreign `from`, also reach the host (SHOULD ignore). - **Root cause:** `tacky/xmpp/modules/captcha.tcl:224-238` only base64-decodes the data. Compare `adhoc.tcl:312`, which uses `::tacky::bob::check $cid … $MEDIA_MAX` plus a raster-only type filter. - **Fix:** apply the same `bob::check` and raster allowlist as `adhoc.tcl:312-319`. Drop challenges whose referenced stanza id we never sent. - **Upstream:** fixed in v1.2.1 by [03b0c666](https://dev.another.im/another-im/libtacky/commit/03b0c666e626514a9a9dd305cef3cfc31aeeeb60) (our patch verbatim). ### S6. spans-0: any range marked as fallback is stripped, so a sender can hide text - [ ] verified by a human - **Spec:** urn:tacky:spans-0 (libtacky's own `docs/protocol`). Recorded as INFO, not as a doc violation. - **Seen:** [prosody 110023](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-110023-urn-tacky-spans-0-slixmpp-prosody). - **What happens:** a `<fallback for='urn:tacky:spans:0'>` range is removed without checking that it is ` (href)`. Text such as "PS: wire the money…" is shown by other clients but hidden from libtacky users. A range past the body end is clipped. A childless `<fallback for=spans/>` drops the whole message. Forwards and quotes lose the hidden URL. - **Root cause:** `tacky/xmpp/modules/message.tcl:8864-8867` (fallback ranges for spans) and `:9521-9522`. - **Fix:** strip only an exact ` (<href>)` directly after a link span. Ignore other ranges and a childless spans fallback. - **Upstream:** fixed in v1.2.1 by [0b3f2385](https://dev.another.im/another-im/libtacky/commit/0b3f2385ddbf351c0589ce5c5a22bccfe3d46501) (our patch verbatim). ### S7. XEP-0100: a user's full JID claiming gateway identity gets added to the roster - [ ] verified by a human - **Spec:** XEP-0100 §6.1 (a gateway address SHOULD be a hostname only). libtacky's own GatewayTarget rule. - **Seen:** [prosody 114621](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-114621-XEP-0100-slixmpp-prosody), [ejabberd 115158](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-115158-XEP-0100-slixmpp-ejabberd). It was not run on anotherim on purpose. - **What happens:** after `adhoc execute node=register` at `ai2b@ejabberd.asxp.io/gw-…` (disco identity `gateway/legacy`), libtacky sent `<iq type='set'><query xmlns='jabber:iq:roster'><item jid='ai2b@…/gw-…'/></query></iq>` plus `<presence type='subscribe'/>`. On ejabberd this replaced the existing bare contact (subscription `both` became `to`, losing `from`). Where pre-approval is used, it also gives our presence away. - **Root cause:** `tacky/xmpp/modules/adhoc.tcl:340-345` `GatewayRegistered`, then `search Linked` (`search.tcl:675`), then `roster.tcl:600` `IfGateway`. None of them checks that the JID has no node or resource. - **Fix:** in `GatewayRegistered`/`IfGateway`, return early unless `jid username` and `jid resource` are both empty, as `gateway register` already refuses ("is not a remote service"). - **Upstream:** fixed in v1.2.1 by [c9c3ae27](https://dev.another.im/another-im/libtacky/commit/c9c3ae276f40dc456ffb529821e6763e2ecae2e0) (our patch verbatim). ### S8. `geoloc stop` overtaken by a stale republish after `set_allowed` - [ ] verified by a human - **Spec:** XEP-0080 §4.1 (stop = empty `<geoloc/>`), §8 (access control). - **Seen:** [ejabberd 113228](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-113228-XEP-0080-slixmpp-ejabberd), [anotherim 113802](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-113802-XEP-0080-slixmpp-anotherim-server). First seen in [112745](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-112745-XEP-0080-slixmpp-ejabberd). - **What happens:** the calls `set_allowed []`, `set_allowed [peer]` and `stop` were made back to back. iq 78 publishes the empty `<geoloc/>` and is acked. Then iq 80 sets the peer as member, and iq 81 publishes `<item id='current'><geoloc>…<lat>12.3456</lat>…</geoloc></item>` again. The peer reads the location, and `geoloc get` says `active true`. - **Expected:** the stop is the last word. - **Root cause (suspected):** `tacky/xmpp/modules/geoloc.tcl:257-266` `AfterListChange` republishes `Stored` own `loc` for added members without checking that sharing is still active. The refill of `Stored` was not traced. - **Fix:** in `AfterListChange`, return if the own state is stopped/inactive. Serialise `stop` after pending list changes. - **Needs live check:** on ejabberd/anotherim, run `set_allowed []`, `set_allowed [peer]`, `stop` back to back; read the geoloc node as the peer 8 s later (must be empty) — on rc2 and on 1dae0a6c. - **Upstream:** fixed in v1.2.1 by [ba1f07cf](https://dev.another.im/another-im/libtacky/commit/ba1f07cfa28177be1c52b0246d978cb8ae918d75) (our patch verbatim); rig case [d5ecda72](https://dev.another.im/another-im/libtacky/commit/d5ecda72917f609a993711458f226843dfeb82dc). ### S9. OTR ssid and fingerprint mangled by Tcl `expr` - [ ] verified by a human - **Spec:** OTR v3 AKE (the ssid is shown for out-of-band comparison). - **Seen:** [ejabberd 130347](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-130347-XEP-0364-slixmpp-ejabberd). The other servers did not hit it (the ssid is random). - **What happens:** the ssid `02802368162e5437` was reported as `"ssid": "Inf"` in `otr <State>` (client-events.log:89). - **Root cause:** `tacky/xmpp/otr.tcl:277-278` builds `fingerprint` and `ssid` inside `expr {… ? "" : [hex …]}`. Tcl canonicalises numeric-looking results (`…e…` becomes Inf; all digits lose leading zeros). - **Fix:** `if {$x eq ""} {set s ""} else {set s [string tolower [binary encode hex $x]]}`, not `expr`. Same class as C11. - **Upstream:** fixed in v1.2.1 by [10ca7f9f](https://dev.another.im/another-im/libtacky/commit/10ca7f9f7f981d518ccfafbb34e7419b76de457b) (our patch verbatim). ### S10. `account parse_uri`: a decoded `?` splits the address (link spoofing); ports accepted - [ ] verified by a human - **Spec:** RFC 5122 §2.8.1 (separate the query before decoding; the address must conform), §5.2. XEP-0147. - **Seen:** [prosody 121127](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-121127-XEP-0147-slixmpp-prosody), [ejabberd 122029](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-122029-XEP-0147-slixmpp-ejabberd), [anotherim 122401](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-122401-XEP-0147-slixmpp-anotherim-server). - **What happens:** `xmpp:x%3Fy…@example.invalid?subscribe` gives jid `x`, so `xmpp:target.example%3Fz@innocent.example?subscribe` subscribes to target.example. `?invite;jid=a%3Fb@…` gives `a`. `xmpp:ai1b@prosody.asxp.io:5222?message` is accepted with the port in the domain. - **Root cause:** in `tacky/xmpp/jid.tcl`, the rc2 pattern refused `?` in a localpart, so `jid bare` split at it. Used from `account.tcl:1791` `LinkUri`. `jid valid` does not refuse `:` in a domain. - **Fix:** the `?` split is fixed upstream. Also refuse a `:port` (and `?`) in the decoded domain, and add URI tables to `test_link.tcl`. - **Needs live check:** re-run XEP-0147.py R7 against libtacky 1dae0a6c (local parse only, any server): `%3F` link now names `x?y@…`; does `…:5222?message` still parse? - **Upstream:** fixed in v1.2.1 by [e706c4ad](https://dev.another.im/another-im/libtacky/commit/e706c4ad7a24775d051c6d3413bcbfcffbfd1505) (our patch verbatim): a port or a decoded query in the address is refused. The `?` split was fixed in v1.2.0 by [cd3e39c5](https://dev.another.im/another-im/libtacky/commit/cd3e39c571ca01243028d3679a5af319f373e313). ### S11. XEP-0227 export: every PEP node exported as open; own vcard-temp written as a PEP node - [ ] verified by a human - **Spec:** XEP-0227 §4.7. - **Seen:** [anotherim 030802](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-030802-XEP-0227-tackyd-anotherim-server), [ejabberd 031202](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-031202-XEP-0227-tackyd-ejabberd), [prosody 031526](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-031526-XEP-0227-tackyd-prosody). - **What happens:** `<user>` holds `<pubsub#owner><configure node='vcard-temp'>` (access open) plus items, and no `<vCard xmlns='vcard-temp'/>` child. On Prosody the `urn:xmpp:vcard4` node is exported as `open` although the server has it as `presence`. An importing server would publish the vCard to everyone. - **Root cause:** `tacky/xmpp/modules/backup.tcl:584` hard-codes `open` except for bookmarks. `WriteUser` exports the `vcard-temp` pseudo-node (`vcard.tcl` Keep). - **Upstream:** fixed in v1.2.0 by 0213e2ea ([commit](https://dev.another.im/another-im/libtacky/commit/0213e2eafc6ba94aed38caff9c5e5a2c6b674f4d)). ### S12. A peer can choose the stanza-id of its own message (forged `by=` our account) - [ ] verified by a human - **Spec:** XEP-0359 §3. The server part (Prosody keeps the forged element) is listed under server-side issues. - **Seen:** [prosody 222405](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-222405-XEP-0359-slixmpp-prosody). - **What happens:** `<stanza-id by=ai1a id=forged-me-…/>` came before Prosody's own, and libtacky stored `server_id=forged-me-…` even after MAM catch-up. Replies, retractions and markers then name the peer's choice. - **Root cause:** `tacky/xmpp/modules/message.tcl:9474` `ArchiveStanzaId` takes the first element with `by=` our account. - **Upstream:** fixed in v1.2.0 by 267e5bc4 ([commit](https://dev.another.im/another-im/libtacky/commit/267e5bc43557fe0d33058a15115dcfbbb38f29af)). ### S13. Secrets reach host-facing output - [ ] verified by a human - **Spec:** none (hygiene). - **Seen:** night notes, around the XEP-0077 runs ([prosody 001423](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-001423-XEP-0077-tackyd-prosody)) and XEP-0401 runs ([prosody 010250](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-010250-XEP-0401-tackyd-prosody)). - **What happens:** (a) `sm <Ack>` hands the host the raw acked stanzas, including `change_password`'s new password (it reached client-events.log; the scenario redacts it). (b) The XML console logs the invite form URI with its preauth token unredacted, because `redact::uriParams` is used only by jlog. - **Fix:** strip `jabber:iq:register` `<password/>` and SASL/FAST data from `<Ack>` payloads. Run `redact::uriParams` on debugtap output. - **Upstream:** fixed in v1.2.1 by [fd8de84e](https://dev.another.im/another-im/libtacky/commit/fd8de84e543c2783e653a877353637332a4fd492) (our patch verbatim). ## Correctness ### C1. Invalid `<jinglepub from>` throws; the whole message is lost (and fails again on every MAM catch-up) - [ ] verified by a human - **Spec:** XEP-0358 §2.1. - **Seen:** [anotherim 124106](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-124106-XEP-0358-slixmpp-anotherim-server), [ejabberd 125512](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-125512-XEP-0358-slixmpp-ejabberd), [prosody 130302](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-130302-XEP-0358-slixmpp-prosody). - **What happens:** `<jinglepub from='@@@/evil-….invalid@@' …>` causes client-debug.log `bgerror: Invalid JID: @@@/evil-….invalid@@`. No row and no `<New>` is created. Any contact can make a message vanish. - **Root cause:** `tacky/xmpp/modules/message.tcl:11132` (`ExtractSfsAttachments`: `jid norm [jid bare $pubFrom]` with no `catch`). - **Fix:** `if {[catch {jid norm [jid bare $pubFrom]} b]} { continue }`, which drops that source and keeps the message. - **Upstream:** fixed in v1.2.1 by [7efc7c82](https://dev.another.im/another-im/libtacky/commit/7efc7c8273d516dab5100d4c9d4a9430abfbc538) (our patch verbatim). ### C2. IBB: a data error never closes the bytestream (callback arity), 60 s stall - [ ] verified by a human - **Spec:** XEP-0047 §2.2 (sender MUST close on error; recipient MUST close on bad seq). XEP-0261. - **Seen:** [prosody 112315](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-112315-XEP-0047-slixmpp-prosody), [anotherim 112907](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-112907-XEP-0047-slixmpp-anotherim-server), [ejabberd 113720](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-113720-XEP-0047-slixmpp-ejabberd). - **What happens:** `<data seq='1'>` is answered `<unexpected-request/>`, then client-debug.log shows `ibb callback failed: wrong # args: should be "...jinglefile OnIbbSent sid n result"`. No `<close/>` is sent, and the session ends only after the 60 s stall timer. As receiver, an out-of-sequence block terminates the Jingle session but sends no IBB `<close/>`. - **Root cause:** `tacky/xmpp/modules/ibb.tcl:94,126` calls `Callback $cmd err <text>` (two args). `jinglefile.tcl:2711` `OnIbbOpened {sid result}` and `:2741` `OnIbbSent {sid n result}` take one. - **Fix:** have `ibb.tcl` pass one list (`[list err $text]`), or change the jinglefile methods to `{sid n status args}`. On error, send `<close/>` before unsetting `Out(sid)`. Send `<close/>` on the receiver's bad-seq path. - **Upstream:** fixed in v1.2.1 by [01f262a2](https://dev.another.im/another-im/libtacky/commit/01f262a25952cce93342f8f2ea457058d1a7aea9) (our patch; only a comment rewrapped). ### C3. Mention offsets point at the wrong text after XML-forbidden characters are stripped - [x] verified by a human - **Spec:** XEP-0426 §2. - **Seen:** [anotherim 131221](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-131221-XEP-0426-slixmpp-anotherim-server), [prosody 132640](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-132640-XEP-0426-slixmpp-prosody), [ejabberd 153155](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-153155-XEP-0426-slixmpp-ejabberd). - **What happens:** the body `'… ctl\x01 nonchar￾ lone\uD83D @Bee end'` with mention 30..34 goes out with U+0001 and U+FFFE removed, but `<reference begin='30' end='34'/>` now covers `ee e`. - **Root cause:** `tacky/xmpp/modules/message.tcl:3798-3800`: `XmlText` runs, then `CheckMentions` uses the cleaned body without shifting offsets. Edits and captions behave the same. - **Fix:** compute the index map while stripping and shift mention offsets, or refuse the send when stripping touches a mentioned range. - **Upstream:** fixed in v1.2.1 by [67d627cf](https://dev.another.im/another-im/libtacky/commit/67d627cf78a6b488f703615d89a495a13eae88ed) (our patch verbatim, libtacky#25). Also covers the second symptom (a mention at the end of the body pushed past it, so the send was refused). See C3.1 for drafts. ### C4. A reply fallback naming only `<subject/>` is read as covering the whole body, and the reply is dropped - [ ] verified by a human - **Spec:** XEP-0428 §2.2 (only a childless `<fallback/>` covers everything). - **Seen:** [anotherim 064613](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-064613-XEP-0428-slixmpp-anotherim-server), [ejabberd 065302](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-065302-XEP-0428-slixmpp-ejabberd), [prosody 065529](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-065529-XEP-0428-slixmpp-prosody). - **What happens:** for `<fallback for='urn:xmpp:reply:0'><subject start='0' end='3'/></fallback>` no row and no `<New>` are created. The same reply without `<fallback/>` is stored. - **Root cause:** `tacky/xmpp/modules/reply.tcl:51-55`: `if {[llength $bodies] == 0} { lappend ranges [list 0 $len] }`. - **Fix:** apply the whole-body range only when `[llength [dict get $fb children]] == 0`. - **Upstream:** fixed in v1.2.1 by [77ea7932](https://dev.another.im/another-im/libtacky/commit/77ea793237cdc95b56981ec9d35464623ee19b04) (our patch verbatim). ### C5. service-0 notices raise `notify <Notify>` - [ ] verified by a human - **Spec:** libtacky `docs/protocol/service-0.md` §4 ("never unread, never notified"). - **Seen:** [anotherim 110355](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-110355-urn-tacky-service-0-slixmpp-anotherim-server), [prosody 110829](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-110829-urn-tacky-service-0-slixmpp-prosody), [ejabberd 111044](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-111044-urn-tacky-service-0-slixmpp-ejabberd). - **What happens:** for all 11 service rows (pin, ttl, screenshot…), events like `notify <Notify> {"id": "svc-pin-…", "body": "Peer did pin …"}` are raised. The unread count stays correct. - **Root cause:** `tacky/xmpp/modules/notify.tcl:287-293` `OnNew` skips only content types `call` and `omemo_session`. - **Fix:** also skip `service` (and any other notice content types). - **Upstream:** fixed in v1.2.1 by [659997ee](https://dev.another.im/another-im/libtacky/commit/659997ee53dbab10f7fe6658e2f440fbf5c6aaaf) (our patch, narrowed). `OnNew` skips content type `service` beside `omemo_session`; ours skipped every notice row. Timer, ttl and screenshot notices still raise `<Notify>`, by upstream's choice. ### C6. In a room, a caption is folded by origin-id rather than the room's stanza-id - [ ] verified by a human - **Spec:** XEP-0367 §4.1, §5. - **Seen:** [ejabberd 071802](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-071802-XEP-0367-slixmpp-ejabberd), [anotherim 072110](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-072110-XEP-0367-slixmpp-anotherim-server), [prosody 072653](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-072653-XEP-0367-slixmpp-prosody). - **What happens:** a groupchat `<attach-to id='go2-…'/>` naming the file's origin-id is folded (`message <Edited> content.caption …`) instead of being shown as a normal message. The author check still applies, so there is no spoofing. - **Root cause:** `tacky/xmpp/modules/message.tcl:9224` `FoldCaption`, then `messagestore.tcl:2448` `rowsByTarget`, which matches server_id, own_id and origin_id in rooms too. - **Fix:** for `?join` chats, match attach-to against `server_id` only. - **Upstream:** fixed in v1.2.1 by [8de65a15](https://dev.another.im/another-im/libtacky/commit/8de65a15f618808b83af3fcc202015acfb17b92c) (our patch verbatim). ### C7. XEP-0482 reject uses the wrong ids - [ ] verified by a human - **Spec:** XEP-0482 0.1.0 §3.1. - **Seen:** [ejabberd 093754](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-093754-XEP-0482-slixmpp-ejabberd), [prosody 094412](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-094412-XEP-0482-slixmpp-prosody), [anotherim 094906](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-094906-XEP-0482-slixmpp-anotherim-server). - **What happens:** (1) A 1:1 invite without Dino's `<invite id>` is declined locally, but no `<reject/>` is sent. The expected answer is `<reject id='<origin-id>'/>`. (2) In a room, the decline sends `<reject id='ci7-…'/>` (the invite@id) instead of the room's stanza-id. libtacky's own invites have a message id that differs from invite@id and no origin-id, so 0.1.0-only peers never match. - **Root cause:** `tacky/xmpp/modules/groupcall.tcl:376-391` `decline` uses only `invite id`. - **Fix:** keep invite@id (for Dino), falling back to origin-id, then message id, and in rooms to stanza-id. Accept answers naming any of them. Set origin-id equal to invite@id on our own invites. - **Upstream:** fixed in v1.2.1 by [6f004395](https://dev.another.im/another-im/libtacky/commit/6f0043957278d104575714c31edddef748b5f93d) (our patch minus one part). `decline` falls back to `CallInviteRef` (stanza-id in a room, else origin-id, own id, wire id) and answers are matched the same way (`CallInvitesByRef`). Upstream did not set origin-id = invite@id on our own invites (re-invites share one `<invite id/>`); a 0.1.0 peer's answer naming our random message id is matched by `own_id` instead. ### C8. XEP-0492: `<advanced/>` dropped when the attribute-free element is rewritten - [ ] verified by a human - **Spec:** XEP-0492 0.2.0 §3 (MUST NOT delete or alter `<advanced/>`; SHOULD add a fallback). - **Seen:** [ejabberd 091607](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-091607-XEP-0492-slixmpp-ejabberd), [prosody 092506](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-092506-XEP-0492-slixmpp-prosody), [anotherim 092531](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-092531-XEP-0492-slixmpp-anotherim-server). - **What happens:** `<notify><always><advanced><rule…/></advanced></always>…</notify>` passed through `set_notification -value on-mention` becomes `…<on-mention/></notify>` with no `<advanced/>`. Two more problems: (a) a scoped write with no setting adds no attribute-free fallback (SHOULD); (b) `notify get` answers `{muted: 0, mentions: 1}` regardless of the bookmark setting, while `<Notify>` alerts do follow it. - **Root cause:** `tacky/xmpp/modules/bookmarks.tcl:841-890` `NotifyMerge`, around 867/882: the matching element is skipped and the new one gets `children {}`. - **Fix:** carry the old element's `<advanced/>` children over to the new one. Add the fallback on scoped writes. Make `notify get` read the bookmark. - **Upstream:** partly fixed in v1.2.1 by [e576b749](https://dev.another.im/another-im/libtacky/commit/e576b749d995636451bbcbfab18836d200ee2a63) (our patch verbatim): `NotifyMerge` carries `<advanced/>` over. Not done: (a) the attribute-free fallback on a scoped write (SHOULD). (b) upstream says `notify get` already reads the bookmark once a `?join` chat is in scope (not a bug). ### C9. Geoloc on Prosody: the owner's node `<delete/>` event ends sharing; `set_allowed` after item-not-found is marked synced - [ ] verified by a human - **Spec:** XEP-0080 §4.1/§8. libtacky's row ("deleting the node and publishing afresh"; members set before the item). - **Seen:** [prosody 113745](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-113745-XEP-0080-slixmpp-prosody). - **What happens:** `set_allowed []` sends iq 41 `<delete node=geoloc/>`. Prosody pushes the owner `<delete/>` event, after which `geoloc <Changed> active false` fires and the node is never republished. `set_allowed [ai1b]` then reads affiliations, gets `item-not-found`, and sets `geoloc_allowed_dirty 0`. `stop` publishes under a whitelist without making ai1b a member, so ai1b reads `<forbidden/>`. Nothing leaks. - **Root cause:** `tacky/xmpp/modules/geoloc.tcl:445-451` `OnNotification` treats our own `delete` as a stop. `:372` clears the dirty flag after an error-ish sync. - **Fix:** ignore our own delete events while a delete-and-republish is in flight. Keep the dirty flag when the affiliations read fails. Set members before every publish. - **Needs live check:** on prosody.asxp.io, `set_allowed []` then `set_allowed [peer]`: does the owner get its own `<delete/>` event, and does a peer read item-not-found/forbidden afterwards. - **Upstream:** fixed in v1.2.1 by [0df268dd](https://dev.another.im/another-im/libtacky/commit/0df268ddee3346d29a5b5270c01ca4e12d21fd6a) (our patch, same code; upstream added an integration case). ### C10. XEP-0470 attachments node made without `pubsub#max_items` (Prosody keeps 1, so our own reaction is evicted) - [ ] verified by a human - **Spec:** XEP-0470 §4.1/§4.2 (one item per JID). - **Seen:** [prosody 132847](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-132847-XEP-0470-slixmpp-prosody). - **What happens:** after our reaction (`item id='ai1a@…'`) and the peer's, the node holds only `ai1b`. - **Root cause:** `tacky/xmpp/modules/microblog.tcl:688-690` `OnPostPublished` creates the node with `access_model/publish_model/persist_items` only. - **Fix:** add `pubsub#max_items max` (as `create_feed` does at `:1140-1143`). - **Upstream:** fixed in v1.2.1 by [707ddaf2](https://dev.another.im/another-im/libtacky/commit/707ddaf2246db2940b7ff27665b6d53ef56d4922) (our patch, same code; comments and an integration case added). ### C11. `pubsub publish/create` return a numeric-looking id altered (`1E…`→`Inf`, `0x10`→`16`) - [ ] verified by a human - **Spec:** XEP-0060 §3, §7.1.2. - **Seen:** [anotherim 042352](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-042352-XEP-0060-slixmpp-anotherim-server), [ejabberd 043115](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-043115-XEP-0060-slixmpp-ejabberd), [prosody 043422](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-043422-XEP-0060-slixmpp-prosody). ejabberd's own hex ids hit this too (`70262E937439`→`Inf`). - **Root cause:** `tacky/xmpp/modules/pubsub.tcl:1044` `expr {$made eq "" ? $node : $made}` and `:1158` `Done $command [expr {$given ne "" ? $given : $id}]`. - **Fix:** use `if/else`. Also grep for other `expr {… ? $str : $str}` on ids (see S9). - **Upstream:** fixed in v1.2.1 by [4a00f894](https://dev.another.im/another-im/libtacky/commit/4a00f894c4b948d4f3b065d6b5e9cee418edb757) (upstream's own change, broader). Every id/text picked with `expr ?:` across 13 modules now uses `if`; ours touched `pubsub.tcl` only. Left: the create error text (`pubsub.tcl:1072`, `Could not create [expr {...? "a node" : $node}]`) still goes through `expr` (cosmetic). ### C12. XEP-0153: the kept photo hash is advertised before the own vCard is downloaded - [ ] verified by a human - **Spec:** XEP-0153 §4.2 (MUST NOT). - **Seen:** [ejabberd 044317](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-044317-XEP-0153-slixmpp-ejabberd), [anotherim 044833](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-044833-XEP-0153-slixmpp-anotherim-server), [prosody 044857](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-044857-XEP-0153-slixmpp-prosody). - **What happens:** the first presence after sign-in carries `<x xmlns='vcard-temp:x:update'><photo>74f5…</photo></x>`, and the own `<vCard/>` get goes out after it. - **Root cause:** `tacky/xmpp/modules/presencemod.tcl:155-169` (`PhotoKnown`/`LoadPhoto`, deliberately, for an Android cold start). - **Fix:** send an empty `<x/>` until the vCard is fetched, or document the deviation in the row. - **Upstream:** not changed, by decision: [bc534bf0](https://dev.another.im/another-im/libtacky/commit/bc534bf04da78eb42fe5142ac00eada9fba9664f) documents the deviation (photo hash advertised at bind for an Android cold start) in features.md. Our branch `fix/C12-photo-hash-before-vcard` (empty `<x/>` until the vCard is fetched) was not taken. ### C13. SIMS `<file/>` lacks `<hash/>` and `<desc/>` - [ ] verified by a human - **Spec:** XEP-0385 §4.1 (MUST), §4.2. - **Seen:** [anotherim 065654](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-065654-XEP-0385-slixmpp-anotherim-server), [ejabberd 070001](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-070001-XEP-0385-slixmpp-ejabberd), [prosody 070606](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-070606-XEP-0385-slixmpp-prosody). Also noted for XEP-0491 on ejabberd. - **What happens:** `<media-sharing><file><media-type/><name/><size/><thumbnail/></file>…` has no hash, while the XEP-0447 `<file/>` beside it has the sha-256 and desc. - **Root cause:** `tacky/xmpp/modules/message.tcl:3462` `ShareNodes`. - **Fix:** reuse the SFS file's `<hash xmlns='urn:xmpp:hashes:2'/>` and `<desc/>` in the SIMS file. - **Upstream:** fixed in v1.2.1 by [5a194a64](https://dev.another.im/another-im/libtacky/commit/5a194a643011af548243633f1755bc92fd17222b) (our patch, same code reordered). ### C14. `send_album` source messages carry a url body without the sfs fallback marker - [ ] verified by a human - **Spec:** XEP-0447 §3.3 (MUST add `<fallback for='urn:xmpp:sfs:0'>`). - **Seen:** [ejabberd 031219](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-031219-XEP-0447-slixmpp-ejabberd), [prosody 034725](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-034725-XEP-0447-slixmpp-prosody), [anotherim 035238](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-035238-XEP-0447-slixmpp-anotherim-server). - **Root cause:** `tacky/xmpp/modules/message.tcl:4683` `SourceWrite`. - **Fix:** add `j fallback -ns urn:xmpp:fallback:0 -for urn:xmpp:sfs:0 { j body }`, as `send_file` does. - **Upstream:** fixed in v1.2.1 by [84347d15](https://dev.another.im/another-im/libtacky/commit/84347d154566fa1bcfa8b629dc2f75570b0bf1bb) (our patch, comment reworded). ### C15. Outgoing inline thumbnails have no size cap (a 70 KB thumb gives a ~95 KB stanza) - [ ] verified by a human - **Spec:** XEP-0264 §5. libtacky's row ("≤ 160 px, 64 KiB"). - **Seen:** [ejabberd 052434](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-052434-XEP-0264-slixmpp-ejabberd), [prosody 063013](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-063013-XEP-0264-slixmpp-prosody), [anotherim 063101](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-063101-XEP-0264-slixmpp-anotherim-server). - **Root cause:** `tacky/xmpp/modules/file.tcl:2763` `thumb_data_parts` checks only syntax and type. `thumb_data_uri` (`:2756`) does check `thumb_max_bytes`. - **Fix:** in `thumb_data_parts`, return `""` when the decoded size is over `[thumb_max_bytes]`. - **Upstream:** fixed in v1.2.1 by [3c58decb](https://dev.another.im/another-im/libtacky/commit/3c58decbde288536ecc89fecd8319c56a599ca8e) (our patch, same check in `thumb_data_parts`; comment and test reworded). ### C16. disco#info lacks `urn:ietf:params:xml:ns:vcard-4.0` - [ ] verified by a human - **Spec:** XEP-0292 §7 (MUST). - **Seen:** [anotherim 052450](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-052450-XEP-0292-slixmpp-anotherim-server), [prosody 052758](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-052758-XEP-0292-slixmpp-prosody), [ejabberd 062115](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-062115-XEP-0292-slixmpp-ejabberd). - **Root cause:** `tacky/xmpp/modules/vcard.tcl:783` adds only `${NODE4}+notify`. - **Fix:** also `$client caps addFeature urn:ietf:params:xml:ns:vcard-4.0`. - **Upstream:** fixed in v1.2.1 by [6dd6be8f](https://dev.another.im/another-im/libtacky/commit/6dd6be8f5e32c9000b027494241be0d72d3c3303) (our patch, comment reworded; our doc rows left out). ### C17. disco#info lacks `urn:xmpp:eme:0`; `name=` sent for listed protocols - [ ] verified by a human - **Spec:** XEP-0380 §3.3 (MUST); §3.2/§4 (SHOULD NOT send name for listed ns). - **Seen:** [ejabberd 063100](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-063100-XEP-0380-slixmpp-ejabberd), [anotherim 063509](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-063509-XEP-0380-slixmpp-anotherim-server), [prosody 064133](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-064133-XEP-0380-slixmpp-prosody). - **Root cause:** no module calls `caps addFeature urn:xmpp:eme:0`. `message.tcl:3375` puts `-name OMEMO` on the `urn:xmpp:omemo:2` hint. - **Fix:** add the feature (in the omemo or message module). Drop `name` for listed namespaces. - **Upstream:** fixed in v1.2.1 by [fca586fb](https://dev.another.im/another-im/libtacky/commit/fca586fb50cd3f8611e9ecf5702f3540825c05ae) (our patch, same code; comments and tests reworded). ### C18. `microblog publish` leaves `pubsub#notify_retract` false on a fresh node - [ ] verified by a human - **Spec:** XEP-0277 §4.1 (MUST be true; send_last_published_item never, SHOULD). - **Seen:** [ejabberd 123051](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-123051-XEP-0277-slixmpp-ejabberd), [anotherim 125031](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-125031-XEP-0277-slixmpp-anotherim-server). - **Root cause:** `tacky/xmpp/modules/microblog.tcl:671-675` `pubOptions` (access_model, persist_items, max_items only). - **Fix:** add `pubsub#notify_retract true pubsub#send_last_published_item never`. The notes also say `<script>` content in html entries is passed to the host verbatim; check that the HANDBOOK warns hosts. - **Upstream:** fixed in v1.2.1 by [d2c3a50d](https://dev.another.im/another-im/libtacky/commit/d2c3a50d1f92a2f75a02e831e5dad4c87cf35496) (our patch, same options in another order; our two commits squashed). ### C19. messagestore `IsDuplicate` merges two different messages (different `@id`, no stanza-id, same body/sender/second) - [ ] verified by a human - **Spec:** none (data loss). - **Seen:** [anotherim 052745](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-052745-XEP-0249-slixmpp-anotherim-server) (two direct MUC invitations). - **Root cause:** `tacky/xmpp/modules/messagestore.tcl:511` `IsDuplicate`. - **Fix:** never treat rows whose wire `@id`s differ as duplicates. - **Needs live check:** on anotherim-server, send two direct MUC invitations with the same body in the same second (different @id); expect two rows on 1dae0a6c. - **Upstream:** fixed in v1.2.1 by [752e4825](https://dev.another.im/another-im/libtacky/commit/752e4825b00a4cc3739fab591d8557f3c03fcead) (upstream's own change). `IsDuplicate` treats two stanzas that each name an id and share none as two messages, matching origin-id and `@id` across each other; ours compared `wire_id` with `wire_id` only. ### C20. Forged XEP-0425 moderation from an occupant stored as a message showing its fallback - [ ] verified by a human - **Spec:** XEP-0425 §5/§6 (MUST discard non-service moderation). XEP-0424 §5. - **Seen:** [ejabberd 064423](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-064423-XEP-0425-slixmpp-ejabberd), [anotherim 064909](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-064909-XEP-0425-slixmpp-anotherim-server). - **What happens:** the target was rightly untouched, but both the `:1` `<retract><moderated/>` form and the legacy `apply-to` form became rows (`message <New> 'mod-… forged fallback occupant 1'`). - **Needs live check:** re-run XEP-0425.py on ejabberd/anotherim with libtacky 1dae0a6c; expect no `message <New>` for the forged `:1` and `:0` forms. - **Upstream:** fixed. Room-relayed notices in v1.2.0 by [292016a5](https://dev.another.im/another-im/libtacky/commit/292016a5f536d04f0a93c70da6c0ae5038ec875e); the remaining 1:1 legacy `:0` notice in v1.2.1 by [95ef9888](https://dev.another.im/another-im/libtacky/commit/95ef9888afff6f74923872f1dd5d36d590872912) (upstream's own change; no branch of ours): a `:0` moderation outside a room is dropped. ### C21. Stream-error replay loop: the stanza that killed the stream is replayed on every new stream, with no backoff - [ ] verified by a human - **Spec:** RFC 6120 §4.9, §3.3. XEP-0198 §4 (count stanzas only). - **Seen:** [ejabberd 215429](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-215429-RFC-6120-tackyd-ejabberd), [anotherim 215659](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-215659-RFC-6120-tackyd-anotherim-server). There were 24 `<invalid-from/>` errors and reconnects in 45 s, always `retry_in 1000 attempt 1`. - **Upstream:** fixed in v1.2.0 by dc48ac80 ([commit](https://dev.another.im/another-im/libtacky/commit/dc48ac80eaabb0e699a82eed0f563305c9885486)), 5f5b8c3e ([commit](https://dev.another.im/another-im/libtacky/commit/5f5b8c3e2e84f16cb99cf508bc8b1a71c07a1551)) and 198f4438 ([commit](https://dev.another.im/another-im/libtacky/commit/198f44389df2459a7d2710342cfbecb4f31257a6)). ### C22. On SASL2/Bind 2, post-auth stream features are ignored (no roster `ver`, `preapprove` refused, no pre-approval) - [ ] verified by a human - **Spec:** RFC 6121 §2.6.1, §3.4. XEP-0237. XEP-0388 §2.6.1. XEP-0379 §3.4. - **Seen:** RFC 6121 on [prosody 215620](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-215620-RFC-6121-slixmpp-prosody), [ejabberd 215717](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-215717-RFC-6121-slixmpp-ejabberd), [anotherim 215754](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-215754-RFC-6121-slixmpp-anotherim-server). XEP-0237 on [prosody 002928](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-002928-XEP-0237-tackyd-prosody), [anotherim 003649](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-003649-XEP-0237-tackyd-anotherim-server), [ejabberd 003726](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-003726-XEP-0237-tackyd-ejabberd). XEP-0379 on [prosody 065020](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-065020-XEP-0379-slixmpp-prosody), [ejabberd 065452](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-065452-XEP-0379-slixmpp-ejabberd), [anotherim 065926](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-065926-XEP-0379-slixmpp-anotherim-server). - **Root cause:** `tacky/xmpp/modules/roster.tcl:251-280` (`StreamHas` and `PostAuthFeaturesUnknown` see only the Bind 2 inline list). - **Upstream:** fixed in v1.2.0 by 8b25b7d3 ([commit](https://dev.another.im/another-im/libtacky/commit/8b25b7d35f25411bb5ff428e7988b7645e89bfbf)), 0eaa4a5e ([commit](https://dev.another.im/another-im/libtacky/commit/0eaa4a5ec650d20210effce67b5cdf25b32c560e)) and f4ad2e47 ([commit](https://dev.another.im/another-im/libtacky/commit/f4ad2e475d89c945f0e77c755e595b015adea26a)). Upstream then chose on purpose not to send server pre-approval on `accept_invite` (ce96d4c5, [commit](https://dev.another.im/another-im/libtacky/commit/ce96d4c59e42b7dbcbbbe12380601d7fc4d6a311)): approval on arrival only, because ejabberd 26.09 left gateways at `to`. The row now says so, so the XEP-0379 part is a documented deviation. See also issue [#22](https://dev.another.im/another-im/libtacky/issues/22). ### C23. `message send` neither validates nor prepares JIDs (forbidden chars accepted; `AI1B@…`, fullwidth or final-dot JIDs become separate chats; sends stuck pending) - [ ] verified by a human - **Spec:** RFC 7622 §3.2-3.4. - **Seen:** [prosody 230844](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-230844-RFC-7622-slixmpp-prosody), [anotherim 233631](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-233631-RFC-7622-slixmpp-anotherim-server), [ejabberd 233948](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-233948-RFC-7622-slixmpp-ejabberd). The bad chats persist in the ai1a/ai2a/ai3a stores (later runs still query OMEMO lists for `ai2b@ejabberd.asxp.io.`), so a store cleanup is needed. - **Upstream:** fixed in v1.2.0 by 246a66fe ([commit](https://dev.another.im/another-im/libtacky/commit/246a66fee0ba2464735a1696ed1b68727e5f17b3), every jid argument normalised) and bc454657 ([commit](https://dev.another.im/another-im/libtacky/commit/bc45465744c595426680d415ccf774d029048f0e), invalid ones refused at the door). Issue [#19](https://dev.another.im/another-im/libtacky/issues/19) is still open. ### C24. Prosody: a vCard4 publish refused with precondition-not-met is retried unchanged after a newer one, wiping the name - [ ] verified by a human - **Spec:** XEP-0054/XEP-0292/XEP-0398. - **Seen:** [prosody 234725](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-234725-XEP-0054-slixmpp-prosody) (client.log iq 58 then 64). - **Upstream:** fixed in v1.2.0 by 6b9bac06 ([commit](https://dev.another.im/another-im/libtacky/commit/6b9bac06e7a418e93426c6cedf59f155c1e12f98)). ### C25. `account unregister` never answers on ejabberd-family servers and the removed account redials - [ ] verified by a human - **Spec:** XEP-0077 §3.2. RFC 6120 §8.1.2.1. - **Seen:** [anotherim 000550](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-000550-XEP-0077-tackyd-anotherim-server). - **What happens:** the result comes from the user's own full JID and is dropped by `iq.tcl:151-165`. The following `<conflict/>` "User removed" is read as a resource clash, leading to a not-authorized loop. Minor: `<remove/>` carried `to=domain` (SHOULD NOT). - **Upstream:** fixed in v1.2.0 by 1dff6016 ([commit](https://dev.another.im/another-im/libtacky/commit/1dff601618468e4b8a87a66da7c9141ed7dab8e8)) and 5f8c84cf ([commit](https://dev.another.im/another-im/libtacky/commit/5f8c84cf64b04656ed870576c467e24beef036b0)). The latter also drops the `to`. ### C26. Forwarded inner `<message/>` has no `xmlns='jabber:client'` - [ ] verified by a human - **Spec:** XEP-0297 §3.2. - **Seen:** [anotherim 003420](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-003420-XEP-0297-slixmpp-anotherim-server), [prosody 004939](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-004939-XEP-0297-slixmpp-prosody), [ejabberd 005842](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-005842-XEP-0297-slixmpp-ejabberd). - **Root cause:** `message.tcl:7018` `ForwardNodes`. Minor: `message forward` returns `""` although the HANDBOOK says it returns a string. Its upstream status is unclear. - **Upstream:** fixed in v1.2.0 by 86ccda9a ([commit](https://dev.another.im/another-im/libtacky/commit/86ccda9a69a51b1b27d6505b344be75384b7e4b8)). ### C27. XEP-0440 rules 4/5 not enforced on SASL2 - [ ] verified by a human - **Spec:** XEP-0440 §3 rules 4 and 5 (MUST abort). - **Seen:** fake server, all three slots: [anotherim 011841](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-011841-XEP-0440-tackyd-anotherim-server), [prosody 012341](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-012341-XEP-0440-tackyd-prosody), [ejabberd 012909](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-012909-XEP-0440-tackyd-ejabberd). - **Root cause:** `sasl.tcl` `SelectWith`. - **Upstream:** fixed in v1.2.0 by c186eaa7 ([commit](https://dev.another.im/another-im/libtacky/commit/c186eaa7524baf109f828ec72dfb163695b61030)). ### C28. An IQ result over the XEP-0478 limit is dropped instead of answered with policy-violation - [ ] verified by a human - **Spec:** XEP-0478. libtacky's row. - **Seen:** [prosody 022717](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-022717-XEP-0478-tackyd-prosody), [anotherim 023215](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-023215-XEP-0478-tackyd-anotherim-server), [ejabberd 023403](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-023403-XEP-0478-tackyd-ejabberd). - **Upstream:** fixed in v1.2.0 by 70aae84e ([commit](https://dev.another.im/another-im/libtacky/commit/70aae84ed61a974e0878a1c7c7d760054ff5effe)). ### C29. The `iap` (XEP-0509) and `happy_eyeballs` (XEP-0495) installation settings never reach the connection - [ ] verified by a human - **Seen:** XEP-0509 on [ejabberd 025031](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-025031-XEP-0509-tackyd-ejabberd), [prosody 025705](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-025705-XEP-0509-tackyd-prosody), [anotherim 031653](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-031653-XEP-0509-tackyd-anotherim-server). XEP-0495 on [ejabberd 025705](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-025705-XEP-0495-tackyd-ejabberd), [prosody 030220](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-030220-XEP-0495-tackyd-prosody), [anotherim 031339](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-031339-XEP-0495-tackyd-anotherim-server). - **Root cause:** `tacky/xmpp/client/client.tcl:1093,1099` calls `tacky_setting_get` on the backend (no `-owner`), so `setting.tcl:221-233` returns the default. - **Upstream:** fixed in v1.2.0 by 5a87d4ec ([commit](https://dev.another.im/another-im/libtacky/commit/5a87d4ec40de5e96698ac7229e074fd191c0cd0e)). ### C30. A MUC decline is sent to the room itself when the room names the inviter by occupant JID - [ ] verified by a human - **Spec:** XEP-0045 §7.8.2. - **Seen:** [prosody 021513](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-021513-XEP-0045-slixmpp-prosody). - **Root cause:** `message.tcl:10739-10747` `ParseInvite` takes the bare JID. Note: the scenario's R14 check should accept the inviter as given. - **Upstream:** fixed in v1.2.0 by 616beba4 ([commit](https://dev.another.im/another-im/libtacky/commit/616beba4dd6d69eedf746ff8a61b0aaf8982238f)). ### C31. The Jingle file sender tears down on `<received/>` and refuses the receiver's `session-terminate` (unknown-session) - [ ] verified by a human - **Spec:** XEP-0166 §6.7. XEP-0234 §6.6. - **Seen:** [ejabberd 015809](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-015809-XEP-0166-slixmpp-ejabberd), [prosody 020302](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-020302-XEP-0166-slixmpp-prosody), [anotherim 020805](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-020805-XEP-0166-slixmpp-anotherim-server). - **Root cause:** `jinglefile.tcl:1839` `HandleSessionInfo`, which goes Done, then Teardown. - **Upstream:** fixed in v1.2.0 by 4d485589 ([commit](https://dev.another.im/another-im/libtacky/commit/4d4855899137ccd0d53ce478d346dbd717e91f2f)). ### C32. XEP-0424: a retraction naming the `@id` is ignored when origin-id differs; refused retractions are stored as messages with the fallback body - [ ] verified by a human - **Spec:** XEP-0424 §5, §5.2, §6.1. - **Seen:** [ejabberd 025329](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-025329-XEP-0424-slixmpp-ejabberd), [anotherim 025637](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-025637-XEP-0424-slixmpp-anotherim-server), [prosody 025906](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-025906-XEP-0424-slixmpp-prosody). - **Upstream:** fixed in v1.2.0 by 64378ebe ([commit](https://dev.another.im/another-im/libtacky/commit/64378ebe1d675c20e9b438d007b9f1e8b7cf5e2e)) and 292016a5 ([commit](https://dev.another.im/another-im/libtacky/commit/292016a5f536d04f0a93c70da6c0ae5038ec875e)). ### C33. XEP-0444: the reaction set is not reverted on a not-acceptable error - [ ] verified by a human - **Spec:** XEP-0444 §3.3 (MUST revert). - **Seen:** [prosody 025420](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-025420-XEP-0444-slixmpp-prosody), [anotherim 025944](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-025944-XEP-0444-slixmpp-anotherim-server), [ejabberd 030024](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-030024-XEP-0444-slixmpp-ejabberd). - **Root cause:** `message.tcl:7306` `SetReactions` (stores the set optimistically, with no error path). - **Upstream:** fixed in v1.2.0 by 5bdefcae ([commit](https://dev.another.im/another-im/libtacky/commit/5bdefcae3879db1b40831bdf1317839e2971ab32)) for 1:1 and ecfd1682 ([commit](https://dev.another.im/another-im/libtacky/commit/ecfd1682a9e5e118cdb27ba8d7f95c9ba270c077)) for rooms. ### C3.1. A draft holding a character XML cannot carry is never synced - [ ] verified by a human - **Seen:** by hand in anotherim-js (`009c9884`, libtacky `56d29734`) on anotherim-server, 2026-11-08: paste `hi\x01\x02 ` into the composer ([comment](https://dev.another.im/another-im/interop/issues/1#issuecomment-1014)). - **What happens:** `chats draft` keeps the text locally, then `PublishDraft` fails: `bgerror: text contains U+0001, which XML cannot carry`. The draft never reaches the other devices (urn:tacky:drafts:0 / sealed:1), and the error escapes the module. - **Root cause:** `tacky/xmpp/modules/chatsync.tcl:972-985` `PublishDraft` writes `<draft><body>` through `::tacky::core::xml::write` without `XmlText`, unlike `message send`. - **Fix:** clean the text with `XmlText` before `PublishDraft`, or catch and log the write error. Test with U+0001. - **Upstream:** not fixed in v1.2.1 (`chatsync.tcl:983` `PublishDraft` writes the text as is). Upstream says 7dddfd32 for 1.2.2; not on the forge yet. ### C34. A destroyed room comes back on the next sign-in - [ ] verified by a human - **Spec:** XEP-0045 §10.9, XEP-0402 (autojoin). - **Seen:** by hand in anotherim-js (`009c9884`, libtacky `56d29734` + C3/S2) on anotherim-server, 2026-11-08 ([comment](https://dev.another.im/another-im/interop/issues/1)). Playbook: `fixes/C34/`. - **What happens:** the owner's `muc destroy_room` succeeds, but the XEP-0402 bookmark keeps `autojoin='true'`. On the next sign-in disco#info answers `item-not-found`, libtacky joins anyway, and the server creates a new room (status 201/110, owner): empty, default config, same address. - **Root cause:** `tacky/xmpp/modules/muc.tcl:2290` `destroy_room` only sends the iq; nothing acts on `<Destroyed>` (`muc.tcl:3058`, `:3941`); autojoin ignores a disco#info `item-not-found`. - **Fix:** never autojoin a bookmarked room whose disco#info says `item-not-found` (report it), and clear autojoin after a successful `destroy_room`. Host side (anotherim-js `ui/src/state/muc-room.ts:204`): show the row as destroyed and offer Remove. - **Upstream:** not fixed in v1.2.1. Issue [libtacky#26](https://dev.another.im/another-im/libtacky/issues/26), our PR [libtacky#27](https://dev.another.im/another-im/libtacky/pulls/27) (`fix/C34-destroyed-room-autojoin`). ## Minor / SHOULD ### M1. `file slot` / `message upload_slot` request slots for empty files (OMEMO adds the 16-byte tag first) - [ ] verified by a human - **Seen:** XEP-0363 on [anotherim 222643](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-222643-XEP-0363-tackyd-anotherim-server), [ejabberd 223657](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-223657-XEP-0363-tackyd-ejabberd), [prosody 223657](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-223657-XEP-0363-tackyd-prosody), [prosody 224208](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-224208-XEP-0363-tackyd-prosody). - **Upstream:** fixed in v1.2.0 by f396065d ([commit](https://dev.another.im/another-im/libtacky/commit/f396065d18d5b98334ffa0c9cec7fd27dcee8f91)). ### M2. `adhoc list` returns command nodes whose `jid` is not the responder's - [ ] verified by a human - **Spec:** XEP-0050 §5 (SHOULD ignore). - **Seen:** [prosody 042022](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-042022-XEP-0050-slixmpp-prosody), [ejabberd 042705](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-042705-XEP-0050-slixmpp-ejabberd), [anotherim 044651](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-044651-XEP-0050-slixmpp-anotherim-server). - **Root cause:** `adhoc.tcl:214-216`. - **Fix:** `if {$ij ne "" && [jid norm $ij] ne [jid norm $service]} continue`. - **Upstream:** fixed in v1.2.1 by [81f4ace7](https://dev.another.im/another-im/libtacky/commit/81f4ace7b5eac6abe978ac9ef69e98c2b34181bb) (our patch, `jid compared` for `jid norm`, no debug line). ### M3. `message send` accepts `thread_parent == thread` - [ ] verified by a human - **Spec:** RFC 6121 §5.2.5 (MUST differ). XEP-0201. - **Seen:** [ejabberd 121739](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-121739-XEP-0201-slixmpp-ejabberd), [anotherim 122558](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-122558-XEP-0201-slixmpp-anotherim-server), [prosody 122700](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-122700-XEP-0201-slixmpp-prosody). - **Root cause:** `message.tcl:3271-3275` (and `send` at `:3814`). - **Fix:** refuse the call (or drop the parent) when they are equal. - **Upstream:** fixed in v1.2.1 by [6e8203ce](https://dev.another.im/another-im/libtacky/commit/6e8203ce99a8c78b107a863bc99a6d9626800441) (upstream's own change). `CheckThreadParent` refuses `thread_parent == thread` in send, send_file and send_album, and the builder never writes such a parent; unlike ours it does not refuse a parent without a thread. ### M4. `<attachments>` in a foreign namespace is read as an attachment - [ ] verified by a human - **Spec:** XEP-0470 §4.1.1/§4.5. - **Seen:** [ejabberd 131801](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-131801-XEP-0470-slixmpp-ejabberd), [anotherim 153239](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-153239-XEP-0470-slixmpp-anotherim-server). - **Root cause:** `microblog.tcl:1009` (and `:925`) checks only `tag eq "attachments"`. - **Fix:** also require `xmlns eq $NS_ATTACH`. - **Upstream:** fixed in v1.2.1 by [40640d58](https://dev.another.im/another-im/libtacky/commit/40640d5891b36cd863e0eb0c135b52dbcb2692c0) (our patch, `dict getdef` for the namespace). ### M5. `payment get_invoice` sends `<get-invoice/>` without a disco check - [ ] verified by a human - **Spec:** XEP-0518 §4.4 (SHOULD). The HANDBOOK says it sends only to an entity advertising `#invoice-request`. - **Seen:** [ejabberd 161842](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-161842-XEP-0518-slixmpp-ejabberd), [prosody 162650](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-162650-XEP-0518-slixmpp-prosody). - **Root cause:** `payment.tcl:508`. - **Upstream:** fixed in v1.2.1 by [6d620727](https://dev.another.im/another-im/libtacky/commit/6d620727e74a44d5cd8efb65e73461436fc819aa) (upstream's own change; triage had it as a decision): `get_invoice` asks disco#info first and sends only to an entity advertising `#invoice-request`. ### M6. XEP-0472 side issues - [ ] verified by a human - **Seen:** [ejabberd 132926](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-132926-XEP-0472-slixmpp-ejabberd), [prosody 153205](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-153205-XEP-0472-slixmpp-prosody), [anotherim 153635](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-153635-XEP-0472-slixmpp-anotherim-server). - **What happens:** - An open feed's attachments node gets `access_model=presence` (XEP-0470 §4.1.1 SHOULD match). - Comments nodes lack `itemreply=publisher`. - A hostile post's comments/reply_to `http://` URLs surface in `<Post>`. - An edit re-creates the attachments node (logged as "no attachments node"). - **Upstream:** fixed in v1.2.1 by [2d82b42d](https://dev.another.im/another-im/libtacky/commit/2d82b42db6112c98fbab3ecbe5a25e7661ab8588) (upstream's own change, broader than ours): all four points, including the attachments node's access model and the re-create on edit that triage left as decisions. ### M7. XEP-0501 story entry lacks `atom:author` - [ ] verified by a human - **Spec:** RFC 4287 §4.1.2. - **Seen:** [anotherim 160304](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-160304-XEP-0501-slixmpp-anotherim-server). - **Upstream:** fixed in v1.2.1 by [5e8b4565](https://dev.another.im/another-im/libtacky/commit/5e8b45652760840265cc92fee9de266f7b418053) (our patch, same code). ### M8. A forged roster push gets no IQ reply - [ ] verified by a human - **Spec:** RFC 6120 §8.2.3. RFC 6121 §2.1.6 (should be answered with an error). - **Seen:** XEP-0100 runs ([prosody 114621](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-114621-XEP-0100-slixmpp-prosody)). - **Upstream:** fixed in v1.2.1 by [4ac96afd](https://dev.another.im/another-im/libtacky/commit/4ac96afd0abfcceec2fcb7ddfee308b3f25b3156) (upstream's own change; triage had it as not a bug): a push from anyone but our server is answered `service-unavailable`, nothing stored. ### M9. XEP-0198 `<r/>` unanswered for ~50 min (network outage 05:31-06:20 UTC) without the stream being declared dead - [ ] verified by a human - **Seen:** night notes, during the 2026-11-07 outage. This is only a possible bug. - **Needs live check:** hold a session through a network cut (drop packets to the server) and see whether libtacky declares the stream dead after its `<r/>` timeout. - **Upstream:** not reproduced on v1.2.0 (ejabberd 175338: dead 60 s after `<r/>`); no change in v1.2.1. ### M10. XEP-0410 self-pings rooms already left, during the resume replay (Prosody ordering) - [ ] verified by a human - **Seen:** [prosody 010924](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-010924-XEP-0410-slixmpp-prosody). - **Upstream:** fixed in v1.2.1 by [7a177c07](https://dev.another.im/another-im/libtacky/commit/7a177c0735c25ae65960f37ee35f0f570a9c15a0) (upstream's own change; triage had it as not a bug): self-pings after a resume wait for the replay and skip rooms left or leaving. ### M11. `mam query` hides RSM `<count>`; disco `Truncated` count is empty although page 1 had `<count>` - [ ] verified by a human - **Seen:** XEP-0059 on [ejabberd 235156](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-235156-XEP-0059-tackyd-ejabberd), [prosody 235904](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-235904-XEP-0059-tackyd-prosody), [anotherim 001123](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-001123-XEP-0059-tackyd-anotherim-server). - **Upstream:** fixed in v1.2.1 by [6b9ba1fc](https://dev.another.im/another-im/libtacky/commit/6b9ba1fc2ef58fe93d2ed6008280ebd355a1821d) (upstream's own change): `mam query` answers `count` from `::tacky::rsm::parse` (`""` when absent; ours left the key out), disco `<Truncated>` keeps page 1's count. ### M12. `account untrust_certificate -acc <registration domain>` fails with "Account doesn't exist" (trust works; HANDBOOK CERTPIN names both) - [ ] verified by a human - **Seen:** night notes (run not named). - **Needs live check:** `account trust_certificate` then `untrust_certificate` with `-acc <registration domain>` during an IBR flow, on 1dae0a6c. - **Upstream:** not reproduced on v1.2.0 (ejabberd 175154: works while the registration session is open); no change in v1.2.1. ### M13. tackyd-json v1.2.0-rc2 build: `::tacky::version` unset - [ ] verified by a human - **What happens:** software version reads `0.1` and the caps node is `https://tacky.example`. - **Seen:** XEP-0115 on [anotherim 221514](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-221514-XEP-0115-slixmpp-anotherim-server), [prosody 221754](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-221754-XEP-0115-slixmpp-prosody). - **Fix:** check the build stamping in the tackyd-json packaging. - **Upstream:** fixed in v1.2.1 by [761c0bb0](https://dev.another.im/another-im/libtacky/commit/761c0bb0c567fe5a675582766d9cd7c4b35e73ff) (upstream's own change; triage had it as a decision): `::tacky::LibraryVersion` answered, caps node is the DOAP home. ### M14. OTR whitespace tag kept in the stored plaintext body - [ ] verified by a human - **Spec:** OTR v3 says to strip it before display. - **Seen:** [prosody 125746](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-125746-XEP-0364-slixmpp-prosody), [ejabberd 130347](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-130347-XEP-0364-slixmpp-ejabberd), [anotherim 132541](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-132541-XEP-0364-slixmpp-anotherim-server). - **Upstream:** fixed in v1.2.1 by [60daed8b](https://dev.another.im/another-im/libtacky/commit/60daed8b71d95339ed2cc1ebdce6ea7e1551d877) (upstream's own change): only a tag that ends the body is cut, so no offset moves; ours cut it anywhere and moved mentions after it. A mid-body tag stays. ### M15. Duplicate vCard gets for a MUC avatar (after 104 + x:update, and on join) - [ ] verified by a human - **Seen:** XEP-0486 on [prosody 090404](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-090404-XEP-0486-slixmpp-prosody), [ejabberd 090905](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-090905-XEP-0486-slixmpp-ejabberd). - **Upstream:** fixed in v1.2.1 by [7e939060](https://dev.another.im/another-im/libtacky/commit/7e939060af2d7805d9b59718126a9d223d6e906a) (upstream's own change): `avatar FetchVCard` keeps one get in flight per JID and hash; a 104 and our own set ask regardless (`-force`). ### M16. Republishing another device's bookmark adds a `<nick>` it lacked - [ ] verified by a human - **Seen:** [anotherim 092531](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-092531-XEP-0492-slixmpp-anotherim-server). - **Upstream:** fixed in v1.2.1 by [318f210b](https://dev.another.im/another-im/libtacky/commit/318f210b83e735fe4c3617fbaecdfa9d10b5ce11) (our patch, comments reworded). ### M17. Stale store state after server-side deletes - [ ] verified by a human - **What happens:** - A contact PEP item deleted by node delete without notice (ejabberd `notify_delete false`) stays in the store for good. - The stored roster kept the XEP-0100 full-JID item until a full roster fetch. - **Seen:** [ejabberd 115158](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-115158-XEP-0100-slixmpp-ejabberd) and the night notes. - **Upstream:** not changed, by decision: a PEP item deleted with its node and no notice cannot be told from no item without a re-read; the stale full-JID roster item is S7's and no longer created. ### M18. Replayed or equal-stamp sealed items are dropped without a debug line (other drops are logged) - [ ] verified by a human - **Seen:** sealed-1 runs ([prosody 093734](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-093734-urn-tacky-sealed-1-slixmpp-prosody)). - **Upstream:** partly fixed in v1.2.1 by [86b86680](https://dev.another.im/another-im/libtacky/commit/86b866802e0cd11eafbe11920ac470c9fbf56a91) (upstream's own change): chatsync's list path and `pte_seal` now log older and equal-stamp drops. The draft path (`chatsync.tcl:1128`, `:1131`, the `Drafts`/`Cleared` checks) still returns silently; our branch logged those too. ### M19. The own call-invite row reads `state joined` although no call started (no media backend) - [ ] verified by a human - **Seen:** [ejabberd 093754](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-093754-XEP-0482-slixmpp-ejabberd). - **Upstream:** fixed in v1.2.1 by [c24cddf6](https://dev.another.im/another-im/libtacky/commit/c24cddf6a15f1243ca9e0d50307bc42efd8bbebe) (upstream's own change; triage had it as a decision): our invite reads `joined` only while this device is in the call, `pending` otherwise, `elsewhere` for another device's. ### M20. tls-server-end-point is computed for Ed25519 certificates, where RFC 5929 leaves it undefined - [ ] verified by a human - **Seen:** XEP-0440 runs ([anotherim 011841](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-011841-XEP-0440-tackyd-anotherim-server)). - **Upstream:** not a bug: SHA-256 for Ed25519/Ed448, as other XMPP stacks; the RFC 5929 row says so since [625d4462](https://dev.another.im/another-im/libtacky/commit/625d4462f55ed11b538dd81a4290ba820a78eb0a). ### M21. PIE import oddities - [ ] verified by a human - **What happens:** - A restored custom tag appears only after a restart. - An imported enabled account connects during the import. - `pie-0.md` lacks `<quick/>`. - **Seen:** [anotherim 025824](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-025824-urn-tacky-pie-0-tackyd-anotherim-server). - **Upstream:** fixed in v1.2.1 by [ddde3fc9](https://dev.another.im/another-im/libtacky/commit/ddde3fc9c37bb192aab8b912d1375e4a9de54ed6) (our patch, comments reworded): tags reload after import; pie-0.md lists every `<row/>` facet. An enabled account coming up during the import is by design. ### M22. A refused `muc accept_invite` leaves its autojoin bookmark - [ ] verified by a human - **Seen:** XEP-0249 runs ([prosody 052252](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-052252-XEP-0249-slixmpp-prosody)). - **Upstream:** fixed in v1.2.1 by [da2984cc](https://dev.another.im/another-im/libtacky/commit/da2984ccbabe722efd7cdd16d4e1c8cd02ee51bc) (upstream's own change; triage had it as a decision): a terminal refusal restores the room's previous bookmark (or removes it); wait-type errors keep it. ### M23. OMEMO list and store hygiene - [ ] verified by a human - **What happens:** - `publish_list` drops OMEMO 2 `label` attributes on republish. - `forget_inactive` is unsafe when contacts have older inactive rows; a per-device forget is needed. - `trust_list` `active` reads false for devices on current lists (check the meaning in the HANDBOOK). - Fresh-store runs keep adding own devices (ai3a has ~46). - **Seen:** XEP-0384 runs ([prosody 024328](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-024328-XEP-0384-slixmpp-prosody)) and XEP-0450 runs ([prosody 084617](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-084617-XEP-0450-slixmpp-prosody)). - **Upstream:** partly fixed in v1.2.1 by [d99bcf28](https://dev.another.im/another-im/libtacky/commit/d99bcf28d19fcb3d04f2f59fb04dddbc6d907ae1) (upstream's own change): unsigned OMEMO 2 labels are kept on republish; `trust_list` `active` is documented (listed on a list read on this connection). Left as decisions: a per-device forget, own-device rows piling up on fresh stores. ### M24. XEP-0377 report: the row says `stanza-id by=` is the reported JID, but §6 says to copy the received `<stanza-id/>` - [ ] verified by a human - **Seen:** XEP-0377 untestable on all three servers ([ejabberd 125134](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-125134-XEP-0377-slixmpp-ejabberd)). It needs Prosody `mod_spam_reporting` or a fake. - **Upstream:** not changed, by decision: XEP-0377's text and its example disagree; left to the maintainer or the XEP author. ### M25. INFO-level oddities - [ ] verified by a human - **What happens:** - live-location ([ejabberd 110656](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-110656-urn-tacky-live-location-0-slixmpp-ejabberd)): the own device's correction of a peer's share is stored as an outgoing live row. An out-of-range correction becomes a text edit with body ≠ place. `live_stopped` is not set at expiry, although the HANDBOOK suggests it is. - pep-expiry: the writer accepts year 10000, which its own reader treats as no expiry. A replaced item's expiry stays pending until the next sign-in. - poll-fluux: `<fallback for=urn:fluux:poll:0/>` has no `<body/>`, unlike libtacky's own `poll-fluux-0.md` §3.1. - MUC/Sub: in a semi-anonymous room, subscriber rows without a jid give `subscribers []` and no `SubscriberChanged`. - XEP-0511: the `rdf:about`-in-body check is a substring match (untested). - **Upstream:** partly fixed in v1.2.1 (upstream's own changes; ours covered the first three): poll-fluux `<body/>` [3dad47ab](https://dev.another.im/another-im/libtacky/commit/3dad47aba847480b7515ca5170a754d374914b15), XEP-0511 whole-link check [c4d00bc9](https://dev.another.im/another-im/libtacky/commit/c4d00bc915ea0cda5ad3d2a73bd43349c103183d), pep-expiry year bound and replaced-item pending [e364005c](https://dev.another.im/another-im/libtacky/commit/e364005c57925f7efaf9ca5cc0142d73b5f49b48), live-location bad move dropped and `live_stopped` doc [e9379baf](https://dev.another.im/another-im/libtacky/commit/e9379baf15dbbe1dbc3cd95e49bb6b4a8b7955b8), MUC/Sub nick-only subscribers [2336d35a](https://dev.another.im/another-im/libtacky/commit/2336d35a2f889f4520e5cd26efb2d771281abc91). Left: the own device's correction of a peer's share still stored as an outgoing live row. --- ## Server-side issues (not libtacky) - **ejabberd / anotherim-server, XEP-0191 §3.3:** the bounce for a blocked JID lacks `<blocked xmlns='urn:xmpp:blocking:errors'/>`. Runs: [anotherim 221228](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-221228-XEP-0191-tackyd-anotherim-server), [ejabberd 221627](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-221627-XEP-0191-tackyd-ejabberd). - **Prosody, XEP-0359 §3:** delivers a sender-forged `<stanza-id by=recipient/>` ahead of its own and keeps it in MAM. libtacky is hardened (S12). Run: [prosody 222405](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-222405-XEP-0359-slixmpp-prosody). - **ejabberd / anotherim-server, RFC 7395 + RFC 5802 §6:** WebSocket offers SCRAM without -PLUS, then refuses gs2 `y` ("Invalid channel binding"). libtacky works around it with `n` (20f0aecc, [commit](https://dev.another.im/another-im/libtacky/commit/20f0aecc917857c29b1aa32b9dfe2b95eba69780)). Runs: [ejabberd 230523](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-230523-RFC-7395-tackyd-ejabberd), [anotherim 233905](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261104-233905-RFC-7395-tackyd-anotherim-server). - **ejabberd, XEP-0163 §4.3:** no PEP notifications to a contact whose subscription was redone during the publisher's session. Runs: [000849](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-000849-XEP-0172-slixmpp-ejabberd), [001339](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261105-001339-XEP-0172-slixmpp-ejabberd). - **ejabberd / anotherim-server, XEP-0045 §7.2.6:** a non-member is admitted to a members-only moderated room (`mod_muc_room.erl` `get_occupant_initial_role` → stored role). Report to ProcessOne. Runs: [ejabberd 014838](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-014838-XEP-0045-slixmpp-ejabberd), [anotherim 015135](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-015135-XEP-0045-slixmpp-anotherim-server). - **Prosody 13.0.7 mod_proxy65:** relays only the first 4096 bytes of a larger single write, then stalls. Reproduced without libtacky. The run is recorded `fail` although libtacky passed R1-R10; relabel it, or make the scenario chunk writes. Run: [prosody 113200](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-113200-XEP-0065-slixmpp-prosody). - **ejabberd test config:** mod_proxy65 advertises streamhost `127.0.0.2:7777`, and public port 7777 accepts then closes. This is a config fix and the user's decision. *Needs live check:* disco#info of proxy65 on ejabberd.asxp.io and a connect to public :7777. - **Prosody:** advertises only `tls-exporter` (XEP-0440 says servers MUST advertise `tls-server-end-point`). Maybe a config or version matter; not checked. *Needs live check:* read the stream features on prosody.asxp.io (no sign-in needed) and the channel-binding config. - **Prosody:** stopped routing ai1b's c2s stanzas after a 20.8 KB share (mod_limits?). Run: [prosody 063013](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-063013-XEP-0264-slixmpp-prosody). Check the config. *Needs live check:* Prosody `limits`/`c2s_stanza_size_limit` config and a 20 KB stanza from a test account. - **Prosody:** an attribute newline sent as `&#10;` arrives as a space (INFO). Run: [contact-0 prosody 104729](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-104729-urn-tacky-contact-0-slixmpp-prosody). - **ejabberd, XEP-0503 §4:** lacks the MUST meta-data feature and leaves the owner's own private-space subscription pending. Run: [161316](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-161316-XEP-0503-slixmpp-ejabberd). - **Peer library (slixmpp 1.17, for the harness):** `xep_0202` cannot answer time queries (set_tzo ValueError). The `xep_0080` timestamp is broken. Iterating `pubsub_event` items in a handler hangs at 100% CPU. ## Harness / scenario issues already fixed in the interop repo - `peer.py`: each Peer's wire log now holds only its own stream (commit "ai: keep each Peer's wire log to its own stream"). Runs before ~11:15 UTC on 2026-11-07 still have mixed `peer-slixmpp*.log`. - `common.wire()`: `splitlines()` broke on raw U+0085 in libtacky JSON lines. Fixed in 2633218. Other scenarios with their own `splitlines()` loops carry the same latent bug. - `nix/https443.nix` redirected container egress on port 443 too. Fixed, so a fresh anotherim server can build its image. - `nix develop .#ai` copied the repo into the store on every tree change, which filled the disk. Fixed with `tools/ai/aish` (pinned rev). Old copies are still in /nix/store. - XEP-0420 scenario: peer signals outside the envelope are now a FAIL (R7), and Prosody was re-run. - Redaction now covers XEP-0379 pre-approval tokens, and two 2026-11-04 RFC 5122 runs were redacted. **The tokens are still in git history: revoke them** (`roster revoke_invite`) and decide whether to rewrite history. - `interop-log` rotated-files fix: deployed to ejabberd only (Prosody and anotherim were not redeployed). - Store repair: stale `muc_features/ai{1,2,3}b` rows deleted (see S4). Backups are in the scratchpad `store-bak/`. ## Not bugs: documented deviations or judgement calls - XEP-0379: `accept_invite` sends no server pre-approval; it approves on arrival (upstream ce96d4c5, row updated). - XEP-0333: `<received/>` marker kept beside the XEP-0184 receipt (upstream 2dd5a78f documents why). - XEP-0466: expired ephemeral text kept under `preserve_history` (default). `<ephemeral/>` in clear beside OMEMO 0.3. Documented. The OMEMO 2 case was fixed in d78fd98c ([#17](https://dev.another.im/another-im/libtacky/issues/17)). - XEP-0396 R1: peer devices on the OMEMO 2 list are excluded from 0.3 key transport per libtacky's row. A strict §3 reading differs; the user decides. - XEP-0448: tagless aes-gcm uploads are refused (§4 only RECOMMENDS the tag). The OMEMO 2 envelope's aesgcm:// body has no XEP-0428 fallback mark. - XEP-0491: update/realtime refused under OMEMO (documented). The upload slot request names the filename and `application/webxdc+zip` in clear, as XEP-0363 requires. - XEP-0501: `pubsub#type` and `item_expire` unset (the row says so). - XEP-0420: envelopes without `rpad`/`from` are refused (INFO, stricter than the spec). - SASL: SCRAM-SHA-256-PLUS is preferred over SHA-512-PLUS (a preference question). - XEP-0077: the register form does not set `legacy` for legacy-field forms (INFO). - sealed:1: which Ed25519 conversion verifies seal signatures varies per device (XEdDSA sign bit?). A person should judge this against `sealed-1.md`. - Not covered by any run: XEP-0431 (no full-text MAM), XEP-0114 (no component listener), XEP-0377 (no server support), XEP-0317 R3/R5/R7 on ejabberd-family servers, XEP-0398 R4 (only ejabberd or a fake), XEP-0452 R1/R3 (needs mod_muc_mention_notifications on Prosody), XEP-0507 and other call paths (no media backend). - libtacky docs out of date (not bugs in code): - RFC 5929 and XEP-0440 rows (upstream 38bcfa35 rewrote XEP-0440's). - HANDBOOK `fast_token` needs token-mechanism + user-agent-id. - HANDBOOK mam intro says XEP-0441 prefs are unimplemented. - XEP-0493 row says the issuer is not checked. - XEP-0450 row and the `omemo.tcl` ATM comment (~7532) say trust messages go to every usable device, but the code sends to authenticated devices only. - HANDBOOK says a MUC invite password never reaches the host, but `<Invite>` and the stored row carry it. - The XEP-0292 row's reason for no vcard-temp copy. - `message forward`'s documented return value. 6 comments
Author
Member

Live re-checks, 2026-11-07 (rc2 vs upstream v1.2.0 1dae0a6c)

All three test servers were restarted; every check is an interop run (commits 3ededa3, febb903, 68490c1).

Bug rc2 v1.2.0 Runs
S1 meeting messages in clear with OMEMO on present still present (7/7 in clear) anotherim 175105
S8 geoloc stop overtaken by stale republish present still present (ejabberd, anotherim); not on Prosody because C9 ends sharing first. New variant: set_allowed [] then stop also republishes ejabberd 174959, anotherim 174826
S10 parse_uri both cases wrong %3F split fixed; :port still accepted, and a %3F in a domainpart ejabberd 174759
C9 own <delete/> ends geoloc sharing (Prosody) present still present prosody 174532
C19 same-body invitations merged present still present anotherim 174754
C20 forged XEP-0425 moderation present fixed for room-relayed notices; a 1:1 legacy :0 notice from a contact is still stored as text (INFO) ejabberd 174846, anotherim 174953
M9 unanswered <r/> never ends the stream — not reproduced: with 5222 dropped server-side, dead 60 s after the <r/>; idle cut detected by the probe ejabberd 175338
M12 untrust_certificate -acc <registration domain> — not reproduced: works while a registration session is open (by design otherwise) ejabberd 175154

Server-side:

  • ejabberd proxy65: confirmed — listens only on 127.0.0.2:7777 (mod_proxy65: { access: local, max_connections: 5, port: 7777 }, no ip/hostname). Test-config fix: add ip and hostname: ejabberd.asxp.io.
  • Prosody channel binding: confirmed — Prosody 13.0.7 advertises only tls-exporter; ejabberd and anotherim-server advertise tls-exporter and tls-server-end-point.
  • Prosody 20 KB stall: a 20 KB plain body is routed fine; an SFS share whose thumbnail data: URI is one 20 KB attribute stalls the sender's stream (both directions, prosody 174914). Prosody's debug.log shows every byte RECV'd but no stanza dispatched until the client closed, no error. Prosody 13.0.7 with expat 2.9.0: expat ≥ 2.6 reparse deferral on a single large token is the likely cause. mod_limits is not loaded. The right error would be RFC 6120 §4.9.3.14 <policy-violation/>.

Fix branches and step-by-step playbooks for the security bugs are being prepared under fixes/<ID>/ in this repo.

## Live re-checks, 2026-11-07 (rc2 vs upstream v1.2.0 `1dae0a6c`) All three test servers were restarted; every check is an interop run (commits 3ededa3, febb903, 68490c1). | Bug | rc2 | v1.2.0 | Runs | |---|---|---|---| | S1 meeting messages in clear with OMEMO on | present | **still present** (7/7 in clear) | [anotherim 175105](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-175105-XEP-0483-slixmpp-anotherim-server) | | S8 `geoloc stop` overtaken by stale republish | present | **still present** (ejabberd, anotherim); not on Prosody because C9 ends sharing first. New variant: `set_allowed []` then `stop` also republishes | [ejabberd 174959](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-174959-XEP-0080-slixmpp-ejabberd), [anotherim 174826](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-174826-XEP-0080-slixmpp-anotherim-server) | | S10 `parse_uri` | both cases wrong | `%3F` split **fixed**; `:port` still accepted, and a `%3F` in a domainpart | [ejabberd 174759](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-174759-XEP-0147-slixmpp-ejabberd) | | C9 own `<delete/>` ends geoloc sharing (Prosody) | present | **still present** | [prosody 174532](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-174532-XEP-0080-slixmpp-prosody) | | C19 same-body invitations merged | present | **still present** | [anotherim 174754](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-174754-XEP-0249-slixmpp-anotherim-server) | | C20 forged XEP-0425 moderation | present | **fixed** for room-relayed notices; a 1:1 legacy `:0` notice from a contact is still stored as text (INFO) | [ejabberd 174846](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-174846-XEP-0425-slixmpp-ejabberd), [anotherim 174953](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-174953-XEP-0425-slixmpp-anotherim-server) | | M9 unanswered `<r/>` never ends the stream | — | **not reproduced**: with 5222 dropped server-side, dead 60 s after the `<r/>`; idle cut detected by the probe | [ejabberd 175338](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-175338-XEP-0198-tackyd-ejabberd) | | M12 `untrust_certificate -acc <registration domain>` | — | **not reproduced**: works while a registration session is open (by design otherwise) | [ejabberd 175154](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-175154-XEP-0077-tackyd-ejabberd) | Server-side: - **ejabberd proxy65**: confirmed — listens only on `127.0.0.2:7777` (`mod_proxy65: { access: local, max_connections: 5, port: 7777 }`, no `ip`/`hostname`). Test-config fix: add `ip` and `hostname: ejabberd.asxp.io`. - **Prosody channel binding**: confirmed — Prosody 13.0.7 advertises only `tls-exporter`; ejabberd and anotherim-server advertise `tls-exporter` and `tls-server-end-point`. - **Prosody 20 KB stall**: a 20 KB plain body is routed fine; an SFS share whose thumbnail `data:` URI is one 20 KB attribute stalls the sender's stream (both directions, [prosody 174914](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-174914-XEP-0264-slixmpp-prosody)). Prosody's debug.log shows every byte RECV'd but no stanza dispatched until the client closed, no error. Prosody 13.0.7 with expat 2.9.0: expat ≥ 2.6 reparse deferral on a single large token is the likely cause. mod_limits is not loaded. The right error would be RFC 6120 §4.9.3.14 `<policy-violation/>`. Fix branches and step-by-step playbooks for the security bugs are being prepared under `fixes/<ID>/` in this repo.
asxpi referenced this issue from a commit 2026-11-07 21:13:00 +00:00
Author
Member

Fix playbooks ready (PR #2)

Every bug here now has a playbook in fixes/ on PR #2's branch. Each one covers reproducing the bug, verifying it by hand, the libtacky issue body, reviewing and testing the fix branch, retesting, and the upstream PR body.

Kind Count IDs
fix branch (local ../libtacky-fixes, signed, test fails without it, v1.2.0 fail / fix pass runs) 42 S1–S10, S13, C1–C19, M2 M3 M4 M6 M7 M11 M14 M15 M16 M18 M21 M25
verify-only, already fixed in v1.2.0 17 S11 S12, C20–C33, M1
not a bug / not reproducible on v1.2.0 6 M8 M9 M10 M12 M17 M20
needs a maintainer decision 6 M5 M13 M19 M22 M23 M24

Corrections to the list above:

  • C20 is fixed in v1.2.0 for room-relayed notices. Only a 1:1 legacy notice from a contact is still stored as text, and that's INFO.
  • M9 and M12 don't reproduce on v1.2.0.

Branches that touch the same code: S8 with C9, and S6 with C4. Whichever merges second needs a rebase.

## Fix playbooks ready (PR #2) Every bug here now has a playbook in [`fixes/`](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/fixes/README.md) on PR #2's branch. Each one covers reproducing the bug, verifying it by hand, the libtacky issue body, reviewing and testing the fix branch, retesting, and the upstream PR body. | Kind | Count | IDs | |---|---|---| | fix branch (local `../libtacky-fixes`, signed, test fails without it, v1.2.0 fail / fix pass runs) | 42 | S1–S10, S13, C1–C19, M2 M3 M4 M6 M7 M11 M14 M15 M16 M18 M21 M25 | | verify-only, already fixed in v1.2.0 | 17 | S11 S12, C20–C33, M1 | | not a bug / not reproducible on v1.2.0 | 6 | M8 M9 M10 M12 M17 M20 | | needs a maintainer decision | 6 | M5 M13 M19 M22 M23 M24 | Corrections to the list above: - C20 is fixed in v1.2.0 for room-relayed notices. Only a 1:1 legacy notice from a contact is still stored as text, and that's INFO. - M9 and M12 don't reproduce on v1.2.0. Branches that touch the same code: S8 with C9, and S6 with C4. Whichever merges second needs a rebase.
Author
Member

C3 verified by a human (2026-11-08): reproduced in anotherim-js 0.8.0-beta5 by pasting hi\x01\x02 before a picked @Nick. The highlight shifted two characters. This happened with OMEMO on, so encrypted chats are affected as well.

**C3 verified by a human** (2026-11-08): reproduced in anotherim-js 0.8.0-beta5 by pasting `hi\x01\x02 ` before a picked `@Nick`. The highlight shifted two characters. This happened with **OMEMO on**, so encrypted chats are affected as well. - libtacky issue: another-im/libtacky#24 - libtacky PR: another-im/libtacky#25 (`fix/C3-mention-offsets-after-strip`, rebased on develop `56d29734`) - runs: [v1.2.0 R9 fail](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-215610-XEP-0426-slixmpp-prosody), [fix R9 pass](https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-215616-XEP-0426-slixmpp-prosody)
Author
Member

New: C3.1, and a second C3 symptom (found by hand in anotherim-js, 2026-11-08)

Setup: anotherim-js upstream develop (009c9884, XML_LOG=1) with libtacky develop 56d29734, on anotherim-server as ai3a.

C3.1: a draft with a character XML cannot carry is never synced (correctness)

chats draft keeps the text locally (dict set Drafts, SaveDraft). PublishDraft (tacky/xmpp/modules/chatsync.tcl:972-985) then writes <draft><body> through ::tacky::core::xml::write without cleaning it, as message send does with XmlText. The writer refuses the text, and the error escapes as a bgerror:

[2026-11-08 02:36:49.635 error] bgerror: text contains U+0001, which XML cannot carry
"::tacky::core::xml::write [j draft -ns $NS_DRAFT -ts ... {

Effect: the draft never reaches the user's other devices (urn:tacky:drafts:0 / sealed:1), and the error escapes the module as a bgerror instead of being handled there. To trigger it, paste hi\x01\x02 into the composer.

Suggested fix: run the draft text through XmlText (or the same cleaning) before PublishDraft, or catch the write error and log it. Add a test that publishes a draft holding U+0001.

C3, second symptom: the message is not sent at all

If the mention is the last thing in the message, the two stripped characters push its end past the end of the cleaned body. message send then refuses the whole send, because a mention out of the body is an error and nothing is sent. No stanza goes out (the XML log has none). In anotherim-js the message just doesn't send. The C3 fix (libtacky#25) moves the offsets, so the send succeeds.

Side note, anotherim-js: media fetched from received messages

The test build's log shows repeated frontend.media: fetch failed host=example.invalid warnings. anotherim-js fetches URLs that appear in received messages, here from old test-run messages, on its own. With a real host, this would show the sender the user's IP address and that the user is online. Check which setting governs it and whether it is on by default.

## New: C3.1, and a second C3 symptom (found by hand in anotherim-js, 2026-11-08) Setup: anotherim-js upstream `develop` (`009c9884`, `XML_LOG=1`) with libtacky `develop` `56d29734`, on anotherim-server as ai3a. ### C3.1: a draft with a character XML cannot carry is never synced (correctness) `chats draft` keeps the text locally (`dict set Drafts`, `SaveDraft`). `PublishDraft` (`tacky/xmpp/modules/chatsync.tcl:972-985`) then writes `<draft><body>` through `::tacky::core::xml::write` without cleaning it, as `message send` does with `XmlText`. The writer refuses the text, and the error escapes as a `bgerror`: ``` [2026-11-08 02:36:49.635 error] bgerror: text contains U+0001, which XML cannot carry "::tacky::core::xml::write [j draft -ns $NS_DRAFT -ts ... { ``` **Effect:** the draft never reaches the user's other devices (urn:tacky:drafts:0 / sealed:1), and the error escapes the module as a `bgerror` instead of being handled there. To trigger it, paste `hi\x01\x02 ` into the composer. **Suggested fix:** run the draft text through `XmlText` (or the same cleaning) before `PublishDraft`, or catch the write error and log it. Add a test that publishes a draft holding U+0001. ### C3, second symptom: the message is not sent at all If the mention is the last thing in the message, the two stripped characters push its end past the end of the cleaned body. `message send` then refuses the whole send, because a mention out of the body is an error and nothing is sent. No stanza goes out (the XML log has none). In anotherim-js the message just doesn't send. The C3 fix (libtacky#25) moves the offsets, so the send succeeds. ### Side note, anotherim-js: media fetched from received messages The test build's log shows repeated `frontend.media: fetch failed host=example.invalid` warnings. anotherim-js fetches URLs that appear in received messages, here from old test-run messages, on its own. With a real host, this would show the sender the user's IP address and that the user is online. Check which setting governs it and whether it is on by default.
Author
Member

New: C34, a destroyed room comes back on the next sign-in (found by hand in anotherim-js, 2026-11-08)

Setup: anotherim-js upstream develop (009c9884, XML_LOG=1) with libtacky develop 56d29734 plus C3/S2 (bdb54e89), on anotherim-server as ai3a. ai3a, the owner, destroyed c3-test@conference.anotherim.asxp.io from the room menu.

What happens:

  1. 03:00:51: muc destroy_room sends <destroy/>, and the server confirms with presence <destroy/>, affiliation='none'. The room is gone.
  2. Nothing removes the room's XEP-0402 bookmark, which still has autojoin='true'.
    • libtacky's destroy_room (tacky/xmpp/modules/muc.tcl:2290) only sends the iq.
    • The <Destroyed> event (muc.tcl:3058, :3941) is not acted on by bookmarks.
    • anotherim-js (ui/src/state/muc-room.ts:204) only clears the room's state, so the row stays in the list.
  3. On the next sign-in (03:04:32), autojoin rejoins.
    • The room's disco#info answers item-not-found "Conference room does not exist".
    • libtacky sends the join presence anyway.
    • The server creates a new room: status 201 and 110, affiliation owner.

Effect: a room destroyed on purpose is quietly recreated by the owner's own client on every sign-in, empty, with the server's default configuration, under the same address. Anyone who knew the address can join it. The list row also stays after the destroy.

Spec: XEP-0045 §10.9 (destroying a room; the <destroy/> with an optional alternate venue), XEP-0402 (autojoin bookmarks).

Who should fix what:

libtacky (the real fix):

  • libtacky runs autojoin itself (HANDBOOK, XEP-0402 row), so no host can stop the rejoin cleanly.
  • libtacky asked disco#info, got item-not-found "Conference room does not exist", and joined anyway. The server took that join as "create".
  • libtacky already treats a room whose disco#info says it is gone as Left (HANDBOOK, XEP-0410 row) but does not apply that rule to autojoin at sign-in.
  • Fix: never autojoin a bookmarked room whose disco#info answered item-not-found (report it instead), and clear autojoin after a successful destroy_room. Then a bookmark left behind cannot turn a destroy into a recreate.

anotherim-js (UX, a separate small item):

  • What a destroyed room's row does is the host's call. libtacky's destroy_room promises nothing about bookmarks.
  • On muc <Destroyed>, show the row as "destroyed" and offer Remove (bookmarks remove). Offer the alternate venue when altRoom is set.
  • Today ui/src/state/muc-room.ts:204 only clears the room's state, so the row stays as if nothing happened.

Evidence: the test build's XML logs (not committed): aim-fix-xml.log lines 1365-1371 (destroy) and aim-fix-xml-2.log lines 86, 96, 142, 144 (rejoin and recreate).

## New: C34, a destroyed room comes back on the next sign-in (found by hand in anotherim-js, 2026-11-08) Setup: anotherim-js upstream `develop` (`009c9884`, `XML_LOG=1`) with libtacky `develop` `56d29734` plus C3/S2 (`bdb54e89`), on anotherim-server as ai3a. ai3a, the owner, destroyed `c3-test@conference.anotherim.asxp.io` from the room menu. **What happens:** 1. 03:00:51: `muc destroy_room` sends `<destroy/>`, and the server confirms with presence `<destroy/>`, `affiliation='none'`. The room is gone. 2. Nothing removes the room's XEP-0402 bookmark, which still has `autojoin='true'`. - libtacky's `destroy_room` (`tacky/xmpp/modules/muc.tcl:2290`) only sends the iq. - The `<Destroyed>` event (`muc.tcl:3058`, `:3941`) is not acted on by `bookmarks`. - anotherim-js (`ui/src/state/muc-room.ts:204`) only clears the room's state, so the row stays in the list. 3. On the next sign-in (03:04:32), autojoin rejoins. - The room's disco#info answers `item-not-found` "Conference room does not exist". - libtacky sends the join presence anyway. - The server creates a new room: status `201` and `110`, affiliation `owner`. **Effect:** a room destroyed on purpose is quietly recreated by the owner's own client on every sign-in, empty, with the server's default configuration, under the same address. Anyone who knew the address can join it. The list row also stays after the destroy. **Spec:** XEP-0045 §10.9 (destroying a room; the `<destroy/>` with an optional alternate venue), XEP-0402 (autojoin bookmarks). **Who should fix what:** *libtacky (the real fix):* - libtacky runs autojoin itself (HANDBOOK, XEP-0402 row), so no host can stop the rejoin cleanly. - libtacky asked disco#info, got `item-not-found` "Conference room does not exist", and joined anyway. The server took that join as "create". - libtacky already treats a room whose disco#info says it is gone as Left (HANDBOOK, XEP-0410 row) but does not apply that rule to autojoin at sign-in. - Fix: never autojoin a bookmarked room whose disco#info answered `item-not-found` (report it instead), and clear `autojoin` after a successful `destroy_room`. Then a bookmark left behind cannot turn a destroy into a recreate. *anotherim-js (UX, a separate small item):* - What a destroyed room's row does is the host's call. libtacky's `destroy_room` promises nothing about bookmarks. - On `muc <Destroyed>`, show the row as "destroyed" and offer Remove (`bookmarks remove`). Offer the alternate venue when `altRoom` is set. - Today `ui/src/state/muc-room.ts:204` only clears the room's state, so the row stays as if nothing happened. Evidence: the test build's XML logs (not committed): `aim-fix-xml.log` lines 1365-1371 (destroy) and `aim-fix-xml-2.log` lines 86, 96, 142, 144 (rejoin and recreate).
Owner

Verified against libtacky v1.2.1 (https://dev.another.im/another-im/libtacky/releases/tag/v1.2.1), built on 1.2.0. One comment covering the whole list.

Security / privacy

ID Verdict
S1 Fixed in 1.2.1: group-call invites and answers now ride inside the OMEMO 2 envelope in a chat whose OMEMO is on, refused where nothing can read them sealed (groupcall start/invite answer {TACKY GROUPCALL ENCRYPTED} for an OMEMO 0.3-only peer); meeting messages are refused the same way (the URL is a bearer secret, {TACKY MEETINGS ENCRYPTED}).
S2 Fixed in 1.2.1: <active/>, the receipt request and <markable/> now go inside an OMEMO 2 message's envelope instead of beside it in the clear.
S3 Kept behind the installation setting legacy_file_metadata (default/unset = on, as before) by the user's ruling, not removed outright. Off (new in 1.2.1) drops the SIMS file metadata that used to sit beside OMEMO 0.3 ciphertext.
S4 Fixed in 1.2.1: a JID that answers as no room no longer leaves stale room-features state behind, so a fake/failed "join" at a contact's bare JID can no longer downgrade that contact's 1:1 OMEMO to plaintext.
S5 Fixed in 1.2.1: CAPTCHA inline BoB data is now hash/size/type checked the same way the ad-hoc path already was.
S6 Fixed in 1.2.1: a spans-0 fallback range is stripped only when it is exactly a hidden link's own " (href)" fallback, not any other range.
S7 Fixed in 1.2.1: no roster add or subscribe is sent for a "gateway" JID that carries a node or a resource.
S8 Fixed in 1.2.1: a stale geoloc republish from a list change can no longer overtake and undo a stop.
S9 Fixed in 1.2.1: OTR ssid, fingerprint and the SMP question are built without Tcl expr, so a numeric-looking value is no longer turned into Inf or stripped of leading zeros.
S10 Fixed in 1.2.1: parse_uri/jid valid now refuse both a decoded ? in an address and a :port on the domain (the ?-split half was already fixed earlier, commit cd3e39c5).
S11 Already fixed earlier, in 1.2.0 (commit 0213e2ea).
S12 Already fixed earlier, in 1.2.0 (commit 267e5bc4).
S13 Fixed in 1.2.1: no credentials reach sm <Ack> output or the XML console log.

Correctness

ID Verdict
C1 Fixed in 1.2.1: an invalid jinglepub from no longer throws; that source is dropped and the message is kept.
C2 Fixed in 1.2.1: an IBB data error now closes the stream instead of stalling 60s on a callback-arity bug.
C3 Fixed in 1.2.1: mention offsets are shifted to stay correct after characters are stripped for XML. See also the comment-1014 addenda below (C3.1, and a second C3 symptom) found after this fix landed.
C4 Fixed in 1.2.1: a reply fallback naming only <subject/> no longer swallows the whole body; the reply is kept.
C5 Fixed in 1.2.1, narrowed to content type service: service-0 notices no longer raise notify <Notify>. Other notice types (timer, ttl, screenshot) still alert; that is a design call, not part of this bug.
C6 Fixed in 1.2.1: a room caption now folds by the room's stanza-id, not by origin-id.
C7 Fixed in 1.2.1 for the id a <reject/> names (falls back through origin-id, message id, then stanza-id in rooms); our own invites' id scheme was deliberately left as is (re-invites share one <invite id/> on purpose) rather than changed.
C8 Fixed in 1.2.1 for the main bug: <advanced/> is kept when the attribute-free element is rewritten. Not done: the SHOULD fallback on a scoped write with no setting. The notify get-ignores-bookmark report was not a bug on the base code (it already reads the bookmark once a ?join chat is in scope).
C9 Fixed in 1.2.1: our own geoloc node <delete/> is no longer read as a stop; a rig case for this is in the test suite.
C10 Fixed in 1.2.1: the XEP-0470 attachments node is now created with pubsub#max_items max, so Prosody's default no longer evicts our own reaction.
C11 Fixed in 1.2.1: pubsub publish/create ids (and every other id/text picked by a Tcl expr {... ? ... : ...}) go through if/dict getdef instead, same class as S9.
C12 Documented deviation, no code change, kept with reason by the user's ruling: the own photo hash is advertised at bind on purpose, before the vCard is re-fetched, for an Android cold start; the row now says so.
C13 Fixed in 1.2.1: an outgoing SIMS <file/> carries <hash/> and <desc/>.
C14 Fixed in 1.2.1: send_album source messages carry the sfs fallback marker.
C15 Fixed in 1.2.1: outgoing inline thumbnails are capped at 64 KiB.
C16 Fixed in 1.2.1: disco#info advertises urn:ietf:params:xml:ns:vcard-4.0.
C17 Fixed in 1.2.1: disco#info advertises urn:xmpp:eme:0; name= is dropped for listed EME methods.
C18 Fixed in 1.2.1: microblog publish sets pubsub#notify_retract true on a fresh node.
C19 Fixed in 1.2.1: two rows with different wire @ids are no longer merged as one duplicate by content alone.
C20 Fixed in 1.2.1 for the remaining case: a legacy :0 moderation outside a room is dropped. The :1/room-relayed case was already fixed earlier (commit 292016a5).
C21 Already fixed earlier (commits dc48ac80, 5f5b8c3e, 198f4438).
C22 Already fixed earlier (commits 8b25b7d3, 0eaa4a5e, f4ad2e47). The XEP-0379 pre-approval part is a documented deviation (commit ce96d4c5): accept_invite approves on arrival rather than ahead of time, because ejabberd 26.09 leaves gateways at subscription to.
C23 Already fixed earlier (commits 246a66fe, bc454657).
C24 Already fixed earlier (commit 6b9bac06).
C25 Already fixed earlier (commits 1dff6016, 5f8c84cf).
C26 Already fixed earlier (commit 86ccda9a).
C27 Already fixed earlier (commit c186eaa7).
C28 Already fixed earlier (commit 70aae84e).
C29 Already fixed earlier (commit 5a87d4ec).
C30 Already fixed earlier (commit 616beba4).
C31 Already fixed earlier (commit 4d485589).
C32 Already fixed earlier (commits 64378ebe, 292016a5).
C33 Already fixed earlier (commit 5bdefcae for 1:1, ecfd1682 for rooms).

Minor / SHOULD

ID Verdict
M1 Already fixed earlier (commit f396065d).
M2 Fixed in 1.2.1: adhoc list drops command nodes whose jid is not the responder's.
M3 Fixed in 1.2.1: thread_parent == thread is refused.
M4 Fixed in 1.2.1: <attachments> is read only from its own namespace.
M5 Fixed in 1.2.1: get_invoice checks disco for #invoice-request first.
M6 Fixed in 1.2.1: the XEP-0472 side issues (attachments node access model, comments node itemreply, xmpp:-only comments/reply_to, an edit no longer re-creating the attachments node).
M7 Fixed in 1.2.1: a story entry carries atom:author.
M8 Fixed in 1.2.1: a forged roster push is answered service-unavailable.
M9 Not reproduced: a live re-check with the connection dropped server-side went dead 60s after the unanswered <r/>, as expected. No change needed.
M10 Fixed in 1.2.1: self-pings resume after idle and skip rooms already left or leaving.
M11 Fixed in 1.2.1: mam query answers the RSM <count>; disco's Truncated count keeps the page-1 value.
M12 Not reproduced: trust_certificate/untrust_certificate are symmetric in code; a live re-check found it works while a registration session is open, which is by design otherwise.
M13 Fixed in 1.2.1: the answered software version is the release, not 0.1; the caps node is the library's home.
M14 Fixed in 1.2.1: a trailing OTR whitespace tag is cut before the body is stored (a mid-body tag is left, by design — only offsets are at stake there).
M15 Fixed in 1.2.1: a vCard get already in flight is deduped instead of sent again.
M16 Fixed in 1.2.1: a default nick is added only for new bookmarks.
M17 Not changed: (a) a contact's PEP item deleted with its node and no notice can't be told apart from the item simply not existing without a re-read — a design call on cost vs. freshness, left to the user. (b) the stale full-JID roster item is S7's case and is no longer created at the source.
M18 Fixed in 1.2.1: a debug line is now logged for a replayed or equal-stamp sealed item dropped.
M19 Fixed in 1.2.1: an own call-invite row reads joined only while this device is actually in the call.
M20 Not a bug, documented choice: hashing an Ed25519/Ed448 certificate with SHA-256 for tls-server-end-point is the choice other XMPP implementations make, since RFC 5929 has no rule for those algorithms; the docs row says so now.
M21 Fixed in 1.2.1: tags reload after a storage import.
M22 Fixed in 1.2.1: a refused accept_invite join restores or removes its autojoin bookmark instead of leaving it behind.
M23 Part fixed in 1.2.1: unsigned OMEMO 2 labels are now kept on republish. Left as design calls for the user: a per-device forget method (separate from forget_inactive), and pruning own-device rows that accumulate on fresh-store runs. trust_list active's per-connection meaning is documented, not changed.
M24 Not changed, design call: the XEP-0377 report's stanza-id by= question reads differently from the XEP's own text versus its example and is untestable on the three servers; left for the user (or the XEP's author) to decide.
M25 Fixed in 1.2.1, five separate fixes: poll-fluux fallback <body/>, a whole-link check for XEP-0511, a pep-expiry year bound plus a pending replaced item, a dropped bad live-location move, and nick-only MUC/Sub subscribers.

From comment 1014 (found after the above fixes landed)

  • C3.1 (a draft holding a character XML can't carry, e.g. pasted U+0001, is never synced and escapes as a bgerror): fixed, but not in 1.2.1 — targeted at 1.2.2, commit 7dddfd32, not released yet.
  • C3's second symptom (a message whose mention is the last thing in the body doesn't send at all once stripped characters push the mention past the body's end): already covered by the C3 fix that shipped in 1.2.1 — offsets are shifted correctly, so the send goes through.
  • The media auto-download note (anotherim-js fetching media URLs found in received messages, which can reveal the reader's address and that they are online): being changed in anotherim-js so pictures and stickers auto-download only from contacts; in progress for the next releases, not shipped yet.
Verified against libtacky v1.2.1 (https://dev.another.im/another-im/libtacky/releases/tag/v1.2.1), built on 1.2.0. One comment covering the whole list. ## Security / privacy | ID | Verdict | |----|---------| | S1 | Fixed in 1.2.1: group-call invites and answers now ride inside the OMEMO 2 envelope in a chat whose OMEMO is on, refused where nothing can read them sealed (`groupcall start`/`invite` answer `{TACKY GROUPCALL ENCRYPTED}` for an OMEMO 0.3-only peer); meeting messages are refused the same way (the URL is a bearer secret, `{TACKY MEETINGS ENCRYPTED}`). | | S2 | Fixed in 1.2.1: `<active/>`, the receipt request and `<markable/>` now go inside an OMEMO 2 message's envelope instead of beside it in the clear. | | S3 | Kept behind the installation setting `legacy_file_metadata` (default/unset = on, as before) by the user's ruling, not removed outright. Off (new in 1.2.1) drops the SIMS file metadata that used to sit beside OMEMO 0.3 ciphertext. | | S4 | Fixed in 1.2.1: a JID that answers as no room no longer leaves stale room-features state behind, so a fake/failed "join" at a contact's bare JID can no longer downgrade that contact's 1:1 OMEMO to plaintext. | | S5 | Fixed in 1.2.1: CAPTCHA inline BoB data is now hash/size/type checked the same way the ad-hoc path already was. | | S6 | Fixed in 1.2.1: a spans-0 fallback range is stripped only when it is exactly a hidden link's own " (href)" fallback, not any other range. | | S7 | Fixed in 1.2.1: no roster add or subscribe is sent for a "gateway" JID that carries a node or a resource. | | S8 | Fixed in 1.2.1: a stale geoloc republish from a list change can no longer overtake and undo a `stop`. | | S9 | Fixed in 1.2.1: OTR ssid, fingerprint and the SMP question are built without Tcl `expr`, so a numeric-looking value is no longer turned into `Inf` or stripped of leading zeros. | | S10 | Fixed in 1.2.1: `parse_uri`/`jid valid` now refuse both a decoded `?` in an address and a `:port` on the domain (the `?`-split half was already fixed earlier, commit cd3e39c5). | | S11 | Already fixed earlier, in 1.2.0 (commit 0213e2ea). | | S12 | Already fixed earlier, in 1.2.0 (commit 267e5bc4). | | S13 | Fixed in 1.2.1: no credentials reach sm `<Ack>` output or the XML console log. | ## Correctness | ID | Verdict | |----|---------| | C1 | Fixed in 1.2.1: an invalid jinglepub `from` no longer throws; that source is dropped and the message is kept. | | C2 | Fixed in 1.2.1: an IBB data error now closes the stream instead of stalling 60s on a callback-arity bug. | | C3 | Fixed in 1.2.1: mention offsets are shifted to stay correct after characters are stripped for XML. See also the comment-1014 addenda below (C3.1, and a second C3 symptom) found after this fix landed. | | C4 | Fixed in 1.2.1: a reply fallback naming only `<subject/>` no longer swallows the whole body; the reply is kept. | | C5 | Fixed in 1.2.1, narrowed to content type `service`: service-0 notices no longer raise `notify <Notify>`. Other notice types (timer, ttl, screenshot) still alert; that is a design call, not part of this bug. | | C6 | Fixed in 1.2.1: a room caption now folds by the room's stanza-id, not by origin-id. | | C7 | Fixed in 1.2.1 for the id a `<reject/>` names (falls back through origin-id, message id, then stanza-id in rooms); our own invites' id scheme was deliberately left as is (re-invites share one `<invite id/>` on purpose) rather than changed. | | C8 | Fixed in 1.2.1 for the main bug: `<advanced/>` is kept when the attribute-free element is rewritten. Not done: the SHOULD fallback on a scoped write with no setting. The `notify get`-ignores-bookmark report was not a bug on the base code (it already reads the bookmark once a `?join` chat is in scope). | | C9 | Fixed in 1.2.1: our own geoloc node `<delete/>` is no longer read as a stop; a rig case for this is in the test suite. | | C10 | Fixed in 1.2.1: the XEP-0470 attachments node is now created with `pubsub#max_items max`, so Prosody's default no longer evicts our own reaction. | | C11 | Fixed in 1.2.1: pubsub publish/create ids (and every other id/text picked by a Tcl `expr {... ? ... : ...}`) go through `if`/`dict getdef` instead, same class as S9. | | C12 | Documented deviation, no code change, kept with reason by the user's ruling: the own photo hash is advertised at bind on purpose, before the vCard is re-fetched, for an Android cold start; the row now says so. | | C13 | Fixed in 1.2.1: an outgoing SIMS `<file/>` carries `<hash/>` and `<desc/>`. | | C14 | Fixed in 1.2.1: `send_album` source messages carry the sfs fallback marker. | | C15 | Fixed in 1.2.1: outgoing inline thumbnails are capped at 64 KiB. | | C16 | Fixed in 1.2.1: disco#info advertises `urn:ietf:params:xml:ns:vcard-4.0`. | | C17 | Fixed in 1.2.1: disco#info advertises `urn:xmpp:eme:0`; `name=` is dropped for listed EME methods. | | C18 | Fixed in 1.2.1: `microblog publish` sets `pubsub#notify_retract` true on a fresh node. | | C19 | Fixed in 1.2.1: two rows with different wire `@id`s are no longer merged as one duplicate by content alone. | | C20 | Fixed in 1.2.1 for the remaining case: a legacy `:0` moderation outside a room is dropped. The `:1`/room-relayed case was already fixed earlier (commit 292016a5). | | C21 | Already fixed earlier (commits dc48ac80, 5f5b8c3e, 198f4438). | | C22 | Already fixed earlier (commits 8b25b7d3, 0eaa4a5e, f4ad2e47). The XEP-0379 pre-approval part is a documented deviation (commit ce96d4c5): `accept_invite` approves on arrival rather than ahead of time, because ejabberd 26.09 leaves gateways at subscription `to`. | | C23 | Already fixed earlier (commits 246a66fe, bc454657). | | C24 | Already fixed earlier (commit 6b9bac06). | | C25 | Already fixed earlier (commits 1dff6016, 5f8c84cf). | | C26 | Already fixed earlier (commit 86ccda9a). | | C27 | Already fixed earlier (commit c186eaa7). | | C28 | Already fixed earlier (commit 70aae84e). | | C29 | Already fixed earlier (commit 5a87d4ec). | | C30 | Already fixed earlier (commit 616beba4). | | C31 | Already fixed earlier (commit 4d485589). | | C32 | Already fixed earlier (commits 64378ebe, 292016a5). | | C33 | Already fixed earlier (commit 5bdefcae for 1:1, ecfd1682 for rooms). | ## Minor / SHOULD | ID | Verdict | |----|---------| | M1 | Already fixed earlier (commit f396065d). | | M2 | Fixed in 1.2.1: `adhoc list` drops command nodes whose jid is not the responder's. | | M3 | Fixed in 1.2.1: `thread_parent == thread` is refused. | | M4 | Fixed in 1.2.1: `<attachments>` is read only from its own namespace. | | M5 | Fixed in 1.2.1: `get_invoice` checks disco for `#invoice-request` first. | | M6 | Fixed in 1.2.1: the XEP-0472 side issues (attachments node access model, comments node `itemreply`, `xmpp:`-only comments/reply_to, an edit no longer re-creating the attachments node). | | M7 | Fixed in 1.2.1: a story entry carries `atom:author`. | | M8 | Fixed in 1.2.1: a forged roster push is answered `service-unavailable`. | | M9 | Not reproduced: a live re-check with the connection dropped server-side went dead 60s after the unanswered `<r/>`, as expected. No change needed. | | M10 | Fixed in 1.2.1: self-pings resume after idle and skip rooms already left or leaving. | | M11 | Fixed in 1.2.1: `mam query` answers the RSM `<count>`; disco's Truncated count keeps the page-1 value. | | M12 | Not reproduced: `trust_certificate`/`untrust_certificate` are symmetric in code; a live re-check found it works while a registration session is open, which is by design otherwise. | | M13 | Fixed in 1.2.1: the answered software version is the release, not `0.1`; the caps node is the library's home. | | M14 | Fixed in 1.2.1: a trailing OTR whitespace tag is cut before the body is stored (a mid-body tag is left, by design — only offsets are at stake there). | | M15 | Fixed in 1.2.1: a vCard get already in flight is deduped instead of sent again. | | M16 | Fixed in 1.2.1: a default nick is added only for new bookmarks. | | M17 | Not changed: (a) a contact's PEP item deleted with its node and no notice can't be told apart from the item simply not existing without a re-read — a design call on cost vs. freshness, left to the user. (b) the stale full-JID roster item is S7's case and is no longer created at the source. | | M18 | Fixed in 1.2.1: a debug line is now logged for a replayed or equal-stamp sealed item dropped. | | M19 | Fixed in 1.2.1: an own call-invite row reads `joined` only while this device is actually in the call. | | M20 | Not a bug, documented choice: hashing an Ed25519/Ed448 certificate with SHA-256 for `tls-server-end-point` is the choice other XMPP implementations make, since RFC 5929 has no rule for those algorithms; the docs row says so now. | | M21 | Fixed in 1.2.1: tags reload after a storage import. | | M22 | Fixed in 1.2.1: a refused `accept_invite` join restores or removes its autojoin bookmark instead of leaving it behind. | | M23 | Part fixed in 1.2.1: unsigned OMEMO 2 labels are now kept on republish. Left as design calls for the user: a per-device forget method (separate from `forget_inactive`), and pruning own-device rows that accumulate on fresh-store runs. `trust_list active`'s per-connection meaning is documented, not changed. | | M24 | Not changed, design call: the XEP-0377 report's `stanza-id by=` question reads differently from the XEP's own text versus its example and is untestable on the three servers; left for the user (or the XEP's author) to decide. | | M25 | Fixed in 1.2.1, five separate fixes: poll-fluux fallback `<body/>`, a whole-link check for XEP-0511, a pep-expiry year bound plus a pending replaced item, a dropped bad live-location move, and nick-only MUC/Sub subscribers. | ## From comment 1014 (found after the above fixes landed) - **C3.1** (a draft holding a character XML can't carry, e.g. pasted U+0001, is never synced and escapes as a `bgerror`): fixed, but not in 1.2.1 — targeted at 1.2.2, commit 7dddfd32, not released yet. - **C3's second symptom** (a message whose mention is the last thing in the body doesn't send at all once stripped characters push the mention past the body's end): already covered by the C3 fix that shipped in 1.2.1 — offsets are shifted correctly, so the send goes through. - **The media auto-download note** (anotherim-js fetching media URLs found in received messages, which can reveal the reader's address and that they are online): being changed in anotherim-js so pictures and stickers auto-download only from contacts; in progress for the next releases, not shipped yet.
Owner

Follow-up to our comment 1028 (v1.2.1).

C3.1 (a draft holding a character XML cannot carry) is now fixed and released, in libtacky 1.2.2, commit 7dddfd32: https://dev.another.im/another-im/libtacky/releases/tag/v1.2.2

C34 (comment 1015, a destroyed room recreated by autojoin) is fixed in libtacky 1.2.2 and anotherim-js 0.8.0-rc8: libtacky issue 26, anotherim-js issue 95.

The media auto-download note from comment 1014: pictures and stickers now auto-download only from contacts. The setting takes contacts (default), never or anyone; the old everyone value is read as contacts and rewritten to contacts when the store opens. A room occupant is not a contact for this; a service on the account's own server, such as the sticker catalogue, counts as one.

Side note: the C34 change exposed a catch-up walk-order regression, which the release gate caught and fixed before the 1.2.2 tag (commit d04ed76a). Nothing to report there.

Follow-up to our comment 1028 (v1.2.1). C3.1 (a draft holding a character XML cannot carry) is now fixed and released, in libtacky 1.2.2, commit 7dddfd32: https://dev.another.im/another-im/libtacky/releases/tag/v1.2.2 C34 (comment 1015, a destroyed room recreated by autojoin) is fixed in libtacky 1.2.2 and anotherim-js 0.8.0-rc8: libtacky issue 26, anotherim-js issue 95. The media auto-download note from comment 1014: pictures and stickers now auto-download only from contacts. The setting takes contacts (default), never or anyone; the old everyone value is read as contacts and rewritten to contacts when the store opens. A room occupant is not a contact for this; a service on the account's own server, such as the sticker catalogue, counts as one. Side note: the C34 change exposed a catch-up walk-order regression, which the release gate caught and fixed before the 1.2.2 tag (commit d04ed76a). Nothing to report there.
Sign in to join this conversation.
No labels
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
another-im/interop#1
No description provided.