Type filtering (include_types/exclude_types) was applied post-fetch after
the database LIMIT, which could return zero results when all top-N
results were of the filtered type. This pushes type filters into the SQL
WHERE clause in keyword_search_with_scores() so they apply before the
limit. Semantic results still get post-fetch filtering as a safety net
since the vector index cannot filter by type.
Also adds hybrid_search_filtered() as the new primary method, with the
original hybrid_search() delegating to it with no filters for backward
compatibility. The MCP search tool now exposes include_types and
exclude_types parameters.
Includes 5 new test cases covering include, exclude, precedence,
empty results, and backward compatibility.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Dashboard now disabled by default to reduce memory footprint
- Enable with VESTIGE_DASHBOARD_ENABLED=true
- Update --help text to document new env var
The Stage 8 `recommended` selector and the evidence sort both rank by
FSRS-6 trust only, discarding the `combined_score` signal that the
upstream hybrid_search + cross-encoder reranker just computed. Confidence
is then derived from `recommended.trust + evidence_count`, neither of
which moves with the query — so any query against the same corpus
returns the same primary memory and the same confidence score.
Empirical reproduction (15 deep_reference probes against an 11-memory
corpus, 9 with a unique correct answer + 6 with no relevant memories):
- Distinct primary memories returned : 1 / 15
- Confidence values returned : 1 distinct (0.82 for all)
- Ground-truth accuracy on specific queries : 1 / 9 (11.1%)
The single hit is coincidental: the always-returned memory happened to
be the correct answer for one query. Random guessing across the 11-memory
corpus would be ~9% baseline, so the tool is performing at random.
Fix
---
Replace trust-only ranking at three sites with a 50/50 composite of
combined_score (query relevance) and FSRS-6 trust:
let composite = |s: &ScoredMemory| s.combined_score as f64 * 0.5 + s.trust * 0.5;
Used in:
- cross_reference.rs:573 — `recommended` max_by
- cross_reference.rs:589 — `non_superseded` evidence sort_by
- cross_reference.rs:622 — `base_confidence` formula
The 50/50 weighting is a design choice — see PR body for the knob to
tweak if a different blend is preferred. The pre-existing updated_at
tiebreaker is preserved.
Tests
-----
Two regression tests, both verified to FAIL on `main` and PASS with the
fix via negative control (temporarily set the composite weights to
1.0 trust + 0.0 relevance and confirmed both tests fail again):
- test_recommended_uses_query_relevance_not_just_trust
Two-memory corpus, ingested in order so the off-topic memory wins
the trust tiebreaker. Query targets the on-topic memory. The fix
ensures `recommended` is the on-topic one.
- test_confidence_varies_with_query_relevance
Single-memory corpus. Identical execute() calls with a relevant
query and an irrelevant query. The fix ensures the relevant
query produces higher confidence.
Full crate suite: 410 / 410 passing (was 408 + 2 new).
Out of scope
------------
While running the live MCP probes I observed two further inconsistencies
in `cross_reference.rs` that I cannot reproduce in cargo test (the
synthetic test environment with mock embeddings does not trigger the
required combined_score > 0.2 floor condition):
- The `effective_sim` floor at line 551 fabricates contradictions
between memories with no real topical overlap when one contains a
CORRECTION_SIGNALS keyword.
- The Stage 5 `contradictions` field (strict) and the Stage 7
`pair_relations` feeding the reasoning text (loose, post-floor)
disagree, producing responses where `reasoning` claims N
contradictions while `contradictions` is empty and `status` is
"resolved".
I have empirical data for both from live MCP usage but no reproducible
cargo test, so they are intentionally not addressed in this PR. Happy to
file them as a separate issue with the raw probe data if useful.
Collapsed nested if statements into single conditions using
let-chains (if a && let Ok(b) = ...). Fixes CI clippy failures
on both macOS and Ubuntu.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The public JSON schema in schema() declares `in_minutes` and `file_pattern`
in snake_case, but TriggerSpec uses `#[serde(rename_all = "camelCase")]`
which makes serde expect `inMinutes` / `filePattern`. Snake_case inputs are
silently dropped to None, so time-based intentions with `in_minutes` never
fire (triggerAt becomes null) and file_pattern-only context intentions
never match.
Added `#[serde(alias = ...)]` so both naming conventions deserialize
correctly — purely additive, existing camelCase callers unaffected.
Two regression tests added, verified to FAIL without the aliases
(negative control confirmed the snake_case duration test sees
`triggerAt: null` and the file_pattern test sees an empty `triggered`
array). Both pass with the fix. Full crate suite: 408/408 passing.
Related to #25 (Bug #8 was half-fixed — check-side re-derivation works,
but the set-side was still dropping the value before it could be persisted).
- Removed vestige-agent and vestige-agent-py from workspace members
(ARC-AGI-3 code, not part of Vestige release — caused CI failure)
- Improved deep_reference reasoning chain: fuller output with arrows on
supersession reasoning, longer primary finding preview, fallback message
when no relations found, boosted relation detection for search results
with high combined_score
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Handle 'vestige/memory://' and 'vestige/codebase://' URIs by stripping the
provider prefix before scheme matching. This fixes compatibility with
MCP clients like OpenCode that prepend the provider name to resource URIs.
Fixes#19
All sidebar links, mobile nav links, command palette navigation, logo link,
and the graph page "Explore Connections" link now correctly use SvelteKit's
base path. Also fixes favicon.svg and manifest.json paths in app.html.
Fixes: https://github.com/samvallad33/vestige/issues/17
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When memories are created, promoted, deleted, or dreamed via MCP tools,
the 3D graph now shows spectacular live animations:
- Rainbow particle burst + elastic scale-up on MemoryCreated
- Ripple wave cascading to nearby nodes
- Green pulse + node growth on MemoryPromoted
- Implosion + dissolution on MemoryDeleted
- Edge growth animation on ConnectionDiscovered
- Purple cascade on DreamStarted/DreamProgress/DreamCompleted
- FIFO eviction at 50 live nodes to guard performance
Also: graph center defaults to most-connected node, legacy HTML
redirects to SvelteKit dashboard, CSS height chain fix in layout.
Testing: 150 unit tests (vitest), 11 e2e tests (Playwright with
MCP Streamable HTTP client), 22 proof screenshots.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a second transport layer alongside stdio — Streamable HTTP on port
3928. Enables Claude.ai, remote clients, and web integrations to connect
to Vestige over HTTP with per-session McpServer instances.
- POST /mcp (JSON-RPC) + DELETE /mcp (session cleanup)
- Bearer token auth with constant-time comparison (subtle crate)
- Auto-generated UUID v4 token persisted with 0o600 permissions
- Per-session McpServer instances with 30-min idle reaper
- 100 max sessions, 50 concurrency limit, 256KB body limit
- --http-port flag + VESTIGE_HTTP_PORT / VESTIGE_HTTP_BIND env vars
- Module exports moved from binary to lib.rs for reusability
- vestige CLI gains `serve` subcommand via shared lib
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ort-sys v2.0.0-rc.11 has no prebuilt ONNX Runtime binaries for
x86_64-apple-darwin, and vestige-mcp requires embeddings to compile.
- Remove x86_64-apple-darwin from CI release matrix (discontinued 2020)
- Fix vestige-mcp Cargo.toml: add default-features=false to vestige-core dep
- Extract sanitize_fts5_query to always-available fts.rs module
- Gate embeddings-only imports in storage/sqlite.rs behind #[cfg]
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dashboard v2.1 "Nuclear" upgrade:
- Dark glassmorphism UI system (4-tier glass utilities, ambient orbs, nav glow)
- Graph3D decomposed from 806-line monolith into 10 focused modules
- Custom GLSL shaders (nebula FBM background, chromatic aberration, film grain, vignette)
- Enhanced dream mode with smooth 2s lerped transitions and aurora cycling
- Cognitive pipeline visualizer (7-stage search cascade animation)
- Temporal playback slider (scrub through memory evolution over time)
- Bioluminescent color palette for node types and events
Fix flaky CI test on macOS:
- vector::tests::test_add_and_search used near-identical test vectors (additive phase shift)
- Changed to multiplicative frequency so each seed produces a distinct vector
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ort crate no longer ships prebuilt ONNX Runtime binaries for macOS Intel.
Build that target with --no-default-features so it uses keyword-only search
instead of failing the release pipeline.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove pnpm dashboard build step from release.yml and ci.yml
(dashboard build output is committed to git, embedded via include_dir!)
- Fix macos-13 → macos-14 (macos-13 runners deprecated)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
explore_connections and memory_graph returned empty results because
in-memory cognitive modules were never loaded from the database.
Connections were persisting to SQLite correctly (795 in production)
but the query path only checked empty ActivationNetwork.
- Add CognitiveEngine::hydrate() to load connections at startup
- Add storage fallback in explore_connections associations
- Hydrate live engine after dream persists new connections
- Add error logging for save_connection failures
- Add 7 integration tests for the full round-trip
Closes#14
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite for MCP server architecture (was Tauri app), correct license
to AGPL-3.0, add project structure guide, test commands, new tool/module
contribution guides, and dashboard build instructions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Includes HN post with prepared FAQ, Reddit cross-posts (r/rust, r/ClaudeAI,
r/LocalLLaMA), MCP Dev Summit demo scripts (30s/3min/10min versions), and
technical blog post covering FSRS-6, PE Gating, HyDE, STC, and dreaming.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Triggers 2 (force after 6h stale) and 3 (mini-consolidation after 2h)
fired immediately on fresh schedulers even when user was active, because
they didn't check activity state. Added MIN_BRIEF_IDLE_MINS (5 min)
guard so both triggers require a brief idle period before firing.
Fixes test_consolidation_idle_trigger in CI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Discovered that Xcode's claudeai-mcp feature gate blocks custom MCP
servers from the global .claude config. Project-level .mcp.json files
bypass this gate entirely — this is now the documented method.
- Add scripts/xcode-setup.sh: auto-installs vestige-mcp and configures
.mcp.json for any Xcode project with checksum verification
- Rewrite docs/integrations/xcode.md with .mcp.json method, gate bypass
docs, and new troubleshooting for "Agent has been closed" error
- Add docs/blog/xcode-memory.md: launch blog post for Vestige on Xcode