Commit Graph
2 Commits
Author SHA1 Message Date
OrcaWinandOrcaWin 7d6603aa17 [comment audit] Complete repository-wide comment cleanup (#33249)
* [comment audit] Align legacy failure-read counts with cached display

* [comment audit] Condense shared provider lifecycle and browser recovery comments [skip ci]

* [comment audit] Condense shared generation, path and preview comments [skip ci]

* [comment audit] Condense host, file and Git contract rationale [skip ci]

* [comment audit] Tighten Git lifecycle and provider contract comments [skip ci]

* [comment audit] Clarify shared host authority and launch isolation [skip ci]

* [comment audit] simplify local access mobile and native chat contracts [skip ci]

* [comment audit] simplify native chat presentation and state contracts [skip ci]

* [comment audit] simplify native runtime and provider contracts [skip ci]

* [comment audit] simplify migration and orchestration contracts [skip ci]

* [comment audit] simplify plugin trust and process capture rationale [skip ci]

* [comment audit] simplify terminal delivery and remote compatibility rationale [skip ci]

* [comment audit] clarify remote recovery and launch wire rationale [skip ci]

* [comment audit] shorten shared RPC compatibility and runtime evidence comments [skip ci]

* [comment audit] simplify secure storage shell startup and sidebar rationale [skip ci]

* [comment audit] clarify sidebar, skill and SSH invariants [skip ci]

* [comment audit] condense structured chat delivery and timing rationale [skip ci]

* [comment audit] condense terminal replay and telemetry invariants [skip ci]

* [comment audit] clarify launch permission and terminal delivery rationale [skip ci]

* [comment audit] clarify workspace ownership and layout contracts [skip ci]

* [comment audit] wait for fitted and painted SSH terminal links

* [comment audit] clarify layout persistence and session ownership [skip ci]

* [comment audit] clarify host routing and workspace lifecycle contracts [skip ci]

* [comment audit] clarify startup persistence and app lifetime comments [skip ci]

* [comment audit] clarify recovery and activity boundaries [skip ci]

* [comment audit] condense activity and artifact invariants [skip ci]

* [comment audit] condense automation authority contracts [skip ci]

* [comment audit] simplify automation scheduling and history contracts [skip ci]

* [comment audit] clarify browser chrome and annotation lifecycles [skip ci]

* [comment audit] clarify browser routing and retained guest ownership [skip ci]

* [comment audit] clarify browser recovery and document ownership comments [skip ci]

* [comment audit] restore hosted runners required by native IME fixtures

* [comment audit] shorten preview, palette and dashboard invariants [skip ci]

* [comment audit] clarify terminal preview, dashboard and retention comments [skip ci]

* [comment audit] clarify diff-note recovery and editor lifecycle comments [skip ci]

* [comment audit] shorten rich-text and combined-diff ownership comments [skip ci]

* [comment audit] shorten autosave, draft recovery and model ownership comments [skip ci]

* [comment audit] shorten save-queue, notebook and Markdown constraints [skip ci]

* [comment audit] shorten Monaco, PDF and rich Markdown safeguards [skip ci]

* [comment audit] clarify rich Markdown source and selection safeguards [skip ci]

* [comment audit] clarify editor loading and emulator stream lifetimes [skip ci]

* [comment audit] trim emulator and feature tour narration [skip ci]

* [comment audit] clarify floating workspace and GitHub cache ownership [skip ci]

* [comment audit] trim provider controls and Linear filter explanations [skip ci]

* [comment audit] clarify pairing and chat resume lifetimes [skip ci]

* [comment audit] clarify chat delivery and transcript lifetimes [skip ci]

* [comment audit] clarify session options and host-owned status [skip ci]

* [comment audit] clarify draft durability and live-status precedence [skip ci]

* [comment audit] Trim chat send and model ownership explanations [skip ci]

* [comment audit] Shorten transcript ownership and send recovery comments [skip ci]

* [comment audit] Simplify native chat composer and transcript hook comments [skip ci]

* [comment audit] Shorten native chat scroll and structured session explanations [skip ci]

* [comment audit] Trim workspace picker and onboarding commentary [skip ci]

* [comment audit] Simplify pet rendering, review cache and quick open comments [skip ci]

* [comment audit] Trim sidebar and session history explanations [skip ci]

* [comment audit] Condense session resume and review checks comments [skip ci]

* [comment audit] Shorten checks state and file explorer refresh comments [skip ci]

* [comment audit] Trim plugin bridge and source-control action rationale [skip ci]

* [comment audit] Trim source-control listing and review rationale [skip ci]

* [comment audit] Shorten sidebar lifecycle and explorer safeguards [skip ci]

* [comment audit] Condense Settings account and appearance rationale [skip ci]

* [comment audit] Trim pairing and repository Settings explanations [skip ci]

* [comment audit] Condense Settings search SSH and terminal safeguards [skip ci]

* [comment audit] Shorten Settings voice and provider ownership comments [skip ci]

* [comment audit] Condense Settings draft persistence and host-state rationale [skip ci]

* [comment audit] Trim Settings hooks and sidebar setup rationale [skip ci]

* [comment audit] Condense sidebar deletion and board-filter safeguards [skip ci]

* [comment audit] Condense worktree cards, host ownership and Markdown contracts [skip ci]

* [comment audit] Condense sidebar drag, folder and filtering contracts [skip ci]

* [comment audit] Condense sidebar parity, sleep and host ownership contracts [skip ci]

* [comment audit] Prune focus-read baseline after comment cleanup

* [comment audit] Clarify sidebar visibility, board drops and agent evidence [skip ci]

* [comment audit] Tighten sidebar listing, drag and reveal contracts [skip ci]

* [comment audit] Clarify viewport geometry and skill update safeguards [skip ci]

* [comment audit] Tighten skill inventory, usage and host status comments [skip ci]

* [comment audit] Clarify usage ownership and resource kill safeguards [skip ci]

* [comment audit] Tighten tab selection, rename and search contracts [skip ci]

* [comment audit] Tighten tab-strip geometry and drag ownership comments [skip ci]

* [comment audit] Tighten Tasks recovery, pagination and mutation comments [skip ci]

* [comment audit] Tighten provider loading and terminal recovery comments [skip ci]

* [comment audit] Tighten completion, cadence and PTY ownership comments [skip ci]

* [comment audit] Clarify terminal restore and parked-pane boundaries [skip ci]

* [comment audit] Tighten PTY startup and replay explanations [skip ci]

* [comment audit] Clarify PTY identity and delivery ownership [skip ci]

* [comment audit] Shorten remote reconnect and input replay rationale [skip ci]

* [comment audit] Condense terminal parking clipboard and file link comments [skip ci]

* [comment audit] Clarify IME ownership and trim trace history [skip ci]

* [comment audit] Shorten pane recovery and parked watcher explanations [skip ci]

* [comment audit] Condense snapshot replay and visibility recovery rationale [skip ci]

* [comment audit] Shorten terminal parking and keyboard ownership rationale [skip ci]

* [comment audit] Trim renderer lifecycle and menu rationale [skip ci]

* [comment audit] Condense workspace cleanup ownership and settlement notes [skip ci]

* [comment audit] Clarify renderer hook evidence and source ownership [skip ci]

* [comment audit] Tighten IPC ownership and reconnect explanations [skip ci]

* [comment audit] Trim renderer focus, paste and attention comments [skip ci]

* [comment audit] Shorten scroll, locale and agent lifecycle comments [skip ci]

* [comment audit] Trim agent launch, resume and ownership commentary [skip ci]

* [comment audit] Shorten account, browser and editor comments [skip ci]

* [comment audit] Clarify host-mirror waits, previews and input ownership [skip ci]

* [comment audit] Condense launch recovery and editor tokenization comments [skip ci]

* [comment audit] Condense workspace selection and terminal pane rationale [skip ci]

* [comment audit] Condense terminal fitting and rendering recovery comments [skip ci]

* [comment audit] Condense terminal input and host routing explanations [skip ci]

* [comment audit] Condense ownership and sleeping-session recovery rationale [skip ci]

* [comment audit] Condense structured launch and terminal link explanations [skip ci]

* [comment audit] Condense terminal ownership and workspace file routing rationale [skip ci]

* [comment audit] Condense session persistence and workspace activation rationale [skip ci]

* [comment audit] Condense workspace routing and browser ownership rationale [skip ci]

* [comment audit] Condense mirror recovery and layout authority rationale [skip ci]

* [comment audit] Condense runtime transport and file safety rationale [skip ci]

* [comment audit] Condense runtime graph and structured session rationale [skip ci]

* [comment audit] Condense browser creation and remote tab recovery rationale [skip ci]

* [comment audit] Condense snapshot authority and publisher recovery rationale [skip ci]

* [comment audit] Condense frame, startup and provider cache rationale [skip ci]

* [comment audit] Condense host twin and agent lifecycle rationale [skip ci]

* [comment audit] Condense browser authority and editor cleanup rationale [skip ci]

* [comment audit] Condense editor buffer identity and review cache rationale [skip ci]

* [comment audit] Condense provider lifetime and repository ownership rationale [skip ci]

* [comment audit] Condense reconnect, hydration and terminal retirement rationale [skip ci]

* [comment audit] Condense recovery, reconciliation and persistence rationale [skip ci]

* [comment audit] Condense cleanup ownership and listing admission rationale [skip ci]

* [comment audit] Condense teardown ordering and terminal ownership rationale [skip ci]

* [comment audit] Condense recovery ledger and web host-boundary rationale [skip ci]

* [comment audit] Condense web reconnect and credential lifecycle rationale [skip ci]

* [comment audit] Condense cloud rollout and assignment safety rationale [skip ci]

* [comment audit] Condense relay session and database recovery rationale [skip ci]

* [comment audit] Condense relay placement and protocol compatibility rationale [skip ci]

* [comment audit] Condense build and packaging constraints [skip ci]

* [comment audit] Condense CI gates and validation isolation rationale [skip ci]

* [comment audit] Condense catalog identity and browser validation rationale [skip ci]

* [comment audit] Condense mobile browser and frame-budget rationale [skip ci]

* [comment audit] Shorten mobile route and browser test explanations [skip ci]

* [comment audit] Condense editor and session seam test rationale [skip ci]

* [comment audit] Trim session and terminal closure history [skip ci]

* [comment audit] Shorten terminal browser and census explanations [skip ci]

* [comment audit] Preserve root-only E2E diagnostic baseline

* [comment audit] Condense mobile seam and HTML preview test rationale [skip ci]

* [comment audit] Condense preview instrumentation and render harness rationale [skip ci]

* [comment audit] Condense bundle contracts and native-build constraints [skip ci]

* [comment audit] Shorten native packaging and CI routing rationale [skip ci]

* [comment audit] Condense release tooling and benchmark constraints [skip ci]

* [comment audit] Condense packaging and platform gate rationale [skip ci]

* [comment audit] Shorten mobile route and history rationale [skip ci]

* [comment audit] Condense mobile browser and component rationale [skip ci]

* [comment audit] Shorten drawer and workspace-form rationale [skip ci]

* [comment audit] Trim mobile review and editor-document explanations [skip ci]

* [comment audit] Condense editor lifecycle and Markdown explanations [skip ci]

* [comment audit] Trim mobile file, diagnostics and dictation commentary [skip ci]

* [comment audit] Simplify mobile host-list and workspace-view explanations [skip ci]

* [comment audit] Clarify mobile shell lifetime and bridge delivery constraints [skip ci]

* [comment audit] Condense bridge stream, native request and audio rationale [skip ci]

* [comment audit] Reduce bridge schema and page-client commentary [skip ci]

* [comment audit] Tighten mobile page bridge contracts [skip ci]

* [comment audit] Clarify mobile cache and session constraints [skip ci]

* [comment audit] Condense mobile route and lifecycle rationale [skip ci]

* [comment audit] Tighten mobile shell hook timing rationale [skip ci]

* [comment audit] Clarify route handoff and notification compatibility [skip ci]

* [comment audit] Clarify push registration and dictation cleanup constraints [skip ci]

* [comment audit] Condense keyboard geometry and native media ownership rationale [skip ci]

* [comment audit] Tighten mobile chat scroll and composer concurrency rationale [skip ci]

* [comment audit] Condense mobile reply compatibility and upload ownership rationale [skip ci]

* [comment audit] Condense optimistic echo and scroll ownership rationale [skip ci]

* [comment audit] Tighten stream replay and queued session ownership rationale [skip ci]

* [comment audit] Condense mobile composer and reply-schema constraints [skip ci]

* [comment audit] Clarify mobile transcript recovery and session ownership [skip ci]

* [comment audit] Clarify mobile queue and source-control compatibility [skip ci]

* [comment audit] Condense storage and task launch constraints [skip ci]

* [comment audit] Clarify task schemas and terminal document ownership [skip ci]

* [comment audit] Tighten terminal input and viewport rationale [skip ci]

* [comment audit] Shorten terminal and RPC recorder contracts [skip ci]

* [comment audit] Condense recorder engine and connection contracts [skip ci]

* [comment audit] Shorten host credential and relay recovery comments [skip ci]

* [comment audit] Tighten pairing recovery and bundle transport rationale [skip ci]

* [comment audit] Clarify RPC delivery and workspace catalog boundaries [skip ci]

* [comment audit] Condense catalog and relay entry contracts [skip ci]

* [comment audit] Shorten shutdown and SSH relay delivery contracts [skip ci]

* [comment audit] Condense WSL relay and E2E regression rationale [skip ci]

* [comment audit] Shorten cross-version harness and renderer fixture explanations [skip ci]

* [comment audit] Condense paired-host and E2E lifecycle rationale [skip ci]

* [comment audit] Shorten layout oracle and regression explanations [skip ci]

* [comment audit] Condense paired recovery and ownership regression contracts [skip ci]

* [comment audit] Shorten restart, sidebar and SSH lifecycle contracts [skip ci]

* [comment audit] Condense terminal rendering and IME regression rationale [skip ci]

* [comment audit] Shorten terminal recovery and benchmark contracts [skip ci]

* [comment audit] Condense tooling and Windows lifecycle proof rationale [skip ci]

* [comment audit] Condense workflow routing and release rationale [skip ci]

* [comment audit] Condense mobile security and installer contracts [skip ci]

* [comment audit] Shorten native rationale and stylesheet workarounds [skip ci]

* [comment audit] Shorten Windows visibility probe rationale [skip ci]

* [comment audit] Condense embedded release and signing rationale [skip ci]

* [comment audit] Retain current main test behavior in final reconciliation [skip ci]

* [comment audit] Complete final comment review across current source inventory

* [comment audit] Handle consolidated audit reports before final CI

* [comment audit] Preserve credential storage census detail [skip ci]

* [comment audit] Scale broad changed E2E selections with verified timing shards

* [comment audit] Align E2E assertions with browser close and settled session metadata

* [comment audit] Match existing E2Es to current resource and windowing contracts

* [comment audit] Observe the shared server outage notice in reconnect coverage

* [comment audit] Make existing renderer probes measure settled tab and PTY work

* [comment audit] Align palette E2E selector with task search

* [comment audit] Refresh remaining palette search selectors

* [comment audit] Keep selector correction within selected audit specs

* [comment audit] Await emoji fixture settings inside renderer evaluation

* [comment audit] Cancel fixture fit retries between terminal tests

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-25 04:05:46 -07:00
Brennan Benson 135c92e01f fix(native-chat): an unsent draft survives a reload or quit (#24905)
* fix(native-chat): an unsent draft survives a reload or quit

The composer's draft text, its editor document and settled image refs lived
only in module memory, so a reload, quit or crash lost whatever was typed,
including text a Stop had just given back. They are now saved per pane scope
in localStorage: typing is debounced and flushed when the window hides or
closes, text given back to the composer is saved at once, an emptied or sent
draft is removed at once, and only the newest drafts within the composer
caches' existing bound are kept.

* fix(native-chat): save draft images outside the state updater

* fix(native-chat): one store owns each unsent draft

The draft's text and its image chips were saved by two writers that each
rebuilt the stored record from what storage held, so a draft that once went
over the size cap, or one refused write, lost its images on the next save.

One store now holds each composer scope's whole draft in memory and writes
storage from it: typing is coalesced, returned text, chips and clears land at
once, a refused write stays pending for the next flush, and all drafts
together keep to a budget so the outbox can still save a send. Closing a tab
drops its panes' drafts.

* test(native-chat): returned text is stored before its images arrive

* fix(native-chat): keep returned text and drop launch-seed copies across reloads

A message given back from the outbox could be larger than one draft was
allowed to store, so the saved draft was deleted and the returned text was
gone after a reload. One draft may now use the whole draft budget, which
holds the largest message a send accepts.

An adopted launch link is also parked in the agent's input line. Restoring
it after a reload, with no seed left to replace that copy, typed it twice,
so the untouched copy is shown but not saved.

A composer reused for another pane now shows that pane's images, so adding
one never saves the previous pane's over them.

* test(native-chat): a plain 260k given-back message stays saved

* fix(native-chat): saved drafts drop pasted images and die with their worktree

A pasted image lives in a temp file Orca wrote, and the permission to show
it is held in memory only, so after a restart a restored pasted chip showed
a generic icon, and once the temp file was cleaned it looked fine but the
send failed after the composer cleared. Pasted images now stay in the
draft for the current run only; images the user attached from their own
files are still saved.

Removing a worktree now deletes its terminal tabs' drafts, as closing the
tab does.

A paste that finished late in a composer that had already been replaced
wrote that composer's old images back over a newer send. Dropping a
placeholder chip no longer writes the saved draft.

The pane-change reload in the images hook is removed: the composer is
keyed by pane, so a pane change always mounts a new one.

* fix(native-chat): the composer renders the draft store instead of keeping a copy

A composer that had been replaced, for example by a question prompt, could
still finish an attach or a send later and write its own old copy of the
draft over the store, so a sent message or image came back. The composer
now reads text and images from the draft store and changes the draft as it
is now: an added image or file reference joins what is there, and a send
that settles after a round trip, or after its composer was replaced, clears
the draft only if it is still what was sent. Only chips still being written
and an IME composition in progress stay local to the composer.

Closing a tab now deletes drafts by the exact tab id: a second chat for one
session has an id that extends the first one's, so a prefix match deleted
its drafts too.

* fix(native-chat): keep images pasted during a command and on shown composers

An image pasted while /compact or /clear was still on its way to the host
vanished when the command was accepted: the clear that followed also wiped
the chip still being saved. A command that settles now clears only the
draft it sent, and an image pasted meanwhile stays.

A composer on screen could lose its pasted images, and its unsaved launch
text, once 128 other drafts pushed its record out of memory, because those
are never stored. A draft that a composer is showing is no longer evicted.

* fix(native-chat): a draft being written is never evicted from memory

A write to a pane while every other cached draft was on screen could evict
the record it had just written, losing it. Also adds the test that a send
settling after its composer unmounted clears the saved draft, through the
real send hook.

* fix(native-chat): restored images Orca couldn't keep come back to attach again

A pasted screenshot in an unsent draft vanished after a restart with no
notice, and a restored image whose file had been deleted looked fine until
the send failed. Both now come back as a placeholder chip that names the
image and says it wasn't saved with the draft. Send stays disabled, and
the send button says to attach the image again or remove it. Attaching a
file with the same name takes the placeholder's place.

Two browser tabs of the web client on one chat now follow each other: when
one sends or edits the draft, the other drops its copy and shows the new
one, unless it has an edit of its own not yet saved.

* test(native-chat): no send while an image waits to be attached again

* fix(native-chat): pasted images in a draft come back after a restart

A pasted screenshot lived in the OS temp folder with a read permission held
in memory, so a draft could only bring it back as a placeholder. Local
pastes are now written to Orca's own native-chat-pastes folder under the
app's user data, and a draft keeps them as real images. On restore the
composer asks the main process to re-grant each one; main grants a read
only when the file's real path, symlinks and junctions resolved, is inside
that folder, and reports anything else as not kept, which becomes the
placeholder. Pastes older than 30 days are deleted at startup, far past
the host's 24 hour window for a resent message; the sweep never follows a
link and never blocks startup. SSH pastes and older temp-folder pastes
still come back as placeholders.

* test(native-chat): the paste sweep test ages the link itself

* fix(native-chat): type the paste-folder path helper with PlatformPath

* fix(native-chat): type the paste-folder path helper from path.posix

* fix(native-chat): placeholder chips say what happened and only a user attach replaces one

A placeholder now shows the image's name and a short hint on the chip
itself, "Attach again" for a file and "Not kept" for a pasted image, with
the longer explanation in its tooltip. The copy no longer says the image
wasn't saved: it says it couldn't be brought back, and for a pasted image
it asks only for removal, since a new paste can't match it. The send
button now says to remove the image to send.

Only an image the user attaches (picking, dropping or pasting) takes the
place of a placeholder with its file name. An image Stop gives back is
added beside it, so a different file with the same name no longer hides
the reminder.

* fix(native-chat): only composer pastes use the paste folder, and restore grants only real paths

Every local clipboard image save had moved into the paste folder, whose
macOS path has a space, so a screenshot pasted into a terminal or sent to
a terminal-backed agent no longer attached. Only a native-chat composer
paste goes there now, through an optional field on the existing save
call; terminal, editor and phone pastes stay in the system temp folder as
before. An image path sent to an agent's input is escaped the way a
dropped image is.

The restore re-grant now grants only the file's real path, and only when
both the real path and the path as written are inside the paste folder,
which must not itself be a link. The sweep deletes only Orca's paste
files and skips a linked folder.

* fix(native-chat): a restored paste is readable by the path its draft stored

Restore granted only a paste's real path, but the composer reads the
preview by the path its draft stored, so with user data reached through a
link the restored chip showed a generic icon. The stored spelling is
granted too; it is already proven to sit inside the paste folder. A test
also pins that a composer paste asks for the paste folder.

* fix(native-chat): grant a paste's stored spelling only when it names the same file

A grant also covers its path's own real path, so a stored spelling that is
itself a link inside the paste folder could have granted an outside file
while the path as restored reached a real paste. The stored spelling is
now granted only when it resolves to the same file; otherwise only the real
path is, and the preview falls back to the generic icon.

* test(native-chat): check the outside file by its real path too

* fix(native-chat): a structured chat's draft belongs to its conversation

Drafts of a structured chat were saved under the pane (tab id plus a hash
of the session), so the follow-up that keys them by conversation would
have left every draft saved by this build invisible after an upgrade,
never shown and never deleted. They are now keyed by the conversation
(`agent-session:<sessionId>`) from the start: every composer showing the
conversation shares one draft, Stop and a queued card's Edit give text
back to it, closing the tab keeps it, and removing the worktree deletes
it. Terminal-backed chats keep the pane key and lose their draft when the
tab is closed.

A send now leaves whatever was added since it was sent, text typed or
composed and images attached meanwhile, and clears only what was sent;
a draft replaced in the meantime is left alone.

Lifted from #25207 (62ef8e7804): the conversation key, the composer's
draftScopeKey, keep-on-close and delete-on-worktree-removal, and the
leave-what-was-added send settle.

* fix(native-chat): every path that drops a worktree's tabs deletes their drafts

A worktree's chat drafts were deleted only by the removal's own renderer
teardown, which looked them up from the worktree's tab lists after the
removal round trip. The host announces the change before it replies, and
the listing refresh that starts can purge those tab lists first, so the
teardown found no tabs and the drafts stayed. The bulk purge now deletes
the drafts of the tabs it drops, and the teardown deletes them before it
closes any tab.

* fix(native-chat): only a user's delete removes a workspace's chat drafts

The listing purge is reconciliation, not a delete: re-pairing a server under
the same id purges its worktrees' tabs, and the host then restores the same
chats under the same draft keys, so deleting drafts there erased them.

Removing a worktree, a project or a folder workspace now reads the draft
keys of the workspace's open chats before the host round trip, and deletes
them only once the host confirms. A listing refresh that drops the tabs
during the round trip no longer hides them, and a refused delete keeps them.

* feat(native-chat): drafts live in IndexedDB with no budget, and a refused save shows

Unsent drafts shared localStorage with the send outbox, so they kept to a
128-draft, 1M-character budget and the oldest quietly did not come back.
They now live in their own IndexedDB store, all loaded once at startup,
with no budget and no eviction.

- Startup waits up to 1.5 s for the load alongside the session read; a
  slower load still fills in every draft not edited meanwhile.
- Each write commits explicitly; on pagehide, beforeunload and hiding,
  anything storage has not confirmed is also journaled synchronously to
  localStorage and replayed by the next run.
- A BroadcastChannel replaces the storage event: another window's save is
  taken unless this window has a change of its own not yet saved.
- A refused save is retried on the next flush and shown: a warning icon
  by Send and on the draft's image chips, only after a refusal.
- Each draft records the workspace and host it was written in, so removing
  a worktree, project or folder workspace also deletes the drafts of chats
  whose tab was closed earlier.

* fix(native-chat): drafts set from the store are never saved back, and early appends merge

- The editor no longer saves a value the field sets from the store (a
  late-loaded or adopted draft): that echo made another window's draft a
  local change here, so a send in one web tab came back from the other.
  A whole draft set on the editor uses its saved document, keeping its
  skill chips. Equal documents no longer count as a change.
- Text or images given back, or attached, before the startup load lands
  are added to the loaded draft instead of replacing it; only typing wins.
- The unload journal leaves out drafts already refused, keeps to 256,000
  characters, and drops a draft's entry once any window confirms a change
  to it, so a replay never brings back a draft sent since.
- A failed load is retried three times with backoff, warned about once,
  then left.
- Adopting another window's write keeps images already checked, so their
  chips don't flash.
- A refused draft shows one icon, by Send, with plainer copy; the chip
  badge and its string are gone.
- A comment that said drafts' bounds retire orphans is corrected.

* test(native-chat): an early append the load already read is not added twice

* test(native-chat): the store-value editor test waits for the editor and checks no document is saved

* fix(native-chat): early appends are read-modify-writes, and the load can't be skipped

- Before the load lands, an append (text or images given back, a paste)
  reads the stored draft and writes it back with the append in one storage
  change, so a load that failed and was retried can never lose the saved
  draft. On landing, only appends that load could not have read (made after
  it began reading, or never written) are applied again, by in-run order
  rather than by comparing clocks.
- The editor saves a value set from the store when this window has a change
  of its own behind it, so a mention accepted next to a skill chip keeps the
  chip; another window's draft or a late load still isn't saved back.
- A refused draft is journaled again; the 256,000-character cap bounds it.
- The draft load starts before the startup chain, and the first write
  starts it in a window whose startup never did; startup still waits for it
  before the session's tabs mount.

* fix(native-chat): text given back is durable before its source is deleted

Draft writes reach IndexedDB asynchronously, but Stop's restore and a queued
card's Edit delete their source (the outbox entry, the card) right after
adding the text to the draft. A crash before the write committed lost it.

An addition (text or images given back or attached) is now journaled to
localStorage synchronously, as data, the moment it is made, and dropped
once storage confirms a change at least as new. The next run replays it onto
the stored draft only when storage doesn't already hold it, and only where
the draft doesn't already end with that text or hold that image, so a crash
either side of the commit gives the text back exactly once and resends
nothing. Only earlier runs' entries are replayed.

The append reports whether the addition is durable. Edit, when it isn't
(the journal full or refused), deletes the card only once the draft is
saved, and keeps it if storage refuses. Additions may grow the journal to
800,000 characters; whole drafts still stop at 256,000.

* test(native-chat): a kept paste is readable by the composer preview through chat-image access, with no grant

* fix(native-chat): a per-scope write confirm, and the paste rule as C2 has it

- nativeChatComposerDraftWriteSettled(scopeKey) settles once every write of
  that scope issued before the call has: true only after IndexedDB completed
  each transaction (an append made before the load landed included), false
  when one was refused or failed, and never on a timeout. A change still
  waiting for its deferred write is issued first.
- A queued card's Edit deletes the card only on true, and keeps it on false.
- A restored paste is kept when its real path is a file inside Orca's paste
  folder, as C2 resolved it. The tests keep every containment case and now
  check that neither an outside file nor the file a stored spelling names
  becomes readable through the preview's chat-image access, which reads only
  image files and needs no grant.

* test(native-chat): the per-scope confirm settles at the IndexedDB transaction's complete, and false on abort, for an append before the load

* fix(native-chat): a journaled removal always fits, and a load replays only what preceded it

- A removal is never capped in the journal (it is tiny, and it is what
  keeps a sent draft from coming back); only whole drafts count against
  their 256,000 characters, and additions keep their own 800,000.
- A load replays the journal as it stood when the load began reading, so an
  addition a live window journals later, whose own write is ordered after
  that read, isn't replayed over its newer typing.
- A lifecycle test no longer says the paste is re-granted.

* fix(native-chat): a chat with a draft is never reused or taken over

#24917's empty-chat check read the composer draft under the pane key, while
this branch keeps a structured chat's draft under its conversation key, so a
chat holding typed or given-back text, or only an image, read as empty: a new
chat could reuse it and another request's text could go into it. It reads
the conversation's draft now, as C2 adapted it (d4e469b697), with the tests
moved to that key.

While the startup load of saved drafts is still running, no chat reads as
empty: one may hold a saved draft memory doesn't have yet. The cost is only
that a new chat opens instead of reusing one during that moment.

* fix(native-chat): a returned text counts as already there only as its own paragraph

Replaying an addition after a crash skipped it whenever the draft merely ended with its text, so
"go" given back onto "please go" was lost. It now counts only when the draft equals the text or
ends with it after a blank line. A whitespace-only draft counts as empty when text is added, and
an addition made before the startup load lands is made again on the loaded draft only where that
draft doesn't already hold it.

* fix(native-chat): a hand-back the draft already holds stays safe until that draft is saved

After merging main's shared returned-text rule, a hand-back the draft
already ends with changes nothing, so it wrote no backup entry yet
reported durable. If the draft holding that text was not saved yet, a
crash after the source copy was deleted lost it. Journal the addition
whenever the draft is not confirmed saved.

* fix(lint): import worktree removal names once in the delete failure toast

Main's #25668 imported from shared/worktree/removal twice in this file,
which fails the type-aware lint gate (no-duplicate-imports) for every
branch that merges current main.
2026-10-05 17:22:02 -07:00