Skip to content

release: onboarding reliability and post-0.0.103 fixes#571

Open
alichherawalla wants to merge 299 commits into
mainfrom
fix/onboarding-analyzing-device-hang
Open

release: onboarding reliability and post-0.0.103 fixes#571
alichherawalla wants to merge 299 commits into
mainfrom
fix/onboarding-analyzing-device-hang

Conversation

@alichherawalla

@alichherawalla alichherawalla commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Consolidates the onboarding reliability fix and the recent post-0.0.103 work into one release candidate.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (code change that neither fixes a bug nor adds a feature)
  • Chore (build process, CI, dependency updates, etc.)

Screenshots / Screen Recordings

The UI regressions are covered by rendered integration tests. Manual screenshot capture remains for release QA.

Android

Before After
Onboarding could remain on Analyzing your device... Setup renders without waiting for network metadata; 11 GB devices show 11.00 GB RAM

iOS

Before After
Onboarding could remain on Analyzing your device... Setup renders without waiting for network metadata; physical RAM is displayed

Checklist

General

  • My code follows the project's coding style and conventions
  • I have performed a self-review of my code
  • I have added/updated comments where the logic isn't self-evident
  • My changes generate no new warnings or errors

Testing

  • I have tested on Android (native compile, lint, and unit suite)
  • I have tested on iOS (physical device or simulator)
  • I have tested in light mode and dark mode
  • Existing tests pass locally (npm test)
  • I have added tests that prove my fix is effective or my feature works

React Native Specific

  • No new native module without corresponding platform implementation (Android + iOS)
  • New native modules are added to the Xcode project build target (project.pbxproj)
  • No hardcoded pixel values — uses SPACING / TYPOGRAPHY constants from the theme
  • Styles use useThemedStyles pattern (not inline or static StyleSheet.create)
  • Animations/gestures work smoothly on both platforms
  • Large lists use FlatList / FlashList (not .map() inside ScrollView)
  • No unnecessary re-renders introduced

Performance & Models

  • Downloads / long-running tasks report progress to the UI
  • File paths are resolved correctly on both platforms (no hardcoded / vs \\)
  • Large files (models, assets) are not committed to the repository

Security

  • No secrets, API keys, or credentials are included in the code
  • User input is validated/sanitized where applicable

Related Issues

Supersedes #560, #561, #568, and #569.

Additional Notes

Local verification:

  • 557 Jest suites passed; 7,819 tests passed and 4 skipped.
  • Coverage: 90.44% statements, 84.18% branches, 85.74% functions, 91.72% lines.
  • Targeted onboarding/model regressions: 7 suites and 70 tests passed.
  • TypeScript, ESLint, dependency-cruiser, and knip passed.
  • Android compile, lint, and tests passed (BUILD SUCCESSFUL, 589 tasks).
  • iOS could not be run locally because the configured iPhone 16e simulator is not installed; CI/device QA must provide that signal.
  • Jest reports existing post-teardown async leaks under force-exit. These are tracked as audit debt and are not introduced by this release.

Summary by CodeRabbit

  • New Features

    • Model browsing now shows device-fit indicators and includes models that can run within the device’s maximum memory capacity.
    • Added a retry option when model file details fail to load.
    • Onboarding now displays total device memory and becomes available without waiting for model-file searches.
  • Bug Fixes

    • Improved cleanup reporting when cancelling downloads.
    • Added timeouts for model-file requests to prevent indefinite loading.
  • Documentation

    • Streamlined engineering and repository guidance.

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Too many files!

This PR contains 451 files, which is 151 over the limit of 300.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Usage-priced reviews support at most 300 files.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7692f474-afd7-4083-b20a-816e98ebb27c

📥 Commits

Reviewing files that changed from the base of the PR and between 9cacd2f and eb58b51.

⛔ Files ignored due to path filters (1)
  • docs/RELEASE_TEST_CHECKLIST.csv is excluded by !**/*.csv
📒 Files selected for processing (524)
  • .gitignore
  • .husky/pre-push
  • AGENTS.md
  • App.tsx
  • CLAUDE.md
  • README.md
  • __tests__/hardening/batch2-send.test.ts
  • __tests__/hardening/batch5-speakMessageStateMachine.test.ts
  • __tests__/hardening/batch9-diagnostics-debuglog.test.ts
  • __tests__/harness/appJourney.ts
  • __tests__/harness/fullAppRemoteJourney.ts
  • __tests__/harness/nativeBoundary.ts
  • __tests__/harness/remoteHarness.ts
  • __tests__/harness/sqliteFake.ts
  • __tests__/integration/app/appLockCannotBypassFullApp.rendered.redflow.test.tsx
  • __tests__/integration/app/bootNotBlockedByDownloadDb.rendered.test.tsx
  • __tests__/integration/app/corruptPersistenceRecovery.rendered.redflow.test.tsx
  • __tests__/integration/app/emptyStates.rendered.happy.test.tsx
  • __tests__/integration/app/freshInstallOnboarding.rendered.happy.test.tsx
  • __tests__/integration/app/interruptedPersistenceFullApp.rendered.redflow.test.tsx
  • __tests__/integration/app/persistedSchemaMigrationFullApp.rendered.happy.test.tsx
  • __tests__/integration/app/proExtensionFailureFullApp.rendered.redflow.test.tsx
  • __tests__/integration/app/relaunchPersistence.rendered.happy.test.tsx
  • __tests__/integration/app/startupFilesystemFailureFullApp.rendered.redflow.test.tsx
  • __tests__/integration/audio/audioBubbleSpeechTextSingleSource.redflow.test.tsx
  • __tests__/integration/audio/chatModeDictationFullApp.rendered.happy.test.tsx
  • __tests__/integration/audio/kokoroDownloadConcurrencyFullApp.rendered.happy.test.tsx
  • __tests__/integration/audio/kokoroDownloadConsistency.test.ts
  • __tests__/integration/audio/kokoroMidDownloadTruthFullApp.rendered.redflow.test.tsx
  • __tests__/integration/audio/litertChatSttToInputBox.rendered.redflow.test.tsx
  • __tests__/integration/audio/micDoubleTapRaceCollision.rendered.redflow.test.tsx
  • __tests__/integration/audio/micStopsOnLeaveFullApp.rendered.redflow.test.tsx
  • __tests__/integration/audio/microphonePermissionFullApp.rendered.happy.test.tsx
  • __tests__/integration/audio/slideCancelThenRecordFullApp.rendered.redflow.test.tsx
  • __tests__/integration/audio/speakReplyFullApp.rendered.happy.test.tsx
  • __tests__/integration/audio/streamingPlayback.test.ts
  • __tests__/integration/audio/streamingStateMachine.test.ts
  • __tests__/integration/audio/ttsDeleteResidencyStale.redflow.test.ts
  • __tests__/integration/audio/ttsPressureRecoveryFullApp.rendered.redflow.test.tsx
  • __tests__/integration/audio/voiceArtifactsFullApp.rendered.happy.test.tsx
  • __tests__/integration/audio/voiceCalculatorFullApp.rendered.happy.test.tsx
  • __tests__/integration/audio/voiceImageFullApp.rendered.happy.test.tsx
  • __tests__/integration/audio/voiceModeCalculatorJourney.rendered.happy.test.tsx
  • __tests__/integration/audio/voiceModeImageJourney.rendered.happy.test.tsx
  • __tests__/integration/audio/voiceModeResendEnhancedImage.rendered.redflow.test.tsx
  • __tests__/integration/audio/voiceModeResendImageRoutes.rendered.redflow.test.tsx
  • __tests__/integration/audio/voiceModeStrayEmptyBubble.rendered.redflow.test.tsx
  • __tests__/integration/audio/voiceModeThinkingBlockWidth.rendered.redflow.test.tsx
  • __tests__/integration/audio/voiceStopFullApp.rendered.redflow.test.tsx
  • __tests__/integration/audio/voiceTranscriptFullApp.rendered.happy.test.tsx
  • __tests__/integration/audio/whisperRealtimeBlockedRecovers.redflow.test.tsx
  • __tests__/integration/audio/whisperStartSupersededNoGhost.redflow.test.tsx
  • __tests__/integration/chat/attachmentPreviewFullApp.rendered.happy.test.tsx
  • __tests__/integration/chat/conversationCrudFullApp.rendered.happy.test.tsx
  • __tests__/integration/chat/imageAttachmentDurabilityFullApp.rendered.redflow.test.tsx
  • __tests__/integration/chat/micDownloadFullApp.rendered.redflow.test.tsx
  • __tests__/integration/chat/newChatModelSelectionFullApp.rendered.redflow.test.tsx
  • __tests__/integration/chat/nonVisionImageRefusalFullApp.rendered.happy.test.tsx
  • __tests__/integration/chat/photoPermissionDeniedFullApp.rendered.happy.test.tsx
  • __tests__/integration/chat/photoPermissionFirstAttachFullApp.rendered.happy.test.tsx
  • __tests__/integration/chat/remoteEnhanceSkipped.redflow.test.ts
  • __tests__/integration/chat/thinkingAcrossToolCall.test.tsx
  • __tests__/integration/chat/toolEmbeddingStaleDim.redflow.test.ts
  • __tests__/integration/chat/toolEmptyFinal.redflow.test.tsx
  • __tests__/integration/chat/toolEmptyFinalFullApp.rendered.redflow.test.tsx
  • __tests__/integration/chat/toolMessyJson.rendered.redflow.test.tsx
  • __tests__/integration/chat/toolStringifiedArgs.rendered.redflow.test.tsx
  • __tests__/integration/chat/voiceNoteChatModeEmptyTurn.redflow.test.ts
  • __tests__/integration/downloads/cancelAndDuplicateDownloadFullApp.rendered.happy.test.tsx
  • __tests__/integration/downloads/downloadCountDivergence.rendered.redflow.test.tsx
  • __tests__/integration/downloads/downloadQueueDuringLocalGenerationFullApp.rendered.happy.test.tsx
  • __tests__/integration/downloads/downloadedCountBadge.rendered.happy.test.tsx
  • __tests__/integration/downloads/foregroundHydrationDedupFullApp.rendered.happy.test.tsx
  • __tests__/integration/downloads/imageExtractionKillRelaunchFullApp.rendered.redflow.test.tsx
  • __tests__/integration/downloads/imageExtractionMismatchRetryFullApp.rendered.redflow.test.tsx
  • __tests__/integration/downloads/imageModelDownload.rendered.happy.test.tsx
  • __tests__/integration/downloads/imageModelQueuedCardFullApp.rendered.happy.test.tsx
  • __tests__/integration/downloads/imageNetworkRetryFinalizesFullApp.rendered.redflow.test.tsx
  • __tests__/integration/downloads/iosImageStagingPurgedRedownloads.redflow.test.ts
  • __tests__/integration/downloads/iosImageStagingPurgedRedownloads.rendered.redflow.test.tsx
  • __tests__/integration/downloads/iosInterruptedNoFailedEntry.redflow.test.ts
  • __tests__/integration/downloads/iosTextRetryReissues.rendered.redflow.test.tsx
  • __tests__/integration/downloads/litertModelDownload.rendered.happy.test.tsx
  • __tests__/integration/downloads/networkFailureRetry.rendered.redflow.test.tsx
  • __tests__/integration/downloads/queuedDownloadsKillDrainFullApp.rendered.happy.test.tsx
  • __tests__/integration/downloads/queuedDownloadsRelaunch.rendered.happy.test.tsx
  • __tests__/integration/downloads/queuedDownloadsSurviveKill.redflow.test.ts
  • __tests__/integration/downloads/secondWhisperDownloadFullApp.rendered.happy.test.tsx
  • __tests__/integration/downloads/sttModelDownload.rendered.happy.test.tsx
  • __tests__/integration/downloads/textModelDownload.rendered.happy.test.tsx
  • __tests__/integration/downloads/textRetryReissuesOnIosLostDownloadId.rendered.redflow.test.tsx
  • __tests__/integration/downloads/ttsModelDownload.rendered.happy.test.tsx
  • __tests__/integration/downloads/visionModelDownload.rendered.happy.test.tsx
  • __tests__/integration/downloads/whisperDeleteCancelsOther.rendered.redflow.test.tsx
  • __tests__/integration/downloads/whisperTruncatedListed.rendered.redflow.test.tsx
  • __tests__/integration/gallery/galleryDeleteFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/airplaneModeLocalFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/backgroundForegroundGenerationFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/backgroundForegroundWithDownloadsFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/batchSizeAppliesFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/calculatorToolFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/classifierDoesNotBecomeChatModel.rendered.redflow.test.tsx
  • __tests__/integration/generation/contextFullNewChatFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/contextLengthAppliesFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/coreGenerationRecovery.rendered.redflow.test.tsx
  • __tests__/integration/generation/datetimeToolFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/deviceInfoToolFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/editAndResendFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/enhancementNoThinking.rendered.redflow.test.tsx
  • __tests__/integration/generation/enhancementNoThinkingFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/enhancementProgressFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/enhancementStreamingProgress.rendered.redflow.test.tsx
  • __tests__/integration/generation/firstLiteRTMessageFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/firstMessageLazyLoadFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/gemmaThinkingToolFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/generatedImageGalleryFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/generationFlow.test.ts
  • __tests__/integration/generation/ggufCpuBackendFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/ggufGpuFallbackFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/ggufGpuLayersFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/ggufNpuBackendFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/ggufOpenClBackendFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/gpuFallbackNoticeVisible.rendered.redflow.test.tsx
  • __tests__/integration/generation/imageGenerateAndRender.rendered.happy.test.tsx
  • __tests__/integration/generation/imageGenerationFlow.test.ts
  • __tests__/integration/generation/imageSizeFloorFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/imageSizeGuidanceFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/imageWarmupNoticeFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/killMidGenerationRecoveryFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/litertCompactionPersistenceFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/litertCpuFailureRecoveryFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/litertSamplerChangeFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/litertTerminalContract.test.ts
  • __tests__/integration/generation/litertThinkingToolFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/longOutputCutoffFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/longTextWrappingFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/messageActionsFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/messyToolJsonFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/midChatModelSwitchFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/mtpEmbeddedDraftHeads.rendered.happy.test.tsx
  • __tests__/integration/generation/nonDrawRoutesToTextFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/parallelToolsFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/plainReplyNoThinkTagsFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/queuedChatFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/queuedForceImagePreservesMode.rendered.redflow.test.tsx
  • __tests__/integration/generation/queuedSendFeedback.test.ts
  • __tests__/integration/generation/regenerateReplyFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/reloadRaceKeepsThinking.rendered.redflow.test.tsx
  • __tests__/integration/generation/reloadRaceKeepsThinkingFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/remoteDisconnectMidGenerationFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/remoteEnhancementFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/remoteFailureRecoveryFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/remoteModelIndicatorFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/remoteModelRepliesFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/remoteParallelTools.rendered.happy.test.tsx
  • __tests__/integration/generation/remoteParallelToolsFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/remoteProviderRouting.test.ts
  • __tests__/integration/generation/remoteReasoningFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/remoteThinkingToolFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/resendImageFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/resendImageRoutes.rendered.redflow.test.tsx
  • __tests__/integration/generation/resendImageRoutesLlama.rendered.redflow.test.tsx
  • __tests__/integration/generation/resendImageTurnFallsBackToText.rendered.redflow.test.tsx
  • __tests__/integration/generation/sharePromptOnceFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/staleFailureCardFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/systemPromptAppliesFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/temperatureAppliesFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/thinkingHeaderFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/thinkingRendersInBlockMidStream.rendered.redflow.test.tsx
  • __tests__/integration/generation/toolTurnReasoningRenders.rendered.redflow.test.tsx
  • __tests__/integration/generation/topPAppliesFullApp.rendered.happy.test.tsx
  • __tests__/integration/generation/unifiedModelSelection.test.ts
  • __tests__/integration/generation/visionDecodeRecoveryFullApp.rendered.redflow.test.tsx
  • __tests__/integration/generation/webSearchToolFullApp.rendered.happy.test.tsx
  • __tests__/integration/happy/copyMessage.happy.test.tsx
  • __tests__/integration/happy/gpuInitTimeoutFallback.rendered.happy.test.tsx
  • __tests__/integration/happy/imageBackends.happy.test.tsx
  • __tests__/integration/happy/imageIntentRouting.happy.test.tsx
  • __tests__/integration/happy/imageLightbox.happy.test.tsx
  • __tests__/integration/happy/imageModeToggle.happy.test.tsx
  • __tests__/integration/happy/imageOomCard.happy.test.tsx
  • __tests__/integration/happy/multimodalVision.happy.test.tsx
  • __tests__/integration/happy/smartBudgeting.happy.test.tsx
  • __tests__/integration/happy/speakMessage.happy.test.tsx
  • __tests__/integration/happy/tools.happy.test.tsx
  • __tests__/integration/home/remoteActiveTextCountFullApp.rendered.happy.test.tsx
  • __tests__/integration/image/imageTunablesReadFreshFromStore.redflow.test.ts
  • __tests__/integration/knowledge-base/embeddingSidecarResident.rendered.happy.test.tsx
  • __tests__/integration/knowledge-base/indexDocumentRollback.redflow.test.ts
  • __tests__/integration/knowledge-base/kbIndexEmbedFailAbort.rendered.redflow.test.tsx
  • __tests__/integration/knowledge-base/projectKnowledgeBaseFullApp.rendered.happy.test.tsx
  • __tests__/integration/knowledge-base/searchKnowledgeBaseRoundtrip.test.ts
  • __tests__/integration/memory/aggressiveDirtyOverCommit.rendered.redflow.test.tsx
  • __tests__/integration/memory/aggressiveLargerModelFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/budgetRedflow.test.ts
  • __tests__/integration/memory/ejectAllUnloadsEveryType.rendered.redflow.test.tsx
  • __tests__/integration/memory/ejectOneResidentFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/heavyModelSidecarsFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/imageMemoryCard.guard.test.tsx
  • __tests__/integration/memory/imageToChatSwapFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/lazyReloadAfterEject.rendered.redflow.test.tsx
  • __tests__/integration/memory/loadingModeSharedPersistence.rendered.happy.test.tsx
  • __tests__/integration/memory/loadingModes.redflow.test.ts
  • __tests__/integration/memory/loadingModesFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/loadingModesInMemory.rendered.happy.test.tsx
  • __tests__/integration/memory/modelSelectorEjectResident.rendered.redflow.test.tsx
  • __tests__/integration/memory/modelSelectorShowsLoadedRam.rendered.redflow.test.tsx
  • __tests__/integration/memory/osMemoryWarningFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/overrideFloor.redflow.test.ts
  • __tests__/integration/memory/oversizedImageFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/remoteActivationFreesLocalFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/repeatedTextImageRemoteEjectAllFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/sttReclaimedInVoiceTurnFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/sttReclaimedOnSend.rendered.happy.test.tsx
  • __tests__/integration/memory/survivalFloorFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/textWhisperCoresidentFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/ttsCoresidentInVoiceTurn.rendered.happy.test.tsx
  • __tests__/integration/memory/ttsDeleteClearsResidencyFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/whisperBlockedFreeRetry.rendered.happy.test.tsx
  • __tests__/integration/memory/whisperBlockedFreeRetryFullApp.rendered.happy.test.tsx
  • __tests__/integration/memory/whisperResidentOnDownload.rendered.redflow.test.tsx
  • __tests__/integration/models/activeModelService.test.ts
  • __tests__/integration/models/browseFitChipShowsLoadableModels.rendered.test.tsx
  • __tests__/integration/models/chatHomeSelectorParity.test.ts
  • __tests__/integration/models/curatedLiteRTMemoryWarning.rendered.test.tsx
  • __tests__/integration/models/deleteActiveResidentFallbackFullApp.rendered.happy.test.tsx
  • __tests__/integration/models/detailFilesFitHintUsesOwnedBudget.rendered.test.tsx
  • __tests__/integration/models/homeChatPickerParityFullApp.rendered.happy.test.tsx
  • __tests__/integration/models/imageDownloadRecovery.test.ts
  • __tests__/integration/models/imageQueuedCardState.test.tsx
  • __tests__/integration/models/litertWarningBothScreensFullApp.rendered.happy.test.tsx
  • __tests__/integration/models/loadAnywayOverrideChain.test.ts
  • __tests__/integration/models/localModelImportValidationFullApp.rendered.redflow.test.tsx
  • __tests__/integration/models/missingCorruptModelSelfHealFullApp.rendered.redflow.test.tsx
  • __tests__/integration/models/modelBrowseLifecycleFullApp.rendered.happy.test.tsx
  • __tests__/integration/models/modelFilesLoadErrorShowsRetry.rendered.test.tsx
  • __tests__/integration/onboarding/deviceAnalysisDoesNotWaitForNetwork.rendered.test.tsx
  • __tests__/integration/onboarding/deviceCardShowsTotalRam.rendered.test.tsx
  • __tests__/integration/onboarding/networkEmptyStateGetDesktop.test.tsx
  • __tests__/integration/onboarding/proBootFlow.test.ts
  • __tests__/integration/onboarding/proEntitlementFullApp.rendered.happy.test.tsx
  • __tests__/integration/onboarding/remoteModelSkipsDownloadFullApp.rendered.happy.test.tsx
  • __tests__/integration/onboarding/spotlightFlowIntegration.test.ts
  • __tests__/integration/projects/createProjectFullApp.rendered.happy.test.tsx
  • __tests__/integration/projects/deleteProjectChatsFullApp.rendered.happy.test.tsx
  • __tests__/integration/projects/deleteProjectOrphansChats.redflow.test.tsx
  • __tests__/integration/projects/newChatFilesPendingProject.guard.test.ts
  • __tests__/integration/projects/newChatFilesPendingProject.rendered.guard.test.tsx
  • __tests__/integration/rag/embeddingFlow.test.ts
  • __tests__/integration/rag/ragFlow.test.ts
  • __tests__/integration/remote/remoteServerLifecycleFullApp.rendered.happy.test.tsx
  • __tests__/integration/settings/contextLimitStableFullApp.rendered.happy.test.tsx
  • __tests__/integration/settings/cpuThreadsFullApp.rendered.happy.test.tsx
  • __tests__/integration/settings/deviceInformationMemory.rendered.happy.test.tsx
  • __tests__/integration/settings/emptyLanScan.rendered.happy.test.tsx
  • __tests__/integration/settings/experimentalFeatures.rendered.happy.test.tsx
  • __tests__/integration/settings/flashAttentionFullApp.rendered.happy.test.tsx
  • __tests__/integration/settings/imageSliderParityFullApp.rendered.happy.test.tsx
  • __tests__/integration/settings/lanDiscoveryRepeatFullApp.rendered.happy.test.tsx
  • __tests__/integration/settings/maxTokenContextPersistenceFullApp.rendered.redflow.test.tsx
  • __tests__/integration/settings/resetImageSettingsFullApp.rendered.happy.test.tsx
  • __tests__/integration/settings/resetTextSettings.rendered.happy.test.tsx
  • __tests__/integration/settings/settingsNavigation.rendered.happy.test.tsx
  • __tests__/integration/settings/settingsPolishFullApp.rendered.happy.test.tsx
  • __tests__/integration/settings/settingsRelaunch.rendered.happy.test.tsx
  • __tests__/integration/settings/storageMaintenanceFullApp.rendered.happy.test.tsx
  • __tests__/integration/stores/chatStoreIntegration.test.ts
  • __tests__/integration/stores/tts.test.ts
  • __tests__/integration/tools/mcpFullApp.rendered.happy.test.tsx
  • __tests__/integration/tools/mcpOAuthLifecycleFullApp.rendered.happy.test.tsx
  • __tests__/integration/tools/toolTogglePersistenceFullApp.rendered.happy.test.tsx
  • __tests__/integration/vision/litertVisionAffordanceFullApp.rendered.happy.test.tsx
  • __tests__/integration/vision/litertVisionContextRecoveryFullApp.rendered.redflow.test.tsx
  • __tests__/integration/vision/visionAnswersImageFullApp.rendered.happy.test.tsx
  • __tests__/integration/voiceDownloadManagerRouting.test.tsx
  • __tests__/pro/audio/engines/KokoroEngine.extra.test.ts
  • __tests__/pro/audio/ttsEngineSubscription.extra.test.ts
  • __tests__/pro/audio/ttsPlayback.extra.test.ts
  • __tests__/pro/audio/ttsStore.extra.test.ts
  • __tests__/pro/audio/ui/MessageAudioMode.test.tsx
  • __tests__/pro/audio/ui/MessageAudioModeThinkingStream.test.tsx
  • __tests__/pro/audio/ui/TTSSection.test.tsx
  • __tests__/pro/audio/ui/VoicePickerPopover.test.tsx
  • __tests__/pro/mcp/McpToolExtension.extra.test.ts
  • __tests__/pro/mcp/mcpService.test.ts
  • __tests__/pro/mcp/oauthClient.test.ts
  • __tests__/rntl/components/ChatInput.test.tsx
  • __tests__/rntl/components/ChatMessageAccordionPersistence.test.tsx
  • __tests__/rntl/components/ChatMessageTools.test.tsx
  • __tests__/rntl/components/GenerationSettingsModal.test.tsx
  • __tests__/rntl/components/McpServersScreen.test.tsx
  • __tests__/rntl/components/ToolAccordionStreaming.test.tsx
  • __tests__/rntl/components/VoiceModelsPanel.test.tsx
  • __tests__/rntl/screens/ChatScreen.test.tsx
  • __tests__/rntl/screens/ModelDownloadHelpers.test.tsx
  • __tests__/rntl/screens/ModelDownloadScreen.test.tsx
  • __tests__/rntl/screens/ModelSettingsScreen.test.tsx
  • __tests__/rntl/screens/NoModelScreen.test.tsx
  • __tests__/rntl/screens/ProDetailScreen.test.tsx
  • __tests__/unit/audio/streamingSpeech.test.ts
  • __tests__/unit/audio/ttsDownloadProvider.test.ts
  • __tests__/unit/audio/ttsEngineSubscription.test.ts
  • __tests__/unit/audio/turnSpeech.test.ts
  • __tests__/unit/hooks/useChatModelActions.test.ts
  • __tests__/unit/hooks/useDownloads.test.ts
  • __tests__/unit/hooks/useVoiceRecording.test.ts
  • __tests__/unit/mcp/McpToolExtension.test.ts
  • __tests__/unit/screens/DownloadManager/useVoiceDownloadItems.test.ts
  • __tests__/unit/screens/ModelsScreen/imageDownloadActions.test.ts
  • __tests__/unit/screens/ModelsScreen/imageDownloadResume.test.ts
  • __tests__/unit/screens/ModelsScreen/importHelpers.test.ts
  • __tests__/unit/services/activeModelService.imageOverridable.test.ts
  • __tests__/unit/services/activeModelService.loaders.branches.test.ts
  • __tests__/unit/services/activeModelService.loaders.test.ts
  • __tests__/unit/services/activeModelService.memory.test.ts
  • __tests__/unit/services/downloadHelpers.test.ts
  • __tests__/unit/services/downloadHydration.test.ts
  • __tests__/unit/services/generationService.test.ts
  • __tests__/unit/services/generationServiceHelpers.branches.test.ts
  • __tests__/unit/services/generationToolLoop.branches.test.ts
  • __tests__/unit/services/huggingface.test.ts
  • __tests__/unit/services/intentClassifier.test.ts
  • __tests__/unit/services/liteRTCompaction.test.ts
  • __tests__/unit/services/llmHelpers.branches.test.ts
  • __tests__/unit/services/llmHelpers.test.ts
  • __tests__/unit/services/llmMtp.test.ts
  • __tests__/unit/services/loadPolicySync.test.ts
  • __tests__/unit/services/loadProFeatures.test.ts
  • __tests__/unit/services/modelManager.test.ts
  • __tests__/unit/services/modelManager/scan.branches.test.ts
  • __tests__/unit/services/modelManager/scan.test.ts
  • __tests__/unit/services/modelPreloader.test.ts
  • __tests__/unit/services/modelResidency.test.ts
  • __tests__/unit/services/proLicenseService.test.ts
  • __tests__/unit/services/proPrompt.test.ts
  • __tests__/unit/services/providers/registry.test.ts
  • __tests__/unit/services/rag/index.test.ts
  • __tests__/unit/services/remoteServerManager.test.ts
  • __tests__/unit/services/toolEmbeddingRouter.test.ts
  • __tests__/unit/stores/appStore.test.ts
  • __tests__/unit/stores/chatStore.test.ts
  • __tests__/unit/stores/remoteModelCapabilities.test.ts
  • __tests__/unit/stores/remoteServerStore.test.ts
  • __tests__/unit/stores/ttsStore.test.ts
  • __tests__/unit/utils/logSanitizer.test.ts
  • __tests__/unit/utils/network.test.ts
  • android/app/src/main/java/ai/offgridmobile/download/DownloadManagerModule.kt
  • android/app/src/main/java/ai/offgridmobile/download/WorkerDownload.kt
  • docs/CHECKLIST_TEST_COVERAGE.md
  • docs/DEVICE_TEST_LOG.md
  • docs/E2E_DEVICE_AUTOMATION.md
  • docs/GAPS_BACKLOG.md
  • docs/MANUAL_TEST_CHECKLIST.md
  • docs/P0_P2_INTEGRATION_STATUS.md
  • docs/PR_571_TARGETED_MANUAL_TESTS.md
  • docs/RELEASE_DEVICE_CHECKLIST_pr558.md
  • docs/RELEASE_MANUAL_TEST_GUIDE.md
  • fastlane/Fastfile
  • jest.config.js
  • jest.setup.ts
  • package.json
  • pro
  • scripts/check-no-pro-mocks.mjs
  • scripts/run-device-e2e.sh
  • scripts/start-ios-wda.sh
  • scripts/uat.sh
  • src/bootstrap/hookRegistry.ts
  • src/bootstrap/loadProFeatures.ts
  • src/bootstrap/proFeatureLifecycle.ts
  • src/bootstrap/slotRegistry.ts
  • src/components/ChatInput/Attachments.tsx
  • src/components/ChatMessage/MessageBubble.tsx
  • src/components/ChatMessage/components/GenerationMeta.tsx
  • src/components/ChatMessage/components/MessageAttachments.tsx
  • src/components/ChatMessage/index.tsx
  • src/components/GenerationSettingsModal/TextGenerationAdvanced.tsx
  • src/components/GenerationSettingsModal/TextGenerationSection.tsx
  • src/components/GenerationSettingsModal/index.tsx
  • src/components/ModelCardActions.tsx
  • src/components/ModelCardContent.tsx
  • src/components/ModelInfoBadges.tsx
  • src/components/ModelSelectorModal/index.tsx
  • src/components/VoiceRecordButton/index.tsx
  • src/components/VoiceRecordButton/useVoiceErrorAlert.ts
  • src/components/models/ModelsManagerSheet.tsx
  • src/components/models/useResidentRows.ts
  • src/components/settings/AppearanceSelector.tsx
  • src/components/settings/SettingsEngagementSections.tsx
  • src/components/settings/sectionRegistry.ts
  • src/components/settings/textGenAdvancedSections.tsx
  • src/config/contextLimits.ts
  • src/config/textGenerationDefaults.ts
  • src/hooks/useDownloadRecovery.ts
  • src/hooks/useDownloads.ts
  • src/hooks/useVoiceRecording.ts
  • src/hooks/useWhisperTranscription.ts
  • src/navigation/AppNavigator.tsx
  • src/navigation/screenRegistry.ts
  • src/navigation/types.ts
  • src/screens/AboutScreen.tsx
  • src/screens/ChatScreen/ChatScreenComponents.tsx
  • src/screens/ChatScreen/chatScreenSettings.ts
  • src/screens/ChatScreen/chatScreenTypes.ts
  • src/screens/ChatScreen/modelReadiness.ts
  • src/screens/ChatScreen/useChatActiveModels.ts
  • src/screens/ChatScreen/useChatGenerationActions.ts
  • src/screens/ChatScreen/useChatModelActions.ts
  • src/screens/ChatScreen/useChatModelEffects.ts
  • src/screens/ChatScreen/useChatScreen.ts
  • src/screens/ChatScreen/useChatScreenActions.ts
  • src/screens/ChatScreen/useChatScreenEffects.ts
  • src/screens/ChatsListScreen.tsx
  • src/screens/ChatsListScreen/ConversationRowControls.tsx
  • src/screens/DownloadManagerScreen/items.tsx
  • src/screens/DownloadManagerScreen/useVoiceDownloadItems.ts
  • src/screens/ExperimentalFeaturesScreen.styles.ts
  • src/screens/ExperimentalFeaturesScreen.tsx
  • src/screens/GalleryScreen/GridItem.tsx
  • src/screens/HomeScreen/hooks/useHomeScreen.ts
  • src/screens/HomeScreen/hooks/useRemoteModelHandlers.ts
  • src/screens/ModelDownloadHelpers.tsx
  • src/screens/ModelDownloadScreen.tsx
  • src/screens/ModelSettingsScreen/ImageGenerationSection.tsx
  • src/screens/ModelSettingsScreen/TextGenerationAdvanced.tsx
  • src/screens/ModelSettingsScreen/TextGenerationSection.tsx
  • src/screens/ModelSettingsScreen/index.tsx
  • src/screens/ModelsScreen/ImageModelsTab.tsx
  • src/screens/ModelsScreen/TextFiltersSection.tsx
  • src/screens/ModelsScreen/TextModelsTab.tsx
  • src/screens/ModelsScreen/imageDownloadActions.ts
  • src/screens/ModelsScreen/imageDownloadResume.ts
  • src/screens/ModelsScreen/imageDownloadShared.ts
  • src/screens/ModelsScreen/imageMultifileDownloadActions.ts
  • src/screens/ModelsScreen/imageZipFinalization.ts
  • src/screens/ModelsScreen/importHelpers.ts
  • src/screens/ModelsScreen/index.tsx
  • src/screens/ModelsScreen/styles.ts
  • src/screens/ModelsScreen/useImageModels.ts
  • src/screens/ModelsScreen/useModelsScreen.ts
  • src/screens/ModelsScreen/useTextModels.ts
  • src/screens/OnboardingScreen.tsx
  • src/screens/OrphanedFilesSection.tsx
  • src/screens/ProDetailScreen/index.tsx
  • src/screens/RemoteServersScreen.tsx
  • src/screens/SettingsScreen.tsx
  • src/screens/StorageSettingsScreen.tsx
  • src/screens/ToolsScreen/index.tsx
  • src/screens/index.ts
  • src/services/activeDownloadPersistence.ts
  • src/services/activeModelService/index.ts
  • src/services/activeModelService/loaders.ts
  • src/services/activeModelService/memory.ts
  • src/services/backgroundDownloadService.ts
  • src/services/contextCompaction.ts
  • src/services/curatedLiteRTRegistry.ts
  • src/services/downloadHydration.ts
  • src/services/engines.ts
  • src/services/generationService.ts
  • src/services/generationServiceHelpers.ts
  • src/services/generationToolLoop.ts
  • src/services/huggingface.ts
  • src/services/imageAttachmentService.ts
  • src/services/intentClassifier.ts
  • src/services/liteRTCompaction.ts
  • src/services/litert.ts
  • src/services/llm.ts
  • src/services/llmCapabilities.ts
  • src/services/llmHelpers.ts
  • src/services/llmModelParams.ts
  • src/services/llmMtp.ts
  • src/services/llmRuntimeSettings.ts
  • src/services/llmToolGeneration.ts
  • src/services/llmTypes.ts
  • src/services/loadModelWithOverride.ts
  • src/services/loadPolicySync.ts
  • src/services/memoryBudget.ts
  • src/services/modelDownloadService/index.ts
  • src/services/modelDownloadService/providers/imageProvider.ts
  • src/services/modelDownloadService/providers/textProvider.ts
  • src/services/modelManager/directories.ts
  • src/services/modelManager/downloadHelpers.ts
  • src/services/modelManager/imageModelStorage.ts
  • src/services/modelManager/index.ts
  • src/services/modelManager/mmProjLinker.ts
  • src/services/modelManager/scan.ts
  • src/services/modelManager/storage.ts
  • src/services/modelPreloader.ts
  • src/services/modelResidency/index.ts
  • src/services/modelResidency/logging.ts
  • src/services/modelResidency/overrideSurvival.ts
  • src/services/proLicenseService.ts
  • src/services/proPrompt.ts
  • src/services/providers/index.ts
  • src/services/providers/localProvider.ts
  • src/services/providers/openAICompatibleStream.ts
  • src/services/providers/registry.ts
  • src/services/rag/index.ts
  • src/services/remoteModelSelection.ts
  • src/services/remoteServerManager.ts
  • src/services/remoteServerManagerUtils.ts
  • src/services/storageCache.ts
  • src/services/toolEmbeddingRouter.ts
  • src/services/tools/extensions.ts
  • src/stores/accordionStore.ts
  • src/stores/appStore.ts
  • src/stores/appStorePersistence.ts
  • src/stores/chatStore.ts
  • src/stores/chatStoreTypes.ts
  • src/stores/debugLogsStore.ts
  • src/stores/generativeModelFilter.ts
  • src/stores/index.ts
  • src/stores/projectStore.ts
  • src/stores/remoteModelCapabilities.ts
  • src/stores/remoteServerStore.ts
  • src/theme/index.ts
  • src/theme/useTheme.ts
  • src/types/index.ts
  • src/utils/debugLogFile.ts
  • src/utils/externalLinks.ts
  • src/utils/imageModelIntegrity.ts
  • src/utils/logSanitizer.ts
  • src/utils/network.ts
  • src/utils/proPricing.ts
  • src/utils/sharePrompt.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Changes

The pull request adds RAM-based model fit tiers and compact fit badges, introduces timeout-aware model-file loading with inline retry UI, makes onboarding device analysis non-blocking, updates total-RAM display, hardens download and release scripts, and modernizes numerous integration assertions and repository instructions.

Model fit and onboarding

Layer / File(s) Summary
Fit-tier model browsing and presentation
src/services/memoryBudget.ts, src/screens/ModelsScreen/*, src/components/ModelCardContent.tsx, src/types/index.ts, __tests__/integration/models/*
Models and files are classified as easy, fits, tight, or wontFit; loadable models remain visible and compact cards display the fit tier.
Model-file timeout and retry flow
src/services/huggingface.ts, src/screens/ModelsScreen/*, __tests__/integration/models/modelFilesLoadErrorShowsRetry.rendered.test.tsx
Timed-out file requests surface an inline error with a Retry action instead of being treated as an empty compatible-file result.
Non-blocking onboarding readiness
src/screens/ModelDownloadScreen.tsx, __tests__/integration/onboarding/*, __tests__/rntl/screens/ModelDownloadScreen.test.tsx
Onboarding renders after device recommendation data is ready, displays total physical RAM, and uses rendered integration coverage for hardware behavior.

Reliability and maintenance

Layer / File(s) Summary
Download and release reliability
android/app/src/main/java/.../download/*, src/services/activeDownloadPersistence.ts, src/services/modelPreloader.ts, src/screens/DownloadManagerScreen/useVoiceDownloadItems.ts, fastlane/Fastfile, scripts/uat.sh, __tests__/unit/services/modelManager.test.ts
Download IDs and persistence signatures are normalized, failed cleanup is logged, optional hooks are awaited directly, Play promotion status is explicit, and UAT checks use safer conditionals and artifact validation.
Integration assertion modernization
__tests__/integration/**/*
Array counts use toHaveLength, null checks use toBeNull, dynamic-require lint suppressions are removed, and enhancement cases use a table-driven test.

Repository guidance

Layer / File(s) Summary
Canonical engineering guidance
AGENTS.md, CLAUDE.md
Engineering, testing, repository, quality-gate, and branch workflow guidance is consolidated in AGENTS.md, which CLAUDE.md references.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main release candidate changes.
Description check ✅ Passed The description follows the template and covers summary, change type, screenshots, checklist, related issues, and notes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/onboarding-analyzing-device-hang

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/services/huggingface.ts (1)

30-88: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Timeout clears prematurely, leaving the body stream unprotected.

fetchWithTimeout clears the timer as soon as fetch resolves (which happens when the HTTP headers are received). Consequently, await response.json() is executed after the timeout has been cleared. If the network connection drops or the server stalls while streaming the JSON body, the app will hang indefinitely on response.json(), bypassing the intended 5-second limit entirely.

Refactor the timeout logic into a wrapper that keeps the AbortSignal active until the body is fully read.

🛠️ Proposed fix using a holistic timeout wrapper

Replace fetchWithTimeout with withTimeout, and update fetchJson and getModelFiles to wrap the entire parse operation:

-  private async fetchWithTimeout(url: string, timeoutMs = HF_REQUEST_TIMEOUT_MS): Promise<Response> {
+  private async withTimeout<T>(operation: (signal: AbortSignal) => Promise<T>, timeoutMs = HF_REQUEST_TIMEOUT_MS): Promise<T> {
     const controller = new AbortController();
     const timer = setTimeout(() => controller.abort(), timeoutMs);
     try {
-      return await fetch(url, { headers: { Accept: 'application/json' }, signal: controller.signal });
+      return await operation(controller.signal);
     } finally {
       clearTimeout(timer);
     }
   }
 
   private async fetchJson<T>(url: string): Promise<T> {
-    const response = await this.fetchWithTimeout(url);
-    if (!response.ok) throw new Error(`API error: ${response.status}`);
-    return response.json() as Promise<T>;
+    return this.withTimeout(async (signal) => {
+      const response = await fetch(url, { headers: { Accept: 'application/json' }, signal });
+      if (!response.ok) throw new Error(`API error: ${response.status}`);
+      return response.json();
+    });
   }
 
// ...
 
   async getModelFiles(modelId: string): Promise<ModelFile[]> {
     try {
-      const response = await this.fetchWithTimeout(`${this.apiUrl}/models/${modelId}/tree/main`);
-      if (!response.ok) return this.getModelFilesFromSiblings(modelId);
-      const files: Array<{ type: string; path: string; size?: number; lfs?: { size: number } }> = await response.json();
-      const allGguf = files.filter(f => f.type === 'file' && f.path.endsWith('.gguf'));
-      const mmProjFiles = allGguf.filter(f => this.isMMProjFile(f.path));
-      const modelFiles = allGguf.filter(f => !this.isMMProjFile(f.path));
-      return modelFiles
-        .map(file => ({
-          name: file.path,
-          size: file.lfs?.size || file.size || 0,
-          quantization: this.extractQuantization(file.path),
-          downloadUrl: this.getDownloadUrl(modelId, file.path),
-          mmProjFile: this.findMatchingMMProj(file.path, mmProjFiles, modelId),
-        }))
-        .sort((a, b) => a.size - b.size);
+      return await this.withTimeout(async (signal) => {
+        const response = await fetch(`${this.apiUrl}/models/${modelId}/tree/main`, { headers: { Accept: 'application/json' }, signal });
+        if (!response.ok) throw new Error('API Error'); // Triggers the catch block to run the sibling fallback
+        const files: Array<{ type: string; path: string; size?: number; lfs?: { size: number } }> = await response.json();
+        const allGguf = files.filter(f => f.type === 'file' && f.path.endsWith('.gguf'));
+        const mmProjFiles = allGguf.filter(f => this.isMMProjFile(f.path));
+        const modelFiles = allGguf.filter(f => !this.isMMProjFile(f.path));
+        return modelFiles
+          .map(file => ({
+            name: file.path,
+            size: file.lfs?.size || file.size || 0,
+            quantization: this.extractQuantization(file.path),
+            downloadUrl: this.getDownloadUrl(modelId, file.path),
+            mmProjFile: this.findMatchingMMProj(file.path, mmProjFiles, modelId),
+          }))
+          .sort((a, b) => a.size - b.size);
+      });
     } catch (e) {
       // A timed-out/aborted request means the network is down — don't pay a second 5s on the
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/huggingface.ts` around lines 30 - 88, Refactor fetchWithTimeout
into a withTimeout wrapper that keeps the AbortController active until the
entire asynchronous operation completes, including response.json(). Update
fetchJson and getModelFiles to wrap both fetching and body parsing in this
timeout, while preserving existing non-OK handling, abort propagation, and
siblings fallback behavior.
src/screens/ModelsScreen/useTextModels.ts (1)

209-231: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Race condition in handleSelectModel state updates.

State updates are applied unconditionally after the async file fetch. If a user quickly navigates between different models, concurrent fetch responses can resolve out-of-order. This TOCTOU (Time-of-Check to Time-of-Use) race condition will overwrite modelFiles with stale data, causing the detail view to display and eventually download files belonging to a completely different model.

Guard the state updates to ensure only the latest active selection modifies the state.

🔒️ Proposed fix to ignore stale responses

(Note: ensure useRef is included in your react imports)

+  const fetchIdRef = useRef(0);
+
   const handleSelectModel = async (model: ModelInfo) => {
+    fetchIdRef.current += 1;
+    const currentFetchId = fetchIdRef.current;
+
     setSelectedModel(model); setIsLoadingFiles(true); setFilesLoadError(false);
     // Curated entries under the offgrid/ namespace (e.g. the synthetic LiteRT
     // parent) ship with their files baked into the ModelInfo — skip the
     // HuggingFace fetch and use them as-is. Real HF models always go through
     // the fetch path even when factories/mocks pre-populate model.files.
     if (model.id.startsWith('offgrid/') && model.files && model.files.length > 0) {
       setModelFiles(model.files);
       setIsLoadingFiles(false);
       return;
     }
     try {
       const files = await huggingFaceService.getModelFiles(model.id);
+      if (fetchIdRef.current !== currentFetchId) return;
       setModelFiles(files);
     } catch {
       // Fetch failed (offline / HF unreachable / timeout). Surface an inline retry state rather
       // than a transient modal — the detail view reads filesLoadError and offers Retry.
+      if (fetchIdRef.current !== currentFetchId) return;
       setModelFiles([]);
       setFilesLoadError(true);
     } finally {
+      if (fetchIdRef.current === currentFetchId) {
         setIsLoadingFiles(false);
+      }
     }
   };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/screens/ModelsScreen/useTextModels.ts` around lines 209 - 231, Update
handleSelectModel to track the latest selection with a useRef-based request or
selection token, and verify that token before applying fetched files, errors, or
loading-state updates. Ensure stale responses from prior model selections cannot
modify modelFiles, filesLoadError, or loading state, while preserving the
existing offgrid fast path and current behavior for the active selection.
🧹 Nitpick comments (1)
src/types/index.ts (1)

25-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer top-level import type over inline imports.

Using a top-level type import is more idiomatic and improves readability compared to an inline import() type inside the interface definition.

♻️ Proposed refactor

Add the type import at the top of the file:

+import type { FitTier } from '../services/memoryBudget';

And update the field definition:

   /** Device-fit tier of this model's BEST (most-fitting) quant, for the browse fit chip. Set by the
    *  models VM from memoryBudget.fitTier; undefined until the file sizes are known. */
-  fitTier?: import('../services/memoryBudget').FitTier;
+  fitTier?: FitTier;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/types/index.ts` around lines 25 - 27, Replace the inline import type used
by the fitTier property in the relevant interface with a top-level import type
for FitTier from the memoryBudget service, then reference FitTier directly in
the property declaration.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@__tests__/unit/services/huggingface.test.ts`:
- Around line 596-604: Update the test around the custom global.fetch stub to
capture the original fetch implementation and restore it in a finally block,
ensuring restoration occurs whether the test passes, fails, or aborts.
Alternatively, replace the direct assignment with a jest.spyOn mock configured
with the existing behavior and ensure it is restored after the test.

In `@CLAUDE.md`:
- Around line 1-4: Update the references in batch9-diagnostics-debuglog.test.ts
and DEVICE_TEST_LOG.md that point to CLAUDE.md, replacing them with AGENTS.md so
debug-log and gate guidance directs contributors to the canonical source. Leave
unrelated repository instructions unchanged.

---

Outside diff comments:
In `@src/screens/ModelsScreen/useTextModels.ts`:
- Around line 209-231: Update handleSelectModel to track the latest selection
with a useRef-based request or selection token, and verify that token before
applying fetched files, errors, or loading-state updates. Ensure stale responses
from prior model selections cannot modify modelFiles, filesLoadError, or loading
state, while preserving the existing offgrid fast path and current behavior for
the active selection.

In `@src/services/huggingface.ts`:
- Around line 30-88: Refactor fetchWithTimeout into a withTimeout wrapper that
keeps the AbortController active until the entire asynchronous operation
completes, including response.json(). Update fetchJson and getModelFiles to wrap
both fetching and body parsing in this timeout, while preserving existing non-OK
handling, abort propagation, and siblings fallback behavior.

---

Nitpick comments:
In `@src/types/index.ts`:
- Around line 25-27: Replace the inline import type used by the fitTier property
in the relevant interface with a top-level import type for FitTier from the
memoryBudget service, then reference FitTier directly in the property
declaration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4b441aab-6882-473d-8878-0f40b74e98ce

📥 Commits

Reviewing files that changed from the base of the PR and between 856bca1 and 9cacd2f.

📒 Files selected for processing (63)
  • AGENTS.md
  • CLAUDE.md
  • __tests__/integration/audio/voiceModeImageJourney.rendered.happy.test.tsx
  • __tests__/integration/audio/voiceModeResendEnhancedImage.rendered.redflow.test.tsx
  • __tests__/integration/audio/voiceModeResendImageRoutes.rendered.redflow.test.tsx
  • __tests__/integration/chat/voiceNoteChatModeEmptyTurn.redflow.test.ts
  • __tests__/integration/downloads/downloadedCountBadge.rendered.happy.test.tsx
  • __tests__/integration/downloads/iosImageStagingPurgedRedownloads.redflow.test.ts
  • __tests__/integration/downloads/iosImageStagingPurgedRedownloads.rendered.redflow.test.tsx
  • __tests__/integration/downloads/iosInterruptedNoFailedEntry.redflow.test.ts
  • __tests__/integration/downloads/iosTextRetryReissues.rendered.redflow.test.tsx
  • __tests__/integration/downloads/queuedDownloadsSurviveKill.redflow.test.ts
  • __tests__/integration/downloads/textRetryReissuesOnIosLostDownloadId.rendered.redflow.test.tsx
  • __tests__/integration/generation/enhancementNoThinking.rendered.redflow.test.tsx
  • __tests__/integration/generation/enhancementStreamingProgress.rendered.redflow.test.tsx
  • __tests__/integration/generation/generationFlow.test.ts
  • __tests__/integration/generation/imageGenerationFlow.test.ts
  • __tests__/integration/generation/queuedForceImagePreservesMode.rendered.redflow.test.tsx
  • __tests__/integration/generation/queuedSendFeedback.test.ts
  • __tests__/integration/generation/reloadRaceKeepsThinking.rendered.redflow.test.tsx
  • __tests__/integration/generation/remoteParallelTools.rendered.happy.test.tsx
  • __tests__/integration/generation/resendImageRoutes.rendered.redflow.test.tsx
  • __tests__/integration/generation/resendImageRoutesLlama.rendered.redflow.test.tsx
  • __tests__/integration/generation/resendImageTurnFallsBackToText.rendered.redflow.test.tsx
  • __tests__/integration/happy/imageBackends.happy.test.tsx
  • __tests__/integration/happy/imageIntentRouting.happy.test.tsx
  • __tests__/integration/happy/imageLightbox.happy.test.tsx
  • __tests__/integration/happy/imageModeToggle.happy.test.tsx
  • __tests__/integration/happy/imageOomCard.happy.test.tsx
  • __tests__/integration/happy/smartBudgeting.happy.test.tsx
  • __tests__/integration/happy/speakMessage.happy.test.tsx
  • __tests__/integration/happy/tools.happy.test.tsx
  • __tests__/integration/image/imageTunablesReadFreshFromStore.redflow.test.ts
  • __tests__/integration/models/activeModelService.test.ts
  • __tests__/integration/models/browseFitChipShowsLoadableModels.rendered.test.tsx
  • __tests__/integration/models/detailFilesFitHintUsesOwnedBudget.rendered.test.tsx
  • __tests__/integration/models/modelFilesLoadErrorShowsRetry.rendered.test.tsx
  • __tests__/integration/onboarding/deviceAnalysisDoesNotWaitForNetwork.rendered.test.tsx
  • __tests__/integration/onboarding/deviceCardShowsTotalRam.rendered.test.tsx
  • __tests__/integration/onboarding/spotlightFlowIntegration.test.ts
  • __tests__/integration/rag/embeddingFlow.test.ts
  • __tests__/integration/rag/ragFlow.test.ts
  • __tests__/integration/stores/chatStoreIntegration.test.ts
  • __tests__/rntl/screens/ModelDownloadScreen.test.tsx
  • __tests__/unit/services/huggingface.test.ts
  • __tests__/unit/services/modelManager.test.ts
  • android/app/src/main/java/ai/offgridmobile/download/DownloadManagerModule.kt
  • android/app/src/main/java/ai/offgridmobile/download/WorkerDownload.kt
  • fastlane/Fastfile
  • scripts/uat.sh
  • src/components/ModelCardContent.tsx
  • src/screens/DownloadManagerScreen/useVoiceDownloadItems.ts
  • src/screens/ModelDownloadScreen.tsx
  • src/screens/ModelsScreen/TextModelsTab.tsx
  • src/screens/ModelsScreen/index.tsx
  • src/screens/ModelsScreen/styles.ts
  • src/screens/ModelsScreen/useModelsScreen.ts
  • src/screens/ModelsScreen/useTextModels.ts
  • src/services/activeDownloadPersistence.ts
  • src/services/huggingface.ts
  • src/services/memoryBudget.ts
  • src/services/modelPreloader.ts
  • src/types/index.ts

Comment thread __tests__/unit/services/huggingface.test.ts
Comment thread CLAUDE.md
@sonarqubecloud

Copy link
Copy Markdown

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