Direct answer
Finalizing a model download is a separate release step after receiving bytes. The application must prove that the temporary file is complete, any configured integrity check passed, the destination is on a compatible volume, the final operation succeeded, and the next load opens the intended artifact. Android File.renameTo returns a Boolean; its API documentation lists same-mount restrictions among likely failures and says to check the return value. A call to rename is not evidence that a model is now present at the destination. In particular, a temporary file on internal storage cannot be assumed to rename atomically into a removable SD-card path. Check source and destination parent volumes before choosing rename. If they differ, use a documented copy-and-verify strategy with enough space for both copies, write the replacement under a unique candidate path on the destination volume, close it, verify destination bytes and any configured trusted digest, then promote it only after validation. Preserve the source and previous working model until the candidate path and application state are committed. For API 26 and later, Files.move with StandardCopyOption.ATOMIC_MOVE requests an atomic filesystem move; if that operation is unsupported, handle the exception as a failed move, not as an implicit copy. The API contract says other options are ignored when ATOMIC_MOVE is requested, and when the target already exists it is implementation-specific whether it is replaced or the move fails. Do not rely on REPLACE_EXISTING to protect the only known-good model: use a unique candidate/final artifact path and apply an explicit replacement policy after validation. Record the final destination, partial source, operation type, result value or exception, source/destination volume, free-space observations, expected artifact identity, actual length, digest state, and cleanup result. Cove’s ModelDownloader writes a temporary artifact under its configured storage directory, may verify SHA-256 when a value is configured, and then calls renameTo for the target file. The current Gemma E2B SHA-256 is empty, so this code path must not be represented as digest-verified for that configuration. The checked source currently calls renameTo without using its Boolean result to gate the completion state; that is a code observation, not proof of a device outcome or a claim that the implementation has been fixed. In a test, force failure after the transfer but before final placement, simulate a full target volume, use a destination on a different volume, make the target unwritable, and interrupt the process during copy or promotion. Confirm the previous model remains intact and the app reports a recoverable state rather than emitting Completed. After restart, do not trust that a destination exists just because a temporary path existed; re-check artifact identity, size and configured digest before loading. If the move API reports failure, do not return success based on the source file’s existence. If a copy is required, keep source and target distinct until the new file is verified, then delete the source only after the app has committed the destination state. Clean up stale temporary files conservatively using artifact identity and age policy; avoid deleting files while another downloader owns them. A user-facing state should separate bytes received, verification, finalization and model readiness. Download completion is not the same as successful storage promotion or runtime load. Do not publish broad reliability, compatibility or speed claims from this method. Test with an artifact fixture whose expected digest is known, a missing digest, an intentionally wrong digest, a short transfer, same-volume replacement, cross-volume rejection/copy, no-space error, process death at each stage, existing-target collision, and a second load after recovery. Keep the result matrix scoped to the tested filesystem and Android build. The safe protocol is to pin source identity; download to a temporary path on a chosen volume; recheck length and integrity; create a uniquely named destination candidate; verify that operation returned success and destination bytes match; open the artifact through the selected runtime; update persistent state only after these checks; and clean temporary data without removing the previous valid model until replacement is committed. This procedure is about file finalization semantics. It does not certify Cove’s current implementation or any device-wide support claim.
A completed transfer fails while moving to the final model path
The network stream reaches its expected byte count, but the destination is on a different external volume and storage becomes nearly full. The app currently has an older usable model and must not announce success merely because the temporary file exists.
Decision
Separate transfer completion from storage finalization, check the actual move or copy outcome and verify the final path before changing the model-ready state.
Expected outcome
A move failure leaves the prior model intact and presents a retryable storage error; a successful transfer alone never appears as an installed, verified, loadable model.
Evidence to collect
The claim becomes reviewable only when the following evidence is attached to the same artifact and test run:
- Path and volume identity
- Filesystem operation trace
- Interrupted transfer and final verification
A completed byte stream is not enough. Final placement, integrity, runtime load, and recovery must also pass.
Implementation workflow
- Pin source and destination identity. Record artifact revision, temporary path, intended final path, destination volume, existing target state, expected length, optional digest configuration, and the download attempt that owns the temporary file.
- Check rename and existing-target semantics. Check the selected Android API contract and actual source/destination mount. `File.renameTo` returns a Boolean and can fail across mount points. `Files.move` and `StandardCopyOption.ATOMIC_MOVE` are available from API 26; ATOMIC_MOVE ignores other options and existing-target behavior is implementation-specific. Use a unique destination candidate rather than assuming REPLACE_EXISTING preserves the old model.
- Copy across volumes without mutating the source. If a cross-volume transfer needs copying, write to a uniquely named candidate on the destination volume, close it, and verify the destination bytes and any configured trusted digest. Keep the source and previous active model unchanged until the destination and application state are committed; if atomic promotion is unsupported, report that state or apply a separately tested, explicitly non-atomic policy.
- Check the finalization result. Inspect the Boolean or exception from the chosen move API, verify the final path and content, and do not emit a completed model state if the operation failed or only the temporary source remains.
- Recover after interruption. Inject process death, full storage, permission loss, and target collision at each stage; on restart, verify the candidate again before loading and remove only stale, app-owned temporary data.
Keep each transition observable. A failure should identify the stage, artifact, runtime, and recovery action without logging private user content.
Acceptance criteria
- A final model state is emitted only after the move or copy reports success and final-path identity and bytes are verified.
- Cross-volume behavior is explicitly tested; a failed atomic move is not described as an atomic copy fallback, and any copy candidate is verified at the destination while the source and prior model remain intact.
- No-space, wrong-digest, short-transfer, interruption, and target-collision cases preserve the previous valid model and user data.
- Logs distinguish bytes received, integrity verification, finalization, runtime load, and cleanup without claiming unverified support.
Decision table
| Dimension | Choice or evidence | How to interpret it |
|---|---|---|
| Call rename and ignore its result | Optimistic finalization | Unsafe: the API can report failure while only the temporary file exists. |
| Check same-mount rename result | Conditional promotion | Check the Boolean result and verify the final path; a mount match does not by itself prove atomicity. |
| Use API 26+ ATOMIC_MOVE | Requested atomic filesystem move | The API may throw when unsupported; it does not promise a copy fallback or a portable replacement behavior. |
| Copy across volumes to a new candidate | Copy, verify, then promote | A separate non-atomic workflow: retain source and old model, verify destination bytes, then commit under an explicit policy. |
| Replace current model before validation | Destructive update | Can remove a usable artifact before a replacement is known to be complete. |
Failure patterns to prevent
- Assuming cross-volume rename is atomic
- Deleting partial state before validating replacement
Also prevent silent fallback, unpinned artifacts, missing cancellation, and conclusions that combine unlike configurations. Store unsuccessful runs alongside successful ones.
Minimum reproducibility record
| Layer | Record |
|---|---|
| Device | Manufacturer, model, chipset, RAM class, operating-system build |
| Software | Application version and git commit |
| Model | Family, variant, revision, format, file length, hash, quantization |
| Runtime | Name, revision, requested backend, observed backend evidence |
| Workload | Fixture revision, input hash, prompt hash, output policy |
| Outcome | Completed, failed, cancelled, fallback, and privacy-safe diagnostics |
Release checklist
- ☐ The primary query is answered without an unsupported number.
- ☐ Every artifact and runtime is pinned.
- ☐ The representative task and failure policy are explicit.
- ☐ Lifecycle, cancellation, cleanup, and fallback are tested.
- ☐ User-content and network boundaries are documented.
- ☐ Result wording applies only to the recorded configuration.
- ☐ The page links to raw method or evidence when results are added.
Sources and related evidence
- Android API — File.renameTo and required result checking
- Android API 26+ — Files.move and file operation contract
- Android API 26+ — StandardCopyOption.ATOMIC_MOVE
- Cove ModelDownloader temporary file and finalization path at 0ec9e8f
Chinese deployment and troubleshooting content is organized in the .奇连 AI 端侧专题.
Frequently asked questions
Does File.renameTo guarantee an atomic move?
No. Android documents possible failures, including paths on different mount points, and requires checking the Boolean result. Do not assume cross-volume rename is atomic or successful just because the source remains.
How does ATOMIC_MOVE behave when the destination already exists?
For API 26 and later, `Files.move` with `StandardCopyOption.ATOMIC_MOVE` requests an atomic operation; if unsupported, it can throw `AtomicMoveNotSupportedException`. Other options, including `REPLACE_EXISTING`, are ignored, and target replacement versus failure is implementation-specific. Use a unique candidate/final artifact path, preserve the old model until validation and commit, or reject the update; a failed atomic move does not become an atomic copy.
Is a completed download the same as an installed model?
No. The bytes still need integrity checks, successful final placement, and a runtime-open check before the app reports readiness for that specific model file.
Can I delete the old model before moving the replacement?
Not if the old model is the only known-good copy. Preserve it until the replacement is verified at the final location and the application state has committed.
Does Cove verify every downloaded Gemma file by SHA-256?
No. The current Gemma E2B SHA-256 configuration is empty. The source currently calls `renameTo` without using its Boolean result to gate the completion state; that is a code observation, not proof of a device outcome or a claim that the implementation has been fixed.