Skip to content

Report missing reply quotes before sending and preserve the composed text - #486

Merged
gustavo-barrios2006 merged 5 commits into
gabrielhhaber:mainfrom
m-enes-senovali:fix/quoted-reply-not-found
Oct 13, 2026
Merged

gustavo-barrios2006 merged 5 commits into
gabrielhhaber:mainfrom
m-enes-senovali:fix/quoted-reply-not-found

Conversation

@m-enes-senovali

@m-enes-senovali m-enes-senovali commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

An ordinary quoted reply can fail because WhatsApp Web cannot find the quoted message while the connection remains healthy. The generic HTTP 500 then becomes an uncertain-delivery warning referring to connectivity, and the user cannot safely recover the composed reply.

Resolve ordinary text reply quotes before the first recipient send, including replies with mentions. Only an explicit in-page msg_not_found produces a structured no-send verdict. Keep HTTP 500 so older clients do not strip the quote and resend. New clients recognize the complete verdict before any fallback, keep the connection state unchanged and never retry automatically. Unknown lookup failures and every send-stage failure retain the existing ambiguity protection; status and media send paths retain their current behavior.

Keep the refused reply and its composed text/mention metadata in the original chat and message database. The message menu and Alt+E offer editing without the unavailable quote, without overwriting another draft or inserting into another chat. A database write failure reports that the text must be copied before closing. Single, self-chat and bulk deletion handle this never-sent row locally; real messages in mixed selections keep their normal deletion scope. Four UI strings and the current release note are included in all seven locales. The new API utility is in every setup/install/build shipping list.

CI validation at head 9d243d01a92be73c839b88a6490377f88c1185c5:

  • CI run 38458726817 succeeded: 20184 passed / 322 skipped in 1083.60s; its separate pip-environment job reports 28 passed in 0.30s.
  • macOS run 38458726762 succeeded for both ARM64 and Intel. All four check-run head SHAs match this exact PR head. These are PR-head results, not current-main or release acceptance.

Local validation:

  • Final affected headless group: 209 passed / 1 deselected; the deselected case is the separately executed SQLite close/reopen test, 1 passed. That test reloads the failed row and restores its exact text and mentions after reopening the database.
  • A preceding repair group passed 223 checks; it overlaps the final group and is not additive. Earlier broader compatibility and structure checks passed before the review repairs; their counts are not claimed as final full-suite coverage.
  • Final locale/key/gettext group: 66 passed. Seven catalogs compile and validate with 0 pending entries. git diff --check passes.
  • Independent source review approved the final patch after persistence, edit routing and deletion-path repairs. This is local source review, not a GitHub APPROVED review.

The source/test base is 32da4b151fd19125da746e7788719fda1cbee256. A read-only upstream comparison found only country-list/changelog changes through d54d77ef8482a3789e7cf3d48437cbb60df92545; no local fetch or synchronization was performed. No dependency or provider build/install changes. The updated API must be rebuilt by the normal packaging flow to provide the structured verdict; older APIs retain the existing conservative behavior.

Copied production logs establish repeated quote lookup failures, not the full cause of every reported sending problem. No private logs or identifiers are included. No local full suite, wx.App/GUI, live account/provider/phone, packaged NVDA or recovery operations were run. This change is separate from updater PR #485. Ready for maintainer review after exact-head CI and independent source review completed. No merge, release or manual workflow is requested.

@m-enes-senovali
m-enes-senovali marked this pull request as ready for review October 13, 2026 20:26
Copilot AI balanced review requested due to automatic review settings October 13, 2026 20:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

- "Edit unsent reply without its quote" compares the record's chat with
  the open one through _chat_jids_equivalent(): a reply refused while the
  chat was keyed by its @lid kept that address after deduplicate_chats()
  re-keyed the chat to its phone JID, and the restore silently did
  nothing. Tested with the real resolver, both directions and @c.us.
- Romanian: the four new strings use the catalog's formal register, like
  the neighbouring menu items ("Editați", "Alegeți", "copiați-l").
- send-contract.md: the new bullet moves below the file's header block.
- Import order in core/message_edit.py; en-US changelog wording.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WmFGjY3WDiwbRjXL6zhiyY
Every quoted reply carries _reply_draft_text, _reply_draft_mentions and
_reply_draft_mention_names so a pre-send "quote missing" refusal can
give the text back. On a successful send nothing reads them again, yet
the echo match saved them to messages.db with the row: a second copy of
every reply's text and a JID-to-name map, kept indefinitely.

clear_reply_draft() (core/reply_failure.py) drops them where a send is
confirmed: the echo match, before its DB write, and _mark_message_sent
when it has the real id. An unconfirmed send keeps them for the echo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WmFGjY3WDiwbRjXL6zhiyY
_restore_cancelled_message() puts back a reply whose cancel lost the
race and stores it under its real id; it mirrors _mark_message_sent()
and now clears the _reply_draft_* keys too. The _mark_message_sent test
gives the tracked copy and the row separate dicts, so both clears are
covered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WmFGjY3WDiwbRjXL6zhiyY
@gustavo-barrios2006

Copy link
Copy Markdown
Collaborator

Excellent improvements, Muhammet.
Now the response flow through WinZapp is much more robust and responsive to the user. Thank you very much for the improvements.

# Conflicts:
#	client/changelog_en-US.txt
#	client/changelog_es-ES.txt
#	client/changelog_pl.txt
#	client/changelog_pt-BR.txt
#	client/changelog_pt-PT.txt
#	client/changelog_ro.txt
#	client/changelog_tr-TR.txt
@gustavo-barrios2006
gustavo-barrios2006 merged commit be9f475 into gabrielhhaber:main Oct 13, 2026
4 checks passed
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.

4 participants