Skip to content

feat: defer attachment preparation until durable send admission - #712

Draft
zxch3n wants to merge 3 commits into
feat/attachment-submit-recoveryfrom
feat/attachment-drafts
Draft

zxch3n wants to merge 3 commits into
feat/attachment-submit-recoveryfrom
feat/attachment-drafts

Conversation

@zxch3n

@zxch3n zxch3n commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Problem / pressure

Adding an attachment currently starts transfer inside the composer. Upload failure, navigation, and send ownership can separate the attachment from its intended message. New, child, and continuing conversations need one recoverable send lifecycle.

Summary

Stack layer 4/4, based on #709 (preceded by #705 and #707). Attachment selection now validates and previews locally. Send persists the complete input and Blob snapshots, releases the composer, and prepares files through the workspace owner before publishing history/queue operations. Same-session text preserves order; retry reuses successful files. Pending new conversations remain reachable through local metadata until commit.

Warmup cleanup, current eligibility checks, versioned recovery, and durable cancellation share the same lifecycle. Cancellation joins late work and preserves later messages. Permanent local references/zero upload remain a separate follow-up. Specs stay draft; implementation details and limits are recorded in the owning Note.

Visual explanation

flowchart LR
  A[New / child / continuing composer] --> B[Save complete input + Blob snapshots]
  B --> C[Release composer / pending view]
  B --> D[Workspace Effect owner]
  D --> E[Prepare files / checkpoint each success]
  E --> F[Recheck current eligibility]
  F --> G[Persist exact operations / commit / existing delivery]
  E --> H[Failure: retain complete message]
  H --> E
Loading

Before / after

Before After
Selection starts transfer and blocks Send. Selection stays local; Send saves the complete input and prepares it in the workspace.
Composer lifetime owns file work. Pending-message recovery owns accepted input across navigation.

Test plan

  • Full TMPDIR=/private/tmp NODE_ENV=test pnpm check passed (480 component files / 3,677 tests). After restacking and the final concurrent-admission and idle-warmup refinements, 60 targeted tests, component typecheck, and targeted lint pass. Idle warmup is joined without triggering an unsaved-input warning.
  • Deterministic tests exercise partial upload failure, late cancellation, cross-connection cancellation, persisted source bytes, creation transfer to the next message, attachment-only input, and repeated preparation without duplicated blocks.
  • pnpm format, targeted component Prettier, and pnpm run docs check.
  • Packaged desktop, real multi-window networking, and native mobile-shell acceptance have not been run.

Context handoff

Instructions for reviewing agents

  • Review focus: Trace both composer entry points through session-send-admission and per-file preparation before live history publication.
  • Decisions to challenge: Check version-2 rollback protection, cancellation fencing, and first-message creation transfer.
  • Plausible failures / evidence gaps: Packaged-device exit and real multi-window transport acceptance are not established by deterministic tests.

Authoring context

  • User goal / directives: Implement attachment drafts for new and continuing conversations as a gradual Effect stack.
  • Constraints / non-goals: Final layer of the attachment-draft stack; existing upload, same-machine handoff, fallback, and backfill protocols remain in use.
  • Risk-bearing decisions: Recovery is local and explicit after restart. Version 2 records contain immutable source bytes and require a compatible reader on rollback. Effect owns work and resource cleanup behind ordinary Promise APIs.
  • Deliberately not done or tested: Original-path references and permanent zero upload are separate work. No packaged-device acceptance is claimed.
  • Unknowns / confidence: Automated source tests pass; device/network lifecycle behavior still requires manual acceptance before removing draft status.

@zxch3n
zxch3n added this pull request to stack #713 September 14, 2026 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant