Skip to content

refactor(memory): drop dead migration cruft from InitializeAsync#589

Merged
Aaronontheweb merged 4 commits intodevfrom
remove-domain-migration
Apr 11, 2026
Merged

refactor(memory): drop dead migration cruft from InitializeAsync#589
Aaronontheweb merged 4 commits intodevfrom
remove-domain-migration

Conversation

@Aaronontheweb
Copy link
Copy Markdown
Collaborator

Summary

Pure-deletion PR. Removes 92 lines of dead migration scaffolding from SQLiteMemoryStore.InitializeAsync that existed only for backward compatibility with pre-existing user DBs — unnecessary for a single-user prototype with a disposable DB.

  • Commit 1 (b20cdc2, 56 lines): Drop the DROP COLUMN domain + policy-index recreation block + the DropColumnIfExistsAsync / DropIndexIfExistsAsync helpers.
  • Commit 2 (da0adc0, 36 lines): Drop 14 EnsureColumnExistsAsync calls (every column is already in the CREATE TABLE statements) + the now-orphaned EnsureColumnExistsAsync helper.

Startup-path savings per InitializeAsync invocation

  • 18 PRAGMA table_info scans (14 from ensure-column, 4 from drop-column)
  • 3 DROP INDEX IF EXISTS
  • 2 CREATE INDEX IF NOT EXISTS (policy-index recreate)
  • Up to 14 ALTER TABLE ADD COLUMN + 4 ALTER TABLE DROP COLUMN

All were no-ops on fresh DBs, but the PRAGMA/DROP statements ran unconditionally every boot.

Scope — findings flagged but NOT in this PR

/simplify surfaced three more dead-migration-adjacent blocks in the same method that could be cut with the same reasoning, but each removes defense-in-depth or requires retiring a live contract:

  1. Hygiene UPDATE Bump dotnet-sdk from 10.0.102 to 10.0.103 #1 (lines 141-151) — flips turn-completion / ConversationTrace docs to RecallMode=Never. Band-aid for LlmSessionActor.cs:1488 writing them with RecallMode=Auto. Recall coordinator already filters at query time. No test pins it.
  2. Hygiene UPDATE Bump Akka.Hosting from 1.5.59 to 1.5.60 #2 (lines 153-169) — backfills facets_json for malformed doc:% titles. Pinned by InitializeAsync_demotes_malformed_auto_recall_documents_to_searchable test.
  3. FTS rebuild block (lines 171-202) — unconditional DROP + CREATE VIRTUAL TABLE + full reindex on every boot. Currently the only place the FTS tables are created.

Also noted: memory tables use ad-hoc CREATE TABLE IF NOT EXISTS in InitializeAsync, while the rest of the daemon uses versioned SQL files via SchemaMigrator. Two schema paths run against the same netclaw.db at different lifecycle stages with no ordering guarantee. Consolidation is a future cleanup.

Test plan

  • dotnet build — clean
  • dotnet test — 1,964 tests pass
  • dotnet slopwatch analyze — 0 issues
  • CI green

The fresh CREATE TABLE schema is already domain-free. The DROP COLUMN /
DROP INDEX migration and the DropColumnIfExistsAsync/DropIndexIfExistsAsync
helpers were only there for backward compatibility with existing user DBs,
which is unnecessary — the store is single-user and the DB is disposable.
Every column being "ensured" in InitializeAsync (memory_class, expires_at,
aliases_json, facets_json, slots_json, boundary, audience on both
memory_documents and memory_records) is already declared in the CREATE TABLE
statements in the same method. On every daemon startup the 14 calls issued 14
redundant PRAGMA table_info scans for columns that always existed on fresh
installs. Same reasoning as the DROP COLUMN cleanup: single-user prototype,
disposable DB, no backward-compat requirement.
…ema init

Five related cleanups surfaced during the /simplify review of the
`remove-domain-migration` branch. Each was defensive code that papered
over a latent bug or was cleaning up shapes no current write path
produces.

1. Delete hygiene UPDATE #1 (turn-completion/ConversationTrace → Never)
   and the defensive filters/ranker penalties keyed on them.
   `MemoryCurationPipeline.Extract` early-returns on TurnComplete+!Explicit
   and only emits "Project Fact:" / "Project Milestone:" titles — nothing
   currently writes `title='turn-completion'` to memory_documents.

2. Delete hygiene UPDATE #2 (metadata backfill for malformed doc:% titles)
   plus the pinning test `InitializeAsync_demotes_malformed_auto_recall_
   documents_to_searchable` and the `MissingMetadataFacet` constant.

3. Replace the startup FTS rebuild (unconditional DROP + CREATE VIRTUAL
   TABLE + full INSERT ... SELECT, O(rows) every boot) with
   `CREATE VIRTUAL TABLE IF NOT EXISTS`. To make this safe, fix the
   runtime FTS write paths that the rebuild was papering over:
   - `InsertDocumentFtsAsync` / `InsertRecordFtsAsync` → rename to
     `UpsertDocumentFtsAsync` / `UpsertRecordFtsAsync`, DELETE-then-INSERT
     so repeat upserts do not leave duplicate FTS rows
   - `TombstoneDocumentAsync` now deletes the FTS row
   - `SupersedeRecordAsync` now deletes the old record's FTS row
   - Fix two raw-string-literal SQL interpolation bugs
     (`TombstoneDocumentAsync`, `SupersedeRecordAsync`) where the missing
     `$` prefix caused `{MemoryUpdateSemantics.*.ToWireValue()}` to be
     written literally into the column.

4. Unify startup schema ordering. Move `SchemaMigrationHostedService`
   registration before memory services so its StartAsync runs before
   `MemoryCurationWorkerService`. Delete the synchronous
   `memoryStore.InitializeAsync(...).GetAwaiter().GetResult()` at DI
   registration time. Have the hosted service call both the versioned
   migrator and `SQLiteMemoryStore.InitializeAsync` in sequence so there
   is exactly one startup path for schema setup.
@Aaronontheweb Aaronontheweb marked this pull request as ready for review April 11, 2026 01:22
Two regressions introduced by the previous cleanup commit, caught by
/simplify review:

1. SchemaMigrationHostedService.StartAsync early-returned when the akka
   persistence provider wasn't SQLite or auto-migrate was disabled,
   which silently skipped _memoryStore.InitializeAsync(). The memory
   store always uses SQLite regardless of akka persistence config, so
   its schema init now runs unconditionally outside the guard.

2. TombstoneDocumentAsync, SupersedeRecordAsync, and UpdateDocumentTextAsync
   ran the base-table UPDATE/INSERT and the FTS delete/insert as two
   separate implicit transactions. Before this branch the startup FTS
   rebuild cleaned up any drift; with the rebuild gone, a crash between
   the two statements leaves FTS stale (tombstoned doc still searchable,
   superseded record's old row orphaned). Wrap each path in an explicit
   BeginTransaction/Commit so both writes land together or neither does.
@Aaronontheweb Aaronontheweb merged commit f8ee33c into dev Apr 11, 2026
3 checks passed
@Aaronontheweb Aaronontheweb deleted the remove-domain-migration branch April 11, 2026 02:26
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