Stop filtering discovery by CEFR level - #704
Merged
Merged
Conversation
On-demand simplification (#698) quietly turned the feed's level filter into a starvation filter. `available_cefr_levels` lists the levels for which a version of an article was ALREADY generated: the original's own level plus its simplified children. Once crawl-time simplification was retired there are no children, so the field collapsed to a single value and a learner saw only articles a publisher happened to write at exactly their band. Measured on the live index for Danish over 7 days: 33 documents matched an A2 reader, out of 479 in the language. Meanwhile 266 of those articles already carried an A2 ArticleLevelSummary — content written for precisely that reader, which the filter guaranteed they would never see. The premise no longer holds. An article being above the learner's level is not a reason to hide it when the card shows a level-appropriate summary and the body simplifies on request. So drop the filter from all three discovery paths — recommender feed, video recommendations, search — rather than widen it. Above-level readers are the mirror case and get the same treatment once we complexify. Two things this also fixes, both of which produced empty feeds: - Articles whose LLM assessment failed have no cefr_level and so matched nothing. Every assessment outage (the Aug-13 article_type bug, the Anthropic usage-cap outages) therefore emptied feeds outright. Feeds are now independent of assessment liveness. - document_from_video never writes an available_cefr_levels field, so requiring a level in it excluded every video from every leveled user. feed_delivery_health_check reached its per-segment inventory THROUGH the recommender builder, so it would have silently degraded into six copies of one language-wide query. It now appends the CEFR clause itself, and says what that clause means now: a canary on assessment coverage, not on feed delivery. UserPreference.SHOW_EASIER_ARTICLES is inert as a result — nothing left to widen. Left in place, and flagged, until the web toggle is removed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Why
A learner reported a feed with too few articles. It is not the recommender — it is the level filter, which on-demand simplification (#698) turned into a starvation filter.
available_cefr_levelslists the levels for which a version of an article was already generated: the original's own level, plus its simplified children. Once crawl-time simplification was retired there are no children, so the field collapsed to a single value — and a learner saw only the articles a publisher happened to write at exactly their band.Measured on the live index, Danish, last 7 days:
A2,A1/A2)And 266 of those articles already carry an A2
ArticleLevelSummary— content generated for precisely that reader, which the filter guaranteed they would never see. The level-summary overlay and the level filter have been contradicting each other since #698.What
The premise behind the filter no longer holds: an article above the learner's level is not something to hide when the card carries a level-appropriate summary and the body simplifies on request. So the filter is dropped, not widened — from all three discovery paths (recommender feed, video recommendations, search). Above-level readers are the mirror case and get the same treatment once we complexify.
Two further empty-feed causes go with it:
cefr_level, so they matched nothing. Every assessment outage — the Aug-13article_typebug, the Anthropic usage-cap outages — emptied feeds outright. Feeds no longer depend on assessment liveness. (During the Aug 16–17 cap outage, every article crawled for ~12h was invisible in every language.)document_from_videonever writes anavailable_cefr_levelsfield, so requiring a level in it excluded every video from every leveled user.feed_delivery_health_checkreached its per-segment inventory through the recommender builder, so this change would have silently degraded it into six copies of one language-wide query. It now appends the CEFR clause itself, and the docstrings state what that clause measures now: assessment coverage, not feed delivery.Notes
UserPreference.SHOW_EASIER_ARTICLESis now inert — there is nothing left to widen. Left in place and flagged; the web toggle in Settings → Feed Preferences should be removed or repurposed in a follow-up.User.cefr_level_for_languagedoes[...][cefr_level - 1], so a storedcefr_levelof0maps to C2. Many users have0. Moot for the feed now, but wrong wherever else it is called.Tests
zeeguu/core/test/test_elastic_query_builder.pypins the no-filter behavior on all three queries so it cannot creep back.zeeguu/core/test: 226 passed.zeeguu/api/test: 16 failures, all pre-existing on clean master (test_bookmark_positions,test_verbal_flashcards) — verified by stashing.🤖 Generated with Claude Code