Files
hapi/android/core/protocol
weishu 33d186f444 feat(android): scratchlist (B-M4d)
Per-session notes/drafts workbench, the native twin of the web
ScratchlistPanel + use-hub-scratchlist (tiann/hapi#893):

- wire/ScratchlistApi.kt: entry/attachment/limits DTOs mirroring
  shared/src schemas, caps (200 entries / 10k chars), typed error codes
  (scratchlist_at_cap, _attachment_too_large, _attachment_in_use, ...).
- HapiApi: entries CRUD (POST idempotent-on-entryId), limits GET,
  base64-JSON attachment upload, raw-bytes fetch over the cached image
  client, attachment delete.
- SessionStore now surfaces scratchlistUpdatedAt patches as a
  scratchlistInvalidations SharedFlow (bare refetch trigger, sse.md).
- ScratchlistStore: per-session entries StateFlow, refresh on open +
  on SSE signal (observed sessions only, 16 ms coalesced), optimistic
  create/update/delete with surgical rollback, friendly atCap state
  (local pre-check + hub 409), uploads-in-flight progress, cached
  limits with offline defaults. ScratchlistAttachmentGuard holds the
  pure pre-upload budget verdicts (fits / downscale-to-target / reject).
- feature/scratchlist: chat/{id}/scratchlist route, entry cards (text
  preview, relative age, authed Coil thumbnails), edit sheet (text +
  attachment strip with photo picker, downscale-to-JPEG import, remove,
  delete), FAB new note, full-screen viewer (generated-image pattern).
- Chat seams: top-bar notepad badge (entry count), composer overflow
  "Park draft to scratchlist" (clears only after the hub accepts), and
  per-entry "To composer" that inserts into the live ChatViewModel of
  the chat entry below the route.

Tests: store CRUD optimistic/rollback + cap 409 + invalidation-signal
refetch + upload progress/413 + attachment delete 409 (MockWebServer),
guard verdicts, ChatViewModel park/insert/badge seams (fake store).
2026-08-18 10:47:02 +08:00
..
2026-08-18 10:47:02 +08:00