Skip to content

feat(retrieval): flip entity-persistence demotion default-on in retrieve_v2 (#1096) - #1108

Merged
github-actions[bot] merged 3 commits into
mainfrom
feat/issue-1096-flip-entity-persist-default-on
Jul 6, 2026
Merged

github-actions[bot] merged 3 commits into
mainfrom
feat/issue-1096-flip-entity-persist-default-on

Conversation

@robotrocketscience

@robotrocketscience robotrocketscience commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Summary

Flips use_entity_persist_demote default-on in retrieve_v2 (#1096), the operator-approved default-on call now that every evidence gate has cleared. The demotion mechanism shipped default-off (#1099); this changes only the resolver default (plus a TOML opt-out rung) and the tests/docs that encoded the old posture.

Why now — all gates cleared

  • G1 deterministic / byte-identical when off — pinned by the explicit demote=False arms in the tests.
  • G2 demote-without-recall-loss — the mixed-corpus eval test(retrieval): mixed-corpus G2 eval for entity-persist demote (#1096) #1103 (merged) proves the positive half: durable recall held 20→20, ephemeral coordination demoted 20→3 at the tight pack budget, MRR 0.883→1.000. Recall-safe / inert on LoCoMo (all noun_phrase entities).
  • G3 ablation — S1 mean 0.56 durable vs 0.06 ephemeral, ranking AUC 0.48→0.87.
  • G4 latency — one indexed belief_entities join.

What changed

  • Resolver (is_entity_persist_demote_enabled): default FalseTrue, and it now honours a [retrieval] use_entity_persist_demote TOML rung (precedence env → kwarg → TOML → default True), matching the is_heat_kernel_enabled default-on idiom. This also makes the CONFIG.md precedence claim (which already listed a TOML rung) actually true and gives per-project opt-out without an env var.
  • Tests: test_resolver_default_on + a new TOML opt-out test; the byte-identical-when-off assertions now pin the explicit demote=False path instead of the (now default-on) no-flag path; the G2 gate file's default-posture test reframed to assert default == explicit-on and that the lane still reorders vs the off-path.
  • Docs: CONFIG / ARCHITECTURE / LIMITATIONS + CHANGELOG updated to default-on with the scope caveat below stated explicitly.

⚠️ Scope — this does not change production hook retrieval

The lane is wired into retrieve_v2() only. Production retrieval — the UserPromptSubmit hook (hook_search.retrieve()), context_rebuilder, and mcp_server — all call the legacy retrieve(), which does not expose the flag. So this flip governs retrieve_v2 consumers (benchmarks, the eval suite, direct callers) and does not change what a live host retrieves. That retrieve() / retrieve_v2() production-path gap affects all the recently-staged lanes (this one, origin tie-break #1089, temporal spine #1064, HRR) and is filed for disposition in #1107. The docs in this PR state the retrieve_v2-only scope so they are not misleading in the interim.

Verification

  • Full pytest green: 5825 passed, 69 skipped, 75 xfailed.
  • Discretion grep clean on the diff.
  • 2 atomic signed commits (feat+tests, docs).

Closes #1096. Refs #1103, #1107.

Summary by CodeRabbit

  • New Features

    • Retrieval now defaults to entity-persistence demotion in retrieve_v2.
    • A new configuration option is available through TOML, environment variables, and keyword arguments, with clear precedence handling.
  • Bug Fixes

    • Updated retrieval behavior and tests so the default matches the explicit enabled setting.
    • Clarified that the legacy retrieval path is unchanged.
  • Documentation

    • Revised user, architecture, and limitations docs to reflect the new default behavior and configuration scope.

…1096)

Flip use_entity_persist_demote to default-on in the retrieve_v2 resolver
now that the G2 mixed-corpus eval (#1103) cleared the no-regression gate
(durable recall 20->20, ephemeral demoted 20->3 at the tight budget, MRR
0.883->1.000; recall-safe/inert on LoCoMo). The resolver also gains a
[retrieval] use_entity_persist_demote TOML rung (env -> kwarg -> TOML ->
default True), matching the use_heat_kernel idiom so per-project opt-out
works without an env var.

Scope: the lane is wired into retrieve_v2() only; the legacy retrieve()
hook path does not expose it (production-path gap tracked in #1107).

Tests updated for the flipped default: resolver default-on + TOML opt-out
coverage, and the byte-identical-when-off assertions now pin the explicit
off path instead of the (now default-on) no-flag path.
#1096)

Update CONFIG.md, ARCHITECTURE.md, LIMITATIONS.md, and the CHANGELOG for
the #1096 default-on flip. State the retrieve_v2-only scope explicitly so
the docs do not imply the live retrieve() hook path demotes (it does not;
gap tracked in #1107), correct the precedence line to default true with a
TOML opt-out rung, and note the origin tie-break remains default-off.
@robotrocketscience robotrocketscience added the author-garsecg PR coordination mutex label Jul 6, 2026

@sourcery-ai sourcery-ai 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.

Sorry @robotrocketscience, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR-size soft cap

This PR is over the advisory size threshold:

  • 108 changed lines (limit: 200)
  • 7 changed files (limit: 3)

Bigger PRs collide with more open work, which under the parallel-session workflow tends to produce repeated attn:merge-conflict cycles (see #602). When practical, split into smaller PRs that each touch a focused surface.

This is advisory only — nothing is blocked. If the size is intentional (large refactor, module removal, generated code), apply the size:override label and this comment will be removed on the next push.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@robotrocketscience, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 28 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f7d96e90-1308-4b47-aed4-6c36a591f0a9

📥 Commits

Reviewing files that changed from the base of the PR and between 1368755 and ad60070.

📒 Files selected for processing (1)
  • docs/user/CONFIG.md
📝 Walkthrough

Walkthrough

The entity-persistence demotion flag now defaults to True (previously False) for retrieve_v2, resolved via a precedence chain of environment variable, explicit kwarg, new .aelfrice.toml config, then default. Tests and documentation (CHANGELOG, ARCHITECTURE, CONFIG, LIMITATIONS) are updated to reflect this default-on scope, which is limited to retrieve_v2 and does not affect the legacy retrieve() path.

Changes

Entity-persist-demote default-on flip

Layer / File(s) Summary
Resolver logic: TOML and default flip
src/aelfrice/retrieval.py
is_entity_persist_demote_enabled adds a keyword-only start: Path | None parameter and TOML lookup ([retrieval] use_entity_persist_demote) to the precedence chain; fallback default changes from False to True.
Tests for default-on and TOML precedence
tests/test_entity_persist_demote.py, tests/bench_gate/test_entity_persist_g2_mixed_corpus.py
New/updated tests assert default-on when unset, opt-out via explicit False kwarg, TOML precedence override, and retrieve_v2 output matching explicit demote=True rather than demote=False.
Documentation for scoped default-on behavior
CHANGELOG/v3.md, docs/concepts/ARCHITECTURE.md, docs/user/CONFIG.md, docs/user/LIMITATIONS.md
Changelog, architecture, config, and limitations docs updated to describe the flag as default-on in retrieve_v2 since v4.0, with the legacy retrieve() path unaffected.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related issues

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the main retrieval change and the affected path, matching the PR scope.
Description check ✅ Passed The description includes summary, linked issue, verification, and scope context, with only some template sections left informal.
Linked Issues check ✅ Passed The changes satisfy #1096 by flipping the resolver default, adding TOML opt-out, and updating tests/docs for the new default-on behavior.
Out of Scope Changes check ✅ Passed The diff stays focused on the retrieval demotion flip, tests, and documentation; no unrelated code paths or features were added.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-1096-flip-entity-persist-default-on

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.

@robotrocketscience robotrocketscience added the attn:review Needs review (PR open, awaiting reviewer) label Jul 6, 2026

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/test_entity_persist_demote.py (1)

207-211: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Test relies on ambient cwd for TOML resolution.

Unlike test_resolver_toml_opts_out (which isolates via start=tmp_path), this test calls is_entity_persist_demote_enabled(None) without a start, so the resolver walks up from Path.cwd(). If the repo root (or any ancestor of the test-runner's cwd) ever gains a .aelfrice.toml with [retrieval] use_entity_persist_demote = false, this test would flip to failing even though the resolver logic is correct — a false negative unrelated to the code under test.

♻️ Suggested isolation
-def test_resolver_default_on(monkeypatch: pytest.MonkeyPatch) -> None:
+def test_resolver_default_on(
+    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
+) -> None:
     # v4.0 flip (`#1096/`#1103): with no env/kwarg/TOML rung set, the lane
     # now resolves ON.
     monkeypatch.delenv("AELFRICE_ENTITY_PERSIST_DEMOTE", raising=False)
-    assert is_entity_persist_demote_enabled(None) is True
+    assert is_entity_persist_demote_enabled(None, start=tmp_path) is True
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_entity_persist_demote.py` around lines 207 - 211, The default-on
resolver test is picking up TOML from the ambient current working directory, so
it can fail due to external config rather than the code under test. Update
test_resolver_default_on in tests/test_entity_persist_demote.py to isolate the
filesystem lookup the same way test_resolver_toml_opts_out does, by supplying an
explicit temporary start/root and ensuring no .aelfrice.toml is visible to
is_entity_persist_demote_enabled, while still asserting the default behavior
when AELFRICE_ENTITY_PERSIST_DEMOTE is unset.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/concepts/ARCHITECTURE.md`:
- Around line 125-130: Clarify the scope statement in ARCHITECTURE.md so it does
not claim both rerank modifiers are retrieve_v2-only. Keep the
`use_entity_persist_demote` description tied to `retrieve_v2`, but update the
`use_origin_tiebreak` wording to reflect its support in `retrieve()` as well per
the configuration docs, using the `use_entity_persist_demote`,
`use_origin_tiebreak`, and `retrieve_v2`/`retrieve()` symbols to make the
distinction explicit.

---

Nitpick comments:
In `@tests/test_entity_persist_demote.py`:
- Around line 207-211: The default-on resolver test is picking up TOML from the
ambient current working directory, so it can fail due to external config rather
than the code under test. Update test_resolver_default_on in
tests/test_entity_persist_demote.py to isolate the filesystem lookup the same
way test_resolver_toml_opts_out does, by supplying an explicit temporary
start/root and ensuring no .aelfrice.toml is visible to
is_entity_persist_demote_enabled, while still asserting the default behavior
when AELFRICE_ENTITY_PERSIST_DEMOTE is unset.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d2fd0117-4459-4bee-a34c-02e2debe4091

📥 Commits

Reviewing files that changed from the base of the PR and between 7778fd9 and 1368755.

📒 Files selected for processing (7)
  • CHANGELOG/v3.md
  • docs/concepts/ARCHITECTURE.md
  • docs/user/CONFIG.md
  • docs/user/LIMITATIONS.md
  • src/aelfrice/retrieval.py
  • tests/bench_gate/test_entity_persist_g2_mixed_corpus.py
  • tests/test_entity_persist_demote.py

Comment thread docs/concepts/ARCHITECTURE.md
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

merge-train: blocked

1 review thread(s) are unresolved on these files: docs/concepts/ARCHITECTURE.md. Resolve them on the PR (click 'Resolve conversation' on each) and re-add the label.

The ready-to-merge label has been removed. Address the issue above and re-add the label when you're ready for another attempt.

@github-actions github-actions Bot removed the ready-to-merge Trigger merge-train: FF main to this PR's head label Jul 6, 2026
CodeRabbit review on #1108 flagged the ARCHITECTURE.md 'retrieve()
exposes neither' wording as inconsistent with CONFIG.md. Verified against
code: retrieve()'s signature has no use_origin_tiebreak param (only the
helpers / retrieve_with_tiers / retrieve_v2 thread it), so ARCHITECTURE.md
is correct and CONFIG.md overstated. Fix the CONFIG.md line to retrieve_v2
only, matching the entity-persist scope note.
@robotrocketscience

Copy link
Copy Markdown
Owner Author

Addressed the CodeRabbit thread on ARCHITECTURE.md. Verified against code, not the docs: retrieve()'s signature has no use_origin_tiebreak parameter — only _l1_hits/_l25_hits, retrieve_with_tiers, and retrieve_v2 thread it. So the ARCHITECTURE.md wording ("retrieve() exposes neither") is correct; the real inaccuracy was CONFIG.md, which claimed the use_origin_tiebreak kwarg on retrieve() / retrieve_v2(). Fixed CONFIG.md to retrieve_v2() only in ad60070, matching the entity-persist scope note. (CodeRabbit trusted the stale CONFIG.md line — the same overstatement pattern this PR is correcting.) Resolved.

@robotrocketscience robotrocketscience added the ready-to-merge Trigger merge-train: FF main to this PR's head label Jul 6, 2026
@github-actions
github-actions Bot merged commit ad60070 into main Jul 6, 2026
28 checks passed
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

merge-train: merged ad60070main via FF push.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

attn:review Needs review (PR open, awaiting reviewer) author-garsecg PR coordination mutex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Entity-persistence demotion prior: a deterministic organic sink for coordination junk (follow-up to #1086/#1081)

1 participant