Repository navigation
perf: coalesce automatic consolidation by database and track freshness independently of clustering #753
Description
A10: perf: coalesce automatic consolidation by database and track freshness independently of clustering
- Priority: P1
- Evidence: reproduced
- Audited source:
063e5b8844af735a52fde886217a5d26a0f13064 - Audit date: 2026-10-08
- Disposition: new
Problem
Every engine uses its own consolidation lock/thread state. Startup decides all maintenance is stale solely because message_clusters is empty, so missing/failed clustering causes repeated full maintenance for new engines even when other layers are current. Add-triggered maintenance also rebuilds all layers every25 additions; updates do not trigger it.
Advertised or expected contract
- https://arxiv.org/html/2605.04897v1#S4
- Paper post-ingestion refresh; avoid repeated work while maintaining learning quality.
Source evidence
- Source: Locks and counters belong to each engine; default threshold25.
- Source: Startup uses cluster emptiness as global staleness proxy and creates a new thread.
- Source: Add threshold and exception handling are engine-local; background function calls same-engine consolidate.
- Source: Parallel search creates a new Memory/engine per query.
Reproduction
- Executed: python3 -B docs/audits/2026-10-08-v1/evidence/architecture-repro-v2.py ., from the audited repository source root. The script executes AST-selected production functions unchanged with explicit synthetic dependencies. See the last scope...finished block in evidence/architecture-repro-v1.txt.
- Probe duplicate_startup_maintenance invokes actual startup method on two synthetic engines sharing25rows/empty clusters, replacing Thread with a recorder. No actual worker thread runs.
- Prescribed, not executed: multi-process fixture with clustering missing, verify maintenance ownership and frequency at current workload scale.
Observed result
Two engines each schedule a startup consolidation. Source shows no database-wide single-flight claim or per-layer source-generation checkpoint in this path.
Expected result
Only one maintenance generation owns a database at a time; failed optional layers do not repeatedly force successful layers to recompute; corrections eventually refresh affected artifacts.
Proposed implementation
- Introduce shared maintenance ownership with crash-safe release and independent per-layer freshness/error metadata.
- Coalesce new/updated/deleted source IDs; preserve a forced full rebuild path as the correctness reference.
- Keep CPU/model work outside write locks and make background connection ownership explicit.
Acceptance tests
- Concurrent engines/processes request one shared generation, with no duplicate ML jobs.
- Absent hdbscan does not repeatedly rebuild summaries/surprise on every open.
- Process crash/cancel releases ownership; new evidence after a generation boundary remains dirty.
- Foreground store/search continues during maintenance.
Dependencies and sequencing
- A05
- A06
- A07
- A08
Regression risks
- Do not suppress maintenance permanently when a worker dies or a layer returns no output legitimately.
- Changing consolidation cadence must retain freshness/recall correctness; measure before selecting new thresholds.
Scope and affected paths
Maintenance scheduling/ownership, preserving all enabled learning layers.
Related history
- #498 (CLOSED): Automatic trigger introduced here; current defect is duplicate ownership and wrong freshness proxy.
- #720 (OPEN): Optional clustering failure is a concrete trigger, but dependency installation alone does not provide ownership/freshness.
Uncertainty and measurement limits
No live workload or model inference was run; source and synthetic evidence do not establish this as the cause of the screenshot memory footprint.
Release constraints
Preserve current embedding models, rerankers, internal retrieval depth, and durable source data. A synthetic control-flow reproduction establishes the stated defect only; hardware savings and retrieval quality require the separate release validation gates. Do not close this issue merely because a unit test passes.
Audit package
Full plan and catalogue | Portable reproductions and receipts
Activity
buildingjoshbetter commentedon Oct 8, 2026
Follow-up: exact source tracking on legacy/custom schemas
Evidence class: reproduced with synthetic in-memory SQLite on combined draft commit
4fdcb50fa056f17eac3ce6c792a5e798b8be890d. This is a draft-foundation correctness gap; it is not evidence that the new maintenance runner is deployed. Related FTS scope: #751. Standalone rebuild draft #802 has a separate bridge for these cases; that bridge does not certify canonical maintenance or FTS.Reproduction A: collated source edits
truememory/storage.pymodule withrunpy.run_path; create an in-memory connection._SCHEMA_SQL, replacing onlycontent TEXT NOT NULLwithcontent TEXT COLLATE NOCASE NOT NULL._initialize_maintenance_tracking(conn), insertsynthetic-alpha, and commit.revision, correction_count; update content toSYNTHETIC-ALPHAand commit.Observed: source content changes, but maintenance remains
(1, 0)and FTS retains the old content. Repeating withRTRIMand a trailing-space edit produces the same result. The ordinaryBINARYcontrol advances to(2, 1)and updates FTS.Cause: trigger predicates use
old.field IS NOT new.field, so column collation can hide a byte-level edit. This can incorrectly retain successful provenance and delay required recomputation. FTS token membership may be unchanged for these specific case/space edits; the stored FTS content is nevertheless stale.Reproduction B: replacement removes an older source row
content TEXT NOT NULL UNIQUE.PRAGMA recursive_triggers=0, install source tracking, then insert(id=1, content='synthetic-alpha')and(id=2, content='synthetic-beta'); commit.INSERT OR REPLACE INTO messages(id,content) VALUES(3,'synthetic-alpha'); commit.Observed before counters
(revision, inserts, corrections, high_id, nonappend_revision):(2, 2, 0, 2, 0). After:(3, 3, 0, 3, 0). Source IDs are[2, 3]; FTS IDs are[1, 2, 3]. The counter token incorrectly certifies an append-only transition while source ID 1 has disappeared. The missing delete-trigger notification is relevant to custom unique indexes and indexed primary-key forms too; those variants still require dedicated controls in this canonical path.Implementation plan
Acceptance gates
All inputs above are independently generated strings. No personal database, memory, transcript or machine identifier was read for these reproductions.
buildingjoshbetter commentedon Oct 8, 2026
Engine-routing integration blocker
The unpublished engine-routing candidate produced 13 failures, 2,662 passes and 1,195 passing subtests in the full synthetic GPUBox suite with sqlite-vec enabled. Log SHA256:
4def1dea951493035ab915d9aa368d8bf2e54e1dbcba18bbcef3854cde49cb8b.Independent event-driven reproduction confirmed a real foreground regression. Initial automatic clustering holds the model state lock while capturing source/vector data. A valid add can finish encoding, acquire SQLite writer ownership, then fail the nonblocking model publication fence. The source row rolls back. Increasing the scheduling threshold only postpones this race.
The correction is a separate prerequisite: acquire foreground model admission before opening an owned SQLite write transaction, retain that admission through commit, and preserve nonblocking behavior for caller-owned transactions. Borrowed model capture must use an already-loaded protected model or return typed deferral; it must not load a model or wait for the model lock while holding the caller's writer. Genuine generation changes remain rejection conditions.
The direct rebuild tests also need explicit automatic-maintenance isolation because they test exclusive rebuild ownership. Their batching and durability assertions will remain intact. Fixture isolation alone is not accepted as the production fix.
The scheduler candidate remains uncommitted and unpublished. Deterministic regressions, independent review and a clean full suite are required before publishing it. No native performance or MPS result is claimed.