feat(retrieval): flip use_bm25f_anchors default-on at v1.7.0 (#154) - #430
Conversation
Adding stemming to tokenize_stemmed() raised per-doc tokenisation cost enough to push two 5s-timeout tests over the line at 10k beliefs: - test_ac4_median_latency_under_200ms_on_10k_belief_store - test_fire_cap_independent_per_session Real corpora are Zipfian — the same tokens recur frequently across documents — so a 64K-entry LRU on stemWord() has very high hit rate after warm-up. Cache is module-global; reset on process exit. Both timeouts clear after this commit. This is needed before the default-on flip (which makes BM25F the hot path on every retrieve() call) to keep retrieve() perf characteristic similar to the v1.5/v1.6 FTS5 baseline.
resolve_use_bm25f_anchors default flipped False → True per the bench evidence at #154: - comment 4380842909: pre-stem +0.6010 NDCG@k uplift on the v0.1 retrieve_uplift fixture (30 rows, 6 categories). - comment 4380967901: post-stem +0.6650 NDCG@k uplift after the Porter stemmer addition closed the q="banana" vs content "bananas" gap. - bench-gate test_retrieve_per_flag_no_regression: PASS — no per-row regression vs all-flags-off baseline. Three regression tests pinned to explicit flag values to assert the contract (default-on, opt-out path intact): - test_ac2_weight_zero_byte_identical_to_v10x: explicit use_bm25f_anchors=False to keep the v1.0.x byte-identity check. - test_retrieve_default_off_byte_identical_to_pre_v15_path renamed to test_retrieve_default_on_byte_identical_to_explicit_on; pinned to use_bm25f_anchors=True since the default flipped. - test_lane_telemetry_records_fts5_lane_by_default renamed to test_lane_telemetry_records_fts5_lane_when_opted_out (pinned to False); new test_lane_telemetry_records_bm25f_lane_by_default asserts the new default contract. Opt-out remains via AELFRICE_BM25F=0, kwarg use_bm25f_anchors=False, or [retrieval] use_bm25f_anchors = false in .aelfrice.toml. Closes the v1.7 default-on flip portion of #154.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Reviewer's GuideImplements a performance optimization for Porter stemming in the BM25 index via an LRU cache and flips the retrieval default to use BM25F anchors at v1.7.0, updating the resolution logic and regression tests to enforce and document the new default while preserving explicit opt-out paths and legacy behavior checks. Sequence diagram for resolve_use_bm25f_anchors decision ordersequenceDiagram
participant caller
participant resolve_use_bm25f_anchors
participant env_bm25f_override
participant toml_reader
caller->>resolve_use_bm25f_anchors: call(explicit, start)
resolve_use_bm25f_anchors->>env_bm25f_override: env = _env_bm25f_override()
env_bm25f_override-->>resolve_use_bm25f_anchors: env or None
alt env is not None
resolve_use_bm25f_anchors-->>caller: return env
else env is None
alt explicit is not None
resolve_use_bm25f_anchors-->>caller: return explicit
else explicit is None
resolve_use_bm25f_anchors->>toml_reader: toml_value = _read_toml_flag_for(BM25F_FLAG, start)
toml_reader-->>resolve_use_bm25f_anchors: toml_value or None
alt toml_value is not None
resolve_use_bm25f_anchors-->>caller: return toml_value
else toml_value is None
resolve_use_bm25f_anchors-->>caller: return True
end
end
end
Class diagram for BM25 stemming cache and retrieval flag resolutionclassDiagram
class Bm25Module {
+snowballstemmer stemmer porter_stemmer
+_stem(token str) str
+tokenize_stemmed(text str) list_str
}
class PorterStemmerLRUCache {
+int maxsize
+_stem_cache
+_stem(token str) str
}
class RetrievalConfigResolver {
+resolve_use_bm25f_anchors(explicit bool, start Path) bool
+_env_bm25f_override() bool
+_read_toml_flag_for(flag str, start Path) bool
}
Bm25Module ..> PorterStemmerLRUCache : uses
Bm25Module : tokenize_stemmed(text) calls _stem(token)
PorterStemmerLRUCache : _stem(token) uses porter_stemmer
RetrievalConfigResolver : resolve_use_bm25f_anchors uses default True
RetrievalConfigResolver : resolve_use_bm25f_anchors prefers env
RetrievalConfigResolver : then explicit kwarg
RetrievalConfigResolver : then toml flag
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Updates the v1.7 row to reflect the post-stemming bench result and the actual default-on flip: - BM25F anchor-text retrieval (#148) default-on at v1.7.0 per #154 bench evidence: +0.6650 NDCG@k uplift on the v0.1 retrieve_uplift fixture under Porter stemming. PR #428 added the stemmer; PR #430 flipped the default; bench-gate test_retrieve_per_flag_no_regression PASS. - Other v1.7 components (use_signed_laplacian, use_heat_kernel, use_hrr_structural) remain opt-in — placeholder lanes pending wiring into retrieve(). The v1.7 wave is shipped; the remaining-flags flip waits on those lanes landing. - v2.0 row drops the "default-on flip is a prereq" note since v1.7 is now shipped. Replaces the prior intermediate framing ("shipped (opt-in)"; deferred default-on flip).
|
[claim:review:Kulili:2026-05-05T16:17:27Z] |
Updates the v1.7 row to reflect the post-stemming bench result and the actual default-on flip: - BM25F anchor-text retrieval (#148) default-on at v1.7.0 per #154 bench evidence: +0.6650 NDCG@k uplift on the v0.1 retrieve_uplift fixture under Porter stemming. PR #428 added the stemmer; PR #430 flipped the default; bench-gate test_retrieve_per_flag_no_regression PASS. - Other v1.7 components (use_signed_laplacian, use_heat_kernel, use_hrr_structural) remain opt-in — placeholder lanes pending wiring into retrieve(). The v1.7 wave is shipped; the remaining-flags flip waits on those lanes landing. - v2.0 row drops the "default-on flip is a prereq" note since v1.7 is now shipped. Replaces the prior intermediate framing ("shipped (opt-in)"; deferred default-on flip).
Updates the v1.7 row to reflect the post-stemming bench result and the actual default-on flip: - BM25F anchor-text retrieval (#148) default-on at v1.7.0 per #154 bench evidence: +0.6650 NDCG@k uplift on the v0.1 retrieve_uplift fixture under Porter stemming. PR #428 added the stemmer; PR #430 flipped the default; bench-gate test_retrieve_per_flag_no_regression PASS. - Other v1.7 components (use_signed_laplacian, use_heat_kernel, use_hrr_structural) remain opt-in — placeholder lanes pending wiring into retrieve(). The v1.7 wave is shipped; the remaining-flags flip waits on those lanes landing. - v2.0 row drops the "default-on flip is a prereq" note since v1.7 is now shipped. Replaces the prior intermediate framing ("shipped (opt-in)"; deferred default-on flip).
Updates the v1.7 row to reflect the post-stemming bench result and the actual default-on flip: - BM25F anchor-text retrieval (#148) default-on at v1.7.0 per #154 bench evidence: +0.6650 NDCG@k uplift on the v0.1 retrieve_uplift fixture under Porter stemming. PR #428 added the stemmer; PR #430 flipped the default; bench-gate test_retrieve_per_flag_no_regression PASS. - Other v1.7 components (use_signed_laplacian, use_heat_kernel, use_hrr_structural) remain opt-in — placeholder lanes pending wiring into retrieve(). The v1.7 wave is shipped; the remaining-flags flip waits on those lanes landing. - v2.0 row drops the "default-on flip is a prereq" note since v1.7 is now shipped. Replaces the prior intermediate framing ("shipped (opt-in)"; deferred default-on flip).
Lands the v1.7 default-on flip for
use_bm25f_anchors. Stacked on PR #428 (Porter stemming) — that has to merge first; this PR's base is set to that branch.What ships (2 commits on top of #428)
perf(bm25): LRU-memoise Porter stem— 64K-entrylru_cacheover_stem(token). Stemming added per-doc cost that pushed two 5s-timeout tests over the edge at 10k beliefs (test_ac4_median_latency_under_200ms_on_10k_belief_store,test_fire_cap_independent_per_session). Zipfian token distribution → high cache hit rate; both timeouts clear.feat(retrieval): flip use_bm25f_anchors default-on at v1.7.0—resolve_use_bm25f_anchorsdefaultFalse → True. Three regression tests pinned to explicit flag values:test_ac2_weight_zero_byte_identical_to_v10x— explicituse_bm25f_anchors=Falseto keep the v1.0.x byte-identity check.test_retrieve_default_off_byte_identical_to_pre_v15_path→ renamedtest_retrieve_default_on_byte_identical_to_explicit_on; pinned toTrue.test_lane_telemetry_records_fts5_lane_by_default→ renamedtest_lane_telemetry_records_fts5_lane_when_opted_out(pinned toFalse); newtest_lane_telemetry_records_bm25f_lane_by_defaultasserts the new contract.Bench evidence
test_retrieve_per_flag_no_regression: PASSOpt-out paths preserved
Callers that want the legacy FTS5 path can still:
AELFRICE_BM25F=0env varuse_bm25f_anchors=Falsekwarg[retrieval] use_bm25f_anchors = falsein.aelfrice.tomlTest plan
uv run pytest --ignore=tests/bench_gate -q— 2457 passed, 23 skipped.AELFRICE_CORPUS_ROOT=... uv run pytest tests/bench_gate/test_retrieve_uplift.py— PASS.q="banana"against content"bananas"returns['F1']under default settings.Out of scope
Summary by Sourcery
Flip BM25F anchor-based retrieval to be enabled by default while preserving opt-out paths and stabilizing performance with Porter stemming memoization.
New Features:
Enhancements:
Tests: