Skip to content

fix(queue): classify persistent host-FS I/O errors (is_host_io_error) - #63

Merged
senamakel merged 1 commit into
tinyhumansai:mainfrom
senamakel:drift/d2-classify-host-io-error
Jul 10, 2026
Merged

senamakel merged 1 commit into
tinyhumansai:mainfrom
senamakel:drift/d2-classify-host-io-error

Conversation

@senamakel

Copy link
Copy Markdown
Member

Module

memory::queue::worker

What

Ports OpenHuman host commit d7bee77e3 — drift-ledger row D2 of the TinyCortex memory migration. 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. Distinct from is_sqlite_disk_full (SQLITE_FULL arrives as a SQLite code and stays in that arm) and from the transient is_sqlite_io_transient family. 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::Error downcast 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 (all pub, 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

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).
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 36 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ae45fe64-b465-4ecf-b6d7-25bf6cb5fb25

📥 Commits

Reviewing files that changed from the base of the PR and between 33dda94 and fc62463.

📒 Files selected for processing (2)
  • src/memory/queue/worker.rs
  • src/memory/queue/worker_tests.rs

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

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment on lines +177 to +178
if matches!(io_err.raw_os_error(), Some(5) | Some(28) | Some(30)) {
return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

@senamakel
senamakel merged commit e352435 into tinyhumansai:main Jul 10, 2026
1 of 2 checks passed
senamakel added a commit that referenced this pull request Jul 11, 2026
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
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