Skip to content

fix(fmem): stop ingesting entities that can never be found again - #21

Merged
bkearns merged 1 commit into
mainfrom
fix/fmem-ingest-embeddings
Aug 12, 2026
Merged

fix(fmem): stop ingesting entities that can never be found again#21
bkearns merged 1 commit into
mainfrom
fix/fmem-ingest-embeddings

Conversation

@bkearns

@bkearns bkearns commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

The bug

IngestOptions defaulted embed_missing to false, with the comment:

forge generates embeddings separately; set false here.

forge does not generate embeddings. There is no embedding client anywhere in the workspace, and WireEntity — the authoritative wire type for this call — has no embedding field at all, so it is structurally incapable of attaching a vector. The option promised something the type system had already ruled out.

fmem stores an entity vector only when the caller supplies one or embed_missing is set. Neither held, so every entity forge has ever ingested on this path landed with entity_embedding = None.

Each one is invisible to every ANN retrieval source. And an entity is lexically findable only by its name — its content body is not fts-indexed — so a content query returns nothing at all.

Why nobody noticed

Nothing surfaces it. The ingest succeeds, the entity and edge counts are correct, and retrieval is silently dead.

A fresh FerrosaAi install stored 262 entities and 222 edges from the starter corpus and could not return one of them for any query.

Changes

  • default embed_missing to true, so fmem embeds server-side
  • reject embed_missing=false at the call site rather than writing unreadable memory. The error names the consequence, not the flag. This is the last point that still knows why — by the time a user runs a search, the cause is hundreds of writes in the past
  • smart_paper_loader.rs:148 passed false explicitly; same fix

Verification

Tests written first; both red for the right reasons before the fix.

forge-fmem-client 79/79, forge-ingest 379/379.

Verified end-to-end against a real stack (ferrosa-memory v0.26.0 with a bundled llama.cpp + nomic runtime), not just by unit test: embedding requests served during the same 262-entity ingest rose from ~144 to ~424. The entities now carry vectors.

Scope

Semantic search over that corpus had a second, independent cause — the client config was ingesting into a session partition no search reads — fixed separately in ferrosa-workbench. The combined end-to-end claim is not yet proven; see t_2618e286.

IngestOptions defaulted embed_missing to false, with the comment "forge
generates embeddings separately; set false here."

forge does not generate embeddings. It has no embedding client anywhere in
the workspace, and WireEntity -- the authoritative wire type for this call --
has no embedding field at all, so it is structurally incapable of attaching a
vector. The option promised something the type system already ruled out.

fmem stores an entity vector only when the caller supplies one or
embed_missing is set. Neither held, so every entity forge has ever ingested
on this path landed with entity_embedding = None. Each one is invisible to
every ANN retrieval source, and an entity is lexically findable only by its
NAME -- its content body is not fts-indexed -- so a content query returns
nothing at all.

None of that surfaces anywhere: the ingest succeeds, the entity and edge
counts are correct, and retrieval is silently dead. A fresh FerrosaAi install
stored 262 entities and 222 edges from the starter corpus and could not
return one of them for any query (t_2618e286).

- default embed_missing to true, so fmem embeds server-side
- reject embed_missing=false at the call site rather than writing unreadable
  memory, naming the consequence and not just the flag. This is the last
  point that still knows why; by the time a user searches, the cause is
  hundreds of writes in the past
- smart_paper_loader passed false explicitly; same fix

Verified end to end against a real stack (ferrosa-memory v0.26.0 with the
bundled llama.cpp + nomic runtime): embedding requests served during the same
262-entity ingest went from ~144 to ~424. The entities now carry vectors.

Semantic search over them still returns nothing, which is a SEPARATE defect
and is not fixed here -- current evidence points at session scoping, since
forge ingests under its own session_id while a later search defaults to
scope=both (its own session + global) and therefore never looks at forge's.
Tracked on t_2618e286.
@bkearns
bkearns added this pull request to the merge queue Aug 12, 2026
Merged via the queue into main with commit a5ca296 Aug 12, 2026
5 checks passed
@bkearns bkearns mentioned this pull request Aug 12, 2026
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