Skip to content

State that recall's limit applies to the backend's ordering - #129

Merged
CodeGhost21 merged 1 commit into
tinyhumansai:mainfrom
CodeGhost21:fix/recall-rank-fixture
Sep 2, 2026
Merged

State that recall's limit applies to the backend's ordering#129
CodeGhost21 merged 1 commit into
tinyhumansai:mainfrom
CodeGhost21:fix/recall-rank-fixture

Conversation

@CodeGhost21

@CodeGhost21 CodeGhost21 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #128, where search folded the engine's answer, sorted it by key,
and then truncated to limit — so recall returned whichever keys sorted first
and threw away the engine's best hits. Ranking is the entire reason that
integration exists, and the driver was discarding it at the last step.

The rule it should have been able to read did not exist. The contract said
result ordering is backend-defined and that callers must not assume a stable
order across backends; it never said an implementation may not impose one.
This states it: a driver that receives more candidates than limit and reduces
them itself must keep the backend's order and take a prefix of it.

Related issue

None. Follow-up to #128.

API or behavior changes

None. Documentation, plus test-fixture content.

Validation

  • cargo fmt --all -- --check — clean
  • cargo clippy --all-targets --all-features -- -D warnings — clean
  • cargo build --all-targets --all-features — clean
  • cargo test --all-features — 33 targets, 0 failures

Also RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features (clean), and
the live CortexDB lane (passes, 182s).

Tests

The recall fixture now stores distinct content per key instead of "shared needle text" three times. Identical content leaves a backend free to order ties
however it likes, and an arbitrary order is one nothing downstream can assert
about. All five drivers and the live lane pass unchanged.

What I did not add, and why it matters that it is written down. I looked at
making assert_recall_respects_limit_and_namespace catch the #128 bug directly
and concluded it cannot, so the assertion now says so in its own docs rather
than reading as coverage it does not provide:

  • the suite cannot know how a given engine ranks these particular rows, so it
    cannot name the row that should come back first;
  • comparing two limits does not separate the cases either — a driver that sorts
    before truncating is self-consistent, so recall(limit 1) is still the
    first element of recall(limit 3).

What a black-box assertion here would catch is non-deterministic ordering,
which is a narrower fault, and pinning it would make the suite flaky against any
live engine whose ranking is not stable between two calls. That trade is not
worth it in a fixture that gates five drivers.

So the check belongs to each driver that folds or deduplicates before returning
— every append-only backend does, and the fold is exactly where an order gets
imposed. The docs point at recall_keeps_the_engine_ranking_when_it_truncates
in tinymemory-remote as the shape to copy.

I checked the other four dialects while I was here: supermemory, mem0,
cognee and agentmemory all pass limit down to their backend and none
reorders what it returned, so none has this bug today. The gap was only ever
reachable by a driver that truncates client-side.

Documentation

Memory::recall's contract docs carry the rule; the conformance assertion's
docs carry the gap and where it is covered instead.

Checklist

  • The change is focused on one logical change
  • No new #[allow(...)], #[ignore], or relaxed lints
  • No secrets, tokens, or .env contents in the diff or the description

Summary by CodeRabbit

  • Documentation

    • Clarified that recall limits are applied to the backend’s returned ordering.
    • Implementations must preserve backend ranking and return the leading results rather than re-sorting candidates before truncation.
  • Tests

    • Updated recall and namespace coverage with distinct sample content.
    • Added guidance clarifying that backend-specific ranking behavior is validated separately, while avoiding ambiguous result ordering in shared conformance tests.

A driver that receives more candidates than `limit` and reduces them
itself must keep the order the backend returned and take a prefix. The
contract said ordering was backend-defined but never said an
implementation may not impose its own, and the Cortex driver read that
gap the wrong way: it folded, sorted by key, then truncated, so recall
returned whichever keys sorted first and discarded the engine's best
hits. Fixed there in tinyhumansai#128; this is the rule it should have been able to
read.

The recall fixture now stores distinct content per key. Identical
content leaves a backend free to order ties however it likes, and an
arbitrary order is one nothing downstream can assert about.

The assertion's docs say plainly that it does *not* check this rule, and
why: the suite cannot know how an engine ranks these rows, and a driver
that sorts before truncating is self-consistent, so no black-box
comparison of two limits separates it from a correct one. That check
belongs to each driver that folds before returning, and the doc points
at the one in tinymemory-remote as the shape to copy. Better an
explicit gap than a fixture that reads as coverage and is not.
@tinysweeper

tinysweeper Bot commented Sep 2, 2026

Copy link
Copy Markdown

How this change flows

1 changed behaviour across 4 relationships. 5 surrounding behaviours are shown (60 graph nodes walked). 35 further behaviours left out to keep the diagram readable.

flowchart LR
  n0["assert_taint_is_preserved<br/>changed"]:::changed
  n1["assert_provider"]:::impacted
  n2["ns"]:::impacted
  n3["cleanup"]:::impacted
  n4["Result"]:::impacted
  n5["Memory"]:::impacted
  n0 -->|calls| n2
  n0 -->|calls| n3
  n1 -->|calls| n0
  n5 -->|uses| n4
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading

Green: changed behaviour. Grey: surrounding behaviour. Arrows name the call, use, implementation, or test relationship. Orange: has findings. Red: has a finding that blocks the merge.

tinysweeper 0.1.0

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

tinysweeper found nothing blocking. Approving.

$0.0000 · 0 in / 0 out

@tinysweeper tinysweeper Bot added the priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. label Sep 2, 2026
@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: a961d2df-18f4-490b-b619-52b37a79e3e1

📥 Commits

Reviewing files that changed from the base of the PR and between 00fe2a7 and ab3a1e6.

📒 Files selected for processing (2)
  • crates/tinymemory-api/src/traits.rs
  • crates/tinymemory-conformance/src/suite/mod.rs

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The Memory::recall documentation now defines limit handling based on backend order. The conformance fixture uses distinct row content and documents why backend ranking is not asserted by the shared suite.

Changes

Recall contract and conformance alignment

Layer / File(s) Summary
Recall contract and conformance fixture
crates/tinymemory-api/src/traits.rs, crates/tinymemory-conformance/src/suite/mod.rs
The recall contract requires implementations to preserve backend order when applying limit. The conformance fixture uses distinct content and does not assert engine-specific ranking.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Merge Risk: ⚪ Minimal · up to ab3a1

This PR clarifies recall truncation behavior and updates fixture content without changing production runtime behavior; no actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: senamakel

Poem

A rabbit reads the recall decree
Backend order stays as it should be
Three needles rest in rooms apart
Ties no longer blur the chart
The conformance burrow cheers with glee

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely states the main change: the recall limit must follow the backend's ordering.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

Your free Security trial is over. An organization admin can upgrade to Advanced for continuous pull request security review or dismiss this notice.


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

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

Labels

priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant