fix: classify unmounted chat writes and Settings unavailability - #12916
Draft
undivisible wants to merge 110 commits into
Draft
fix: classify unmounted chat writes and Settings unavailability#12916undivisible wants to merge 110 commits into
undivisible wants to merge 110 commits into
Conversation
Production chat POST, SSE, cancellation, and attachments now return nested not_found without consulting grants or inventing admission. The app maps that 404 to honest send/history copy instead of a retryable outage, paginates chat:chat-main history, and shows typed Settings 503 copy instead of an invented profile. Verification: backends/example-platform `bun run check:deployed` passed (295 tests, 1 skipped real PostgreSQL without Docker). Focused React Native Jest passed for chatClient, chatConversationHistory, pages, Conversations, and DesktopApp. Failure-Class: none
Authorized empty memory, conversation, and task pages with incomplete coverage now show the existing completeness copy instead of "No X yet." Complete empty pages and grant denials keep their current claims. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx src/pages/Memories.test.tsx src/pages/Conversations.test.tsx src/pages/Tasks.test.tsx src/desktop/DesktopApp.test.tsx (5 suites, 66 passed). Failure-Class: none
Production memories declare unavailable accepted-work and STM coverage, which the recall integrity contract maps to degraded completeness. Empty libraries must show that copy instead of claiming nothing was captured. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx src/pages/Memories.test.tsx src/desktop/DesktopApp.test.tsx (3 suites, 58 passed). Failure-Class: none
Authorized empty pages with incomplete or degraded coverage now keep that completeness visible instead of claiming a complete empty library. Failure-Class: none
Production declares accepted-work and STM coverage unavailable. The direct authorized memory read must emit degraded completeness with projection_unavailable so empty libraries cannot look finished. Verification: bun test apps/service/composition/direct-authorized-memory-read.test.ts (7 pass). Wired into check:deployed. Failure-Class: none
Native capture preflight uses GET /v1/device-sessions/ownership. The production memory shell now registers that path explicitly so ownership is not a UUID session 404. Unmounted shells stay a string not_found. Verification: bun test apps/service/memory-service-app.test.ts drivers/postgres/firebase-authorized-memory-service-app.test.ts (16 pass). Failure-Class: none
… proxy Browser and local portable example-platform requests treated GET /v1/chat-messages and completed recording transcript GET as development_backend_unsupported, so mounted reads looked like a retryable outage. The selector now forwards those GETs and still blocks writes, SSE, attachments, ownership, and transcription POST. Verification: bun test tests/proxy-boundary.test.ts (15 pass). Failure-Class: none
Chat copy treated every HTTP 503 as a transient outage, so development_backend_unsupported (retryable:false) looked like "Try again." The client now honors the nested retryable flag and maps that selector door to the existing unusable-backend copy. Omitted 503 retryable still means retry. Verification: bun run --cwd react-native test -- __tests__/chatClient.test.ts (20 pass). Failure-Class: none
Browser SSE treated every 503 as a disconnect and reconnected up to four times, so development_backend_unsupported looked like a stream outage. Non-retryable nested 503s now return immediately. Retryable 503s still exhaust recovery without inventing a terminal frame. Verification: bun test tests/web-adapter.test.ts tests/proxy-boundary.test.ts (30 pass). Failure-Class: none
Authenticated Worker GET /v1/settings used STAGING_DISPLAY_NAME and STAGING_EMAIL as every account's profile. Settings now returns empty identity strings so the page shows unavailable identity instead of a shared staging name. D1 admission usage and the Worker chat limit stay the signed-in entitlement. Verification: bun test test/worker.contract.test.ts (56 pass); bun x vitest run test/account.integration.test.ts (6 pass); bun run --cwd react-native test -- src/pages/pages.test.tsx (22 pass). Failure-Class: none
Capture uploads treated every HTTP 503 as transient, so ownership unavailable and development_backend_unsupported looked like a retryable outage. Library reads did the same for nested retryable:false. Nested false is now honored; omitted 503 retryable still retries. Apple native already refuses capture_ownership_unavailable without a transport retry. Verification: bun run --cwd react-native test -- __tests__/deviceSessionClient.test.ts __tests__/desktopReadClient.test.ts (72 pass). Failure-Class: none
Recording transcript errors always offered Check again, so a blocked transcribe POST or nested retryable:false 503 looked retryable. Those doors now show unavailable copy without a reload control. Omitted 5xx retryable still retries, including capture 500s. Verification: bun run --cwd react-native test -- src/recordingTranscript.test.tsx __tests__/deviceSessionClient.test.ts (42 pass). Failure-Class: none
Conversation detail always offered Check again on history errors, so a nested retryable:false 503 looked retryable. Those doors now show unavailable copy without a reload control. Grant denials still offer Check again. Nested retryable is honored instead of listing selector codes. Verification: bun run --cwd react-native test -- src/chatConversationHistory.test.tsx (6 pass). Failure-Class: none
Saved-data Home Retry and the desktop Try again banner treated every unavailable phase as retryable, so nested retryable:false library 503s looked like a connection outage. Those doors now keep the unavailable copy without a retry control. Mixed retryable failures and unknown outcomes still retry. Verification: bun run --cwd react-native test -- src/chatConversationHistory.test.tsx src/desktop/DesktopApp.test.tsx __tests__/desktopReadClient.test.ts (90 pass). Failure-Class: none
Browser Settings Retry, conversation/task Load more, and Home older-chat load treated nested retryable:false as a transient outage. Those doors now keep unavailable copy without a retry control. Omitted 503 retryable and grant denials still retry. Loaded first pages stay on screen. Verification: bun run --cwd react-native test -- src/pages/pages.test.tsx src/chatConversationHistory.test.tsx __tests__/useDesktopReads.test.tsx __tests__/chatClient.test.ts src/desktop/DesktopApp.test.tsx (112 pass). Failure-Class: none
Worker GET /v1/chat-messages mixed every account session into Home and left named chat: conversations as title-only detail. Default history is now the same main-session grouping as chat:chat-main; optional chatSessionId returns that named session only. Production still rejects the extra query key instead of serving main history for another session. Verification: bun test test/worker.contract.test.ts (56 pass); bun x vitest run test/d1-chat.integration.test.ts (19 pass); bun test apps/service/routes/chat-messages.test.ts (12 pass); bun run --cwd react-native test -- src/chatConversationHistory.test.tsx __tests__/chatClient.test.ts (29 pass). Failure-Class: none
Worker GET /v1/conversations and local task GET returned a 200 empty complete library when D1 was missing, so a mis-bound Worker looked like an empty account. Those handlers now return retryable 503 like chat history. Authenticated fetch of an unready Worker still uses the same predicate as /ready. Empty D1 with a bound database still returns an honest empty page. Verification: bun test test/worker.contract.test.ts (57 pass). Failure-Class: none
Production Listen and processing recordings can arrive with an empty title. Mobile conversation rows and detail used that empty string, so the list looked blank. They now use the same visible fallback desktop already showed, and search/index that label. Verification: bun run --cwd react-native test -- src/pages/Conversations.test.tsx __tests__/desktopReadClient.test.ts src/desktop/DesktopApp.test.tsx (89 pass). Failure-Class: none
Android and Apple example-platform selectors still wrapped GET settings, chat history, and UUID transcript as development_backend_unsupported after the PWA proxy already forwarded those mounted doors. Native allowlists now match the JS proxy. Writes, SSE, ownership, and transcription POST stay blocked. Verification: scripts/test-android-http passed, including the new settings/chat/transcript allow and deny cases. bun run --cwd react-native test -- __tests__/macOSNativeBoundary.test.ts (29 pass). Apple OmiBackendDisposalTest was updated to the same cases but cannot compile on Linux. Failure-Class: none
Empty production Listen/recording summaries still rendered as a blank list subtitle and detail gap after titles gained a visible fallback. Mobile, desktop rows, and search now use the same class of copy. Verification: bun run --cwd react-native test -- src/pages/Conversations.test.tsx __tests__/desktopReadClient.test.ts src/desktop/DesktopApp.test.tsx (90 pass). Failure-Class: none
Conversation detail only loads recording transcripts for omi recording ids and chat history for chat: ids. Listen and microphone rows left a blank gap after the overview. They now say a full transcript is not available yet instead of inventing a Listen producer. Search indexes the same visible title and summary fallbacks. Verification: bun run --cwd react-native test -- src/pages/Conversations.test.tsx __tests__/desktopReadClient.test.ts src/desktop/DesktopApp.test.tsx src/recordingTranscript.test.tsx src/chatConversationHistory.test.tsx __tests__/legacyOmiReads.test.ts (129 pass). Failure-Class: none
The mobile Apps tab without ConnectorsPage content said "No apps connected yet," which looked like a successful empty catalogue. Missing apps content now reports unavailable, matching missing conversation content. Mounted ConnectorsPage is unchanged. Verification: bun run --cwd react-native test -- src/mobile/MobileAppSurface.test.tsx (20 pass). Failure-Class: none
The mobile Settings tab without SettingsPage content rendered a blank stage. Missing settings content now reports unavailable, matching missing conversation and apps content. The unused Worker emptyPage helper that returned a 200 complete empty library is removed so unbound reads cannot be wired back to silent empty success. Verification: bun run --cwd react-native test -- src/mobile/MobileAppSurface.test.tsx (22 pass). bun test --cwd apps/backend-worker test/worker.contract.test.ts (57 pass). Failure-Class: none
Home Daily Recaps used raw conversation titles and "No recaps yet" for any empty ready list. Untitled processing rows stayed blank, and incomplete or degraded conversation pages looked like an empty recap library. Recaps now use conversationDisplayTitle and emptyLibraryCopy. Verification: bun run --cwd react-native test -- src/mobile/MobileAppSurface.test.tsx (25 pass). Failure-Class: none
A ready empty Home or Tasks-tab list always said "Nothing's waiting on you," even when the task page was incomplete or degraded. Those surfaces now use the same empty-library completeness copy as the shared Tasks page and keep the existing complete-empty claim. Verification: bun run --cwd react-native test -- src/mobile/MobileAppSurface.test.tsx (28 pass). Failure-Class: none
Production rejected chatSessionId so a named session could not be served as main history, but listing those ids would 400 on open. GET now filters one optional chatSessionId the same way Worker does, the history cursor binds that session, and conversation composition lists named chat: rows only after that GET can serve them. Verification: bun test from backends/example-platform on apps/service/routes/chat-messages.test.ts apps/service/chat/history-cursor.test.ts apps/service/composition/chat-conversation-sessions.test.ts drivers/sqlite/service-stores/chat-stores.test.ts drivers/postgres/chat-read-repository.test.ts drivers/postgres/migrations/manifest.test.ts drivers/postgres/firebase-chat-read-runtime.test.ts (38 pass). bun run check:deployed passed (307 pass, 1 skip: real PostgreSQL 18.4 without Docker). GitHub Validate backend worker remains the real PostgreSQL 18.4 proof. Failure-Class: none
…lete Home search treated an empty match as "No results" / "Nothing captured matches this search" even when conversation or memory pages were incomplete or degraded. Completeness copy wins; a complete empty match keeps the existing search-miss claim. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx src/desktop/DesktopApp.test.tsx (56 pass). AppOrchestrator macOS/mobile and MobileAppSurface suites also passed (55 pass). Failure-Class: none
Desktop Home search filtered unmatched tasks out of the list and then used the empty-library claim "No tasks yet." Completeness copy still wins; a complete unmatched search now says tasks do not match. Verification: bun run --cwd react-native test -- src/desktop/DesktopApp.test.tsx (40 pass). Failure-Class: none
Rewind showed "No captures saved yet" / "No captures match this search" for an empty page even when a continuation cursor remained, next to Load more. Empty claims now require a terminal page. Verification: bun run --cwd react-native test -- src/desktop/DesktopRewind.test.tsx (17 pass). Failure-Class: none
The conversations, tasks, and memories matrix rows now match the Home-search coverage copy and Rewind terminal-page empty claims already on this branch. Verification: documentation-only; no runtime behavior change. Failure-Class: none
Desktop Settings Current plan already showed plan and status from a successful subscription read, but omitted transcription seconds that mobile Settings Plan already displays. Current plan now includes those used/limit units when both values are present. It does not invent 0 / 0 when those fields are null. Verification: bun run --cwd react-native test -- src/desktop/DesktopApp.test.tsx (63 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 1faf7c9 (run 34157968656). Failure-Class: none
… Settings Desktop Settings Account already showed name from a successful profile read, but omitted company, job, and data protection that mobile Settings already displays when those fields are present. Account now shows those rows. It does not invent empty rows when they are null. Verification: bun run --cwd react-native test -- src/desktop/DesktopApp.test.tsx (64 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 320d851 (run 34158353196). Failure-Class: none
Desktop Settings Account already avoided Signed in to Omi after a nested non-retryable profile read, but a successful profile with a null email still used that invented identity line. Account now uses Email not set on this account, matching mobile Settings. Verification: bun run --cwd react-native test -- src/desktop/DesktopApp.test.tsx (65 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on a5ae2b8 (run 34158706505). Failure-Class: none
Desktop Settings Account already showed email from a successful profile read, but omitted Account id and treated a null name as no Name row. Account now shows those fields, using Name not set on this account when name is null, matching mobile Settings. Nested non-retryable profile reads still omit those rows. Verification: bun run --cwd react-native test -- src/desktop/DesktopApp.test.tsx (66 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 9c2280d (run 34158988868). Failure-Class: none
…ailed Wide Home search still said Saved data is unavailable above the mapped saved-data copy when every conversation and memory read was nested non-retryable. That parent line now uses the mapped copy and still omits Retry. Mixed library failures keep the generic parent with per-library OutcomeStatus copy. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx src/desktop/DesktopApp.test.tsx (84 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on a89cc84 (run 34159362860). Failure-Class: none
Explore kept a live Install control after nested non-retryable /v1/apps/enable, which advertised a write door that cannot succeed. Install now stays disabled and uses Apps-unavailable copy. Nested non-retryable /v1/apps/enabled reads still keep Install because enable POST may still work. Verification: bun run --cwd react-native test -- src/pages/pages.test.tsx (33 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 4d2acbb (run 34159766332). Failure-Class: none
Settings Privacy and macOS Alerts & Privacy kept live Opt in / Update controls after nested non-retryable recording-storage, training, or private-cloud-sync POSTs. Those controls now stay disabled and use account-setting unavailable copy. Each write door latches independently. Retryable 503s still keep the control live. Verification: bun run --cwd react-native test -- src/pages/pages.test.tsx src/desktop/DesktopApp.test.tsx (101 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 9e6fb12 (run 34160225491). Failure-Class: none
…read Conversations kept a live Refresh control after a nested non-retryable first-page library 503, which advertised a retry for a door that cannot succeed. Refresh is now omitted for that mapped unavailable copy, matching the macOS Home banner. Retryable first-page failures still offer Refresh. Verification: bun run --cwd react-native test -- src/pages/Conversations.test.tsx src/recordingTranscript.test.tsx src/chatConversationHistory.test.tsx (37 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 9c47a5c (run 34160771459). Failure-Class: none
Conversations and Memories still said More conversations/memories are available after a nested non-retryable later page omitted Load more, which advertised a continue door that cannot succeed. That status line is now omitted when the later-page notice is mapped unavailable copy. Retryable later-page failures still keep Load more and the more-available copy. Home conversations and tasks still report more-available without a Home pager. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx src/desktop/DesktopApp.test.tsx src/pages/Memories.test.tsx src/pages/Conversations.test.tsx (102 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 9bf8c4b (run 34161148773). Failure-Class: none
… page Tasks still said More tasks are available after a nested non-retryable later page omitted Load more, which advertised a continue door that cannot succeed. That status line is now omitted when the later-page notice is mapped unavailable copy. Retryable later-page failures still keep Load more and the more-available copy. Home tasks still report more-available without a Home pager. Verification: bun run --cwd react-native test -- src/pages/Tasks.test.tsx src/desktop/DesktopApp.test.tsx src/ui/ui.test.tsx (99 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on e2422d1 (run 34161784284). Failure-Class: none
Conversations, Memories, and Tasks empty searches still said More X are available after a nested non-retryable later page omitted Load more. That empty title advertised a continue door that cannot succeed. Those misses now use No loaded X match. An empty unfiltered page with remaining items still reports more-available instead of claiming No X yet. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx src/pages/Tasks.test.tsx src/pages/Conversations.test.tsx src/pages/Memories.test.tsx (49 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on bff42ff (run 34162200580). Failure-Class: none
Conversations already omits Refresh after nested non-retryable first-page library reads and still offers it on retryable failures. Memories and Tasks first-page error states had no recovery CTA. Wire the same Refresh omit for nested non-retryable copy and keep Refresh for retryable first-page failures on the non-mac Memories and Tasks pages. Verification: bun run --cwd react-native test -- src/pages/Memories.test.tsx src/pages/Tasks.test.tsx src/pages/Conversations.test.tsx (34 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 7ee8cd6 (run 34162607103). Failure-Class: none
Compact Home recaps, tasks, and mind map, and the compact Tasks tab, had no recovery CTA on retryable first-page library failures. Refresh is now offered there and omitted after nested non-retryable unavailable copy. Missing Settings/Apps/Conversations content stages still have no Refresh. Verification: bun run --cwd react-native test -- src/mobile/MobileAppSurface.test.tsx src/pages/Memories.test.tsx src/pages/Tasks.test.tsx (67 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 8429c82 (run 34163473853). Failure-Class: none
…or task page macOS Home still said "More conversations/tasks are available" after a nested non-retryable later page omitted Load more on those destinations. Home now omits that more-available copy for the closed door. First-page Home more-available without a Home pager is unchanged. Verification: bun run --cwd react-native test -- src/desktop/DesktopApp.test.tsx (71 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 3e1d36e (run 34163871299). Failure-Class: none
Wide Home and macOS Home still titled a search miss as more-available after a nested non-retryable later page omitted Load more. Those misses now use search-miss copy. An unfiltered empty Home with remaining items still reports more-available instead of claiming nothing is captured yet. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx src/desktop/DesktopApp.test.tsx src/pages/Conversations.test.tsx src/pages/Memories.test.tsx src/pages/Tasks.test.tsx (128 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on ce722cb (run 34164338081). Failure-Class: none
…er page Wide Home search still showed footer "More conversations/memories are available" after a nested non-retryable later page omitted Load more. OutcomeStatus now honors that closed continue door. First-page Home more-available without a closed door is unchanged. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx src/desktop/DesktopApp.test.tsx (95 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 97c85dc (run 34164818232). Failure-Class: none
Compact Home recap and task strips, and the compact Tasks tab, looked complete when the loaded page was incomplete or had more items. Those surfaces now keep the same completeness and more-available copy. Nested non-retryable later pages omit more-available copy. Verification: bun run --cwd react-native test -- src/mobile/MobileAppSurface.test.tsx src/ui/ui.test.tsx (68 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 1cb3a58 (run 34165112816). Failure-Class: none
Wide Home search footer reported conversation and memory completeness and hid task errors, incompleteness, and more-available copy. Search OutcomeStatus now includes the task page and omits more-available after a nested non-retryable later task page. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx (20 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 0e507e9 (run 34165452989). Failure-Class: none
Compact Home mind map preview looked complete when the loaded memory page was incomplete or had more items. The collapsed preview now keeps completeness and more-available copy. Nested non-retryable later pages omit more-available copy. Verification: bun run --cwd react-native test -- src/mobile/MobileAppSurface.test.tsx src/ui/ui.test.tsx (70 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 7614cb7 (run 34165750714). Failure-Class: none
Wide Home search hid task OutcomeStatus whenever conversation and memory reads both failed. Task completeness, more-available copy, and mapped task errors now still show. Conversation and memory footer rows stay behind the parent recovery line. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx __tests__/useDesktopReads.test.tsx (49 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 27cc153 (run 34165967212). Failure-Class: none
…d memories failed Wide Home search said "Showing saved data. Could not refresh." when conversation and memory reads both failed just because tasks still had rows. The search list is conversations and memories, so that parent line now uses the mapped conversation/memory copy. Mixed library failures still keep the generic refresh parent. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx (21 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 27126e8 (run 34166715948). Failure-Class: none
Wide Home search listed only conversations and memories, so a query that matched saved tasks could still say "No results". Matching task rows now join that list. A task page that did not load still omits those rows. macOS Home keeps tasks in its own section. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx __tests__/desktopReadClient.test.ts (77 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 51aa648 (run 34167259841). Failure-Class: none
Wide Home search listed untitled processing Listen/recording rows and empty summaries as blank gaps, even though Conversations, compact Daily Recaps, and macOS Home already use visible title and summary fallbacks. Those search rows now use the same copy. Search still indexes those fallbacks. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx (24 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 9a64d90 (run 34167758113). Failure-Class: none
Compact Home Daily Recap cards were display-only even though the Conversations tab already opens those same rows. Tapping a recap now opens that conversation detail. View All still opens the conversation list. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx src/mobile/MobileAppSurface.test.tsx src/pages/Conversations.test.tsx (86 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 6ef4dcb (run 34168682309). Failure-Class: none
Memories page, macOS memory rows, and wide Home search rendered empty bodies as blank gaps, and old /v3/memories namespaced entity: prefixes as raw titles. Those surfaces now use the same parsed visible text. Search indexes that copy. Verification: bun run --cwd react-native test -- src/ui/ui.test.tsx src/pages/Memories.test.tsx __tests__/desktopReadClient.test.ts __tests__/legacyOmiReads.test.ts (113 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on b90ec9d (run 34169316308). Failure-Class: none
macOS Home memory rows used a helper that preferred summary over title, so a memory with a headline and a longer body hid that headline. List titles now use the parsed title; memory cards still use the parsed body. Empty bodies still show visible fallback copy. Verification: bun run --cwd react-native test -- --runInBand (693 pass) && bun run --cwd pwa test (50 pass). GitHub Validate backend worker failed Client contract regressions on 49f083f (run 34169977662). Failure-Class: none
Compact Home Open calls routed to Conversations, which is already a tab and is not a phone-calls producer. That control is omitted until a calls door exists. Conversations stays on its tab. Verification: bun run --cwd react-native test -- --runInBand (695 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on 2d65d84 (run 34170252733). Failure-Class: none
Compact Home and the Tasks page labeled incomplete read-only tasks Open on controls that cannot open. Incomplete read-only rows stay Task; completed read-only rows stay Completed; Complete/Reopen stay when writes are available. Tasks page Open task still opens the editor when writes and an edit handler are present. Verification: bun run --cwd react-native test -- --runInBand (695 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on c61c541 (run 34170564410). Failure-Class: none
Compact Home Daily Recaps labeled cards with weekday-only dates, so a conversation from last month could read as Monday. Recaps now use the same Today/Yesterday/date grouping as Conversations, preferring startedAt then createdAt. Verification: bun run --cwd react-native test -- --runInBand (696 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on f25a1e7 (run 34171113179). Failure-Class: none
macOS Tasks labeled incomplete read-only rows Complete on a disabled control. Incomplete read-only rows stay Task; completed read-only rows stay Completed; Complete/Reopen stay when writes are available. Verification: bun run --cwd react-native test -- --runInBand (696 pass). GitHub Validate backend worker including Portable PostgreSQL 18.4 passed on fba3e21 (run 34171480621). Failure-Class: none
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #12914. Production chat writes stay unadmitted, but they now use the same nested error grammar the chat client already parses. Browser Settings, conversation detail, empty libraries, capture ownership, and the PWA development selector stop looking like empty success or a generic retryable outage when the producer, coverage, or door is missing.
Granted
chat.readconversation reads no longer dump everychat:row onto the first Listen-sequence page. ProductionGET /v1/conversationspages Listen and granted chat sessions together byupdatedAtdescending thenidascending, matching WorkerreadConversations/paginateConversations. Each page keeps the requestedlimit. The union cursor is a distinct HMAC policy from the Listen-sequence cursor, bound to the Listen revision and chat snapshot sequence. A Listen-sequence cursor cannot continue on the union path. The last item may be achat:or Listen row; the position table stores that identity instead of a fake Listen sequence. Missingchat.readkeeps the Listen sequence reader. Empty history still does not inventchat:chat-main. Migration 0058 is in the checksummed manifest.HEAD continues after the union page is worker-green:
2fea38f4d1/5e90b3d7e6/9c231cb7ca/7fa813af6f/51928e1989/59b1556925/34899a269d/23d1fba7e8/0baa4b0950/8a71bd029b/d74db69efc/7d8e9f0891/1941186ad7/ee83ece2a4/b3470ebc06/2e7944a829/8a6bc1b61e/f167d65b01/7cfd1cc9ed/83dae78a57/05b6a00930/d65bcf3fcb/f8ddd69f8b/8d8a7186da/78ede54213/9e4e6316f2/2360277217/fc56024139/96328b6ff9/f5637cf962/528e1e2d74/a10392f4f6/0459fda85e/97128c21d2/04524f08aa/71247a5d85/874d87687d/c2650d7f4c/8a1479b42b/4be501c906/1faf7c91ac/320d851045/a5ae2b8d92/9c2280dda8/a89cc8473a/4d2acbb59a/9e6fb129a1/9c47a5c78c/9bf8c4beef/e2422d1543/bff42ffece/7ee8cd617f/8429c828c3/3e1d36eec0/ce722cbdc0/97c85dc5be/1cb3a58fba/0e507e9392/7614cb77f0/27cc153c21/27126e8ac6/51aa6489e7/9a64d9027f/6ef4dcb9e4/b90ec9df4e/2d65d843c1/c61c54164b/f25a1e7b6e/fba3e2150fare worker-green including Portable PostgreSQL 18.4.e45def0560is waiting on GitHubValidate backend worker, including Portable PostgreSQL 18.4.49f083f2cffailed GitHubValidate backend workerat Client contract regressions (run 34169977662): macOS Home memory rows preferred summary over title. Portable PostgreSQL was skipped. Repaired in2d65d843c1.{error:{code:"capture_ownership_unavailable",retryable:false,action:"none"}}without inventing a receipt. Production identity-verification and authorization-source 503s stay{error:{code:"unavailable"}}withretry-after: 1.9a64d9027f: wide Home search includes matching tasks instead of claiming "No results" over a complete conversation/memory miss. A task page that did not load still omits those rows.6ef4dcb9e4: wide Home search rows use the same visible conversation title and summary fallbacks as Conversations, compact Daily Recaps, and macOS Home, instead of blank gaps for untitled processing Listen/recording rows or empty summaries.b90ec9df4e: compact Home Daily Recaps open the matching conversation detail instead of remaining display-only. View All still opens the conversation list.2d65d843c1: Memories page, macOS memory rows, and wide Home search use parsed visible memory text instead of blank bodies or rawentity:prefixes. Home list titles stay on the memory title; cards use the body. Search indexes that copy. Old/v3/memoriesstill does not invent provenance digests.c61c54164b: compact Home omits Open calls instead of routing that control to Conversations. Conversations stays on its tab. This does not invent a phone-calls producer.f25a1e7b6e: compact Home and the Tasks page no longer label a disabled read-only task control Open. Incomplete read-only rows stay Task; completed read-only rows stay Completed; Complete/Reopen stay when writes are available. Tasks page Open task still opens the editor when writes and an edit handler are present.fba3e2150f: compact Home Daily Recaps use the same Today/Yesterday/date grouping as Conversations instead of weekday-only labels, preferring startedAt then createdAt.e45def0560: macOS Tasks no longer labels a disabled read-only task control Complete or Reopen. Incomplete read-only rows stay Task; completed read-only rows stay Completed; Complete/Reopen stay when writes are available.Writes still need a source-owned entitlement producer. Settings identity/entitlements still need an owner-backed producer. This PR does not mount admission, project token claims, or invent completeness.
Why this boundary
Unmounted Hono
{error:"not_found"}(string) leftthrowBackendErrorwithcode: unknown, so send failures looked generic. Nested non-retryablenot_foundis the chat client's existing grammar and does not auto-retry. A live Ask/Send control after that door still looks like a working composer. Settings 503 without a producer is unavailable, not an empty signed-in page, and Retry-After on that door advertised a transient outage. Overlaying chats onto listen-sequence pages duplicated rows, skipped listen items, or minted a cursor the listen position table cannot save. Combined Home search that ignores an incomplete task page still claims a complete miss. Worker and production ownership 503s withretryable: trueorretry-afteradvertised a transient outage for a missing receipt producer. Native then reclassified other nested non-retryable ownership 503s asOMI_HTTP_TRANSPORT, which JavaScript treats as transient. Apps Retry that ignores nestedretryable:falseadvertised a live Retry for a catalogue door that cannot succeed until a producer exists. Generation cancel that maps nested non-retryable 404/503 toOMI_HTTP_TRANSPORTmakes Stop look like a blip. Desktop Apps gallery that ignores that same nested catalogue 503 claims a load blip instead of an unmounted catalogue. Memories later-page Load more that ignores nestedretryable:falseclaims a load blip for a door that cannot page further. NativeOMI_DEV_BACKEND_UNSUPPORTEDhistory that falls through to connection copy keeps Check again on a closed door. Conversation-detail Load older that replaces the loaded page with a full-page error makes persisted messages look gone. A later-history error that flips the composer into the resting stage claims "I'm ready." / "Nothing's waiting on you." over a blocked older cursor. Later Rewind Load more afterOMI_REWIND_UNAVAILABLEorOMI_REWIND_AUTHadvertises another page against a capability door that cannot succeed. A chat-write latch that survives Old/New switch keeps Ask disabled on a plane that may have writes, and keeps the previous plane's transcript. Desktop Conversations that report "More conversations are available" without Load more advertises a first-page window the Mac cannot continue. Desktop Home that reports "More memories are available" without Load more advertises a first-page window with no Memories destination. Nested non-retryable task-write 503s andOMI_DEV_BACKEND_UNSUPPORTEDthrows that classify as retryable advertise Retry for a door that cannot succeed. Write-opscontrol_unavailable503s must stay retryable. Native transcript GET throws ofOMI_DEV_BACKEND_UNSUPPORTEDor nestedretryable:falsethat always setretryable: trueadvertised Check again and "Transcript could not be loaded." for a closed door. Closed capture and ownership doors that still say "Reconnect your Omi" or "reopen the app" advertise a recovery action that cannot succeed until a producer exists. Closed task-write doors that omit Retry but still say "This change was not accepted" claim the edit was invalid instead of unavailable. NativeOMI_DEV_BACKEND_UNSUPPORTEDsend throws that already latch Ask but still say "Message not sent. Check your connection and try again" claim a blip instead of an unmounted write door. Nested non-retryablePOST /v1/users/*writes that reuse saved-data copy or "Settings change could not be saved. Try again" claim a library/local blip instead of a closed account-setting door. Desktop Home mixed Conversations & memories that shows a generic Load more while only paging memories looks like it continues conversations. Nested non-retryableGET /v1/users/*slices that still say "This saved data is not available" claim a library door instead of a closed account-setting door. Conversations, Memories, and Rewind Load more controls that still say generic Load more after Home memories and Tasks named their noun look like they continue a mixed list. Conversation-detail and mobile Home Load older that still say generic Load older after desktop Home named Load earlier messages look like they continue a mixed transcript. Desktop Settings Account that falls back to "Signed in to Omi" when/v1/users/profileis nested non-retryable invents a signed-in profile line over a closed account door. Desktop Alerts that treat a still-loading account snapshot as recording storage and private cloud sync being unavailable invent a closed privacy door, and a page-levelloadAccountSettingsthrow that leaves Account on "Loading account…" invents a load that cannot finish. Desktop Alerts that load/v1/users/training-data-opt-inbut never render it hide a closed account-setting door as if that privacy control does not exist. Desktop AI & Automation that load/v1/users/developer/webhooks/statusbut never render it hide a closed developer door as if webhook status does not exist. Connectors My Apps that says owned apps are unavailable until the account profile loads after a nested non-retryable/v1/users/profileread invents a load that cannot finish. Connectors Installed that keeps catalogueenabledbits after a nested non-retryable/v1/apps/enabledread invents an installed list the enablement door cannot confirm. The macOS Apps gallery that drops that same enabled-list error claims "No apps are available" or uninstalled tiles over a closed enablement door. Mobile Home recaps, tasks, and mind map that say "Couldn’t load …" after a nested non-retryable library 503 claim a transient load blip instead of the mapped unavailable door. Home, Tasks, and desktop Tasks that say "Task editing is unavailable for this connection" while the task read is still loading or after that read failed invent a closed write door over an unsettled or failed library read. Explore and the macOS gallery that say "Not installed" / "Not connected" after a nested non-retryable/v1/apps/enabledinvent a known-empty install state the enablement door cannot confirm. Wide Home search that says "Conversations are unavailable" / "Memories are unavailable" after a nested non-retryable library 503 claims a generic load blip instead of the mapped unavailable door. The macOS library banner that says "Some of your history isn't loaded yet" after every failed door is nested non-retryable claims a delay instead of a closed producer. Desktop Settings Current plan that omits already-loaded transcription seconds after a successful subscription read hides usage the mobile Settings Plan already shows. Desktop Settings Account that omits already-loaded company, job, and data protection after a successful profile read hides identity fields mobile Settings already shows. Desktop Settings Account that says "Signed in to Omi" when a successful profile read has no email invents a signed-in identity line over a known-empty email. Desktop Settings Account that omits already-loaded Account id and treats a null name as no Name row hides identity fields mobile Settings already shows. Wide Home search that says "Saved data is unavailable." above mapped saved-data copy when every library door failed claims a generic parent over a closed producer. Explore Install that stays live after a nested non-retryable/v1/apps/enablePOST advertises a write door that cannot succeed. Settings Privacy Opt in / Update that stay live after a nested non-retryable recording-storage, training, or private-cloud-sync POST advertise a write door that cannot succeed. Conversations Refresh that stays live after a nested non-retryable first-page library read advertises a retry for a door that cannot succeed. Conversations, Memories, and Tasks that still say "More X are available" after a nested non-retryable later page omitted Load more advertise a continue door that cannot succeed. Empty searches on those same closed later pages that still say "More X are available" advertise that continue door as the miss title instead of "No loaded X match." Memories and Tasks first-page error states that showed only "Memories/Tasks unavailable" with no Refresh left retryable library failures without a recovery CTA, while a live Refresh after nested non-retryable copy would advertise a retry for a door that cannot succeed. Compact Home recaps, tasks, and mind map, and the compact Tasks tab, that showed only mapped unavailable copy with no Refresh left retryable library failures without a recovery CTA on the surface that actually hosts those errors. macOS Home that still says "More conversations/tasks are available" after a nested non-retryable later page omitted Load more on those destinations advertises a continue door that already closed. A Home search miss that still says "More conversations/memories/tasks are available" after that same closed later page advertises the continue door as the miss title instead of search-miss copy. Claiming "Nothing captured yet" / "No tasks yet" on an unfiltered empty Home that still has more items would invent an empty library over remaining pages. Wide Home search OutcomeStatus that still says "More conversations/memories are available" after that closed later page advertises the continue door in the results footer even when the empty title already omitted it. Compact Home recap and task strips, and the compact Tasks tab, that show loaded rows from an incomplete or has-more page without coverage copy look like a complete library. Wide Home search OutcomeStatus that reports only conversation and memory completeness hides task errors, incompleteness, and more-available copy behind a search that already treats tasks as part of the combined library. Compact Home mind map preview that always shows the same collapsed nodes without coverage copy looks like a complete map over an incomplete or has-more memory page. Wide Home search that hides that task OutcomeStatus whenever conversation and memory reads both failed hides task coverage behind a parent line that only describes conversations or memories. Wide Home search that says "Showing saved data. Could not refresh." when conversation and memory doors both failed invents a loaded search list over empty conversation/memory rows just because tasks still have items. Wide Home search that lists only conversations and memories claims "No results" over tasks that match the query. Wide Home search rows that keep raw empty conversation titles and summaries render untitled processing Listen/recording rows as blank gaps after Conversations, compact Daily Recaps, and macOS Home already use visible fallbacks. Compact Home Daily Recaps that stay display-only hide conversation detail the Conversations tab already opens for those same rows. Memories page, macOS memory rows, and wide Home search that keep raw empty bodies or namespacedentity:prefixes render blank or machine-id rows after canonicalparseMemoryTextalready separates that prefix. A memory list helper that prefers summary over title hides a distinct Home headline. Compact Home Open calls that routes to Conversations invents a phone-calls door over a tab that already exists. Compact Home and Tasks page controls that say Open on a disabled read-only task invent an open action the write door cannot perform. Compact Home Daily Recaps that label cards with weekday-only dates make last-month conversations look like this week's Monday. macOS Tasks controls that say Complete on a disabled read-only task invent a write action the door cannot perform.Verification
fba3e2150fGitHubValidate backend workerpassed, including Portable PostgreSQL 18.4: https://github.com/BasedHardware/omi/actions/runs/34171480621Current HEAD
e45def0560is waiting on that same worker gate, including Portable PostgreSQL 18.4. Local RN suite:bun run --cwd react-native test -- --runInBand(696 pass).A GitHub “1 check success” notice is not worker-green. Remaining production-readiness is producer-gated (chat writes, Settings identity, DEV IAM, hardware). Linux cannot certify Apple Debug builds, ScreenCaptureKit, physical BLE, or iPad.
Linux cannot compile
scripts/test-apple-auth. Docker/test:postgresis still unavailable in this Cloud VM.Not verified here: applying migrations 55–58 to based-hardware-dev, Cloud Run deploy, live Firebase grants, Apple Debug builds, ScreenCaptureKit, physical BLE/iPad.
mainand production deploys are untouched. The New-backend query-origin fix is already onv5(dc0ca0524f/ #12914).Remaining (not this PR)
STAGING_CHAT_LIMITas a lifetime ceiling, not a subscription-period authorityentity:prefixes; Home list titles stay on the memory title. Compact Home omits Open calls instead of routing that control to Conversations. Compact Home and the Tasks page no longer label a disabled read-only task control Open. Compact Home Daily Recaps use the same Today/Yesterday/date grouping as Conversations. macOS Tasks no longer labels a disabled read-only task control Complete or Reopen. First-page Home more-available without a Home pager stays. An unfiltered empty Home with remaining items still reports more-available. Non-mac Memories and Tasks first-page reads and compact Home/Tasks match Conversations Refresh omit/offer. Remaining production-readiness is producer-gated. Do not hide Home conversations/tasks more-available copy just because Home has no pager. Do not claim "No X yet" on an empty unfiltered page that still has more items. Do not mount chat writes or invent Settings identity. Do not add Refresh to missing Settings/Apps/Conversations content stages. Do not expand the collapsed Mind Map.