Repository navigation
Conversation
Lexical related recall admitted a stored memory only when the shared terms met the candidate's own coverage threshold. The requirement grew with the candidate, so a long candidate could need more shared terms than a short memory of the same fact contains, and the two were never compared. Related enumeration now also admits a memory whose shared terms number at least the minimum match count and cover the coverage fraction of the memory's own indexed words. The per-row requirement is computed from the existing searchable text on SQLite, seekDB and OceanBase; the native OceanBase path adds one MATCH block limited to memories short enough to qualify below the candidate threshold. Earlier window candidates use the same rule. Search, prepare-time admission and stored projections are unchanged. The workflow docs also drop an incorrect claim that related enumeration is prefiltered by Owner columns. The OceanBase long-query and native FTS CI steps get the case ceilings for the three new OceanBase cases.
There was a problem hiding this comment.
🔵 Needs a closer look
The backend-specific MATCH/UNION queries and floating-point bindings require OceanBase and embedded seekDB acceptance evidence that this review could not establish.
No open issues 🎉
What changed in this PR
This PR fixes Atomic Memory related recall so long candidates can find short stored memories using a threshold that also considers the stored memory’s indexed words. Ordinary search and prepare-time admission remain unchanged.
Changes:
- Apply the shared relatedness rule across SQLite, OceanBase/seekDB, and earlier candidates in the same processing window.
- Add regression coverage for lexical and hybrid recall, backend threshold consistency, and reconciliation.
- Update bilingual documentation, persistence review metadata, and OceanBase CI time budgets.
| File | Description |
|---|---|
tests/e2e/test_atomic_memory_unrelated_reconciliation.py |
Tests long-candidate reconciliation with stored memories and window siblings. |
tests/e2e/test_atomic_memory_long_fts_query.py |
Adjusts the below-threshold fixture for the new rule. |
tests/e2e/test_atomic_memory_fts_coverage.py |
Tests short-memory recall and SQL/Python admission consistency. |
src/powercontext/builtin/runtime/atomic_memory_processing.py |
Applies the shared threshold to window siblings. |
src/powercontext/builtin/persistence/sqlite/atomic_memory_index.py |
Uses per-memory thresholds for lexical related recall. |
src/powercontext/builtin/persistence/oceanbase/atomic_memory_index.py |
Updates native and whole-word related enumeration. |
src/powercontext/builtin/persistence/atomic_memory_index.py |
Defines shared Python and SQL relatedness thresholds. |
src/powercontext/builtin/artifacts/search.py |
Extracts the existing query-threshold calculation. |
release/upgrade-support.json |
Refreshes the persistence digest and compatibility rationale. |
docs/zh/docs/workflows/atomic-memory.md |
Documents relatedness and corrects owner-prefilter wording in Chinese. |
docs/zh/docs/operate/configuration.md |
Explains the rule and native-query cost in Chinese. |
docs/en/docs/workflows/atomic-memory.md |
Documents relatedness and corrects owner-prefilter wording in English. |
docs/en/docs/operate/configuration.md |
Explains the rule and native-query cost in English. |
.github/workflows/e2e-harness.yml |
Raises OceanBase time budgets for the added cases. |
Review effort: Balanced
hidb4ai
left a comment
There was a problem hiding this comment.
Reviewed dde5979; I found no blocking correctness defect in the changed recall rule. The focused checks passed on SQLite, embedded seekDB 1.4.0.post2, and real OceanBase CE 4.4.2.1, including native MATCH and the long-query fallback.
Merge-readiness note: merging this head with current master (2d47927) produces a content conflict in release/upgrade-support.json. Please resolve it and recompute the persistence digest from the resolved tree before merging. The current head's digest validates, but it does not cover the combined tree. The unit/e2e CI checks are also still pending.
…overage # Conflicts: # release/upgrade-support.json
|
@hidb4ai Thanks for the review, and for running it on seekDB and OceanBase. I merged current master into this branch (merge commit 1f9be31, no rebase). The only conflict was the persistence digest in |
hireview001
left a comment
There was a problem hiding this comment.
- CI failed: CI result (failure).
- CI failed: desktop-validation / linux (failure).
- CI failed: cindy-package (failure).
- CI failed: dsh-package (failure).
- CI failed: Main (failure). Failed steps: dsh-package / Test DSH package; cindy-package / Build and test the standalone Cindy archive; desktop-validation / linux / Run cargo clippy --locked --manifest-path src-tauri/Cargo.toml --all-targets -- -D warnings.
…overage # Conflicts: # docs/en/docs/workflows/atomic-memory.md # docs/zh/docs/workflows/atomic-memory.md # release/upgrade-support.json # src/powercontext/builtin/persistence/oceanbase/atomic_memory_index.py # src/powercontext/builtin/persistence/sqlite/atomic_memory_index.py
|
@hidb4ai #2449 merged after your review and conflicted with this branch, so I merged current master (195be9b) again, as 6bef39c, without a rebase. #2449 changed how related memories are enumerated: one frozen lightweight ranking, then bodies page by page. It kept the admission threshold, so a long candidate still missed a short memory of the same fact. This PR now changes only the two
Paging, the frozen ranking and body batching are unchanged. The workflow docs keep #2449's paging description. They still drop the claim that related enumeration is prefiltered by Owner, because the related filter carries only tags and kind. I recomputed The three behavior tests fail on master's |
hireview001
left a comment
There was a problem hiding this comment.
- Resolve merge conflicts with the target branch.
Which issue or RFC does this PR close?
No issue is closed. The defect was found in a memory-core audit and is described below. Related: RFC 1809 (Atomic Memory) and RFC 1560 (recall sufficiency gate, unchanged here). It builds on #2449, which made related enumeration paged; see Relation to #2449 below.
Rationale for this change
Related-memory recall during Atomic Memory processing queries with the candidate's text. Its lexical channel (used in
ftsandhybridrelated modes) admits a stored memory only when the distinct terms it shares with the candidate reachmax(lexical_min_matched_terms, ceil(lexical_coverage × n)), wherenis the candidate's distinct term count. The requirement grows with the candidate, not with the stored memory. A long candidate can need more shared terms than a short stored memory has, so that memory is never compared. The reverse direction works.This was reproduced on
38fb3508fthrough the public runtime, on SQLite and on a seekDB server using the OceanBase index:The billing database is PostgreSQL 15..RFC 1809 accepts some misses at the threshold. This one is structural, because it depends only on the relative lengths of the two texts.
What changes are included in this PR?
Rule. Related enumeration stays complete. It admits a memory when the distinct candidate terms it contains either:
lexical_min_matched_termsand coverlexical_coverageof the memory's own indexed words (its searchable text, including the kind).The requirement is therefore
min(candidate threshold, max(lexical_min_matched_terms, ceil(lexical_coverage × memory words))). It never exceeds what a short memory can supply. The one-match exception for one- or two-term queries stays a query rule and does not apply to the stored side. Earlier candidates in the same window use the same rule.Why the stored memory's indexed words. An exact distinct non-stopword count would need a new projection column, a migration and a backfill on every backend. The word count is derived in SQL from the existing
searchable_text. Because it includes stopwords, repeats and the kind, it is never lower than the distinct term count, so the rule never admits more than an exact count would.Where.
atomic_memory_related_requirementandatomic_memory_related_requirement_sqlinpersistence/atomic_memory_index.pyown the rule.words × coveragein double precision. For an integer, this is the same as comparing with the ceiling that Python computes._related_fts_rank_sql, added by perf(atomic-memory): bound related recall candidates in SQL to reduce peak memory and recall cost #2449 and used byftsandhybrid) applies the per-row requirement on both backends:LOCATE) path applies the per-row requirement directly.minimum_should_matchblock. It adds a second nativeMATCHblock, withminimum_should_match = lexical_min_matched_terms, only when that minimum is below the candidate's threshold. That block computes the word count for each row it matches, then whole-word coverage for rows whose requirement is below the candidate's threshold. For a long candidate, those are nearly all memories sharing that many terms; see Cost.fts_required_matchesis extracted fromfts_query_requirementsinartifacts/search.py. Its behavior is unchanged.prepare_contextadmission (RFC 1560), recovery probes, Topic Memory and Experience are unchanged. Their threshold measures how much of a query a result answers. Related recall compares two memories, which is the only place where the stored side's length matters.Docs.
operate/configurationandworkflows/atomic-memorypages (en/zh) describe the rule and the cost of the native block for long candidates.CI. Three new OceanBase cases join
test_atomic_memory_fts_coverage.py. To keep the per-case ceilings enforced bytests/test_oceanbase_ci.py, two budgets rise:Release metadata. The persistence digest and rationale in
release/upgrade-support.jsonare refreshed. There are no schema, migration resource or stored projection changes.Relation to #2449. #2449 ranks the complete related set once, with a lightweight query, and then reads bodies page by page. It kept the admission threshold, so a long candidate still missed a short memory of the same fact. This PR changes only that threshold inside #2449's rank query. Paging, the frozen ranking and body batching are unchanged. A long candidate's ranking can hold more memories, so it can span more pages.
Are there any user-facing changes?
Yes. The lexical channel of related recall changes in both
ftsandhybridrelated modes. That includesauto, which resolves tohybridwhen an embedding profile is configured.Precision trade-off. Production related requests use the default floor: coverage 0.25 and a minimum of 2 matched terms. Under that floor, any memory of at most 8 indexed words (kind and stopwords included) is related to any long candidate that shares 2 content terms with it.
For example, the 25-term billing candidate above now also relates to
The holiday traffic dashboard moved.. That memory indexes 6 words (fact the holiday traffic dashboard moved) and sharesholidayandtrafficwith the candidate.This is accepted because the old rule already related exactly this pair when the short text was the candidate and the long text was stored: a 4-term candidate needs 2 shared terms. Relatedness no longer depends on which memory arrived first, and the reconcile model still decides whether anything changes.
Cost. Related enumeration stays complete; no candidate limit is added. All numbers are measured on a laptop against master
195be9b77, which includes #2449. Each figure is the median time to drain one complete related enumeration: the rank query plus every page.Real atomic facts. The LoCoMo observations form one Scope of 2,455 memories. Candidates are 40 held-out observations (short) and 40 concatenations of three held-out observations (long). Latencies are shown as two runs,
a / b. The share with ≥ 1 related memory and the reconcile calls per candidate are derived from the related counts, with comparison batches of 20. No model was called.Synthetic stress Scope. Memories have 6–30 words drawn from a Zipf-distributed 6,000-word vocabulary, with 35% function words. Candidates are 10 long (35–45 words) and 10 short (6–10 words). The vocabulary overlaps far more than real facts do, so related sets are much larger than on LoCoMo. Each cell is one run.
On the native path, the second block makes long-candidate enumeration several times slower: about 8 ms instead of 1 ms on LoCoMo, and 370 ms instead of 59 ms at 50k synthetic memories. It stays below the whole-word path (531 ms at 50k), because the
MATCHprefilter limits the word count and whole-word coverage to rows that share at least the minimum match count of terms. The whole-word path and SQLite were already doing per-row work for those rows; on them, long candidates take about 1.1× (SQLite) and 1.4–2× (whole-word) as long.The larger cost is downstream. On the synthetic Scope, the long candidates' related set grows about 6–7×, and so do the derived reconcile calls. On LoCoMo the derived increase is under one call per long candidate.
How was this change tested?
Regression tests.
tests/e2e/test_atomic_memory_fts_coverage.py:ftsandhybridrelated modes. The reverse direction still works, unrelated and one-shared-term memories stay out, and search with the long query still admits nothing.tests/e2e/test_atomic_memory_unrelated_reconciliation.py: the built-in processor reconciles a long candidate with the earlier short memory, in two Scopes.tests/e2e/test_atomic_memory_long_fts_query.py: the below-threshold related fixture adds 300 unshared terms. The old fixture shared 249 of its own 250 terms with the candidate, so it is now legitimately related.The three behavior tests above (short memory found in
ftsandhybridmodes, long candidate reconciled) fail on master'ssrc/at195be9b77and pass with this change. They do so on SQLite and on a local seekDB server, through both nativeMATCHandLOCATE. The SQL/Python agreement test and the below-threshold fixture pass on both by design: they check that the backends agree with Python and that an unrelated memory stays out.Commands. The test suites ran on the merge of master
195be9b77. A later comment-only edit to the OceanBase index changed the persistence digest; after it,make check, the release gate and the OceanBase CI budget tests were rerun on the final head.make check: passes.tests/test_upgrade_release_gate.py,tests/test_upgrade_publication.py,tests/test_upgrade_schema_equivalence.py,tests/release_upgrades) andtests/test_oceanbase_ci.py: 185 passed and 6 skipped.tests/release_upgrades/test_full_server.pyneeds the CI upgrade harness (PC_UPGRADE_SOURCE_VERSION). It errors locally the same way on master.persistence_sha256is recomputed withmanaged_digestfrom the final tree, and matches a recomputation from agit archiveof the merge commit.tests/e2e/ -k atomic_memoryplustests/builtin/persistence/: 350 passed and 222 skipped.atomic_memory,reconcil,relatedorrecall_sufficiency: 551 passed and 7 skipped.make unit-testwas last run before the merge with perf(atomic-memory): bound related recall candidates in SQL to reduce peak memory and recall cost #2449: 8,899 passed and 13 failed. 12 of those also fail on master in this environment (4 intests/test_ci_installation_roles.py, 8 intests/evaluation/test_jev_rerank_comparison.py). The 13th was the OceanBase step budget, which the CI change above fixes.Backends.
MATCHpath and the whole-word (LOCATE) path:test_atomic_memory_fts_coverage.py;test_atomic_memory_long_fts_query.py;test_related_page_bodies_are_fetched_in_page_sized_batcheson the native path. It fails the same way with master'ssrc/: the test's_RecordingConnectionhas norun_sync, which_supports_native_ftscalls.dde597979, before the merge with perf(atomic-memory): bound related recall candidates in SQL to reduce peak memory and recall cost #2449, on embedded seekDB 1.4.0.post2 and real OceanBase CE 4.4.2.1. CI's OceanBase acceptance jobs run these e2e tests.Self-review. These points were reviewed and either addressed or accepted:
MATCHblock cost is measured above.SCORE()values from two queries. That affects only the order of a complete enumeration.AI usage statement
Claude Code (Claude Opus 5.5) reproduced the defect and wrote the change, tests, docs and this description. It also ran the benchmarks and checks, and reviewed the diff in two independent passes before this PR was opened and again after merging #2449.