@@ -1244,16 +1244,57 @@ browse -> search -> select -> restore flow against mocked `invoke` + a mocked
12441244 webview path is forbidden, so the signature carries the one-shot token the
12451245 backend resolves to the approved directory. The contract is documented on the
12461246 command + the typed wrapper.
1247- - ** No mid-job cancel command.** ROADMAP M8 lists "cancel mid-restore cleans up the
1248- partial file"; partial-file cleanup IS implemented (every per-file write is a
1249- temp file removed on any error, and only renamed into place after blake3
1250- verification, so a failed/aborted file never leaves a partial under the final
1251- name). A USER-driven cancel IPC is not wired in this pass - the background job
1252- runs to completion. The data-safety half of the acceptance (no partial final
1253- files) holds; an explicit cancel button is a follow-up (honest residual, not a
1254- fake-green).
12551247- ** ICU plural not used for ` restore.selectedCount ` .** vue-i18n's default message
12561248 compiler in this repo is not configured for ICU MessageFormat (DESIGN s8.7 names
12571249 it as the V1 target but it is not wired; no existing key uses it). Used a plain
12581250 ` {count} selected ` interpolation rather than introduce an unparseable ICU string
12591251 that breaks the build. Wiring ICU is a cross-cutting i18n change, out of M8 scope.
1252+
1253+ ## M8 codex round-1 fixes (2 P1 + 5 P2; baseline 1a7ad60 @ 887aaab)
1254+
1255+ All findings from ` .claude/codex-reviews/M8-20260624-161042.md ` fixed. The prior
1256+ "no mid-job cancel command" residual is now RESOLVED (P1-1).
1257+
1258+ - ** M8-P1-1 - cancellable restore + cleanup + shutdown drain.** Each restore job
1259+ now holds a shared cancel flag (` Arc<AtomicBool> ` ) + its spawned ` tokio `
1260+ ` JoinHandle ` , tracked on ` AppState ` (` seed_restore_job ` / ` set_restore_job_handle `
1261+ / ` cancel_restore_job ` / ` cancel_all_restore_jobs ` / ` finish_restore_job_handle ` ).
1262+ New ` cancel_restore_job(jobId) ` IPC sets the flag; ` stream_to_disk ` checks it
1263+ BEFORE each file and between frames, and on cancel returns ` Cancelled ` so
1264+ ` restore_one_file ` DELETES the temp (no partial, nothing renamed into place). The
1265+ job emits a terminal CANCELLED ` RestoreJobStatus ` (` cancelled: true ` ,
1266+ ` RestoreFileState::Cancelled ` for the unfinished files). App shutdown
1267+ (` lib.rs::shutdown_orchestrators ` ) now ` cancel_all_restore_jobs() ` + joins every
1268+ restore handle alongside the M5 account drain, so quit leaves no orphaned restore
1269+ task and no partial files. UI: a Cancel button (gated by a ` cancelling ` flag), a
1270+ ` cancelled ` terminal label, and a per-file Cancelled state.
1271+ - ** M8-P1-2 - no-follow, non-truncating, race-safe temp write.** The temp is now a
1272+ RANDOM name (` .driven-restore-tmp.<uuid> ` , not timestamp-derived) opened via
1273+ ` open_temp_no_follow ` : ` create_new(true) ` (O_EXCL - fails if the path exists,
1274+ killing a pre-place / race-to-the-path attack) PLUS platform no-follow flags
1275+ (Unix ` O_NOFOLLOW ` ; Windows ` FILE_FLAG_OPEN_REPARSE_POINT ` ) so a symlinked temp
1276+ leaf cannot redirect the write outside the approved root. After the stream the
1277+ rename target is RE-validated via ` validate_restore_dest ` (catches a TOCTOU leaf
1278+ swap) before renaming. Tests: O_EXCL rejects an existing path; a pre-placed
1279+ symlink at the temp path is refused and the victim target is not overwritten.
1280+ - ** M8-P2-1 - surface tree truncation.** ` list_remote_tree ` now returns
1281+ ` RemoteTreeDto { entries, truncated } ` instead of a bare ` Vec ` ; ` truncated ` is set
1282+ when the folder has more immediate children than the cap (or the scan hit its row
1283+ cap). Restore.vue shows a "showing the first N items" notice. The cap itself is
1284+ unchanged.
1285+ - ** M8-P2-2 - search input limits per DESIGN s18.8.** ` MAX_QUERY_LEN ` tightened
1286+ from 1024 to 256 (counted in CHARS), and ` search_files ` now rejects ` \0 ` , ` \r ` ,
1287+ ` \n ` , and any other control char before the FTS/GLOB path.
1288+ - ** M8-P2-3 - bounded restore-job snapshot memory.** Terminal restore-job records
1289+ are TTL-pruned (1h) and count-capped (32, oldest-terminal first) by
1290+ ` prune_terminal_jobs ` on every register/put; active jobs are never pruned.
1291+ - ** M8-P2-4 - persist active job id + reconcile on remount.** The store keeps the
1292+ returned ` jobId ` and calls ` getRestoreJob(jobId) ` after start AND on
1293+ (re)subscription, so a remount / missed terminal event recovers current state
1294+ instead of going stale.
1295+ - ** M8-P2-5 - classify remote download failures.** ` classify_download_error ` maps
1296+ the Drive ` download ` error into the specific SPEC s24 code (auth.invalid_grant /
1297+ drive.rate_limited / drive.daily_quota_exhausted / drive.quota_exhausted /
1298+ net.intermittent / drive.unreachable for 404/unclassified), reusing the same
1299+ typed ` classification_of ` downcast + string fallback the executor uses. The
1300+ specific code is stored on the per-file restore failure.
0 commit comments