Repository navigation
feat(nlp): entity resolution with Locy, and word and sentence analysis (kniv v7 phases 3 and 2b) - #331
Merged
Conversation
Phase 3 of the kniv v7 proposal, as a documented and tested Locy program rather than engine code. Evidence clauses (exact name, surname, embedding similarity) feed an MNOR fold under a merge threshold; BEST BY keeps each mention's best match; DERIVE writes REFERS_TO; a Cypher command MERGEs an entity for each mention left unmatched. Running the proposal's sketch corrected it: MNOR is a fold over clauses, BEST BY cannot share a rule with MNOR, DERIVE creates an edge on every run (so evidence skips resolved mentions, which makes the program idempotent), and CALIBRATE fits only CREATE MODEL predicates. The docs said to CALIBRATE extraction confidence; they now point to VALIDATE, which scores any PROB rule against labels. Tests (crates/uni/tests/common/nlp_resolve.rs) run the program over mentions from the mock kniv model with a trigram mock embedder, and cover idempotency, best-match selection, type agreement, new-entity creation, EXPLAIN RULE evidence and VALIDATE. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The resolution program gave every unmatched mention its own entity in a single create-and-link step, so "Grace Hopper", "grace hopper" and "Hopper" arriving in one batch became three entities. Across batches the same mentions resolve to one, and since evidence skips linked mentions, a re-run never reconciled them: the result depended on batch boundaries. Unmatched mentions now seed entities first (one per name ignoring case, none for a surname of a longer unmatched name), a second DERIVE links the rest through the same rules, and a last command gives anything left its own entity. Adds variants_of_a_new_name_in_one_batch_make_one_entity and updates the docs, Black Book, proposal and release notes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and DERIVE scale Complete phase 3 of the kniv v7 proposal: - Claims now point at the Mentions they were extracted from, so the resolution program links claim endpoints to entities. Speakers resolve like any name, kept apart from people by their type. - Tests cover claims from prose and conversations meeting at resolved entities, resolution reviewed in a fork and promoted, 300 mentions against 300 entities, a real kniv v7 run (ignored), and a Python run of the program read from the docs page. Engine fixes found by those tests: - A fork's writer now gets the Xervo runtime, so forked sessions can write to auto-embedded labels. - Auto-embedding stores vectors as Value::Vector (and multi-vectors as lists of them). Float lists made the flushed content UID differ from the stored row, so promote duplicated auto-embedded vertices and skipped edges to them. - A DERIVE re-joining its clause materialised the MATCH's cartesian product and compared every row with every fact, cloning nodes each time: 300 x 300 timed out at 30 s. The MATCH is now narrowed to the nodes the IS reference's facts hold, and the in-memory joins index facts by entity identity. Results are unchanged. The program's own cost is still mentions x entities; 1,000 x 1,000 exceeds the default Locy timeout. That needs a nearest-neighbour generator and is documented. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The proposal still said Phase 3 needed no engine change; record the three engine fixes, the claim shape against Mentions, and the scale limit. The skill reference gains claims via Mentions, cost and fork review. The forks page notes the auto-embedded promote fix and that vertices flushed before it keep their old UID until rewritten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase 2b of the kniv v7 proposal, as two procedures rather than one uni.nlp.analyze, since words and sentences are different row grains: - uni.nlp.words: one row per word with UD part of speech, morphology, lemma, and dependency head and relation. Word, sentence and head indices count across the document, so head joins to another row's word. - uni.nlp.sentences: one row per sentence with sentiment, dialogue acts above threshold, and every act's probability from the model's label map. Input is as for extraction (texts or a conversation, with turn and speaker); options take only alias. Each requests only its own heads, and a v1 model is refused. Rust and Python gain analyze_words / analyze_sentences returning AnalyzedWord / AnalyzedSentence. Tested against a mock model and, ignored, the real kniv-v7-xlarge-u-en, including the feature page's query examples. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
Phases 3 and 2b of the kniv v7 NLP proposal (
docs/proposals/kniv_v7_nlp_extraction_2026_11_07.md, rev. 7), on top of phases 1–2 (#327).Phase 3: entity resolution with Locy
:Mentionto an existing:Entity. It combines weighted evidence (exact name, surname, embedding similarity) withMNOR, keeps the best match per mention, and creates one entity per new name, so variants of one name in a batch share an entity.diff, thenpromote) and 300 × 300 scale are covered by tests.Value::Vector, so the content UID matches the stored row.Phase 2b: word and sentence analysis
uni.nlp.words: one row per word, with Universal Dependencies part of speech, morphology, lemma, and dependency head and relation. Indices count across the whole document, soheadjoins to another row'sword.uni.nlp.sentences: one row per sentence, with sentiment, dialogue acts above the threshold, and every act's probability.optionstakes onlyalias, and a v1 model is refused.analyze_words/analyze_sentencesondb.xervo().Known limits (filed)
MATCHreads every pair, so resolution is quadratic in mentions × entities.Tests
nlp_resolve(10 pass, 1 ignored) andnlp_analyze(8 pass against a mock model). The real-model tests are ignored and run in the nightly sweep. I ran them locally againstkniv-v7-xlarge-u-en, including the feature page's query examples, and they pass.uni-querylib 545; Python NLP tests 62.cargo fmt, ruff, stubtest, the strict docs build and the docs snippets all pass.uni-dbintegration suite undercargo test: 3,948 passed, 10 failed. The failures are scratch-directory, bulk-load and deadline tests. Each passed when rerun on its own: plaincargo testruns every test in one process, while CI's nextest gives each test its own.🤖 Generated with Claude Code