fix(queue): classify persistent host-FS I/O errors (is_host_io_error) - #63
Conversation
Port OpenHuman host commit d7bee77e3 (drift ledger D2). Adds an `is_host_io_error` classifier to the queue worker's error family: EIO (5) / ENOSPC (28) / EROFS (30) surfaced as a `std::io::Error` — a dying SD card, a full disk, or a kernel-remounted-read-only mount. These are persistent, user-only-fixable host conditions that never clear on their own, so a host loop backs off long and pages once instead of flooding Sentry (~10k events/50min, CORE-RUST-19J). Matches the typed downcast and the flattened `(os error N)` text through anyhow context layers. EACCES (13) / ENOENT (2) are excluded (genuine bugs that must keep reporting); SQLITE_FULL stays in is_sqlite_disk_full. Only the predicate ports — the Sentry-once emission and the storage-degraded flag remain host-owned (drift ledger D2-host).
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 36 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc6246380c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if matches!(io_err.raw_os_error(), Some(5) | Some(28) | Some(30)) { | ||
| return true; |
There was a problem hiding this comment.
Avoid treating Windows access-denied as host I/O
On non-Unix targets this hard-codes Unix errno values: for example, Windows reports access denied as raw_os_error() == Some(5), so a permission bug from create_dir_all/File would be classified as the EIO host-I/O condition even though this classifier is meant to keep permission bugs reporting. The flattened-text branch repeats the same Unix-number assumption, so this should be gated to Unix errno values or use platform-aware ErrorKind/constants.
Useful? React with 👍 / 👎.
worker::is_host_io_error (the #63 classifier for EIO/ENOSPC/EROFS surfaced as std::io::Error) had no non-test caller, so the runtime worker loop treated a dying/read-only mount as a generic error and re-polled every error_backoff (500ms), flooding instead of paging once. Wire it into backoff_for with a new WorkerLoopConfig::host_io_backoff arm (default 30s), ordered right after the fatal is_sqlite_corrupt check and before the generic arm, mirroring the disk-full "persistent host condition" policy. Regression test: backoff_for on an EIO error returns host_io_backoff, not error_backoff. Claude-Session: https://claude.ai/code/session_01QHnr5vBKE3SaoALwkzCgNz
Module
memory::queue::workerWhat
Ports OpenHuman host commit
d7bee77e3— drift-ledger row D2 of the TinyCortex memory migration. Adds anis_host_io_errorclassifier to the queue worker's error family: EIO (5) / ENOSPC (28) / EROFS (30) surfaced as astd::io::Error— a dying SD card, a full disk, or a kernel-remounted-read-only mount.These are persistent, user-only-fixable host conditions that never clear on their own. Distinct from
is_sqlite_disk_full(SQLITE_FULLarrives as a SQLite code and stays in that arm) and from the transientis_sqlite_io_transientfamily. A host driver loop uses this to back off long and page once instead of re-polling and flooding — the host saw ~10k Sentry events/50min from this (CORE-RUST-19J).Matches the typed
std::io::Errordowncast and the flattened(os error N)text through anyhow context layers. EACCES (13) / ENOENT (2) are deliberately excluded — those are genuine bugs that must keep reporting.Scope
Only the predicate ports. The Sentry-once emission and the storage-degraded flag remain host-owned (drift-ledger D2-host); the crate exposes the classifier for a host loop to consume, matching the existing
is_sqlite_*classifiers (allpub, host-consumed).Tests
cargo test --lib queue::worker— 13 pass, incl. 2 new:is_host_io_error_matches_family_code_context_text(EIO/ENOSPC/EROFS × typed / context-layer / text-fallback)is_host_io_error_negatives(EACCES, ENOENT,SQLITE_FULL, unrelated → not swallowed)Gates host workstream W4 (queue cutover).
https://claude.ai/code/session_01X39btnEnHSTuPSYYvgyjrb