Add entity-aware fact resolution against Nexus (Vikunja #279)

facts gain a Subject/EntityID/ResolutionState triple and an async
enrichment worker that resolves free-text subjects to canonical Nexus
entity_ids, mirroring Praxis's enrichment-worker pattern. Ambiguous or
unreachable Nexus never guesses an entity_id — the fact stays pending
or terminal-ambiguous instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ghELqYhZNLub2TXGMazqA
This commit is contained in:
kami
2026-07-20 12:00:37 +04:00
parent c932cd8677
commit 03fa52dfd4
8 changed files with 485 additions and 0 deletions
+13
View File
@@ -249,6 +249,7 @@ func run(args []string) error {
tl *tickLoop
coreAPI ipc.CoreAPI
eco *ecosystemWiring
factWorker *factEnrichmentWorker
)
if !locked {
@@ -341,6 +342,7 @@ func run(args []string) error {
repeatInterval := time.Duration(cfg.RepeatInterval)
autotuneInterval := time.Duration(cfg.AutotuneInterval)
tl = newTickLoop(st, gatherer, dispatcher, phr, rules, tickInterval, repeatInterval, autotuneInterval, cfg.Digest, routinesFromConfig(cfg.Routines))
factWorker = newFactEnrichmentWorker(st, eco, time.Duration(cfg.FactEnrichmentInterval))
coreAPI = &daemonAPI{
CoreAPI: ipc.NewStoreAPI(st),
@@ -500,6 +502,7 @@ func run(args []string) error {
repeatInterval := time.Duration(cfg.RepeatInterval)
autotuneInterval := time.Duration(cfg.AutotuneInterval)
tl = newTickLoop(st, gatherer, dispatcher, phr, rules, tickInterval, repeatInterval, autotuneInterval, cfg.Digest, routinesFromConfig(cfg.Routines))
factWorker = newFactEnrichmentWorker(st, eco, time.Duration(cfg.FactEnrichmentInterval))
// Swap the CoreAPI from lockedAPI to the real store adapter.
newAPI := &daemonAPI{
@@ -530,6 +533,11 @@ func run(args []string) error {
tl.run(ctx)
}()
// Start fact-entity enrichment worker.
go func() {
factWorker.run(ctx)
}()
dl.unlock()
log.Printf("mavend: unlocked via passkey assertion")
return nil
@@ -563,6 +571,11 @@ func run(args []string) error {
defer wg.Done()
tl.run(ctx)
}()
wg.Add(1)
go func() {
defer wg.Done()
factWorker.run(ctx)
}()
}
<-ctx.Done()