Skip to content

Mobile UX consolidated pass#4503

Open
iscekic wants to merge 142 commits into
mainfrom
mobile-ux-consolidated
Open

Mobile UX consolidated pass#4503
iscekic wants to merge 142 commits into
mainfrom
mobile-ux-consolidated

Conversation

@iscekic

@iscekic iscekic commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Implements the consolidated mobile UX pass: every finding from the mobile UX audit (dead ends, eternal skeletons, invisible errors, missing CTAs, tab-bar/inset defects, disabled-state lies, silent mutations, a11y gaps), built as shared primitives first, then per-domain migrations, then cross-app sweeps.

Correctness & privacy (Phase 0)

  • Sentry replay/screenshots/view-hierarchy now gated on consent (off until accepted, re-disabled on revoke)
  • Route params runtime-validated (code reviewer + security agent) — malformed deep links can no longer coerce to GitHub config mutations
  • Security-agent settings no longer show a spurious "Unsaved changes" after a successful save (no more double-save path)
  • Agent chat drafts survive failed sends; errored attachments block sends, are retryable, and are never silently dropped
  • KiloClaw instance context resolves to explicit loading/error/not-found/ready states (no more eternal skeletons on stale deep links)
  • Login/device-auth got full recovery paths: cancel, fetch timeout, poll classification with backoff, persistence-failure retry
  • Backend timestamps parse via parseTimestamp everywhere (Hermes-safe); code-reviewer domain failures ({success:false}) now route to onError

Shared primitives (Phase 1)

TabScreenScrollView/useTabBarBottomPadding (single source for tab-bar clearance, ~40 screens migrated), useDetailScreenBottomPadding, QueryError variants + placement + retry spinner, EmptyState placement, Button 44pt targets + loading, ConfigureRow disabled/chevron truth, SheetHeader/PickerSheet, shared RenameModal, openExternalUrl (P7), FormField (uncontrolled, a11y error announcement), ChoiceRow (radio/checkbox semantics, single haptic owner), SpinningIcon + reduced-motion support (incl. skeleton shimmer), toaster ordering + Kilo-token styling, form-sheet detent helpers.

Domain passes (Phases 2–6)

  • Home/Agents/Kilo Chat: section-level error states with stale-data preservation, honest pull-to-refresh, optimistic session rename/delete, recoverable model/repo failures on new-session, canCreate gating, session-detail recovery + message-shaped skeletons, picker fallback headers + synchronous bridge init, kilo-chat cached-data-wins routing, token-failure retry, inline rename errors, bot-offline CTA, message retry-send (resolves the failed original), favorites with latest-write-wins optimistic updates, behaviorally-modal reaction picker, single creation affordance on empty surfaces
  • KiloClaw: entitlement-aware instance list + reachable create CTA, provisioning reaches terminal states with technical copy + timeout, onboarding step gating, lifecycle-operation serialization, destroy awaits outcome, billing final-term state, dashboard scoped failures, secure credential fields with single-field rotation, model/exec-policy/version-pin selection states (pagination capped + stale-data preserved), google/device-pairing feedback, actionable changelog entries
  • Profile/Org/Login: org screens surface query errors (no isLoading || !data traps), org boundary discriminates transient failure from stale org (retry vs re-select), sheets own their errors inline (toasts render behind iOS form sheets), field validation via FormField, role guards fail closed, role-aware empty-state CTAs, notifications-card failure feedback, forced-update store fallbacks, Kilo Pass inline feedback + StoreKit timeout, consent card caught mutations + pending states, login field labeling
  • Code Reviewer: discriminated provider/permission states (status errors no longer render the "connect" card), config states, permission guards on all nested routes, connect-form validation, auto-review readiness gating, manual-review provider path + inline URL validation, OptionList saves await outcomes with serialized config writes, review list/detail states (UNAUTHORIZED/FORBIDDEN/NOT_FOUND classified as permanent, no un-retriable retry)
  • Security Agent: role/capability states never masquerade as permission-denied, audit reports reachable from disabled/disconnected states, repository query states, honest analysis capacity (no "capacity full" during load), dashboard sync feedback + lastSync truth, filter modal converted to a native form sheet with a visible/clearable overdue filter, remediation cancel invalidates the right query + optimistic state, settings read-only truth + feature-scoped validation, validation-first dismiss sheet, 44pt targets, SLA zero state ("Not measured", never 100%)

Cross-app sweeps (Phase 7)

Empty/error placement per convention (centered full-screen with tab clearance; top-aligned inline), disabled-vs-loading visual contract, skeleton geometry matched to loaded content, press feedback on inert-feeling controls, KVRow overflow, status colors migrated to Focus tokens (new info family added in the same style), sentence-case copy pass, formatDate consolidation.

Product notes

  • Money formatting now uses @kilocode/app-shared helpers with Intl grouping: $1,234.50 (was $1234.50 at a few residual sites). Signed off.
  • Dates: all toLocaleDateString sites consolidated onto shared formatDate, which follows the device locale (numeric date style). Four sites moved from long month names to the numeric form.
  • Focus palette contrast fixes (light theme) — WCAG AA, measured with a relative-luminance calculator; warm character preserved by shifting lightness only:
Token Before After Before ratio After ratio Target
--muted-foreground #7a756b #6f6a61 3.94:1 4.62:1 4.5:1
--destructive #c25647 #be4e3f 4.26:1 4.61:1 4.5:1
--good #2f9a5f #278150 3.40:1 4.63:1 4.5:1
--warn #b27214 #9f6612 3.78:1 4.60:1 4.5:1
--input border (light) alpha 0.09 alpha 0.45 1.21:1 3.04:1 3:1 (UI)
--input border (dark) alpha 0.07 alpha 0.35 1.17:1 3.18:1 3:1 (UI)

Foreground-on-fill pairs (--good/--warn/--destructive badges) all clear 4.5:1 as well; dark text tokens already passed and were left unchanged. Tinted tile tokens updated to match. Root DESIGN.md now documents that mobile intentionally uses the Focus palette.

Verification

  • pnpm format && pnpm typecheck && pnpm lint && pnpm check:unused clean; 530 mobile + 192 app-shared + 91 kilo-chat-hooks tests green
  • Every task went through an independent spec+quality review with fix waves; a final whole-branch review verified: no boolean ||?? autofix regressions, no backend-string new Date(), error-before-skeleton branch ordering everywhere, single feedback owner per mutation (no double toast+inline, no silent mutations)
  • Pending: on-device matrix — Maestro over changed route families, iOS + Android 3-button-nav tab clearance, keyboard-over-CTA, toast visibility over form sheets (prior on-device finding contradicts the audit's D2 — re-verify after the toaster reordering), VoiceOver/TalkBack spot-checks, light/dark + large-text + reduced-motion. Note: kilo-chat-hooks changed (injected package) — re-inject and clear the Metro cache before device testing.

Known follow-ups (deliberately left)

  • KiloClaw dashboard Resources skeleton shows 3 rows vs 2 for null-flyRegion instances (crossfaded, not popped)
  • Some pre-existing security-finding PR/advisory links keep native Linking.openURL (system handoff arguably better UX than the in-app browser helper)
  • Settings-framework convergence (CN-2) and useConnectFlow dedupe remain deferred per the plan

Update — review round + second e2e pass (2026-07-12)

Review comments (all 18 kilobot findings valid, fixed, threads resolved)

  • kilo-chat retry: replaced "recreate message" with a server redeliverMessage op on the conversation DO — re-enqueues delivery of the existing row (no new message, no attachment re-linking), clears delivery_failed, publishes message.redelivered before enqueueing the attempt (so a fresh failure can't be clobbered by a delayed clear), requires exactly one eligible bot (no fake success with zero bots, no double-delivery with many). Fixes the "attachment already linked" and duplicate-row findings.
  • Sentry consent: 7.x has no runtime replay stop, so consent transitions now Sentry.close() before re-init, serialized through a chain promise that never rejects (a failed transition no longer poisons later ones); the applied-consent ref is un-marked on failure so the next change retries teardown.
  • Session rename/delete: per-session promise chain serializes distinct operations (delete during a settling rename, re-rename to a new title) so optimistic snapshots can't interleave or overwrite a newer result; identical duplicate taps still dedupe.
  • Others: new-session keeps cached repo/model selectors on background-refetch failure; version-pin treats cached null (unpinned) as valid; instance controls block Start/Redeploy during recovering/restoring; security-agent scope list keeps Personal reachable on an org-list outage (and the personal scope entry no longer inherits the shared org-list error); remediation cancel distinguishes "Cancellation requested" from "Remediation cancelled"; onboarding instance_stopped retry actually starts the instance; device-auth cancel aborts the in-flight POST.

Fixes from the second on-device pass (iOS)

  • formSheet picker headers (mode/model/repo) were mounted but painted over by the list — react-native-screens only honors a formSheet header when [header, scrollview] are the screen content's direct children; removed the wrapper View and marked the header collapsable={false}. Verified on-device.
  • device-auth 15s start-timeout was scoped to the whole start() including the auth-browser await, firing mid-sign-in and stomping state with a bogus error + zombie poll; now cleared as soon as the POST resolves. Verified on-device.
  • Reasoning-settings sheet VoiceOver collapse (same accessible={false} fix as the filter sheet); session search retry; provisioning pulse gated on Reduce Motion; header touch targets to 44pt via hitSlop; kiloclaw copy sentence-case + pairing-refresh a11y label.

Verification

  • Full static gate green (format/typecheck/lint/check:unused) across apps/mobile; 530 mobile + 91 kilo-chat-hooks + 107 kilo-chat pkg + 415 kilo-chat service tests pass.
  • Second full iOS e2e pass across agents/home, kiloclaw, profile/org, kilo-chat (incl. the new redeliver flow with attachments), code-reviewer, security-agent, login/device-auth, and a cross-app sweep (VoiceOver, Reduce Motion, Dynamic Type, dark mode). Every new fix reverified on-device.
  • Android: not run this round (emulator needs a host reboot); noted for a follow-up pass.

iscekic added 30 commits July 11, 2026 00:16
@iscekic iscekic self-assigned this Jul 11, 2026
@iscekic iscekic marked this pull request as ready for review July 11, 2026 15:43
…y, money-role gating, session-detail recovery

- code-reviewer manual review: show retryable QueryError on provider status-query failure instead of the connect empty state
- security-agent setup: clear the tab bar so the connect screen centers
- agents platform-filter sheet: mark backdrop + content pressables non-accessible so VoiceOver reaches individual controls
- profile credits: gate the org zero-balance Add credits CTA on money-role
- agent session detail: add Back to sessions to the personal-scope load error
- login: use toast.success for the resend confirmation
- code-reviewer platform error: use the server QueryError variant
Comment thread apps/mobile/src/app/_layout.tsx Outdated
Comment thread apps/mobile/src/components/agents/chat-composer.tsx
Comment thread apps/mobile/src/lib/hooks/use-session-mutations.ts Outdated
Comment thread apps/mobile/src/app/(app)/agent-chat/new.tsx Outdated
Comment thread apps/mobile/src/components/kilo-chat/message-presentation.ts Outdated
Comment thread apps/mobile/src/components/kiloclaw/instance-controls.tsx
Comment thread apps/mobile/src/lib/auth/use-device-auth.ts
Comment thread apps/mobile/src/components/security-agent/scope-list-screen.tsx Outdated
Comment thread apps/mobile/src/lib/hooks/use-security-findings.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-chat-hooks/src/use-messages.ts 757 The HTTP success write can erase a newer failure event

Fix these issues in Kilo Cloud

Files Reviewed (1 file)
  • packages/kilo-chat-hooks/src/use-messages.ts - 1 issue
Previous Review Summaries (5 snapshots, latest commit 9f2cdad)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 9f2cdad)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-chat-hooks/src/use-messages.ts 740 A missed redelivery event leaves the requesting client stale

Fix these issues in Kilo Cloud

Files Reviewed (3 files)
  • apps/mobile/src/lib/hooks/use-session-mutations.ts
  • packages/kilo-chat-hooks/src/use-messages.ts - 1 issue
  • services/kilo-chat/src/do/conversation-do.ts

Previous review (commit 3f0f446)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (9 files)
  • apps/mobile/src/app/(app)/agent-chat/mode-picker.tsx
  • apps/mobile/src/app/(app)/kiloclaw/[instance-id]/settings/device-pairing.tsx
  • apps/mobile/src/app/(app)/kiloclaw/[instance-id]/settings/google.tsx
  • apps/mobile/src/components/kiloclaw/dashboard-parts.tsx
  • apps/mobile/src/components/picker-sheet.tsx
  • apps/mobile/src/components/sheet-header.tsx
  • apps/mobile/src/lib/auth/use-device-auth.ts
  • apps/mobile/src/lib/hooks/use-security-agent.ts
  • services/kilo-chat/src/do/conversation-do.ts

Previous review (commit 504ca27)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 4
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/lib/hooks/use-sentry-consent-sync.ts 24 A failed revocation is not retried while consent stays revoked
apps/mobile/src/lib/hooks/use-session-mutations.ts 85 Duplicate suppression can discard the latest rename intent
packages/kilo-chat-hooks/src/use-messages.ts 768 The reconciliation refetch can overwrite a newer delivery failure
services/kilo-chat/src/do/conversation-do.ts 548 The external event push leaves redelivery outside the webhook serializer

Fix these issues in Kilo Cloud

Files Reviewed (10 files)
  • apps/mobile/src/app/_layout.tsx
  • apps/mobile/src/components/agents/reasoning-settings-modal.tsx
  • apps/mobile/src/lib/hooks/use-sentry-consent-sync.ts - 1 issue
  • apps/mobile/src/lib/hooks/use-session-mutations.ts - 1 issue
  • apps/mobile/src/lib/sentry-consent.ts
  • packages/kilo-chat-hooks/src/use-messages.ts - 1 issue
  • services/kilo-chat/src/__tests__/conversation-do.test.ts
  • services/kilo-chat/src/do/conversation-do.ts - 1 issue
  • services/kilo-chat/src/routes/handler.ts
  • services/kiloclaw/plugins/kilo-chat/src/synced/events.ts

Previous review (commit 58a0bf2)

Status: 6 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 6
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/lib/sentry-consent.ts 49 A rejected teardown permanently poisons later consent transitions
apps/mobile/src/lib/hooks/use-session-mutations.ts 107 Different-title renames can race and overwrite the newest title
packages/kilo-chat/src/events.ts 42 The standalone plugin copy of the event contract is stale
packages/kilo-chat-hooks/src/use-messages.ts 763 An ambiguous HTTP failure can roll back a committed redelivery
services/kilo-chat/src/do/conversation-do.ts 522 Redelivery uses an unvalidated bot target set
services/kilo-chat/src/do/conversation-do.ts 541 Redelivery success can be published after a newer delivery failure

Fix these issues in Kilo Cloud

Files Reviewed (31 files)
  • apps/mobile/src/app/(app)/agent-chat/new.tsx
  • apps/mobile/src/app/(app)/kiloclaw/[instance-id]/dashboard.tsx
  • apps/mobile/src/app/(app)/kiloclaw/[instance-id]/settings/device-pairing.tsx
  • apps/mobile/src/app/(app)/kiloclaw/[instance-id]/settings/version-pin.tsx
  • apps/mobile/src/app/_layout.tsx
  • apps/mobile/src/components/agents/chat-composer.tsx
  • apps/mobile/src/components/agents/session-list-content.tsx
  • apps/mobile/src/components/agents/session-list-header-actions.tsx
  • apps/mobile/src/components/agents/session-list-screen.tsx
  • apps/mobile/src/components/kilo-chat/hooks/use-conversation-message-controller.ts
  • apps/mobile/src/components/kilo-chat/message-presentation.test.ts
  • apps/mobile/src/components/kilo-chat/message-presentation.ts
  • apps/mobile/src/components/kiloclaw/instance-controls.tsx
  • apps/mobile/src/components/kiloclaw/onboarding-flow.tsx
  • apps/mobile/src/components/kiloclaw/onboarding/provisioning-step.tsx
  • apps/mobile/src/components/security-agent/scope-list-screen.tsx
  • apps/mobile/src/lib/auth/use-device-auth.ts
  • apps/mobile/src/lib/hooks/use-security-findings.ts
  • apps/mobile/src/lib/hooks/use-session-mutations.ts - 1 issue
  • apps/mobile/src/lib/sentry-consent.test.ts
  • apps/mobile/src/lib/sentry-consent.ts - 1 issue
  • packages/kilo-chat-hooks/src/use-messages.ts - 1 issue
  • packages/kilo-chat/src/client.ts
  • packages/kilo-chat/src/events.ts - 1 issue
  • packages/kilo-chat/src/types.ts
  • services/kilo-chat/src/__tests__/conversation-do.test.ts
  • services/kilo-chat/src/__tests__/helpers.ts
  • services/kilo-chat/src/__tests__/messages-routes.test.ts
  • services/kilo-chat/src/do/conversation-do.ts - 2 issues
  • services/kilo-chat/src/index.ts
  • services/kilo-chat/src/routes/handler.ts

Previous review (commit 63f995d)

Status: 12 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 12
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/app/_layout.tsx 118 Reinitializing Sentry does not tear down the previously active replay client
apps/mobile/src/components/agents/chat-composer.tsx 132 A completed send can erase the user's next draft
apps/mobile/src/lib/hooks/use-session-mutations.ts 80 The pending guard silently drops distinct operations on a session
apps/mobile/src/app/(app)/agent-chat/new.tsx 384 Background refetch failures hide usable cached selection data
apps/mobile/src/components/kilo-chat/message-presentation.ts 103 Retrying a message reuses attachment IDs that are already consumed
apps/mobile/src/components/kilo-chat/hooks/use-conversation-message-controller.ts 113 Successful retries only hide the failed message until the next refetch
apps/mobile/src/app/(app)/kiloclaw/[instance-id]/settings/version-pin.tsx 78 A valid unpinned cache state is treated as missing data
apps/mobile/src/components/kiloclaw/instance-controls.tsx 34 Lifecycle controls fail open for recovery and restore states
apps/mobile/src/components/kiloclaw/onboarding/provisioning-step.tsx 192 Try again cannot recover an instance that stopped during provisioning
apps/mobile/src/lib/auth/use-device-auth.ts 175 Cancel does not abort the in-progress device-code request
apps/mobile/src/components/security-agent/scope-list-screen.tsx 33 An organization-list outage blocks the independent personal scope
apps/mobile/src/lib/hooks/use-security-findings.ts 323 Running remediations are reported as cancelled before cancellation completes

Fix these issues in Kilo Cloud

Files Reviewed (282 files)
  • apps/mobile/src/app/_layout.tsx - 1 issue
  • apps/mobile/src/components/agents/chat-composer.tsx - 1 issue
  • apps/mobile/src/lib/hooks/use-session-mutations.ts - 1 issue
  • apps/mobile/src/app/(app)/agent-chat/new.tsx - 1 issue
  • apps/mobile/src/components/kilo-chat/message-presentation.ts - 1 issue
  • apps/mobile/src/components/kilo-chat/hooks/use-conversation-message-controller.ts - 1 issue
  • apps/mobile/src/app/(app)/kiloclaw/[instance-id]/settings/version-pin.tsx - 1 issue
  • apps/mobile/src/components/kiloclaw/instance-controls.tsx - 1 issue
  • apps/mobile/src/components/kiloclaw/onboarding/provisioning-step.tsx - 1 issue
  • apps/mobile/src/lib/auth/use-device-auth.ts - 1 issue
  • apps/mobile/src/components/security-agent/scope-list-screen.tsx - 1 issue
  • apps/mobile/src/lib/hooks/use-security-findings.ts - 1 issue
  • 270 additional changed files - 0 issues

Reviewed by gpt-5.6-sol-20260709 · Input: 80.4K · Output: 7.8K · Cached: 720K

Review guidance: REVIEW.md from base branch main

iscekic added 4 commits July 11, 2026 23:51
…ting them

Retry-send previously composed a brand-new message from the failed one:
attachment blocks reused already-linked attachment IDs (server rejects with
'Attachment is already linked', so retries with attachments always failed),
and the original row kept delivery_failed=1 server-side, resurfacing next to
the successful retry on any refetch.

New conversation-DO redeliverMessage op re-enqueues delivery of the existing
row: clears delivery_failed, reuses the stored content and reply context,
touches no attachments, and is an idempotent no-op when the message is not
in a failed state. Human members receive a message.redelivered event
(mirror of message.delivery_failed) so all clients clear the flag; the
mobile retry action now calls it via useRedeliverMessage with an optimistic
flag clear.
Sentry.init in @sentry/react-native 7.x binds a new client without closing
the previous one, and replay sampling is only read at init — so revoking
consent left an in-flight replay recording and accumulated clients on every
transition. The SDK exposes no runtime replay start/stop (native bridge only
has captureReplay/getCurrentReplayId), so consent transitions now await
Sentry.close() before re-initing, serialized through a lifecycle promise so
a fast accept-revoke cannot interleave. Also drops the redundant duplicate
init on mount.
…law, security agent, login

- chat composer: lock text input and attachment controls while a send is in
  flight so the success path cannot wipe a draft typed during the await
- session mutations: key the pending guard by operation (and rename title)
  instead of bare session id, so a delete during a settling rename is no
  longer silently dropped
- new session: only replace the repo/model selectors with an error state
  when there is no cached data; background refetch failures keep selectors
- version pin: treat cached null (valid unpinned state) as data — only
  data === undefined is an initial-load failure
- instance controls: block Start/Redeploy during recovering/restoring, which
  the backend rejects anyway
- security-agent scope list: an organizations.list failure degrades only the
  org section; the Personal scope row stays reachable
- remediation cancel: distinguish 'Cancellation requested' (attempt already
  running) from 'Remediation cancelled' (queued attempt removed)
- kiloclaw onboarding: retry from the instance_stopped terminal state now
  fires the start mutation — previously it looped back to the same state
- device auth: cancel aborts the in-flight device-code POST and a resolving
  request can no longer revive a cancelled flow; the 15s timeout owns its
  error state
… targets

- failed session search shows a retryable QueryError (Clear search kept
  below) instead of a dead-end no-match state; pull-to-refresh retries the
  search query too while one is active
- kiloclaw provisioning breathing pulse goes static under Reduce Motion,
  matching Skeleton/SpinningIcon
- header icon buttons (session-list +/filter, dashboard rename, device
  pairing refresh) get hitSlop to reach 44pt effective targets
Comment thread apps/mobile/src/lib/sentry-consent.ts
Comment thread apps/mobile/src/lib/hooks/use-session-mutations.ts Outdated
Comment thread packages/kilo-chat/src/events.ts
Comment thread packages/kilo-chat-hooks/src/use-messages.ts Outdated
Comment thread services/kilo-chat/src/do/conversation-do.ts Outdated
Comment thread services/kilo-chat/src/do/conversation-do.ts
iscekic added 3 commits July 12, 2026 01:27
…t, session ops

- sentry consent: the close+init chain promise never rejects (resolved via a
  gate in finally), so a failed transition can't poison later ones; the
  caller un-marks the applied consent state on failure so the next change
  re-attempts teardown. Effect extracted to useSentryConsentSync.
- session ops: per-session promise chain serializes rename/delete so
  optimistic snapshots can't interleave and an older request can't overwrite
  a newer result; identical duplicate taps still dedupe
- redeliver: DO requires exactly one eligible bot (zero bots no longer
  clears the flag and fakes success; multiple would double-deliver) and
  publishes message.redelivered BEFORE enqueueing the delivery attempt, so a
  fresh delivery failure can't be clobbered by a delayed clear event; the
  hooks-side retry now always invalidates after a rollback because a lost
  HTTP response can hide a committed redelivery
- synced plugin copy of the kilo-chat event contract regenerated
Backdrop and content pressables default to accessible=true, collapsing the
whole sheet into one VoiceOver node with the Switch unreachable — same bug
class as the platform-filter sheet, same accessible={false} fix.
- 'Copy Command' / 'Destroy Instance' → sentence case per the copy convention
- device-pairing header refresh icon gets a role + label for screen readers
Comment thread apps/mobile/src/lib/hooks/use-session-mutations.ts Outdated
Comment thread packages/kilo-chat-hooks/src/use-messages.ts Outdated
Comment thread services/kilo-chat/src/do/conversation-do.ts Outdated
iscekic added 4 commits July 12, 2026 02:26
Even a disabled organizations.list observer surfaces the shared cache
entry's error state, so an org-list failure rendered the personal scope
entry as a full-screen error although every personal securityAgent call
succeeds. The role query now masks query state entirely for the personal
scope, where the org list is irrelevant.
…ped to the POST

- SheetHeader was invisible on formSheet pickers: react-native-screens lays
  out a formSheet's scroll view natively and only honors a header when
  [header, scroll view] are the screen content's direct children — the
  wrapping View made it pin the list over the header. PickerSheet drops the
  wrapper (fragment) and marks the header collapsable={false} so view
  flattening can't recreate the bug; mode-picker migrates to PickerSheet.
  Verified on-device: mode + model pickers now show title + Done.
- device-auth: the 15s start timeout now clears as soon as the POST
  resolves. start() stays suspended on the auth browser await for as long
  as the sheet is open, so the timer previously fired mid-sign-in, stomped
  the live pending/idle state with a bogus error, and left a zombie poll
  running behind it.
The bots.length !== 1 guard already narrows bots[0] to ActiveMemberRow; the
root oxlint config forbids the non-null assertion and flags it as unnecessary.
…event-driven clear

- session mutations: dedup only an ADJACENT identical op (repeat of the
  chain tail) instead of any op in a global set, so rename A -> B -> A runs
  the final A and the user's latest intent wins; double-taps still coalesce
- kilo-chat redeliver (DO): reserve the webhook-chain slot synchronously with
  no external await first, so a concurrent request can't slot a later message
  ahead of the redelivery or run delivery out of order; the redelivered event
  is pushed inside the serialized task, strictly before deliverToBot
- kilo-chat redeliver (client): drop the optimistic clear + guarded restore +
  invalidate; the server's message.redelivered event is the single source of
  truth for the flag, which removes both the rollback ambiguity on an unclear
  HTTP error and the refetch race that could overwrite a newer delivery
  failure with a stale pre-failure snapshot
Comment thread packages/kilo-chat-hooks/src/use-messages.ts Outdated
…via event

pushEventToHumanMembers is best-effort, so a requesting client whose socket
dropped would miss message.redelivered and keep showing Retry indefinitely
even though the server cleared the flag and retried. Apply the clear on HTTP
success as a targeted single-message cache write (not optimistic, not a
refetch); a strictly-later message.delivery_failed event still restores
failure if the retry ultimately fails.
old
? updateMessageInPages(old, variables.messageId, msg => ({
...msg,
deliveryFailed: false,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: The HTTP success write can erase a newer failure event

The HTTP response and websocket events are independent delivery channels. Even though the server orders message.redelivered before the retry attempt, a fast message.delivery_failed event can reach this handler before the mutation response; this unconditional onSuccess write then changes the cache back to deliveryFailed: false. The server row remains failed, but the UI hides Retry until another refetch. Guard the success write against a failure event observed after this mutation started, or carry an attempt/version through both paths.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid in theory, but this specific ordering is practically unreachable given the current DO structure: redeliverMessage returns its HTTP response immediately after synchronously reserving the webhook slot — before deliverToBot runs. A message.delivery_failed event can only be produced by that delivery attempt exhausting its retries (2 retries with 500ms/1s backoff), so it is always generated seconds after the HTTP ack has already been sent. For it to clobber this onSuccess write, the WS event would have to overtake an already-in-flight HTTP response by several seconds.

The residual is also self-healing (a later refetch/reconnect reconciles from the server row) and non-data-loss — worst case the Retry affordance is briefly hidden.

Fully closing the HTTP-ack-vs-WS-event tie does require carrying a monotonic attempt/version through both channels (message row + both event payloads + client merge), which is a schema-migration-scale change I judged disproportionate to a practically-unreachable, self-healing UI race inside this UX PR. Leaving this thread open rather than resolving it so a maintainer can decide whether to prioritize the attempt-token work as a follow-up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant