Files
orca/src/shared
Brennan Benson da57f47353 fix(native-chat): say a refused chat write in plain words, and keep it with the write it describes (#22999)
* fix(native-chat): say a refused chat write in plain words, and keep it with the write it describes

A send's refusal now lives on the queued message and goes when that message is sent again or delivered, so a resend that succeeds after an agent restart no longer leaves a red line under the composer. Stop, answers, option and goal changes report a refusal once as a toast; a conversation command answers inline. One shared table turns every refusal code into copy with a next step, on desktop and mobile, instead of showing the host's diagnostic text.

* test(native-chat): pin the refused-then-restarted send in the order the live app sees it

* fix(native-chat): tell the phone to send a refused message again, not to press Retry

The phone puts a refused message back in the composer and has no Retry
control, so "Retry to send it again." named something that is not there. A
phone send now reads "Your message was not sent. Send it again."

Also types the rejection-cause test's empty submissions without a cast.

* fix(native-chat): keep why a message failed as a fact, and say only what is true

A queued message saved the words of its failure to local storage, so the copy
lived in users' data. It now saves the fact: the refusal code (with the host's
words only for a failed restart, which the host writes for people), the
provider's rejection reason, or that the host could not be reached. The Retry
row chooses the words when it shows the message. A saved failure this build
cannot read is dropped, and the row says only that the message was not sent.

The words are true for every host path behind each code:
- A refusal whose code does not say why (a cleared conversation, a pending
  question, a provider's own rejection) says only what did not happen, with no
  next step that could repeat the refusal.
- An unsettled owner no longer claims the agent was restarting; it says Orca
  could not confirm which agent process owns the chat.
- A code from a newer host says only what did not happen.

Desktop translates each sentence whole, with the shared English as the
fallback the phone shows as is, so the two never say it differently. The phone
no longer shows transport or host text when a request fails without a
refusal.

* fix(native-chat): never show a host refusal message, including a failed restart's

Every refusal code has at least one host path that writes its message for a
log or carries a marker. A replayed refusal, for one, says "Operation <id> was
already refused: <code>." because the ledger stores no message. A failed
restart's message also embeds the resume's own refusal text, which can be the
ledger's. So no code's message is safe to show, and the failed-restart
exception goes. The Retry row now says "The agent couldn't restart. Your
message was not sent." with no next step, because some restarts need a new
chat. The cause is still in the chat's own status row. The saved failure keeps
only the code.

The test lists one such emitter per code, so a code that later becomes safe to
show has to be argued against that list.

* fix(native-chat): offer only a next step that works, on the phone too

A message the agent turned away on the phone said "Retry to send it again", but the phone has no Retry control; it now says "Send it again." like every other refused phone message, built from the same sentences as the other notices.

The capacity refusal said Orca was handling too many requests "for this chat" and offered a retry. The limit is counted across every chat over a day, so an immediate retry would likely be refused again. It now says so, with no next step.

* chore: restore pnpm-lock.yaml

A local install rewrote it and it was committed by mistake.

* fix(native-chat): say only what is true for every host path behind a refusal

No refusal notice says how to try again any more: the control that sent
the write already does that, and a sentence per code was false for some
of the host situations the code covers. The phone keeps "Send it again."
where a resend under the same operation id can go through, and an older
host still gets "Update Orca, then try again."

A cause is named only for codes whose every emitter means it. The owner
codes and identity_required now say only what did not happen, the
outcome-unknown sentence no longer claims the write itself is in doubt
(a send behind an unconfirmed rewind is refused outright), and a request
that failed without a refusal is recorded as `failed` rather than
`unreachable`, since most such failures are host or compatibility errors.
The census test now pins the cause allowlist and the absence of retry
sentences, and the unused sentences leave every catalog.

* fix(native-chat): don't say a chat write failed when its request may have run

A desktop Stop, answer, option, goal or conversation command whose request threw
said the write did not happen, for every error. A timeout or a lost connection can
come after the host ran the write, so a timed-out /compact said "The command didn't
run." while it ran. Only an RPC error the host answers before running the method
proves that; any other failure now says Orca couldn't confirm what happened.

The phone already drew this line; both clients now read it from one shared rule.

* fix(native-chat): say a refused background-task stop is about the task, not the agent

A background-task stop goes through agentSession.cancel, so a refusal of it
said "The agent wasn't stopped." although the agent was never asked to stop.
The write kind now reads the cancel's scope and names the task or tasks.

* fix(native-chat): say a Stop refused over a moved-on question did not stop the agent

A Stop pressed while a question or approval is pending names that prompt, so the host can refuse it
as already resolved or stale. The notice then spoke only about the question and never said the agent
kept running.

* test(native-chat): check every refusal notice cell against one spec

Replaces the per-rule loops with one table of every failure (each refusal
code, a failed or unconfirmed request, and a code from a newer host) by
every write kind, and five rules each cell must keep: a certain refusal
says that write did not happen, once; a write that may have run never
says it did not; only "Update Orca" and the phone's resend where it can
work say to try again; a cause is named only for allowlisted codes; no
cell is empty or shows the host's text.

* fix(native-chat): the launch path drops a message's old failure when it sends it again

The first message of a new chat is sent by the launch path, which staged it
without removing the failure saved by an earlier attempt. A message that failed
through the outbox and was then refused again through the launch path showed the
earlier reason in its Retry row. Both paths now stage through one shared step
that removes it.
2026-09-27 16:34:42 -07:00
..
2026-05-31 05:55:04 -07:00
2026-09-03 17:32:59 -07:00