Skip to content

feat(memories): per-bank store capabilities on main (writes_memory_rows_in_sql_for / owns_document_store_for) - #3388

Merged
nicoloboschi merged 1 commit into
mainfrom
feat/per-bank-store-capabilities-on-main
Aug 11, 2026
Merged

feat(memories): per-bank store capabilities on main (writes_memory_rows_in_sql_for / owns_document_store_for)#3388
nicoloboschi merged 1 commit into
mainfrom
feat/per-bank-store-capabilities-on-main

Conversation

@nicoloboschi

@nicoloboschi nicoloboschi commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

What

Brings the per-bank store capabilities onto main. The pluggable memories backend (#2917) is on main, but the per-bank capability seam landed later on feat/pluggable-memories-provider (#3350, plus fix #3381) while main advanced ~179 commits. This re-applies that work on current main.

A pluggable memories store may keep memory rows outside SQL and/or own the document store. The existing capability flags writes_memory_rows_in_sql / owns_document_store are process-level; this adds per-bank forms so a store can answer those questions per bank, and every bank-scoped engine call site consults them.

Bundles:

  • feat(memories): per-bank store capabilities #3350 — per-bank store capabilities: writes_memory_rows_in_sql_for(bank_id) / owns_document_store_for(bank_id) on MemoriesExtension (default to the class attrs). Call sites in memory_engine, consolidation/consolidator, retain/*, reflect/tools consult the per-bank form; process-level maintenance gates stay on the class attr.
  • fix(memories): list_banks NameError on per-bank capability check #3381 — list_banks NameError fix: a bare bank_id where the loop var is row["bank_id"].
  • get_chunk NameError fix (new): same class, in get_chunk (chunk["bank_id"]). Surfaced by pyflakes while rebasing.

Conflict resolution

Only consolidation/consolidator.py conflicted — main added consolidation sites since the branch. All 8 are inside bank_id-scoped functions, so all convert to the per-bank form, matching #3350 (0 non-_for sites remained on the branch). Everything else applied cleanly.

Validation

  • pyflakes on all changed engine files: 0 undefined names (the exact check for this NameError class — it found the get_chunk one).
  • py_compile clean.
  • Tests: test_memories_extension.py (per-bank capability unit tests) + test_list_banks_non_sql_store.py. Full suite runs in CI.

Re-applies the per-bank store-capability seam onto current main. The pluggable
memories backend (#2917) is on main, but the per-bank capabilities landed later
on feat/pluggable-memories-provider (#3350, plus fix #3381) while main advanced
~179 commits.

A pluggable memories store may keep memory rows outside SQL and/or own the
document store. The process-level flags writes_memory_rows_in_sql /
owns_document_store gain per-bank forms — writes_memory_rows_in_sql_for(bank_id)
and owns_document_store_for(bank_id), defaulting to the class attrs — and every
bank-scoped call site in memory_engine, consolidation/consolidator, retain/* and
reflect/tools consults the per-bank form. Process-level maintenance gates keep
reading the class attr.

Also two NameError fixes of the same class (a bare bank_id where the in-scope
variable differs): list_banks (row["bank_id"], originally #3381) and get_chunk
(chunk["bank_id"], newly surfaced by pyflakes while rebasing).

Conflict resolution: only consolidation/consolidator.py conflicted — main added
consolidation sites since the branch; all are bank_id-scoped, so all convert to
the per-bank form.

Validation: pyflakes on all changed engine files reports 0 undefined names;
py_compile clean; per-bank + list_banks unit tests included.
@nicoloboschi
nicoloboschi force-pushed the feat/per-bank-store-capabilities-on-main branch from b2b77fa to 1efb1e0 Compare August 11, 2026 12:50
@nicoloboschi
nicoloboschi merged commit efc179f into main Aug 11, 2026
105 of 106 checks passed
nicoloboschi added a commit that referenced this pull request Aug 11, 2026
#3388 moved the store capability to writes_memory_rows_in_sql_for(bank_id) and
added drop_bank_storage, but two duck-typed test doubles still carried the old
surface, so test-api shard 2 has been red on main since it merged:

  test_integrity_violation_not_retried — SimpleNamespace(writes_memory_rows_in_sql=True)
    -> AttributeError: no attribute 'writes_memory_rows_in_sql_for'
  test_list_banks_non_sql_store._NonSqlStore — teardown's delete_bank routes the
    drop through the store for a non-SQL bank
    -> AttributeError: no attribute 'drop_bank_storage'

Both doubles are hand-rolled rather than subclasses of the store base, which is
why the refactor could not update them mechanically.
nicoloboschi added a commit that referenced this pull request Aug 11, 2026
#3387) (#3393)

* fix(retain): match chunk-delete link endpoints through indexable joins (#3387)

The ordered memory_links pre-delete in delete_chunks_by_ids matched link
endpoints with `tu.id = ml.from_unit_id OR tu.id = ml.to_unit_id`. An OR
spanning two columns of ml cannot be driven from either endpoint index, so
PostgreSQL made memory_links the outer relation of a nested-loop semi join
and sequentially scanned the whole table on every delete — O(links x units),
with no bank_id predicate, so every bank scanned every other bank's rows.

Past a few million links that exceeded the asyncpg command timeout and delta
retain failed with a bare TimeoutError (str(TimeoutError()) is empty, so it
logged as "Task execution failed: batch_retain, error:" with nothing after).

Splitting the OR into a UNION of two single-column joins makes each half an
index scan. Measured on PG18 with the current index set, 300k units /
1.5M links, deleting the links of 3 chunks (150 units):

  before  20,420 ms   Seq Scan, 224.9M rows removed by join filter
  after       31 ms   two index scans, same 1,464 rows

10 chunks took 49.8s before — already over the 60s default at a table size
well below production. The row set is identical (EXCEPT in both directions
returns nothing), and the deterministic ORDER BY + FOR UPDATE that #2570
added stay in ordered_links, which still locks the rows in that order.

* test(memories): update store doubles for the per-bank capability API

#3388 moved the store capability to writes_memory_rows_in_sql_for(bank_id) and
added drop_bank_storage, but two duck-typed test doubles still carried the old
surface, so test-api shard 2 has been red on main since it merged:

  test_integrity_violation_not_retried — SimpleNamespace(writes_memory_rows_in_sql=True)
    -> AttributeError: no attribute 'writes_memory_rows_in_sql_for'
  test_list_banks_non_sql_store._NonSqlStore — teardown's delete_bank routes the
    drop through the store for a non-SQL bank
    -> AttributeError: no attribute 'drop_bank_storage'

Both doubles are hand-rolled rather than subclasses of the store base, which is
why the refactor could not update them mechanically.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant