Skip to content

fix(channels): wire SCHEMA_DRIFT error_type for api/crawl4ai JSON parse failures - #71

Open
1012839419a-alt wants to merge 1 commit into
2233admin:mainfrom
1012839419a-alt:fix/schema-drift-json-parse
Open

fix(channels): wire SCHEMA_DRIFT error_type for api/crawl4ai JSON parse failures#71
1012839419a-alt wants to merge 1 commit into
2233admin:mainfrom
1012839419a-alt:fix/schema-drift-json-parse

Conversation

@1012839419a-alt

Copy link
Copy Markdown
Contributor

What

WIRING_GAP_LEDGER W1 (the ledger's highest-ROI item): the control layer's SCHEMA_DRIFT chain (error_kindsevaluatorpoliciesactuator) runs every 60s, but only fires when a channel passes error_type explicitly — control/recorder.py drops failures with error_type is None (the elif error_type is not None guard).

Two JSON parse failure points still raised ChannelFetchError without error_type, so a schema drift in those channels looked like a healthy source:

  • api_channel.pyresponse.json() parse failure
  • crawl4ai_channel.pyextracted_content JSON parse failure

Change

Set error_type=type(exc).__name__ at both points. JSONDecodeError already maps to SCHEMA_DRIFT in backend/control/error_kinds.py, so the failure now reaches the recorder and the 60s control chain fires.

(The rss/cli parse points of W1 were already wired in #60 / the pending rss empty-HTML PR; this closes the remaining channel surface.)

Verification

  • New tests: JSONDecodeError → SCHEMA_DRIFT for api fetch() and collect() paths, and crawl4ai malformed extracted_content
  • Targeted: 76 passed (api + crawl4ai suites)
  • Full regression: 2704 passed, 50 skipped, coverage 88.42% (≥80% gate)
  • ruff: 6 errors = identical to origin/main baseline (net-new 0; pre-existing E501/F841)

Closes the W1 portion of #31.

…se failures

WIRING_GAP_LEDGER W1: the control layer's SCHEMA_DRIFT chain
(error_kinds -> evaluator -> policies -> actuator) runs every 60s but only
fires when a channel passes error_type explicitly — recorder's
`elif error_type is not None` guard drops failures without one.

api_channel.fetch() and crawl4ai_channel.fetch() both raise
ChannelFetchError on JSON parse failure without error_type, so a schema
drift in those channels looked like a healthy source. Set
error_type=type(exc).__name__ (JSONDecodeError maps to SCHEMA_DRIFT in
error_kinds) so the chain fires.

Tests: JSONDecodeError -> SCHEMA_DRIFT for fetch() and collect() paths
(api), malformed extracted_content -> SCHEMA_DRIFT (crawl4ai).
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@1012839419a-alt, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

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 Plus

Run ID: ac5ad71b-4f9b-4cab-b76d-c5bbc1658e0e

📥 Commits

Reviewing files that changed from the base of the PR and between 94ab53d and ccf242e.

📒 Files selected for processing (4)
  • backend/channels/api_channel.py
  • backend/channels/crawl4ai_channel.py
  • tests/unit/channels/test_api_channel.py
  • tests/unit/channels/test_crawl4ai_channel.py

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.

@repowise-bot

repowise-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

✅ Health of changed files: 5.4 (unchanged)
⚠️ Change risk: moderate, riskier than 43% of this repo's commits.

📋 At a glance
4 hotspots touched · 2 new findings introduced · 3 files with recent fix history.

Files & modules (2)
  • backend (2 files)
    • backend/channels/api_channel.py
    • backend/channels/crawl4ai_channel.py
  • tests (2 files)
    • .../channels/test_api_channel.py
    • .../channels/test_crawl4ai_channel.py

✅ Health gate: passed

📌 Before you merge

  • Run .../channels/test_api_auth_deprecation.py: they import the changed files
🔎 More signals (2)

🗺️ Change map

flowchart LR
  subgraph PR ["Changed in this PR (3 with dependents)"]
    f_backend_channels_api_channel_py["backend/channels/api_channel.py 🔥"]:::changed
    f_backend_channels_crawl4ai_channel_py["backend/channels/crawl4ai_channel.py 🔥"]:::changed
    f_tests_unit_channels_test_api_channel_py[".../channels/test_api_channel.py"]:::changed
  end
  f_backend_channels_registry_py["backend/channels/registry.py"]
  f_backend_channels_api_channel_py --> f_backend_channels_registry_py
  f_backend_channels_crawl4ai_channel_py --> f_backend_channels_registry_py
  f_backend_channels_web_scraper_channel_py["backend/channels/web_scraper_channel.py"]
  f_tests_unit_channels_test_api_channel_py --> f_backend_channels_web_scraper_channel_py
  t_tests_unit_channels_test_api_auth_deprecation_py(["✅ .../channels/test_api_auth_deprecation.py"]):::guard
  t_tests_unit_channels_test_api_auth_deprecation_py -.-> f_backend_channels_api_channel_py
  classDef changed fill:#dbeafe,stroke:#1d4ed8,color:#1e3a5f
  classDef warn fill:#fef3c7,stroke:#b45309,color:#78350f
  classDef guard fill:#dcfce7,stroke:#15803d,color:#14532d
Loading

Solid arrows: code that imports the changed files (2 direct dependents, from the last indexed snapshot). Dashed: history/tests.

🔥 Hotspots touched (4)

  • .../channels/test_api_channel.py: 10 commits/90d, 1 dependents · primary owner: Curry (56%)
  • backend/channels/api_channel.py: 14 commits/90d, 3 dependents · primary owner: Curry (77%)
  • .../channels/test_crawl4ai_channel.py: 3 commits/90d, 1 dependents · primary owner: Curry (86%)
1 more
  • backend/channels/crawl4ai_channel.py: 8 commits/90d, 2 dependents · primary owner: Curry (99%)

👀 Suggested reviewers @2233admin


📊 See the full report for this PR
Your repo map with this PR's blast radius lit up, every caller of the contracts it changes, and health before and after. No sign-in. · ⭐ Star Repowise · 📥 Install bot · Silence on a single PR with [skip repowise] in the title · Per-repo toggle on repowise.dev/settings?tab=bot · Updated 2026-08-07 17:37 UTC

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