Repository navigation
semantic search: strut keeps the graph's vectors (the pass, the index reconcile, typed search through the domain indexes, the no-embed mark) - #140
Merged
Conversation
…ch.md) The pass (src/graph/embeddings.ts, EmbeddingPass): a timer in the serving process that keeps Data_Bank + text_embeddings + the domain label current on every node of a Schema-marked type, whoever wrote it — stale = the stored text is not the writer's composition from the Schema's index fields, or no vector. Pages by node_key (an index seek per page), decides in strut, writes what the writer writes, strips the no-embed types last, embeds newcomers by date_added_to_graph between hourly sweeps, 15 s a minute, nothing waits on it. GET /graph/embeddings is its status. The old awaited Domain_strut backfill is gone. The Schema index reconcile (src/graph/index-reconcile.ts): a live index that is a non-empty strict subset of the bundled library's is widened to the library's list, once per fixture version (a Migration ledger row); the pass then sees every node of the type as stale. Search (src/graph/search.ts): a typed search routes through the types' domain vector/fulltext indexes with an over-fetch (k from cap×10 by ×4 to 2000 — the database cannot filter a vector query); an untyped one through the global text_embeddings_vector_index, which the reader never used before. The no-embed mark: `embed` joins the core Schema keys, the resolver reads it, the writer composes Data_Bank but no vector for it (and update drops a stale one), StrutToolCall and StrutTurn carry it in code only (never flattened onto the Schema node — an older jarvis would read a required attribute). MiniLM runs on two intra-op threads. Tests: the pass (another writer's node, a later description, an edit, a stakgraph reset, a clean sweep; skipped types named; the cursor over 2,500 nodes; newcomers; no-embed; labels; the route), the reconcile, the routing and over-fetch (pure + live among 1,300 nearer decoys), the writer's gate, the resolver's mark. npm test 1417, test:graph 268.
Evanfeenstra
added a commit
to stakwork/stakgraph
that referenced
this pull request
Oct 11, 2026
… typed search through the domain indexes, the no-embed mark — stakwork/strut#140)
Evanfeenstra
added a commit
to stakwork/stakgraph
that referenced
this pull request
Oct 11, 2026
…1762) * neo4j: Data_Bank is set once on create, never reset by a re-ingest The node MERGE put `Data_Bank = name` into $properties and ran `ON MATCH SET node += $properties`, so an incremental sync of a file reset every one of its nodes' search text to the bare name while text_embeddings and _search_fields_used survived — a vector that no longer matched its text, and jarvis's data_bank_full_index back to name-only. Data_Bank now stays out of $properties and is seeded from the map's name under ON CREATE alone, like date_added_to_graph (the same set-once rule, for the same reason): a later writer — strut's embedding pass, jarvis — composes the richer text from the type's Schema index fields, and a re-ingest of an unchanged function touches nothing it reads. build_stream() was already ON CREATE only. * bump strut (semantic search: the embedding pass, the index reconcile, typed search through the domain indexes, the no-embed mark — stakwork/strut#140)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds
plans/semantic-search.md(#139), the strut side. On swarm38 a question with no keyword in it finds nothing by meaning: code nodes come from stakgraph's ingest, which never embeds, and what jarvis did embed is the bare name under a Schemaindexthat predates its own library. This makes strut the thing that keeps the graph's vectors current, from the live:Schemameta-graph, on any Neo4j 5.The pass —
src/graph/embeddings.ts,EmbeddingPass. A timer in the serving process, started when the graph backend opens. A node of a marked type is stale when its storedData_Bankis not the text the writer would compose today from the Schema'sindexfields, or its vector is missing — one comparison that catches a node never embedded, one embedded before itsindexwidened, a field filled in or edited later, and a text stakgraph's re-sync reset. It writes what the writer writes (Data_Bank,text_embeddings,_search_fields_used, the resolver's domain label), pages bynode_key(an index seek per page), strips the no-embed types last, embeds newcomers bydate_added_to_graphbetween hourly sweeps, works 15 s a minute, and nothing waits on it.GET /graph/embeddingsreports the sweep, per-type counts, and the types it skips and why. The old awaitedDomain_strutbackfill is gone.The Schema
indexreconcile —src/graph/index-reconcile.ts, a boot step. A liveindexthat is a non-empty strict subset of the bundled library's (Function:"name"→[name, summary, description]) is widened to the library's list — jarvis's own values, written directly, since its Schema API re-embeds a whole type inside one request and rebuilds the shared keyword index per type. Once per fixture version (aMigrationledger row), so a list jarvis narrows on purpose is never fought over. The fixture gained aversionfield.Search —
routeIndexes/overfetchinsearch.ts. A typed search reads the requested types' domain vector/fulltext indexes with an over-fetch (k from cap×10 by ×4 to 2,000 — the database cannot filter a vector query, sotypeis a WHERE after the nearest-k cut); an untyped one reads the globaltext_embeddings_vector_index, which the reader never used before (domain_all_vector_indexnever exists on 5.19).The no-embed mark —
embed: falseon a Schema (ruling 2:Turn,StrutToolCall,StrutTurnget no vector).embedjoins the core-key mirror, the resolver reads it, the writer composesData_Bankbut no vector for it andupdatedrops a stale one, the pass strips what such nodes hold. Strut's two types carry it in code only — never flattened onto the Schema node, since an older jarvis reads an unknown Schema key as a required attribute. MiniLM runs on two intra-op threads.Where the build differs from the plan's text (in the plan's status header): the reconcile only widens (no string→list normalization); the pass addresses a node by
elementId; the newcomer tick is one range seek across all marked types; a failed page moves the sweep to the next type; a tick logs only when it did something; the per-fieldvector_indexvectors are filled by the sweep alone; the status read has no web client.Verified: tsc,
npm test(1417),npm run test:graph(268, the full live suite). New tests: the pass end to end (another writer's node; a later description, an edit and a stakgraph-shaped reset re-embed it; a clean sweep writes nothing; unmarked types left alone and named; the cursor over 2,500 nodes with a tick resuming at it; newcomers without a sweep; no-embed on write, update and sweep; labels and hidden types; the route), the reconcile (widen / leave / stamp / no re-run under the same version), routing and over-fetch pure and live (a code type found through its domain index among 1,300 nearer decoys; a type with no domain through the global index past them), the writer's gate, the resolver's mark.Companions, in their own repos, not stacked — strut waits on neither: stakwork/jarvis-backend#3141 (the mark as a core key, four enqueue sites gated,
Turnmarked) and stakwork/stakgraph#1762 (Data_Bankset once on create). Until each is deployed the pass heals what they do. After the jarvis one lands on a seed, the ontology fixture is re-dumped and one test stops settingTurn's mark by hand. Then the swarm38 validation in the plan, after the mcp pin.