Skip to content

Tiny sends name the sender at once and settle faster - #243

Merged
itz4blitz merged 1 commit into
mainfrom
fix/tiny-send-speed
Nov 11, 2026
Merged

itz4blitz merged 1 commit into
mainfrom
fix/tiny-send-speed

Conversation

@itz4blitz

Copy link
Copy Markdown
Collaborator

What changed and why

Sending in a Tiny conversation took 1 to 10 seconds, and the pending row showed "You" with a plain "Y" avatar until it settled. A Tiny account's own id was stored as the email, so the pending row could not find the person's cached rows; it is now the user id (the session's display name seeds our person until the people list names us). The row also no longer waits for a full /v1/members request after the post, plain sends no longer queue on the shared commands thread, requests reuse pooled connections instead of a new TCP and TLS handshake each, and an encrypted send skips a second sync when the first ended settled on the same lock. Sends now log every stage with elapsed_ms, and a warn with the breakdown when one passes a second.

Type

  • feature
  • fix
  • perf
  • refactor
  • chore
  • docs

Platforms

  • windows
  • macos
  • linux
  • android
  • ios

Proof

Scenario: e2e/scenarios/tiny-send-speed

It is a daemon proof (real chatd and IPC against an invented loopback server whose member list takes 3 s), not a native window run or a measurement against a real server. It fails on main (no such prove) and, with either half of the fix removed, fails on the branch too (own id is the email; the row waits on the member list).

Lab run:

Compatibility

No protocol change. The server already answers a repeated client_id with the same message, which is what makes retrying a message post after a dropped kept connection safe. Accounts stored with the email as their own id are corrected on the next connect.

Risk and rollback

Connection reuse is the main risk (a kept connection the server closed). Reads retry once; only message posts with a client_id retry, nothing else is sent twice. The encrypted path still syncs before the first encrypt unless the sync just ended settled on the same device lock, and still persists the ratchet before the post. Revert the PR to undo.

Release note

Sending a message in a Tiny server shows your name and photo straight away and finishes sooner.

🤖 Generated with Claude Code

The pending row read "You" with no photo because a Tiny account's own id
was stored as the email; it is now the user id, and the session's display
name seeds our person until the people list names us. The row no longer
waits for a full /v1/members request to settle, plain sends leave the
shared commands thread for the account's send thread, HTTP requests share
one pooled agent (a retry on a dropped kept connection for reads and for
client_id-idempotent message posts), and an encrypted send skips the second
sync when the first ended settled on the same device lock. Sends log each
stage with elapsed_ms, and a warn over a second with the breakdown.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@itz4blitz
itz4blitz merged commit 94e9381 into main Nov 11, 2026
5 checks passed
@itz4blitz

Copy link
Copy Markdown
Collaborator Author

Reviewed the diff and the head sources (41a1761). No protocol or wire change, no new unwrap on peer input, logging only records the opaque client_id, and the "sync before encrypt" invariant still holds in post_after. CI is green and the scenario is in the diff. Two things I would fix before merging, because both sit on the send path.

1. crates/chatd/src/adapters/tiny/messages.rs:1377: an encrypted conversation with no label yet goes to the plain queue

send now picks its queue from the cached label only (ctx.known(..).is_sealed()). It used to call sealed_here, which also asked device.is_encrypted. A conversation that is encrypted but has no label yet lands on the #plain queue, where e2ee::send can wait up to JOIN_WAIT (45 s) and hold up every plain send for that account. A label that flips between two sends can also reorder them.

Smallest fix: let sealed = labelled || e2ee::started(saved).is_some_and(|d| lock(&d).is_encrypted(&conversation_id).unwrap_or(false)), or call sealed_here(..) == Ok(true) as before.

2. crates/chatd/src/adapters/tiny.rs:472: nothing tests the new connection reuse or the retry

The proof server in send_prove.rs answers Connection: close, so every request opens a fresh connection and the pool is never used. If dropped() misses the error ureq raises for a stale pooled connection, nothing fails and the retry silently never fires. If it matches too much, a client_id POST is sent twice.

Smallest fix: one unit test with a listener that answers once on keep-alive and then closes. The second request on the shared agent must succeed for a GET and for a POST with a client_id, and must not be retried for a POST without one.

Not verified from the diff: whether a real tinyserver (including older deployed builds) answers a repeated client_id with the same message. The retry's safety depends on that, and the PR is a loopback proof only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant