From 0d273c5641f31b9cd5c15bfe10f2281617145296 Mon Sep 17 00:00:00 2001 From: Jan De Landtsheer Date: Tue, 21 Apr 2026 20:29:40 +0200 Subject: [PATCH 01/31] docs: ADR 0001 + Phase 1-4 implementation plans Pluggable storage backend, network access, and emergent domain classification. Introduces MemoryStore + Embedder traits, PgMemoryStore alongside SqliteMemoryStore, HTTP MCP + API key auth, and HDBSCAN-based domain clustering. Phase 5 federation deferred to a follow-up ADR. - docs/adr/0001-pluggable-storage-and-network-access.md -- Accepted - docs/plans/0001-phase-1-storage-trait-extraction.md - docs/plans/0002-phase-2-postgres-backend.md - docs/plans/0003-phase-3-network-access.md - docs/plans/0004-phase-4-emergent-domain-classification.md - docs/prd/001-getting-centralized-vestige.md -- source RFC --- ...01-pluggable-storage-and-network-access.md | 303 ++++ .../0001-phase-1-storage-trait-extraction.md | 1026 ++++++++++++ docs/plans/0002-phase-2-postgres-backend.md | 1269 +++++++++++++++ docs/plans/0003-phase-3-network-access.md | 1435 +++++++++++++++++ ...-phase-4-emergent-domain-classification.md | 883 ++++++++++ docs/prd/001-getting-centralized-vestige.md | 751 +++++++++ 6 files changed, 5667 insertions(+) create mode 100644 docs/adr/0001-pluggable-storage-and-network-access.md create mode 100644 docs/plans/0001-phase-1-storage-trait-extraction.md create mode 100644 docs/plans/0002-phase-2-postgres-backend.md create mode 100644 docs/plans/0003-phase-3-network-access.md create mode 100644 docs/plans/0004-phase-4-emergent-domain-classification.md create mode 100644 docs/prd/001-getting-centralized-vestige.md diff --git a/docs/adr/0001-pluggable-storage-and-network-access.md b/docs/adr/0001-pluggable-storage-and-network-access.md new file mode 100644 index 0000000..c150c70 --- /dev/null +++ b/docs/adr/0001-pluggable-storage-and-network-access.md @@ -0,0 +1,303 @@ +# ADR 0001: Pluggable Storage Backend, Network Access, and Emergent Domains + +**Status**: Accepted +**Date**: 2026-04-21 +**Related**: [docs/prd/001-getting-centralized-vestige.md](../prd/001-getting-centralized-vestige.md) + +--- + +## Context + +Vestige v2.x runs as a per-machine local process: stdio MCP transport, SQLite + +FTS5 + USearch HNSW in `~/.vestige/`, fastembed locally for embeddings. This is +ideal for single-machine single-agent use but blocks three real needs: + +- **Multi-machine access** -- same memory brain from laptop, desktop, server +- **Multi-agent access** -- multiple AI clients against one store concurrently +- **Future federation** -- syncing memory between decentralized nodes (MOS / + Threefold grid) + +SQLite's single-writer model and lack of a native network protocol make it +unsuitable as a centralized server. PostgreSQL + pgvector collapses our three +storage layers (SQLite, FTS5, USearch) into one engine with MVCC concurrency, +auth, and replication. + +Separately, Vestige today has no notion of domain or project scope -- all memories +share one namespace. For a multi-machine brain, users want soft topical +boundaries ("dev", "infra", "home") without manual tenanting. HDBSCAN clustering +on embeddings produces these boundaries from the data itself. + +The PRD at `docs/prd/001-getting-centralized-vestige.md` sketches the full design. +This ADR records the architectural decisions and resolves the open questions from +that document. + +--- + +## Decision + +Introduce two new trait boundaries, a network transport layer, and a domain +classification module. All four changes ship in parallel phases. + +**Trait boundaries:** + +1. `MemoryStore` -- single trait covering CRUD, hybrid search, FSRS scheduling, + graph edges, and domains. One big trait, not four. +2. `Embedder` -- separate trait for text-to-vector encoding. Storage never calls + fastembed directly. Callers (cognitive engine locally, HTTP server remotely) + compute embeddings and pass them into the store. + +**Backends:** + +- `SqliteMemoryStore` -- existing code refactored behind the trait, no behavior + change. +- `PgMemoryStore` -- new, using sqlx + pgvector + tsvector. Selectable at runtime + via `vestige.toml`. + +**Network:** + +- MCP over Streamable HTTP on the existing Axum server. +- API key auth middleware (blake3-hashed, stored in `api_keys` table). +- Dashboard uses the same API keys for login, then signed session cookies for + subsequent requests. + +**Domain classification:** + +- HDBSCAN clustering over embeddings to discover domains automatically. +- Soft multi-domain assignment -- raw similarity scores stored per memory, every + domain above a threshold is assigned. +- Conservative drift handling -- propose splits/merges, never auto-apply. + +--- + +## Architecture Overview + +### Component Breakdown + +1. **`Embedder` trait** (new module `crates/vestige-core/src/embedder/`) + - `async fn embed(&self, text: &str) -> Result>` + - `fn model_name(&self) -> &str` + - `fn dimension(&self) -> usize` + - Impls: `FastembedEmbedder` (local ONNX, today), future `JinaEmbedder`, + `OpenAiEmbedder`, etc. + - Stays pluggable forever -- no lock-in to fastembed or to nomic-embed-text. + +2. **`MemoryStore` trait** (new module `crates/vestige-core/src/storage/trait.rs`) + - One trait, ~25 methods across CRUD, search, FSRS, graph, domain sections. + - Uses `trait_variant::make` to generate a `Send`-bound variant for + `Arc` in Axum/tokio contexts. + - The 29 cognitive modules operate exclusively through this trait. No direct + SQLite or Postgres access from the modules. + +3. **`SqliteMemoryStore`** (refactor of existing `crates/vestige-core/src/storage/sqlite.rs`) + - Existing rusqlite + FTS5 + USearch code, wrapped behind the trait. + - Add `domains TEXT[]` equivalent (JSON-encoded array column in SQLite). + - Add `domain_scores` JSON column. + - No behavioral change for current users. + +4. **`PgMemoryStore`** (new `crates/vestige-core/src/storage/postgres.rs`) + - `sqlx::PgPool` with compile-time checked queries. + - pgvector HNSW index for vector search, tsvector + GIN for FTS. + - Native array columns for `domains`, JSONB for `domain_scores` and `metadata`. + - Hybrid search via RRF (Reciprocal Rank Fusion) in a single SQL query. + +5. **Model registry** + - Per-database table `embedding_model` with `(name, dimension, hash, created_at)`. + - Both backends refuse writes from an embedder whose signature doesn't match + the registered row. + - Model swap = `vestige migrate --reembed --model=`, O(n) cost, explicit. + +6. **`DomainClassifier` cognitive module** (new `crates/vestige-core/src/neuroscience/domain_classifier.rs`) + - Owns the HDBSCAN discovery pass (using the `hdbscan` crate). + - Computes soft-assignment scores for every memory against every centroid. + - Stores raw `domain_scores: HashMap` per memory; thresholds into + the `domains` array using `assign_threshold` (default 0.65). + - Runs discovery on demand (`vestige domains discover`) or during dream + consolidation passes. + +7. **HTTP MCP transport** (extension of existing Axum server in `crates/vestige-mcp/src/`) + - New route `POST /mcp` for Streamable HTTP JSON-RPC. + - New route `GET /mcp` for SSE (for long-running operations). + - REST API under `/api/v1/` for direct HTTP clients (non-MCP integrations). + - Auth middleware validates `Authorization: Bearer ...` or `X-API-Key`, plus + signed session cookies for dashboard. + +8. **Key management** (new `crates/vestige-mcp/src/auth/`) + - `api_keys` table -- blake3-hashed keys, scopes, optional domain filter, + last-used timestamp. + - CLI: `vestige keys create|list|revoke`. + +9. **FSRS review event log** (future-proofing for federation) + - New table `review_events` -- append-only `(memory_id, timestamp, rating, + prior_state, new_state)`. + - Current `scheduling` table becomes a materialized view over the event log + (reconstructible from events). + - Phase 5 federation merges event logs, not derived state. Zero cost today, + avoids lock-in tomorrow. + +### Data Flow + +**Local mode (stdio MCP, unchanged UX):** +``` +stdio client -> McpServer -> CognitiveEngine -> FastembedEmbedder -> MemoryStore (SQLite) +``` + +**Server mode (HTTP MCP, new):** +``` +Remote client -> Axum HTTP -> auth middleware -> CognitiveEngine + -> FastembedEmbedder (server-side) -> MemoryStore (Postgres) +``` + +The cognitive engine is backend-agnostic. The embedder and the store are both +swappable. The 7-stage search pipeline (overfetch -> cross-encoder rerank -> +temporal -> accessibility -> context match -> competition -> spreading activation) +sits *above* the `MemoryStore` trait and works identically against either backend. + +### Orthogonality of HDBSCAN and Reranking + +HDBSCAN and the cross-encoder reranker solve different problems and both stay: + +- **HDBSCAN** discovers domains by clustering embeddings. Runs once per discovery + pass. Produces centroids. Used to *filter* search candidates, not to rank them. +- **Cross-encoder reranker** (Jina Reranker v1 Turbo) scores query-document pairs + at search time. Runs on every search. Produces ranked results. + +Domain membership is a filter applied before or during overfetch; reranking runs +on whatever candidate set survives the filter. + +--- + +## Alternatives Considered + +| Alternative | Pros | Cons | Why Not | +|-------------|------|------|---------| +| Split into 4 traits (`MemoryStore + SchedulingStore + GraphStore + DomainStore`) | Cleaner interface segregation | Every module holds 4 trait objects, coordinates transactions across them | One trait is fine in Rust; extract sub-traits later if a genuine need appears | +| Embedding computed inside the backend | Simpler call sites for callers | Backend becomes aware of embedding models; can't support remote clients without local fastembed | Keep storage pure; separate `Embedder` trait handles pluggability | +| Unconstrained pgvector `vector` (no dimension) | Flexible for model swaps | HNSW still needs fixed dims at index creation; hides a meaningful migration as "silent" | Fixed dimension per install, explicit `--reembed` migration | +| Dashboard separate auth (cookies only, no keys) | Simpler dashboard UX | Two auth systems to maintain | Shared API keys with session cookie layer on top | +| Auto-tuned `assign_threshold` targeting an unclassified ratio | Adapts to corpus | Hard to debug ("why did this memory change domain?"); magical | Static 0.65 default, config-tunable, dashboard shows `domain_scores` for manual retuning | +| Aggressive drift (auto-reassign memories whose scores drifted) | Always up-to-date domains | Breaks user muscle memory; silent reshuffling | Conservative: always propose, user accepts | +| CRDTs for federation state | Mathematically clean merges | Massive complexity, performance cost, overkill | Defer; design FSRS as event log now so any future sync model works | + +--- + +## Consequences + +### Positive + +- Single memory brain accessible from every machine. +- Multi-agent concurrent access via Postgres MVCC. +- Natural topical scoping emerges from data, not manual tenants. +- Future embedding model swaps are a config + migration, not a rewrite. +- Federation has a clean on-ramp (event log merge) without committing now. +- The `Embedder` / `MemoryStore` split unlocks other storage backends later + (Redis, Qdrant, Iroh-backed blob store, etc.) with minimal work. + +### Negative + +- Operating a Postgres instance is more work than managing a SQLite file. +- Users who stay on SQLite gain nothing from this ADR (but lose nothing either). +- Migration (`vestige migrate --from sqlite --to postgres`) is a sensitive + operation for users with months of memories -- needs strong testing. +- HDBSCAN + re-soft-assignment runs in O(n) over all embeddings. At 100k+ + memories this starts to matter; manageable but not free. + +### Risks + +- **Trait abstraction leaks**: a cognitive module might need backend-specific + behavior (e.g., Postgres triggers for tsvector). Mitigation: keep such logic + inside the backend impl; the trait stays pure. + Escalation: if a module genuinely cannot express what it needs through the + trait, the trait grows, not the module bypasses. +- **Embedding model drift**: users on older fastembed versions silently + producing slightly different vectors after a fastembed upgrade. Mitigation: + model hash in the registry, refuse mismatched writes, surface a clear error. +- **Auth misconfiguration**: a user binds to `0.0.0.0` without setting + `auth.enabled = true`. Mitigation: refuse to start with non-localhost bind + and auth disabled. Hard error, not a warning. +- **Re-clustering feedback loop**: dream consolidation proposes re-clusters, + which the user accepts, which changes classifications, which affects future + retrievals, which affect future dreams. Mitigation: cap re-cluster frequency + (every 5th dream by default), require explicit user acceptance of proposals. +- **Cross-domain spreading activation weight (0.5 default)**: arbitrary choice; + could be too aggressive or too lax. Mitigation: config-tunable; instrument + retrieval quality metrics in the dashboard so the user sees impact. + +--- + +## Resolved Decisions (from Q&A) + +| # | Question | Resolution | +|---|----------|------------| +| 1 | Trait granularity | Single `MemoryStore` trait | +| 2 | Embedding on insert | Caller provides; separate `Embedder` trait for pluggability | +| 3 | pgvector dimension | Fixed per install, derived from `Embedder::dimension()` at schema init | +| 4 | Federation sync | Defer algorithm; store FSRS reviews as append-only event log now | +| 5 | Dashboard auth | Shared API keys + signed session cookie | +| 6 | HDBSCAN `min_cluster_size` | Default 10; user reruns with `--min-cluster-size N`; no auto-sweep | +| 7 | Domain drift | Conservative -- always propose splits/merges, never auto-apply | +| 8 | Cross-domain spreading activation | Follow with decay factor 0.5 (tunable) | +| 9 | Assignment threshold | Static 0.65 default, config-tunable, raw `domain_scores` stored for introspection | + +--- + +## Implementation Plan + +Five phases, each independently shippable. + +### Phase 1: Storage trait extraction +- Define `MemoryStore` and `Embedder` traits in `vestige-core`. +- Refactor `SqliteMemoryStore` to implement `MemoryStore`; no behavior change. +- Refactor `FastembedEmbedder` to implement `Embedder`. +- Add `embedding_model` registry table; enforce consistency on write. +- Add `domains TEXT[]`-equivalent and `domain_scores` JSON columns to SQLite + (empty for all existing rows). +- Convert all 29 cognitive modules to operate via the traits. +- **Acceptance**: existing test suite passes unchanged. Zero warnings. + +### Phase 2: PostgreSQL backend +- `PgMemoryStore` with sqlx, pgvector, tsvector. +- sqlx migrations (`crates/vestige-core/migrations/postgres/`). +- Backend selection via `vestige.toml` `[storage]` section. +- `vestige migrate --from sqlite --to postgres` command. +- `vestige migrate --reembed` command for model swaps. +- **Acceptance**: full test suite runs green against Postgres with a testcontainer. + +### Phase 3: Network access +- Streamable HTTP MCP route on Axum (`POST /mcp`, `GET /mcp` for SSE). +- REST API under `/api/v1/`. +- API key table + blake3 hashing + `vestige keys create|list|revoke`. +- Auth middleware (Bearer, X-API-Key, session cookie). +- Refuse non-localhost bind without auth enabled. +- **Acceptance**: MCP client over HTTP works from a second machine; dashboard + login flow works; unauth requests return 401. + +### Phase 4: Emergent domain classification +- `DomainClassifier` module using the `hdbscan` crate. +- `vestige domains discover|list|rename|merge` CLI. +- Automatic soft-assignment pipeline (compute `domain_scores` on ingest, threshold + into `domains`). +- Re-cluster every Nth dream consolidation (default 5); surface proposals in the + dashboard. +- Context signals (git repo, IDE) as soft priors on classification. +- Cross-domain spreading activation with 0.5 decay. +- **Acceptance**: on a corpus of 500+ mixed memories, discover produces sensible + clusters; search scoped to a domain returns tightly relevant results. + +### Phase 5: Federation (future, explicitly out of scope for this ADR's +acceptance) +- Node discovery (Mycelium / mDNS). +- Memory sync protocol over append-only review events and LWW-per-UUID for + memory records. +- Explicit follow-up ADR before any code. + +--- + +## Open Questions + +None at ADR acceptance time. Follow-up items that are *implementation choices*, +not architectural: + +- Precise cross-domain decay weight (start at 0.5, instrument, tune) +- Dashboard histogram of `domain_scores` (UX design detail) +- Whether to gate Postgres behind a Cargo feature flag (`postgres-backend`) or + always compile it in (lean toward feature flag to keep SQLite-only builds small) diff --git a/docs/plans/0001-phase-1-storage-trait-extraction.md b/docs/plans/0001-phase-1-storage-trait-extraction.md new file mode 100644 index 0000000..9960462 --- /dev/null +++ b/docs/plans/0001-phase-1-storage-trait-extraction.md @@ -0,0 +1,1026 @@ +# Phase 1 Plan: Storage Trait Extraction + +**Status**: Draft +**Depends on**: none +**Related**: docs/adr/0001-pluggable-storage-and-network-access.md (Phase 1) + +--- + +## Scope + +### In scope + +- Introduce a new module `crates/vestige-core/src/storage/memory_store.rs` defining: + - `LocalMemoryStore` base trait (Sync + 'static) + - `MemoryStore` Send-bound alias generated via `#[trait_variant::make(MemoryStore: Send)]` + - Supporting data types referenced by the trait: `MemoryRecord`, `SchedulingState`, `SearchQuery`, `SearchResult`, `MemoryEdge`, `Domain`, `ClassificationResult`, `StoreStats`, `HealthStatus`, `MemoryStoreError`. +- Introduce a new module `crates/vestige-core/src/embedder/` defining: + - `Embedder` async trait with `embed`, `model_name`, `dimension` plus `model_hash` (for the registry) and optional `embed_batch` with a default implementation. + - Move/adapt the existing `EmbeddingService` impl into a new struct `FastembedEmbedder` that implements `Embedder`. +- Refactor `Storage` (existing `crates/vestige-core/src/storage/sqlite.rs`) into `SqliteMemoryStore`: + - Keep the struct, the `writer`/`reader` `Mutex` pair, the `FSRSScheduler`, and the USearch `VectorIndex`. + - Rename the type alias `Storage` to `SqliteMemoryStore` with a `pub type Storage = SqliteMemoryStore;` alias for backward source compatibility during the transition. (The trait method surface is the new public contract.) + - Implement `LocalMemoryStore` by wrapping existing synchronous `rusqlite` methods inside `async fn` bodies that call a small `spawn_blocking`-or-inline adapter. Bodies MAY block; the `async fn` signature exists because `LocalMemoryStore` is async. +- Add a `schema_version = 12` migration that introduces two schema additions: + 1. `embedding_model` registry table (one-row constraint enforced in code). + 2. Two new TEXT columns on `knowledge_nodes`: `domains TEXT NOT NULL DEFAULT '[]'` and `domain_scores TEXT NOT NULL DEFAULT '{}'` (both JSON-encoded). +- Enforce model registry on every write path: on the first non-empty embedding write the model signature is recorded; subsequent writes whose `Embedder::model_name()` / `dimension()` / `model_hash()` disagree must fail with `MemoryStoreError::ModelMismatch` before touching the DB. +- Audit all 29 cognitive modules under `crates/vestige-core/src/neuroscience/` and `crates/vestige-core/src/advanced/` to confirm they hold no direct `rusqlite::Connection` references, no `Storage` struct field, and no SQL strings. Any that do get refactored to take `&dyn LocalMemoryStore` (local-only modules) or `&Arc` (modules crossing `await` points). +- Add unit tests alongside each new trait method and integration tests in `tests/phase_1/`. + +### Out of scope + +- Implementing `PgMemoryStore` on sqlx + pgvector -- that is Phase 2. +- `vestige migrate --from sqlite --to postgres` and `vestige migrate --reembed` -- Phase 2. +- MCP over Streamable HTTP, API key middleware, `api_keys` table, `vestige keys create|list|revoke` -- Phase 3. +- `DomainClassifier` module, HDBSCAN clustering, `vestige domains discover|list|rename|merge` CLI, incremental soft-assignment, cross-domain spreading activation decay -- Phase 4. +- Federation, mycelium/mDNS node discovery, review event log table -- Phase 5. +- Removing the `pub type Storage = SqliteMemoryStore;` compatibility alias -- that cleanup happens at the end of Phase 4 when no consumers still spell the old name. + +## Prerequisites + +### Current code state + +- Single concrete type `Storage` in `crates/vestige-core/src/storage/sqlite.rs` (4592 lines, 216 public symbols on the impl blocks, approximately 85 public methods) is the only storage surface the crate exposes. +- `EmbeddingService` in `crates/vestige-core/src/embeddings/local.rs` holds the fastembed singleton. No trait exists; callers type-erase via `&EmbeddingService`. +- Migrations live in `crates/vestige-core/src/storage/migrations.rs`; the current head is v11. +- All cognitive modules in `neuroscience/` and `advanced/` are pure (verified by `grep rusqlite|Connection::|execute\(|prepare\(` returning no matches in those trees). They operate on `KnowledgeNode`, `Vec`, `ConnectionRecord`, etc. passed in by the caller. +- `vestige-mcp` consumes `Arc` in `crates/vestige-mcp/src/server.rs` and every tool under `crates/vestige-mcp/src/tools/`. These call sites will type-check unchanged after the alias is introduced because the trait methods preserve the exact signatures of the existing `pub fn` on `Storage`. +- Test count reported in `CLAUDE.md`: 758 tests (406 mcp + 352 core). This is the no-regression target. + +### Required crates (add via `cargo add` under `crates/vestige-core`) + +| Crate | Version | Why | +|-------|---------|-----| +| `trait-variant` | `0.1` | Generates the `Send`-bound `MemoryStore` alias from `LocalMemoryStore` so `Arc` works under tokio/axum without hand-writing two traits. Listed in PRD section "Crate Dependencies (new)" under Phase 1. | +| `blake3` | `1` | `Embedder::model_hash() -> [u8; 32]` uses blake3 to stabilise the "model signature" stored in the `embedding_model` registry. Already slated for Phase 3 auth; pulling it forward costs nothing and avoids a second migration to add a hash column. | +| `async-trait` | `0.1` | Not strictly required with `trait-variant` on MSRV 1.91 (RPITIT is stable), but used for one utility trait (`EmbedderExt`) that carries a default `embed_batch` body. OPTIONAL; see Open Implementation Questions below. | + +No changes to `vestige-mcp/Cargo.toml` are required for Phase 1 -- the new trait lives in `vestige-core` and the mcp crate continues to depend on the `SqliteMemoryStore` concrete type (via the `Storage` alias) until Phase 2 introduces backend selection. + +## Deliverables + +1. `crates/vestige-core/src/storage/memory_store.rs` -- `LocalMemoryStore` + `MemoryStore` traits and supporting types. +2. `crates/vestige-core/src/storage/mod.rs` -- updated exports and module wiring. +3. `crates/vestige-core/src/storage/sqlite.rs` -- `Storage` renamed to `SqliteMemoryStore`, `impl LocalMemoryStore for SqliteMemoryStore` block, enforcement hooks for the model registry, serde of `domains` / `domain_scores` columns. +4. `crates/vestige-core/src/storage/migrations.rs` -- `MIGRATION_V12_UP` adding `embedding_model` table and `domains`, `domain_scores` columns. +5. `crates/vestige-core/src/embedder/mod.rs` -- `Embedder` trait and re-exports. +6. `crates/vestige-core/src/embedder/fastembed.rs` -- `FastembedEmbedder` implementation. +7. `crates/vestige-core/src/embeddings/local.rs` -- retained; `EmbeddingService` kept as the underlying fastembed holder; `FastembedEmbedder` wraps it. +8. `crates/vestige-core/src/lib.rs` -- new `pub mod embedder;` + re-exports for `MemoryStore`, `LocalMemoryStore`, `Embedder`, `FastembedEmbedder`, and the data types. +9. `tests/phase_1/trait_round_trip.rs` -- integration test: round-trip of every trait method through `SqliteMemoryStore`. +10. `tests/phase_1/embedding_model_registry.rs` -- integration test: first-write registers, mismatch refuses, dimension mismatch refuses. +11. `tests/phase_1/domain_column_migration.rs` -- integration test: a v11 DB upgraded to v12 reads `domains=[]` and `domain_scores={}` for all existing rows. +12. `tests/phase_1/cognitive_module_isolation.rs` -- integration test: every cognitive module compiles and executes against an `Arc` without touching `SqliteMemoryStore` concretely. +13. `tests/phase_1/send_bound_variant.rs` -- integration test: an `Arc` can be moved across `tokio::spawn`. +14. Updated `tests/phase_1/mod.rs` (if the dir already uses a module layout) or individual `[[test]]` entries in `tests/e2e/Cargo.toml` as needed -- see "Test Plan" for the exact layout. + +## Detailed Task Breakdown + +### D1. Trait + supporting types (`memory_store.rs`) + +- **File**: `crates/vestige-core/src/storage/memory_store.rs` (new). +- **Depends on**: `trait-variant` crate added under vestige-core, `chrono`, `serde_json`, `uuid`, `thiserror` (all already in Cargo.toml). +- **Signatures**: + +```rust +//! Backend-agnostic memory store trait. +//! +//! This is the single abstraction every cognitive module sits above. It is +//! intentionally flat: one trait, ~25 methods, no sub-traits. + +use std::collections::HashMap; + +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +// ---------------------------------------------------------------------------- +// ERROR +// ---------------------------------------------------------------------------- + +/// Error returned by every `LocalMemoryStore` / `MemoryStore` method. +#[non_exhaustive] +#[derive(Debug, thiserror::Error)] +pub enum MemoryStoreError { + #[error("not found: {0}")] + NotFound(String), + + #[error("backend error: {0}")] + Backend(String), + + #[error( + "embedding model mismatch: store registered {registered_name} (dim {registered_dim}, \ + hash {registered_hash}), embedder is {actual_name} (dim {actual_dim}, hash {actual_hash})" + )] + ModelMismatch { + registered_name: String, + registered_dim: usize, + registered_hash: String, + actual_name: String, + actual_dim: usize, + actual_hash: String, + }, + + #[error("invalid input: {0}")] + InvalidInput(String), + + #[error("initialization error: {0}")] + Init(String), +} + +impl From for MemoryStoreError { + fn from(e: crate::storage::StorageError) -> Self { + use crate::storage::StorageError as S; + match e { + S::NotFound(s) => MemoryStoreError::NotFound(s), + S::Database(e) => MemoryStoreError::Backend(e.to_string()), + S::Io(e) => MemoryStoreError::Backend(e.to_string()), + S::InvalidTimestamp(s) => MemoryStoreError::Backend(format!("invalid timestamp: {s}")), + S::Init(s) => MemoryStoreError::Init(s), + } + } +} + +pub type MemoryStoreResult = std::result::Result; + +// ---------------------------------------------------------------------------- +// DATA TYPES +// ---------------------------------------------------------------------------- + +/// Backend-agnostic memory record. +/// +/// Phase 1 intentionally keeps this type independent of `KnowledgeNode` to +/// avoid dragging 30+ legacy fields through the trait surface. The SQLite +/// backend converts between `MemoryRecord` and `KnowledgeNode` at the +/// boundary. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MemoryRecord { + pub id: Uuid, + /// Empty = unclassified. Populated in Phase 4. + pub domains: Vec, + /// Raw similarity per domain centroid. Empty until Phase 4 runs clustering. + pub domain_scores: HashMap, + pub content: String, + pub node_type: String, + pub tags: Vec, + pub embedding: Option>, + pub created_at: DateTime, + pub updated_at: DateTime, + pub metadata: serde_json::Value, +} + +/// FSRS-6 scheduling state, one row per memory. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SchedulingState { + pub memory_id: Uuid, + pub stability: f64, + pub difficulty: f64, + pub retrievability: f64, + pub last_review: Option>, + pub next_review: Option>, + pub reps: u32, + pub lapses: u32, +} + +/// Hybrid search request. +#[derive(Debug, Clone, Default)] +pub struct SearchQuery { + pub domains: Option>, + pub text: Option, + pub embedding: Option>, + pub tags: Option>, + pub node_types: Option>, + pub limit: usize, + pub min_retrievability: Option, +} + +#[derive(Debug, Clone)] +pub struct SearchResult { + pub record: MemoryRecord, + pub score: f64, + pub fts_score: Option, + pub vector_score: Option, +} + +/// Edge in the spreading-activation graph. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MemoryEdge { + pub source_id: Uuid, + pub target_id: Uuid, + pub edge_type: String, + pub weight: f64, + pub created_at: DateTime, +} + +/// A topical domain (populated in Phase 4). Phase 1 only needs the type to +/// shape the trait surface; discover/classify are Phase 4 work. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Domain { + pub id: String, + pub label: String, + pub centroid: Vec, + pub top_terms: Vec, + pub memory_count: usize, + pub created_at: DateTime, +} + +/// Result of classifying one vector against all known domains. +#[derive(Debug, Clone)] +pub struct ClassificationResult { + pub scores: HashMap, + pub domains: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct StoreStats { + pub total_memories: usize, + pub memories_with_embeddings: usize, + pub total_edges: usize, + pub total_domains: usize, + pub registered_model_name: Option, + pub registered_model_dim: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum HealthStatus { + Healthy, + Degraded { reason: String }, + Unavailable { reason: String }, +} + +// ---------------------------------------------------------------------------- +// EMBEDDING MODEL SIGNATURE +// ---------------------------------------------------------------------------- + +/// Snapshot of the embedding model that was used to write vectors into the +/// store. Persisted in the `embedding_model` table; compared on every write +/// before the vector is accepted. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct ModelSignature { + pub name: String, + pub dimension: usize, + /// Lowercase hex-encoded blake3 hash, 64 chars. + pub hash: String, +} + +// ---------------------------------------------------------------------------- +// TRAIT +// ---------------------------------------------------------------------------- + +/// The single storage abstraction. `trait_variant::make` auto-generates a +/// `MemoryStore` alias with `Send`-bound return futures so `Arc` +/// works in tokio/axum contexts. +#[trait_variant::make(MemoryStore: Send)] +pub trait LocalMemoryStore: Sync + 'static { + // --- Lifecycle --- + async fn init(&self) -> MemoryStoreResult<()>; + async fn health_check(&self) -> MemoryStoreResult; + + // --- Embedding model registry --- + async fn registered_model(&self) -> MemoryStoreResult>; + async fn register_model(&self, sig: &ModelSignature) -> MemoryStoreResult<()>; + + // --- CRUD --- + async fn insert(&self, record: &MemoryRecord) -> MemoryStoreResult; + async fn get(&self, id: Uuid) -> MemoryStoreResult>; + async fn update(&self, record: &MemoryRecord) -> MemoryStoreResult<()>; + async fn delete(&self, id: Uuid) -> MemoryStoreResult<()>; + + // --- Search --- + async fn search(&self, query: &SearchQuery) -> MemoryStoreResult>; + async fn fts_search(&self, text: &str, limit: usize) -> MemoryStoreResult>; + async fn vector_search( + &self, + embedding: &[f32], + limit: usize, + ) -> MemoryStoreResult>; + + // --- FSRS Scheduling --- + async fn get_scheduling( + &self, + memory_id: Uuid, + ) -> MemoryStoreResult>; + async fn update_scheduling(&self, state: &SchedulingState) -> MemoryStoreResult<()>; + async fn get_due_memories( + &self, + before: DateTime, + limit: usize, + ) -> MemoryStoreResult>; + + // --- Graph (spreading activation) --- + async fn add_edge(&self, edge: &MemoryEdge) -> MemoryStoreResult<()>; + async fn get_edges( + &self, + node_id: Uuid, + edge_type: Option<&str>, + ) -> MemoryStoreResult>; + async fn remove_edge(&self, source: Uuid, target: Uuid) -> MemoryStoreResult<()>; + async fn get_neighbors( + &self, + node_id: Uuid, + depth: usize, + ) -> MemoryStoreResult>; + + // --- Domains (Phase 1: stubs return empty; full impl in Phase 4) --- + async fn list_domains(&self) -> MemoryStoreResult>; + async fn get_domain(&self, id: &str) -> MemoryStoreResult>; + async fn upsert_domain(&self, domain: &Domain) -> MemoryStoreResult<()>; + async fn delete_domain(&self, id: &str) -> MemoryStoreResult<()>; + /// Phase 1: returns `Ok(vec![])` since no centroids exist. Phase 4 wires + /// the full soft-assignment pass. + async fn classify(&self, embedding: &[f32]) -> MemoryStoreResult>; + + // --- Bulk / Maintenance --- + async fn count(&self) -> MemoryStoreResult; + async fn get_stats(&self) -> MemoryStoreResult; + async fn vacuum(&self) -> MemoryStoreResult<()>; +} +``` + +- **Behavior notes**: + - Every method returns `MemoryStoreResult`; the trait never exposes `rusqlite::Error`. + - `LocalMemoryStore` requires `Sync + 'static` so `Arc` is usable. The auto-generated `MemoryStore` alias adds `Send` bounds on the returned `impl Future`. + - `register_model` is idempotent: writing the same signature twice is `Ok(())`. Writing a different signature after one is registered returns `MemoryStoreError::ModelMismatch`. + - `classify` on Phase 1 returns `Ok(vec![])` and MUST NOT error; cognitive modules call it and Phase 4 will flesh it out without changing the signature. + - `upsert_domain` / `delete_domain` / `list_domains` / `get_domain` operate against a `domains` table that is empty until Phase 4 populates it. Phase 1 still exposes the methods so Phase 2 can implement them against Postgres in one shot. + - `get_neighbors(node_id, depth)` with `depth == 0` returns just `(node, 1.0)` if the node exists, otherwise `NotFound`. `depth > 0` performs breadth-first expansion over edges, weight = product of edge weights along the shortest path discovered, capped at `max_neighbors = 256` to prevent runaway expansion. + +--- + +### D2. Storage module wiring (`storage/mod.rs`) + +- **File**: `crates/vestige-core/src/storage/mod.rs`. +- **Depends on**: D1. +- **Signatures / diff**: + +```rust +//! Storage Module +//! +//! Backend-agnostic memory store abstraction plus SQLite reference impl. + +mod memory_store; +mod migrations; +mod sqlite; + +pub use memory_store::{ + ClassificationResult, Domain, HealthStatus, LocalMemoryStore, MemoryEdge, MemoryRecord, + MemoryStore, MemoryStoreError, MemoryStoreResult, ModelSignature, SchedulingState, + SearchQuery, SearchResult, StoreStats, +}; +pub use migrations::MIGRATIONS; +pub use sqlite::{ + ConnectionRecord, ConsolidationHistoryRecord, DreamHistoryRecord, InsightRecord, + IntentionRecord, Result, SmartIngestResult, SqliteMemoryStore, StateTransitionRecord, + StorageError, +}; + +/// Backwards-compatibility alias. Retained until Phase 4 completes so every +/// existing `Arc` call site keeps compiling. Scheduled for removal +/// once no downstream source file references it. +pub type Storage = SqliteMemoryStore; +``` + +- **Behavior notes**: + - The alias MUST be a `pub type` (not a re-export), because several tool files pattern on `vestige_core::Storage` through `use` statements and we want to keep them compiling verbatim. This has zero runtime cost. + - `StorageError` stays exported for the 29 existing inherent-method callers; the trait exposes `MemoryStoreError` and provides `From`. + +--- + +### D3. Rename + trait impl in `sqlite.rs` + +- **File**: `crates/vestige-core/src/storage/sqlite.rs`. +- **Depends on**: D1, D2, D4 (for schema columns), D5/D6 (to have `Embedder` to accept on `insert`). +- **Signatures (key excerpts)**: + +```rust +pub struct SqliteMemoryStore { + writer: Mutex, + reader: Mutex, + scheduler: Mutex, + #[cfg(feature = "embeddings")] + embedding_service: EmbeddingService, + #[cfg(feature = "vector-search")] + vector_index: Mutex, + #[cfg(feature = "embeddings")] + query_cache: Mutex>>, + /// Cached model signature. `None` until the first embedding is written. + registered_model: std::sync::RwLock>, +} + +impl SqliteMemoryStore { + pub fn new(db_path: Option) -> MemoryStoreResult { /* existing body, Result converted */ } + + /// Internal: convert a row into a `MemoryRecord` (new mapping reading + /// `domains` / `domain_scores` JSON columns). + fn row_to_record(row: &rusqlite::Row) -> rusqlite::Result { /* ... */ } + + /// Internal: given a `MemoryRecord` plus an optional embedding, enforce + /// the registered model signature and return a `MemoryStoreError` if + /// the embedder would produce a mismatched vector. + fn enforce_model( + &self, + incoming: Option<&ModelSignature>, + ) -> MemoryStoreResult<()> { /* ... */ } +} + +impl crate::storage::memory_store::LocalMemoryStore for SqliteMemoryStore { + async fn init(&self) -> MemoryStoreResult<()> { /* no-op; migrations run in `new` */ Ok(()) } + + async fn health_check(&self) -> MemoryStoreResult { + // SELECT 1; check vector index loaded; check embedding_model presence. + } + + async fn registered_model(&self) -> MemoryStoreResult> { + let cached = self.registered_model.read().map_err(|_| MemoryStoreError::Init("registered_model rwlock poisoned".into()))?.clone(); + if cached.is_some() { + return Ok(cached); + } + // Fall through to DB read... + } + + async fn register_model(&self, sig: &ModelSignature) -> MemoryStoreResult<()> { + // INSERT OR IGNORE; if a row exists and differs, return ModelMismatch. + } + + async fn insert(&self, record: &MemoryRecord) -> MemoryStoreResult { + if let Some(vec) = &record.embedding { + // Caller is REQUIRED to have called register_model first (or the + // store auto-registers on the first embedded write -- see + // "embedding_model_registry.rs" test). + let derived = ModelSignature { /* from cache or from record.metadata */ }; + self.enforce_model(Some(&derived))?; + if vec.len() != derived.dimension { + return Err(MemoryStoreError::InvalidInput( + format!("embedding length {} != registered dimension {}", vec.len(), derived.dimension), + )); + } + } + // Delegate to a private `insert_record_blocking` helper that is the + // current `ingest`/`update_node_content` body, rewritten to accept a + // `MemoryRecord` and to also write `domains` / `domain_scores` JSON. + } + + // ... remaining ~24 methods follow the same pattern: convert inputs, + // call the existing synchronous body, convert outputs. +} +``` + +- **SQL** (covered in full in D4 below). +- **Behavior notes**: + - The `async fn` bodies are allowed to be synchronous under the hood (rusqlite is blocking). We do NOT wrap in `spawn_blocking` for Phase 1 -- the current `Storage` is already used from synchronous code paths (CLI, MCP stdio handler) and forcing the tokio runtime is a Phase 2 concern when we also add sqlx. The trait simply lifts the synchronous body into an `async fn` so the signatures match the trait. MSRV 1.91 supports async fn in trait via `trait_variant::make`. + - `insert` preserves the current FSRS initialization logic (stability, difficulty, next_review, etc.) -- the new code path converts `MemoryRecord.metadata` back into `IngestInput`-equivalent fields when needed. All existing inherent methods (`ingest`, `smart_ingest`, `mark_reviewed`, ...) remain on `SqliteMemoryStore` untouched; the trait impl calls into them. + - `registered_model` cache is an `RwLock>`. Invalidated on schema reset. Never mutated after first population until an explicit `--reembed` migration (Phase 2) takes the RwLock exclusively and writes a new row. + - `enforce_model` returns `Ok(())` if no model is registered yet AND `incoming.is_none()` (no-embedding write). Returns `Ok(())` if no model is registered and `incoming.is_some()` after calling `register_model`. Returns `Err(ModelMismatch)` if registered and they disagree. + - `domains` / `domain_scores` serialization uses `serde_json::to_string` on write and `serde_json::from_str` on read. Empty vec -> `"[]"`, empty map -> `"{}"`. `NULL` in the DB is treated as the empty value for pre-migration rows. + - Every existing inherent method is kept verbatim. The trait impl dispatches to them. This is the "no behavior change" guarantee. + +--- + +### D4. Schema migration V12 + +- **File**: `crates/vestige-core/src/storage/migrations.rs`. +- **Depends on**: D2. +- **SQL**: + +```sql +-- Migration V12: embedding model registry + per-memory domain columns. + +-- 1. Embedding model registry. Single logical row; the (id = 1) constraint is +-- enforced in code via `register_model` (SQLite CHECK on a single-row +-- table is uglier than a constraint we already enforce in Rust). +CREATE TABLE IF NOT EXISTS embedding_model ( + id INTEGER PRIMARY KEY CHECK (id = 1), + name TEXT NOT NULL, + dimension INTEGER NOT NULL, + hash TEXT NOT NULL, -- lowercase hex blake3 + created_at TEXT NOT NULL +); + +-- 2. Per-memory domain columns (JSON TEXT; SQLite has no native arrays). +ALTER TABLE knowledge_nodes ADD COLUMN domains TEXT NOT NULL DEFAULT '[]'; +ALTER TABLE knowledge_nodes ADD COLUMN domain_scores TEXT NOT NULL DEFAULT '{}'; + +-- 3. Index on the domains JSON column to enable `LIKE '%"dev"%'`-style +-- filter in Phase 4. Kept lightweight here; Postgres will use GIN. +CREATE INDEX IF NOT EXISTS idx_nodes_domains ON knowledge_nodes(domains); +CREATE INDEX IF NOT EXISTS idx_nodes_domain_scores ON knowledge_nodes(domain_scores); + +-- 4. Domains catalogue (empty until Phase 4 populates). +CREATE TABLE IF NOT EXISTS domains ( + id TEXT PRIMARY KEY, + label TEXT NOT NULL, + centroid BLOB, -- f32 vector, raw bytes + top_terms TEXT NOT NULL DEFAULT '[]', + memory_count INTEGER NOT NULL DEFAULT 0, + created_at TEXT NOT NULL +); + +CREATE INDEX IF NOT EXISTS idx_domains_created_at ON domains(created_at); + +UPDATE schema_version SET version = 12, applied_at = datetime('now'); +``` + +- **Rust changes** to `migrations.rs`: + +```rust +pub const MIGRATIONS: &[Migration] = &[ + // ... V1..V11 unchanged ... + Migration { + version: 12, + description: "Phase 1: embedding_model registry, domains/domain_scores columns, domains table", + up: MIGRATION_V12_UP, + }, +]; + +const MIGRATION_V12_UP: &str = r#"...SQL above..."#; +``` + +- **Behavior notes**: + - Idempotent: `ALTER TABLE ... ADD COLUMN` on SQLite is not idempotent by default, but the `apply_migrations` driver only applies migrations whose version > current. A user who has already applied V12 never sees the SQL again. + - The `CHECK (id = 1)` on `embedding_model` is the only one-row guardrail -- all inserts go through `register_model` which uses `INSERT OR IGNORE INTO embedding_model (id, ...) VALUES (1, ...)` followed by a `SELECT` to detect mismatch. + - `centroid BLOB` stores the f32 vector using the same `Embedding::to_bytes()` format used in `node_embeddings`, for consistency. + +--- + +### D5. Embedder trait (`embedder/mod.rs`) + +- **File**: `crates/vestige-core/src/embedder/mod.rs` (new). +- **Depends on**: `blake3` crate added to vestige-core. +- **Signatures**: + +```rust +//! Text-to-vector encoding trait. Pluggable per-install. + +use std::fmt::Debug; + +mod fastembed; + +pub use fastembed::FastembedEmbedder; + +/// Error returned by every `Embedder` method. +#[non_exhaustive] +#[derive(Debug, thiserror::Error)] +pub enum EmbedderError { + #[error("embedder initialization failed: {0}")] + Init(String), + #[error("embedding generation failed: {0}")] + EmbedFailed(String), + #[error("invalid input: {0}")] + InvalidInput(String), +} + +pub type EmbedderResult = std::result::Result; + +/// Pluggable embedder. The storage layer NEVER calls fastembed directly; +/// callers compute vectors via this trait and pass them into `MemoryStore`. +#[trait_variant::make(Embedder: Send)] +pub trait LocalEmbedder: Sync + 'static { + async fn embed(&self, text: &str) -> EmbedderResult>; + + fn model_name(&self) -> &str; + + fn dimension(&self) -> usize; + + /// Stable blake3 hash of (model_name || dimension || optional weights + /// digest if available). Lowercase hex, 64 chars. + /// + /// Used by `MemoryStore::register_model` to detect silent model drift + /// (e.g. a fastembed minor upgrade that changes vector output). + fn model_hash(&self) -> String; + + async fn embed_batch(&self, texts: &[&str]) -> EmbedderResult>> { + // Default: sequential. Backends with native batching override this. + let mut out = Vec::with_capacity(texts.len()); + for t in texts { + out.push(self.embed(t).await?); + } + Ok(out) + } + + /// Returns the `ModelSignature` describing this embedder. Convenience + /// wrapper over the three accessors above. + fn signature(&self) -> crate::storage::ModelSignature { + crate::storage::ModelSignature { + name: self.model_name().to_string(), + dimension: self.dimension(), + hash: self.model_hash(), + } + } +} +``` + +- **Behavior notes**: + - The `embed_batch` default implementation is non-trivial only in that backends with genuine batching override it. The `FastembedEmbedder` overrides to call `EmbeddingService::embed_batch`. + - `model_hash()` is intentionally a function, not a constant, so backends with configurable weights (a future `OnnxEmbedder` that loads an arbitrary file) can hash the file bytes into the signature. + - `Embedder` (the `Send` variant) is what cognitive modules bind against when they hold `Arc`. `LocalEmbedder` is available for single-threaded callers (CLI, tests). + +--- + +### D6. FastembedEmbedder impl (`embedder/fastembed.rs`) + +- **File**: `crates/vestige-core/src/embedder/fastembed.rs` (new). +- **Depends on**: D5, existing `crate::embeddings::local::EmbeddingService`. +- **Signatures**: + +```rust +use super::{EmbedderError, EmbedderResult, LocalEmbedder}; +use crate::embeddings::{EMBEDDING_DIMENSIONS, EmbeddingService, matryoshka_truncate}; + +pub struct FastembedEmbedder { + inner: EmbeddingService, + cached_hash: std::sync::OnceLock, +} + +impl FastembedEmbedder { + pub fn new() -> Self { + Self { + inner: EmbeddingService::new(), + cached_hash: std::sync::OnceLock::new(), + } + } + + fn compute_hash(name: &str, dim: usize) -> String { + let mut hasher = blake3::Hasher::new(); + hasher.update(name.as_bytes()); + hasher.update(&(dim as u64).to_le_bytes()); + // fastembed's ONNX bytes are not directly accessible at runtime; we + // use `(name, dim, static fastembed crate version)` as the + // signature. If fastembed ever changes its output deterministically + // between minor versions, bumping the crate version triggers a + // mismatch -- which is exactly the drift we want to detect. + hasher.update(env!("CARGO_PKG_VERSION").as_bytes()); + hasher.finalize().to_hex().to_string() + } +} + +impl Default for FastembedEmbedder { + fn default() -> Self { Self::new() } +} + +impl LocalEmbedder for FastembedEmbedder { + async fn embed(&self, text: &str) -> EmbedderResult> { + let emb = self + .inner + .embed(text) + .map_err(|e| EmbedderError::EmbedFailed(e.to_string()))?; + Ok(emb.vector) + } + + fn model_name(&self) -> &str { self.inner.model_name() } + + fn dimension(&self) -> usize { EMBEDDING_DIMENSIONS } + + fn model_hash(&self) -> String { + self.cached_hash + .get_or_init(|| Self::compute_hash(self.inner.model_name(), EMBEDDING_DIMENSIONS)) + .clone() + } + + async fn embed_batch(&self, texts: &[&str]) -> EmbedderResult>> { + let embs = self + .inner + .embed_batch(texts) + .map_err(|e| EmbedderError::EmbedFailed(e.to_string()))?; + Ok(embs.into_iter().map(|e| e.vector).collect()) + } +} +``` + +- **Behavior notes**: + - `EmbeddingService` is kept as the fastembed singleton holder; `FastembedEmbedder` is a thin trait adapter. Existing callers of `EmbeddingService` continue to work during the transition. + - `model_hash` is deterministic for a given `(model_name, EMBEDDING_DIMENSIONS, vestige-core version)` triple. This is the drift detector the ADR calls out under "Risks: Embedding model drift". + - `matryoshka_truncate` is already applied inside `EmbeddingService::embed`, so the vectors returned here are the 256-dim Matryoshka-truncated L2-normalized vectors that the rest of the stack expects. + +--- + +### D7. `lib.rs` re-exports + +- **File**: `crates/vestige-core/src/lib.rs`. +- **Depends on**: D1, D2, D5, D6. +- **Diff** (inserted alongside the existing `pub mod storage;` re-exports): + +```rust +pub mod embedder; + +pub use embedder::{Embedder, EmbedderError, EmbedderResult, FastembedEmbedder, LocalEmbedder}; + +pub use storage::{ + ClassificationResult, Domain, HealthStatus, LocalMemoryStore, MemoryEdge, MemoryRecord, + MemoryStore, MemoryStoreError, MemoryStoreResult, ModelSignature, SchedulingState, + SearchQuery, SearchResult, SqliteMemoryStore, Storage, StoreStats, + // Existing re-exports retained: + ConnectionRecord, ConsolidationHistoryRecord, DreamHistoryRecord, InsightRecord, + IntentionRecord, Result, SmartIngestResult, StateTransitionRecord, StorageError, +}; +``` + +- **Behavior notes**: + - `Storage` remains a top-level re-export so `use vestige_core::Storage;` keeps working in `vestige-mcp` without changes. Post-Phase-4 cleanup will grep the downstream crates and replace. + +--- + +### D8. Cognitive module audit + +- **Files**: all under `crates/vestige-core/src/neuroscience/*.rs` and `crates/vestige-core/src/advanced/*.rs` -- 21 source files. +- **Depends on**: D1..D7. +- **Work**: perform the following grep-gate BEFORE and AFTER the refactor: + +``` +Grep pattern: "rusqlite|Connection::|execute\\(|prepare\\(|&Storage|SqliteMemoryStore" +Expected in neuroscience/ and advanced/ BEFORE: only a single comment-only hit in `neuroscience/active_forgetting.rs:54` referencing `Storage::suppress_memory` in a doc comment. +Expected AFTER: zero hits that reference `SqliteMemoryStore` concretely. References through `&dyn LocalMemoryStore` or `&Arc` are acceptable. +``` + +- **Behavior notes**: + - Current state: the 29 cognitive modules are already pure (they take nodes/vectors/connections as arguments, not a `&Storage`). No refactor is required for their bodies. + - The only work is the `consolidation/sleep.rs` and `consolidation/phases.rs` path, which in the current codebase accepts `&Storage`. These get rewritten to accept `&dyn LocalMemoryStore` (callable from sync contexts) or `&Arc` (callable from async contexts). See file inventory below. + - Actual rewrites (expected number): 3-5 functions across `consolidation/sleep.rs` and `consolidation/mod.rs`. All trait-object refactors; no logic changes. + - `cognitive.rs` in `vestige-mcp` uses `storage.get_all_connections()`. Because `SqliteMemoryStore` keeps `get_all_connections` as an inherent method AND implements `MemoryStore::get_edges`, both call styles keep compiling. `cognitive.rs` does not need to change in Phase 1. + +--- + +### D9. Backwards-compatible inherent methods on `SqliteMemoryStore` + +- **File**: `crates/vestige-core/src/storage/sqlite.rs`. +- **Depends on**: D3. +- **Behavior notes**: + - Every one of the 85 existing `pub fn` on `Storage` (e.g. `ingest`, `smart_ingest`, `mark_reviewed`, `hybrid_search_filtered`, `save_intention`, `save_insight`, `save_connection`, `apply_rac1_cascade`, ...) stays as an inherent method on `SqliteMemoryStore`. The Phase 1 refactor ONLY adds the trait impl; it does NOT remove any method, rename any field, or change any SQL. + - Internal writes that previously embedded `INSERT INTO knowledge_nodes (...)` statements gain two more columns (`domains = '[]'`, `domain_scores = '{}'`) in the INSERT list. These are non-optional columns after migration V12, and their DEFAULT is `'[]'`/`'{}'` respectively, so ALTER behaves correctly for pre-existing rows but INSERT statements need to either list the defaults explicitly or rely on the DB default. Plan: explicitly write `'[]'` and `'{}'` in every `INSERT INTO knowledge_nodes` statement to avoid surprises if a future migration drops the DEFAULT. + +--- + +## Test Plan + +### Unit tests (colocated, `#[cfg(test)] mod tests` at end of each source file) + +Every public trait method on `LocalMemoryStore` gets at least one unit test, exercised through the `SqliteMemoryStore` impl. The unit test file is `crates/vestige-core/src/storage/sqlite.rs` (inside the existing `mod tests`). + +- `vestige_core::storage::sqlite::tests::trait_init_is_idempotent` -- calling `LocalMemoryStore::init` twice returns `Ok(())` both times. +- `vestige_core::storage::sqlite::tests::trait_health_check_reports_healthy_on_fresh_db` -- asserts `HealthStatus::Healthy` on a fresh in-memory DB. +- `vestige_core::storage::sqlite::tests::trait_register_model_first_write_succeeds` -- after registering a signature, `registered_model()` returns it. +- `vestige_core::storage::sqlite::tests::trait_register_model_mismatched_write_refused` -- registering a second, different signature returns `MemoryStoreError::ModelMismatch`. +- `vestige_core::storage::sqlite::tests::trait_register_model_same_signature_idempotent` -- registering the same signature twice returns `Ok(())` both times. +- `vestige_core::storage::sqlite::tests::trait_insert_returns_uuid` -- `insert(record)` returns the UUID from the record. +- `vestige_core::storage::sqlite::tests::trait_insert_refuses_dimension_mismatch` -- inserting a record with a 512-dim vector into a store registered for 256 dims returns `MemoryStoreError::InvalidInput`. +- `vestige_core::storage::sqlite::tests::trait_get_missing_returns_none` -- `get(non_existent_uuid)` returns `Ok(None)`. +- `vestige_core::storage::sqlite::tests::trait_get_after_insert_round_trip` -- insert then get returns a record equal (by content/tags/type) to the input; `domains == []`, `domain_scores == {}`. +- `vestige_core::storage::sqlite::tests::trait_update_modifies_content` -- update with new content reflects in subsequent `get`. +- `vestige_core::storage::sqlite::tests::trait_delete_removes_record` -- `delete` then `get` returns `Ok(None)`. +- `vestige_core::storage::sqlite::tests::trait_search_combines_fts_and_vector` -- with one memory whose content matches by FTS and another by vector, `search` returns both, higher score for the exact content match. +- `vestige_core::storage::sqlite::tests::trait_fts_search_returns_tokens_match` -- verifies FTS path. +- `vestige_core::storage::sqlite::tests::trait_vector_search_returns_cosine_order` -- verifies ordering. +- `vestige_core::storage::sqlite::tests::trait_scheduling_round_trip` -- `update_scheduling` then `get_scheduling` returns equivalent state. +- `vestige_core::storage::sqlite::tests::trait_get_scheduling_missing_returns_none`. +- `vestige_core::storage::sqlite::tests::trait_get_due_memories_returns_in_order` -- inserts 3 records with different `next_review`, asserts older-due listed first. +- `vestige_core::storage::sqlite::tests::trait_add_edge_is_idempotent` -- adding the same edge twice does not duplicate. +- `vestige_core::storage::sqlite::tests::trait_get_edges_filters_by_type`. +- `vestige_core::storage::sqlite::tests::trait_remove_edge_deletes_single`. +- `vestige_core::storage::sqlite::tests::trait_get_neighbors_bfs_depth_zero_returns_self_only`. +- `vestige_core::storage::sqlite::tests::trait_get_neighbors_bfs_depth_two_expands` -- build A->B->C, get_neighbors(A, 2) returns {A, B, C}. +- `vestige_core::storage::sqlite::tests::trait_list_domains_empty_in_phase_1` -- Phase 1 has no clustering, so `list_domains()` returns `[]`. +- `vestige_core::storage::sqlite::tests::trait_upsert_then_get_domain_round_trip`. +- `vestige_core::storage::sqlite::tests::trait_delete_domain_idempotent`. +- `vestige_core::storage::sqlite::tests::trait_classify_with_no_domains_returns_empty` -- verifies Phase 1 stub behavior. +- `vestige_core::storage::sqlite::tests::trait_count_matches_insert_count`. +- `vestige_core::storage::sqlite::tests::trait_get_stats_reports_registered_model`. +- `vestige_core::storage::sqlite::tests::trait_vacuum_succeeds` -- runs and asserts no error. + +Every public method on `LocalEmbedder` gets at least one unit test under `crates/vestige-core/src/embedder/fastembed.rs`: + +- `vestige_core::embedder::fastembed::tests::embedder_reports_correct_name` -- `model_name()` contains "nomic". +- `vestige_core::embedder::fastembed::tests::embedder_reports_256_dimension`. +- `vestige_core::embedder::fastembed::tests::embedder_hash_is_stable` -- `model_hash()` called twice returns identical string. +- `vestige_core::embedder::fastembed::tests::embedder_hash_includes_crate_version` -- a synthetic test that asserts the hash contains the blake3 of `(name, 256, VERSION)`. +- `vestige_core::embedder::fastembed::tests::embedder_embed_smoke` -- gated on `#[cfg(feature = "embeddings")]`; asserts output length == 256. +- `vestige_core::embedder::fastembed::tests::embedder_embed_batch_matches_sequential` -- gated; assert batch result equals sequential result. +- `vestige_core::embedder::fastembed::tests::embedder_signature_matches_accessors`. + +Migration V12 unit tests under `crates/vestige-core/src/storage/migrations.rs`: + +- `vestige_core::storage::migrations::tests::v12_adds_embedding_model_table` -- apply V12 then assert `SELECT count(*) FROM sqlite_master WHERE name='embedding_model'` == 1. +- `vestige_core::storage::migrations::tests::v12_adds_domains_columns` -- assert `PRAGMA table_info(knowledge_nodes)` includes `domains` and `domain_scores`. +- `vestige_core::storage::migrations::tests::v12_default_values_empty_json` -- insert a row via raw SQL, read back, assert `domains == '[]'` and `domain_scores == '{}'`. +- `vestige_core::storage::migrations::tests::v12_is_replayable` -- rewind `schema_version` to 11, re-apply migrations, does not error (MUST use `CREATE TABLE IF NOT EXISTS`; `ALTER TABLE ADD COLUMN` will be skipped because the driver only re-runs migrations whose version > current -- already covered by `apply_migrations`). +- `vestige_core::storage::migrations::tests::v12_preserves_existing_rows` -- insert rows under V11 schema, upgrade to V12, assert `domains='[]'` on those rows. + +Supporting-type unit tests under `crates/vestige-core/src/storage/memory_store.rs`: + +- `vestige_core::storage::memory_store::tests::memory_store_error_from_storage_error` -- converts `StorageError::NotFound` to `MemoryStoreError::NotFound`. +- `vestige_core::storage::memory_store::tests::model_signature_serde_round_trip`. +- `vestige_core::storage::memory_store::tests::memory_record_serde_round_trip`. + +### Integration tests (`tests/phase_1/`) + +Each file is a standalone `[[test]]` target. The Cargo layout: + +- `tests/phase_1/Cargo.toml` with: + +```toml +[package] +name = "vestige-phase-1-tests" +version = "0.0.1" +edition = "2024" +publish = false + +[dependencies] +vestige-core = { path = "../../crates/vestige-core" } +tokio = { version = "1", features = ["macros", "rt-multi-thread"] } +tempfile = "3" +uuid = { version = "1", features = ["v4"] } +chrono = "0.4" +serde_json = "1" +rusqlite = { version = "0.38", features = ["bundled"] } +``` + +And added to the workspace `Cargo.toml` members. Each `.rs` file below is a `#[tokio::test]`-using integration test. + +#### `tests/phase_1/trait_round_trip.rs` + +- `round_trip::insert_get_update_delete` -- exercises CRUD via the trait. Inserts a record with `domains=[]`, gets it, asserts equality, updates content, deletes, asserts not found. +- `round_trip::scheduling_upsert_and_due_scan` -- upserts FSRS state for three memories with different `next_review`, calls `get_due_memories(Utc::now(), 10)`, asserts only past-due ones appear. +- `round_trip::edge_crud` -- add edge, list edges, remove edge, assert gone. +- `round_trip::search_hybrid_returns_results` -- insert three memories, embed one by content match only, one by semantic only, one by both, search with both `text` and `embedding`, assert all three appear with `fts_score`/`vector_score` correctly populated. +- `round_trip::count_and_stats_track_inserts` -- after 10 inserts, `count()` == 10 and `get_stats().total_memories` == 10. +- `round_trip::vacuum_after_deletes_reclaims` -- insert 50, delete 40, call `vacuum`, assert disk file size decreased (informational; test is lenient if VACUUM was a no-op). +- `round_trip::list_domains_empty_then_upsert_then_delete` -- Phase 1 has no discovery, but manual upsert/delete must work so Phase 2's Postgres impl can share the test. +- `round_trip::classify_with_no_domains_returns_empty` -- calls `classify(embedding)` on a fresh store, asserts `Vec<(String, f64)>` is empty. + +#### `tests/phase_1/embedding_model_registry.rs` + +- `model_registry::first_embedded_insert_auto_registers` -- fresh store; insert a record with a 256-dim vector using a `FastembedEmbedder`; subsequent `registered_model()` returns a `Some(ModelSignature)` with dim=256. +- `model_registry::second_insert_with_same_signature_succeeds`. +- `model_registry::second_insert_with_different_dimension_refused` -- register a 256-dim signature, try to insert a 512-dim vector, expect `MemoryStoreError::InvalidInput` (because dimension does not match registered). +- `model_registry::second_insert_with_different_model_name_refused` -- register signature A, call `register_model` with signature B (same dim, different name), expect `MemoryStoreError::ModelMismatch`. +- `model_registry::second_insert_with_different_hash_refused` -- register signature A, try to register signature A' with the same name and dim but a different hash, expect `MemoryStoreError::ModelMismatch`. +- `model_registry::no_embedding_insert_allowed_before_registration` -- a plain text memory without an embedding must insert successfully even when `registered_model()` is `None`. +- `model_registry::stats_reports_registered_model_after_first_write`. + +#### `tests/phase_1/domain_column_migration.rs` + +- `domain_columns::fresh_db_has_v12_schema` -- open a fresh store, query `PRAGMA table_info(knowledge_nodes)`, assert `domains` and `domain_scores` columns are present with the correct defaults. +- `domain_columns::v11_db_upgrades_cleanly` -- programmatically create a DB at V11 by running migrations up to V11 only, insert 5 rows, then invoke the V12 migration, assert all 5 rows now report `domains=='[]'` and `domain_scores=='{}'`. +- `domain_columns::empty_domains_serialize_as_brackets` -- insert a `MemoryRecord { domains: vec![], .. }`, then read the underlying SQLite row via a raw query, assert the stored value is `"[]"`, not `NULL`. +- `domain_columns::populated_domains_round_trip` -- insert a record with `domains=["dev","infra"]` and `domain_scores={"dev":0.82,"infra":0.71}`, read back via the trait, assert equality. +- `domain_columns::domains_table_exists` -- `SELECT name FROM sqlite_master WHERE name='domains'` returns one row. + +#### `tests/phase_1/cognitive_module_isolation.rs` + +- `cognitive_isolation::all_modules_compile_against_dyn_store` -- a test function that allocates a `let store: Arc = Arc::new(SqliteMemoryStore::new(...)?);`, then invokes a representative method from every cognitive module passing in records/vectors/edges it reads through the trait. The point is a compile-time gate: if any module still typed against `SqliteMemoryStore`, this would fail to compile. +- `cognitive_isolation::spreading_activation_traverses_via_trait` -- exercise `ActivationNetwork` seeded from `store.get_edges(...)` results. +- `cognitive_isolation::synaptic_tagging_consumes_records_via_trait` -- build `CapturedMemory` from `store.get(uuid)` and let the tagger compute retroactive importance. +- `cognitive_isolation::hippocampal_index_built_from_store` -- load memories via `store.fts_search`, build `HippocampalIndex`, assert queries against the index work. + +#### `tests/phase_1/send_bound_variant.rs` + +- `send_bound::arc_dyn_memory_store_moves_across_tokio_tasks` -- wrap `SqliteMemoryStore` in `Arc`, spawn 16 tokio tasks each inserting 10 memories, join all tasks, assert final `count() == 160`. This verifies the `#[trait_variant::make(MemoryStore: Send)]` emission actually produces a `Send`-bound future. +- `send_bound::concurrent_readers_one_writer` -- 32 concurrent readers calling `search` while one writer loops inserting; asserts no panics, no deadlocks, eventual consistency on `count`. + +#### `tests/phase_1/embedder_trait.rs` + +- `embedder::fastembed_implements_embedder_trait` -- `let e: Box = Box::new(FastembedEmbedder::new());` compiles and `e.dimension()` == 256. +- `embedder::signature_matches_memory_store_registry` -- take the signature from `Embedder::signature()`, register it via `MemoryStore::register_model`, assert `registered_model()` returns the same. + +### Regression verification + +- `cargo build -p vestige-core` -- zero warnings. +- `cargo build -p vestige-mcp` -- zero warnings. +- `cargo clippy --workspace --all-targets -- -D warnings` -- green. +- `cargo test -p vestige-core --lib` -- existing 352 core lib tests remain green. +- `cargo test -p vestige-mcp --lib` -- existing 406 mcp tests remain green. +- `cargo test -p vestige-core --lib storage::migrations::tests` -- explicitly invokes the migration tests added in Phase 1. +- `cargo test -p vestige-core --lib storage::sqlite::tests` -- invokes the trait-method unit tests added in Phase 1. +- `cargo test -p vestige-core --lib embedder::fastembed::tests` -- invokes embedder unit tests. +- `cargo test -p vestige-phase-1-tests --test trait_round_trip` -- Phase 1 integration test file 1. +- `cargo test -p vestige-phase-1-tests --test embedding_model_registry` -- Phase 1 integration test file 2. +- `cargo test -p vestige-phase-1-tests --test domain_column_migration` -- Phase 1 integration test file 3. +- `cargo test -p vestige-phase-1-tests --test cognitive_module_isolation` -- Phase 1 integration test file 4. +- `cargo test -p vestige-phase-1-tests --test send_bound_variant` -- Phase 1 integration test file 5. +- `cargo test -p vestige-phase-1-tests --test embedder_trait` -- Phase 1 integration test file 6. +- `cargo test -p vestige-phase-1-tests` -- convenience: runs all integration test binaries in the Phase 1 crate. +- `cargo test -p vestige-e2e` -- existing e2e harness runs unchanged; no new tests here but existing ones must pass. + +## Acceptance Criteria + +- [ ] `cargo build -p vestige-core` -- zero warnings. +- [ ] `cargo build -p vestige-mcp` -- zero warnings. +- [ ] `cargo build --workspace --all-targets` -- zero warnings. +- [ ] `cargo clippy --workspace --all-targets -- -D warnings` -- exits 0. +- [ ] `cargo test -p vestige-core` -- all 352 existing core tests plus new Phase 1 unit tests pass. +- [ ] `cargo test -p vestige-mcp` -- all 406 existing mcp tests pass, unchanged. +- [ ] `cargo test -p vestige-phase-1-tests` -- all Phase 1 integration tests pass. +- [ ] `cargo test -p vestige-e2e` -- existing e2e journey suite passes unchanged. +- [ ] Cumulative test count >= 758 (the pre-Phase-1 baseline) plus the new unit and integration additions. +- [ ] `git grep -n 'rusqlite::' crates/vestige-core/src/neuroscience/ crates/vestige-core/src/advanced/` -- zero hits (the single pre-existing doc-comment reference in `active_forgetting.rs` is acceptable and does not introduce SQL dependency; code references must be zero). +- [ ] `git grep -n 'SqliteMemoryStore' crates/vestige-core/src/neuroscience/ crates/vestige-core/src/advanced/` -- zero hits. +- [ ] `git grep -n 'fastembed::' crates/vestige-core/src/storage/sqlite.rs` -- zero hits (Storage must never call fastembed directly; embedding goes through the `Embedder` trait held on the caller side). +- [ ] `SqliteMemoryStore::insert` refuses a vector whose dimension disagrees with the registered model (returns `MemoryStoreError::InvalidInput`). +- [ ] `SqliteMemoryStore::register_model` returns `MemoryStoreError::ModelMismatch` when a second, different signature is provided after a first was already registered. +- [ ] After upgrading a V11 database to V12, every pre-existing row has `domains == "[]"` and `domain_scores == "{}"` with no NULLs. +- [ ] `#[trait_variant::make(MemoryStore: Send)]` compiles; `Arc` is movable across `tokio::spawn`. +- [ ] Migration V12 is idempotent on replay: `apply_migrations` rewound to V11, re-applied, succeeds without error. +- [ ] `vestige-core::storage::Storage` continues to resolve (via the `pub type` alias) at every current call site in `vestige-mcp`. +- [ ] The `embedding_model` table can only hold a single row (programmatic invariant -- verified by an integration test that attempts a second `INSERT INTO embedding_model (id = 1, ...)` and observes the CHECK-enforced uniqueness). +- [ ] `registered_model()` is cached on first read; no SELECT is issued against `embedding_model` after the first hit within the same process (verified by wrapping the reader in a counting proxy in a dedicated test). + +## Rollback Notes + +If Phase 1 fails mid-way, rollback granularity is per-deliverable and the DB can be downgraded by SQL. + +- **D1 (`memory_store.rs`)**: revert the new file. The trait has zero non-test consumers in Phase 1, so deletion is safe. +- **D2 (`storage/mod.rs`)**: revert to the prior export list. The only forward-facing identifier is the `pub type Storage = SqliteMemoryStore;` alias, which becomes `pub use sqlite::Storage;` again once `SqliteMemoryStore` is renamed back to `Storage`. +- **D3 (`sqlite.rs` rename + trait impl)**: revert the struct rename (`SqliteMemoryStore` -> `Storage`). The trait impl is a separate `impl` block and can be deleted wholesale. Inherent methods are unchanged and do not need to be touched. Net diff on revert: delete one `impl LocalMemoryStore for ...` block plus the two helper functions (`row_to_record`, `enforce_model`). +- **D4 (Migration V12)**: DOWN migration script: + +```sql +-- Phase 1 rollback: drop Phase 1 schema additions. +-- WARNING: this deletes any `domains` / `domain_scores` values stored under V12. +-- Execute ONLY when downgrading from V12 to V11 on a database where no Phase 4 +-- work has happened yet (otherwise you lose domain classifications). + +DROP TABLE IF EXISTS domains; +DROP INDEX IF EXISTS idx_nodes_domains; +DROP INDEX IF EXISTS idx_nodes_domain_scores; + +-- SQLite does not support DROP COLUMN before 3.35; the project's bundled +-- rusqlite uses 3.45+ (see `bundled-sqlite` feature). So the DROP COLUMN +-- form below is safe on every target platform. +ALTER TABLE knowledge_nodes DROP COLUMN domains; +ALTER TABLE knowledge_nodes DROP COLUMN domain_scores; + +DROP TABLE IF EXISTS embedding_model; + +UPDATE schema_version SET version = 11, applied_at = datetime('now'); +``` + + Operationally: the DOWN script is NOT included in the source migrations list (migrations are forward-only). If a rollback is required, it is applied manually via `sqlite3 vestige.db < rollback_v12.sql`. A backup via `storage.backup_to(...)` MUST be taken before the Phase 1 migration runs in production -- the `Storage::backup_to` method already exists (line 3903) and does not need changes. + +- **D5/D6 (`embedder/`)**: delete the module. `EmbeddingService` is untouched, so callers that still use it continue to work. The new `Embedder` trait has no pre-Phase-2 consumers. +- **D7 (`lib.rs`)**: revert the re-export additions. Zero downstream impact since the new symbols have no pre-Phase-2 consumers. +- **D8 (cognitive module audit)**: audit-only, no code changes. Nothing to roll back unless `consolidation/sleep.rs` was changed; if so, revert. +- **Crate-level considerations**: + - `trait-variant` must remain in `Cargo.toml` until every consumer of the trait alias has been reverted. Safe to leave in `[dependencies]` indefinitely; it has no runtime cost. + - `blake3` was going to be added in Phase 3 anyway; leaving it in on rollback is harmless. + - `rusqlite` version stays pinned; no bump required for Phase 1. + +## Open Implementation Questions + +Implementation-choice-only. Architectural questions are resolved in ADR 0001. + +1. **`MemoryRecord` vs `KnowledgeNode` as the trait currency.** + - Candidate A: `MemoryRecord` (new, lean type matching the PRD) -- chosen. + - Candidate B: use existing `KnowledgeNode` directly. + - **Recommendation: A.** `KnowledgeNode` carries 30+ FSRS / dual-strength / sentiment / temporal fields that bind callers to the SQLite columns. `MemoryRecord` is what `PgMemoryStore` and future backends will want. SQLite impl converts between the two at the boundary, which is a ~40-line `impl From for MemoryRecord` (and back) shim. Pays for itself in Phase 2. + +2. **`async fn` in traits vs `Box` via `async-trait`.** + - Candidate A: use `trait-variant` (RPITIT-based, MSRV 1.75+, our MSRV is 1.91). + - Candidate B: use `async-trait` (allocates one Box per call). + - **Recommendation: A.** `trait-variant` generates both the base `LocalMemoryStore` and the `Send`-bound `MemoryStore` from one definition, matches what the PRD explicitly calls out, and avoids the allocation overhead of boxed futures on every CRUD call. + +3. **Blocking SQLite under async signatures: spawn_blocking vs inline.** + - Candidate A: bodies call the existing sync `self.writer.lock()...` inline inside the `async fn`. + - Candidate B: bodies wrap in `tokio::task::spawn_blocking`. + - **Recommendation: A for Phase 1.** The current call sites are a mix of sync (CLI, bin/restore.rs) and async (MCP handlers). Introducing `spawn_blocking` would force a tokio runtime even for CLI use. Inline blocking under `async fn` is a documented pattern that compiles and works; under Phase 2 the Postgres impl uses `sqlx` which is natively async, and we can revisit Sqlite blocking policy at that point. Phase 1 priority is "no behavior change". + +4. **Where does `register_model` get called from: storage side auto-register, or caller-side explicit?** + - Candidate A: caller explicitly calls `store.register_model(embedder.signature())` once after `MemoryStore::init`. + - Candidate B: first `insert` with a vector auto-registers. + - **Recommendation: B.** The current code path (`Storage::ingest` -> `generate_embedding_for_node` -> INSERT into `node_embeddings`) has no explicit registration step and we want `--no behavior change`. Auto-register on first embedded write preserves the exact current UX. Callers who care (migration tooling, Phase 2 `--reembed`) can still call `register_model` explicitly; it is a no-op when idempotent. + +5. **`model_hash` content: fastembed ONNX bytes vs `(name, dim, crate_version)`.** + - Candidate A: hash the ONNX file bytes on disk (after model download). + - Candidate B: hash `(name, dim, vestige-core CARGO_PKG_VERSION)`. + - **Recommendation: B.** Fastembed caches ONNX files under `FASTEMBED_CACHE_PATH`; reading them from inside `FastembedEmbedder::new()` couples the embedder to fastembed's caching behavior and adds slow startup. Hashing `(name, dim, our crate version)` catches the "silent model drift between vestige versions" case the ADR calls out under Risks. Phase 2 can add a content-hashed `OnnxEmbedder` that loads any file and genuinely hashes it; the trait method signature stays the same. + +6. **`LocalMemoryStore` `Sync + 'static` or just `Sync`.** + - Candidate A: `Sync + 'static`. + - Candidate B: `Sync`. + - **Recommendation: A.** `'static` is required for `Arc` which is the target call pattern (Axum, MCP server, cognitive engine). Every impl we have in mind -- `SqliteMemoryStore`, `PgMemoryStore` -- holds owned state (connection pool, vector index), so `'static` is free. + +7. **Should trait methods appear on the SQLite impl instead of being separate?** + - Candidate A: keep the current ~85 inherent methods on `SqliteMemoryStore` AND add the `impl LocalMemoryStore` block. + - Candidate B: move every inherent method into the trait. + - **Recommendation: A.** Many inherent methods (e.g. `run_rac1_cascade_sweep`, `apply_rac1_cascade`, `save_insight`, `save_connection`, `preview_review`, `get_memory_subgraph`) have SQLite-specific semantics, transactional behavior, and call patterns that do not belong in a backend-agnostic trait. They will stay SQLite-only or be extracted into new traits in a post-Phase-4 cleanup. Phase 1's job is to expose the `~25 methods` contract the ADR specifies, not to retrofit the entire API. + +8. **Where do `Domain` bytes (centroid) live?** + - Candidate A: `BLOB` column on `domains` table. + - Candidate B: JSON-encoded array of f32 in a `TEXT` column. + - **Recommendation: A.** Consistent with how `node_embeddings.embedding` already stores vectors (little-endian f32 bytes via `Embedding::to_bytes`). JSON would triple the storage size and slow deserialization. The `Domain::centroid: Vec` field round-trips through the same codec. + +9. **Migration numbering when Phase 2 also wants to add a migration.** + - Candidate A: Phase 1 takes V12, Phase 2 takes V13. + - Candidate B: Phase 1 takes V12, Phase 2 re-shapes V12 to include its changes. + - **Recommendation: A.** Migrations are forward-only and append-only in this project. Phase 2 adds V13 (for `review_events` append-only table, if that lands in Phase 2 -- otherwise it is Phase 5 work). + +10. **Integration test crate location: sibling to `tests/e2e/` or inside `crates/vestige-core/tests/`.** + - Candidate A: new workspace member at `tests/phase_1/` (sibling to `tests/e2e/`). + - Candidate B: under `crates/vestige-core/tests/` (standard cargo integration-test layout). + - **Recommendation: A.** Matches the existing pattern of `tests/e2e/`, which is already a workspace member with its own `Cargo.toml`. Keeps the Phase 1 test binary outputs in a predictable location (`target/debug/deps/trait_round_trip-*`). Also avoids the build-graph cycle where `crates/vestige-core/tests/` would re-link everything under `vestige-core` each edit. + +### Critical Files for Implementation + +- /home/delandtj/prppl/vestige/crates/vestige-core/src/storage/memory_store.rs (new; contains the `LocalMemoryStore` / `MemoryStore` traits plus `MemoryRecord`, `SchedulingState`, `SearchQuery`, `SearchResult`, `MemoryEdge`, `Domain`, `ClassificationResult`, `StoreStats`, `HealthStatus`, `MemoryStoreError`, `ModelSignature`) +- /home/delandtj/prppl/vestige/crates/vestige-core/src/storage/sqlite.rs (rename `Storage` -> `SqliteMemoryStore`, add the `impl LocalMemoryStore` block and the `enforce_model` / `row_to_record` helpers; ~200 line diff on a 4592-line file) +- /home/delandtj/prppl/vestige/crates/vestige-core/src/storage/migrations.rs (append `Migration { version: 12, ... }` + `MIGRATION_V12_UP` constant; ~80 new lines) +- /home/delandtj/prppl/vestige/crates/vestige-core/src/embedder/mod.rs (new; `Embedder` + `LocalEmbedder` traits, `EmbedderError`, default `embed_batch`) +- /home/delandtj/prppl/vestige/crates/vestige-core/src/embedder/fastembed.rs (new; `FastembedEmbedder` implementation adapting the existing `EmbeddingService`) diff --git a/docs/plans/0002-phase-2-postgres-backend.md b/docs/plans/0002-phase-2-postgres-backend.md new file mode 100644 index 0000000..a372e27 --- /dev/null +++ b/docs/plans/0002-phase-2-postgres-backend.md @@ -0,0 +1,1269 @@ +# Phase 2 Plan: PostgreSQL Backend + +**Status**: Draft +**Depends on**: Phase 1 (MemoryStore + Embedder traits, embedding_model registry, domain columns) +**Related**: docs/adr/0001-pluggable-storage-and-network-access.md (Phase 2), docs/prd/001-getting-centralized-vestige.md + +--- + +## Scope + +### In scope + +- `PgMemoryStore` struct implementing the Phase 1 `MemoryStore` trait against `sqlx::PgPool`, including compile-time checked queries via `sqlx::query!` / `sqlx::query_as!`. +- First-class `pgvector` integration: typed `Vector` columns, HNSW index (`vector_cosine_ops`, `m = 16`, `ef_construction = 64`), and use of the cosine-distance operator `<=>`. +- First-class Postgres FTS: GENERATED `tsvector` column (`search_vec`) with `setweight` (A=content, B=node_type, C=tags), GIN index, and `websearch_to_tsquery` at query time. +- Hybrid search via Reciprocal Rank Fusion (RRF) expressed as a single SQL statement with CTEs for FTS and vector subqueries, with optional domain filter through array overlap (`&&`). +- sqlx migrations directory at `crates/vestige-core/migrations/postgres/`, numbered `{NNNN}_{name}.up.sql` / `{NNNN}_{name}.down.sql`, runnable by `sqlx::migrate!` at startup and by `sqlx-cli`. +- Offline query cache committed under `crates/vestige-core/.sqlx/` so a DATABASE_URL is not required at build time. +- Backend selection via `vestige.toml`: `[storage]` section with `backend = "sqlite" | "postgres"` plus the per-backend subsection (`[storage.sqlite]`, `[storage.postgres]`). Exclusive at compile time via `postgres-backend` feature, exclusive at runtime via the enum. +- CLI: `vestige migrate --from sqlite --to postgres --sqlite-path

--postgres-url ` -- streaming copy with progress output. +- CLI: `vestige migrate --reembed --model=` -- O(n) re-embed under a new `Embedder`, registry update, HNSW rebuild. +- Testcontainer-based integration tests using the `pgvector/pgvector:pg16` image, behind the `postgres-backend` feature so SQLite-only builds remain untouched. +- `PgMemoryStore` parity with `SqliteMemoryStore` across every public `MemoryStore` method defined in Phase 1. + +### Out of scope + +- Phase 3 (network access): HTTP MCP transport, API key auth, `vestige keys` CLI. The `api_keys` DDL is declared by Phase 3; Phase 2 does not create it. +- Phase 4 (emergent domain classification): `DomainClassifier`, HDBSCAN, discover / rename / merge CLI. Phase 2 provisions the `domains` and `domain_scores` columns and the `domains` table structure so Phase 4 slots in without further migration, but does not compute or classify. +- Phase 5 (federation): cross-node sync. The `review_events` table is declared in Phase 1; Phase 2 only references it where FSRS writes happen. +- Changes to the cognitive engine, Phase 1 traits, or the embedding pipeline itself. Phase 2 only adds a backend. +- SQLCipher parity for Postgres. Operator responsibility (TLS to Postgres, pgcrypto, disk-level encryption) is out of scope for this phase. + +--- + +## Prerequisites + +### Expected Phase 1 artifacts (consumed, not produced) + +Phase 2 treats all of the following as fixed interfaces. Each path is the expected Phase 1 location. + +- `crates/vestige-core/src/storage/mod.rs` -- re-exports the trait and the two concrete backends. +- `crates/vestige-core/src/storage/memory_store.rs` -- defines the `MemoryStore` trait (generated by `trait_variant::make` from `LocalMemoryStore`) with the full CRUD, search, FSRS, graph, and domain surface from the PRD. Phase 2 implements every method here. +- `crates/vestige-core/src/storage/types.rs` -- shared value types: `MemoryRecord`, `SchedulingState`, `SearchQuery`, `SearchResult`, `MemoryEdge`, `Domain`, `StoreStats`, `HealthStatus`. +- `crates/vestige-core/src/storage/error.rs` -- `StoreError` enum plus `pub type StoreResult = Result`. Phase 2 extends this with `StoreError::Postgres(sqlx::Error)` and `StoreError::Migrate(sqlx::migrate::MigrateError)` via `From` impls (the variants themselves MUST live behind `#[cfg(feature = "postgres-backend")]`). +- `crates/vestige-core/src/embedder/mod.rs` -- `Embedder` trait with `embed`, `model_name`, `dimension`, `model_hash`. Phase 2 calls `model_name()`, `dimension()`, and `model_hash()` for the registry. +- `crates/vestige-core/src/storage/sqlite.rs` -- `SqliteMemoryStore: MemoryStore`. Phase 2's `migrate --from sqlite --to postgres` uses this as the source. +- `crates/vestige-core/src/storage/registry.rs` -- `EmbeddingModelRegistry` abstraction that both backends implement. Phase 2 supplies a Postgres version writing to `embedding_model`. +- `crates/vestige-core/migrations/sqlite/` -- V12 (Phase 1) adds `domains TEXT` (JSON-encoded array), `domain_scores TEXT` (JSON), `embedding_model(name, dimension, hash, created_at)`, and `review_events(id, memory_id, timestamp, rating, prior_state, new_state)`. Phase 2 mirrors every column and table in Postgres. + +If any of the above is missing when Phase 2 starts, the first action is to surface the gap back to Phase 1 -- do NOT backfill a partial trait in Phase 2. + +### Required crates (declared in Phase 2, not installed by this doc) + +The agent running Phase 2 uses `cargo add` in `crates/vestige-core/` for each dependency below. Exact versions and feature flags: + +- `sqlx@0.8` with features `runtime-tokio`, `tls-rustls`, `postgres`, `uuid`, `chrono`, `json`, `migrate`, `macros`. Optional (gated by `postgres-backend`). +- `pgvector@0.4` with features `sqlx`. Optional (gated by `postgres-backend`). +- `deadpool` is NOT needed; `sqlx::PgPool` is the pool. +- `toml@0.8` (no features) for `vestige.toml` parsing. Moved to non-optional because both backends share the config surface. +- `figment@0.10` with features `toml`, `env` -- optional, only if Phase 1 has not already picked a config loader. If Phase 1 ships a loader, skip `figment` and reuse. +- `dirs@6` -- already a transitive `directories` dependency; reuse existing. +- `tokio-stream@0.1` (no features). Used by migrate commands for streamed iteration. +- `indicatif@0.17` (no features). Progress bars for the migrate CLI. +- `futures@0.3` with features `std`. Consumed by sqlx stream combinators. + +Dev-only (under `[dev-dependencies]` in `crates/vestige-core/Cargo.toml`, gated by `postgres-backend`): + +- `testcontainers@0.22` with features `blocking` off, `async` on (default). +- `testcontainers-modules@0.10` with features `postgres`. +- `tokio@1` features `macros`, `rt-multi-thread` (already present for core tests). +- `criterion@0.5` already present; add a new `[[bench]]` entry. + +Feature additions in `crates/vestige-core/Cargo.toml`: + +``` +[features] +postgres-backend = ["dep:sqlx", "dep:pgvector", "dep:tokio-stream", "dep:futures"] +``` + +`postgres-backend` is OFF by default. `default = ["embeddings", "vector-search", "bundled-sqlite"]` stays unchanged. `vestige-mcp` forwards a new feature `postgres-backend = ["vestige-core/postgres-backend"]`. + +### External tooling + +- PostgreSQL 16 or newer (uses `gen_random_uuid()` from `pgcrypto` bundled via `CREATE EXTENSION pgcrypto` in migration 0001; pgvector HNSW indexes require pgvector 0.5+). +- The `pgvector` extension installed in the target database (our migration issues `CREATE EXTENSION IF NOT EXISTS vector`). +- `sqlx-cli@0.8` installed on the developer machine for `cargo sqlx prepare --workspace` and `cargo sqlx migrate add` (not a build-time requirement once `.sqlx/` is committed). +- Docker or Podman reachable by the test harness for `testcontainers-modules::postgres` to spin up `pgvector/pgvector:pg16`. + +### Assumed Rust toolchain + +- Rust 2024 edition. +- MSRV 1.91 (per `CLAUDE.md`). `sqlx 0.8` is compatible. +- `rustflags` unchanged. No `nightly`-only features. + +--- + +## Deliverables + +1. Feature gate `postgres-backend` in `crates/vestige-core/Cargo.toml` and `crates/vestige-mcp/Cargo.toml` that cleanly disables all Postgres code paths when off. +2. `crates/vestige-core/src/storage/postgres/mod.rs` -- `PgMemoryStore` struct and `MemoryStore` trait impl (public entry point). +3. `crates/vestige-core/src/storage/postgres/pool.rs` -- `PgMemoryStore::connect(config)` and pool configuration. +4. `crates/vestige-core/src/storage/postgres/search.rs` -- RRF hybrid search query builder and row -> `SearchResult` mapping. +5. `crates/vestige-core/src/storage/postgres/migrations.rs` -- wraps `sqlx::migrate!("./migrations/postgres")` and surfaces typed errors. +6. `crates/vestige-core/src/storage/postgres/registry.rs` -- Postgres `EmbeddingModelRegistry` implementation writing `embedding_model`. +7. `crates/vestige-core/migrations/postgres/0001_init.up.sql` + `0001_init.down.sql` -- extensions, `memories`, `scheduling`, `edges`, `domains`, `embedding_model`, `review_events`, all indexes. +8. `crates/vestige-core/migrations/postgres/0002_hnsw.up.sql` + `0002_hnsw.down.sql` -- HNSW index creation separated so it can be `CREATE INDEX CONCURRENTLY` during reembed. +9. `crates/vestige-core/src/config.rs` -- `VestigeConfig`, `StorageConfig`, `SqliteConfig`, `PostgresConfig`, `EmbeddingsConfig`, plus a single `VestigeConfig::load(path: Option<&Path>)` returning `Result`. +10. `crates/vestige-core/src/storage/postgres/migrate_cli.rs` -- streaming SQLite-to-Postgres copy, domain-aware, with `indicatif` progress. +11. `crates/vestige-core/src/storage/postgres/reembed.rs` -- `ReembedPlan` and its driver; re-encodes all memories via a supplied `Embedder`, updates `embedding_model`, rebuilds HNSW. +12. `crates/vestige-mcp/src/bin/cli.rs` -- two new `clap` subcommands `Migrate` (union of `--from/--to` and `--reembed` variants, one subcommand or two, see Open Questions) wired to deliverables 10 and 11. +13. `crates/vestige-core/.sqlx/` -- offline query cache, committed. +14. `tests/phase_2/` -- six integration test files listed in the Test Plan. +15. `crates/vestige-core/benches/pg_hybrid_search.rs` -- Criterion benches for RRF search at 1k and 100k memories, gated by `postgres-backend`. +16. `docs/runbook/postgres.md` -- brief ops note covering extension install, `max_connections`, backup discipline, and rollback caveats. (Short; only required for the "rollback of migrate" deliverable.) + +--- + +## Detailed Task Breakdown + +### D1. `postgres-backend` feature gate + +- **File**: `crates/vestige-core/Cargo.toml`, `crates/vestige-mcp/Cargo.toml` +- **Depends on**: nothing; this is the first change. +- **Rust snippets**: + +```toml +# crates/vestige-core/Cargo.toml +[features] +default = ["embeddings", "vector-search", "bundled-sqlite"] +bundled-sqlite = ["rusqlite/bundled"] +encryption = ["rusqlite/bundled-sqlcipher"] +postgres-backend = [ + "dep:sqlx", + "dep:pgvector", + "dep:tokio-stream", + "dep:futures", +] + +[dependencies] +sqlx = { version = "0.8", default-features = false, features = [ + "runtime-tokio", "tls-rustls", "postgres", "uuid", "chrono", + "json", "migrate", "macros", +], optional = true } +pgvector = { version = "0.4", features = ["sqlx"], optional = true } +tokio-stream = { version = "0.1", optional = true } +futures = { version = "0.3", optional = true } +toml = "0.8" +indicatif = "0.17" +``` + +- **Behavior notes**: keep the two backends mutually compilable per `CLAUDE.md`. Every `use sqlx::...` sits under `#[cfg(feature = "postgres-backend")]`. Every module under `crates/vestige-core/src/storage/postgres/` carries `#![cfg(feature = "postgres-backend")]` as its file-level attribute. + +### D2. `PgMemoryStore` core struct + +- **File**: `crates/vestige-core/src/storage/postgres/mod.rs` +- **Depends on**: D1, Phase 1 `MemoryStore` trait and value types. +- **Signatures**: + +```rust +#![cfg(feature = "postgres-backend")] + +use std::sync::Arc; +use std::time::Duration; + +use chrono::{DateTime, Utc}; +use pgvector::Vector; +use sqlx::postgres::{PgConnectOptions, PgPoolOptions}; +use sqlx::PgPool; +use uuid::Uuid; + +use crate::embedder::Embedder; +use crate::storage::error::{StoreError, StoreResult}; +use crate::storage::types::{ + Domain, HealthStatus, MemoryEdge, MemoryRecord, SchedulingState, + SearchQuery, SearchResult, StoreStats, +}; +use crate::storage::memory_store::LocalMemoryStore; + +pub mod migrations; +pub mod pool; +pub mod registry; +pub mod search; +pub mod migrate_cli; +pub mod reembed; + +/// Postgres-backed implementation of `MemoryStore`. +/// +/// Cheaply cloneable. Methods take `&self`; interior state lives inside +/// the `PgPool` (which already provides `Sync` via `Arc` internally). +#[derive(Clone)] +pub struct PgMemoryStore { + pool: PgPool, + embedding_dim: i32, + embedding_model: Arc, +} + +#[derive(Debug, Clone)] +pub struct EmbeddingModelDescriptor { + pub name: String, + pub dimension: i32, + pub hash: String, +} + +impl PgMemoryStore { + /// Construct a new store. Runs migrations, reads the registry, validates + /// that the embedder matches the registered model. + pub async fn connect( + url: &str, + max_connections: u32, + embedder: &dyn Embedder, + ) -> StoreResult; + + /// Low-level constructor for tests: supply an existing pool, skip migrate. + pub async fn from_pool( + pool: PgPool, + embedder: &dyn Embedder, + ) -> StoreResult; + + /// Accessor used by migrate/reembed CLI. + pub fn pool(&self) -> &PgPool { &self.pool } + + pub fn embedding_dim(&self) -> i32 { self.embedding_dim } +} + +#[trait_variant::make(crate::storage::memory_store::MemoryStore: Send)] +impl LocalMemoryStore for PgMemoryStore { + async fn init(&self) -> StoreResult<()>; + async fn health_check(&self) -> StoreResult; + + async fn insert(&self, record: &MemoryRecord) -> StoreResult; + async fn get(&self, id: Uuid) -> StoreResult>; + async fn update(&self, record: &MemoryRecord) -> StoreResult<()>; + async fn delete(&self, id: Uuid) -> StoreResult<()>; + + async fn search(&self, query: &SearchQuery) -> StoreResult>; + async fn fts_search(&self, text: &str, limit: usize) -> StoreResult>; + async fn vector_search(&self, embedding: &[f32], limit: usize) -> StoreResult>; + + async fn get_scheduling(&self, memory_id: Uuid) -> StoreResult>; + async fn update_scheduling(&self, state: &SchedulingState) -> StoreResult<()>; + async fn get_due_memories( + &self, + before: DateTime, + limit: usize, + ) -> StoreResult>; + + async fn add_edge(&self, edge: &MemoryEdge) -> StoreResult<()>; + async fn get_edges(&self, node_id: Uuid, edge_type: Option<&str>) -> StoreResult>; + async fn remove_edge(&self, source: Uuid, target: Uuid, edge_type: &str) -> StoreResult<()>; + async fn get_neighbors(&self, node_id: Uuid, depth: usize) -> StoreResult>; + + async fn list_domains(&self) -> StoreResult>; + async fn get_domain(&self, id: &str) -> StoreResult>; + async fn upsert_domain(&self, domain: &Domain) -> StoreResult<()>; + async fn delete_domain(&self, id: &str) -> StoreResult<()>; + async fn classify(&self, embedding: &[f32]) -> StoreResult>; + + async fn count(&self) -> StoreResult; + async fn get_stats(&self) -> StoreResult; + async fn vacuum(&self) -> StoreResult<()>; +} +``` + +- **SQL (inline within impl methods)**: every call uses `sqlx::query!` or `sqlx::query_as!` for compile-time validation. Examples: + +```rust +// insert +sqlx::query!( + r#" + INSERT INTO memories ( + id, domains, domain_scores, content, node_type, tags, + embedding, metadata, created_at, updated_at + ) VALUES ($1, $2, $3, $4, $5, $6, $7::vector, $8, $9, $10) + "#, + record.id, + &record.domains as &[String], + serde_json::to_value(&record.domain_scores)?, + record.content, + record.node_type, + &record.tags as &[String], + record.embedding.as_ref().map(|v| Vector::from(v.clone())) as Option, + record.metadata, + record.created_at, + record.updated_at, +) +.execute(&self.pool) +.await?; +``` + +- **Behavior notes**: + - `StoreError` gets two new variants behind the feature: + +```rust +#[cfg(feature = "postgres-backend")] +#[error("postgres error: {0}")] +Postgres(#[from] sqlx::Error), + +#[cfg(feature = "postgres-backend")] +#[error("postgres migration error: {0}")] +Migrate(#[from] sqlx::migrate::MigrateError), +``` + + - `classify()` on Postgres implements the PRD's cosine-similarity-to-centroid computation inside SQL using `1 - (centroid <=> $1::vector)` over the `domains` table and returns rows sorted descending. This mirrors the behavior a `DomainClassifier` in Phase 4 uses; Phase 2 ships the backend capability but does not call it. + - Connection pool defaults (see D3): `max_connections = 10`, `acquire_timeout = 30s`, `idle_timeout = 600s`, `test_before_acquire = false` (cheap queries; avoid per-acquire roundtrip). + - All methods are `async fn` and use sqlx's `tokio` runtime feature; no blocking `block_on`. + +### D3. Pool construction and config wiring + +- **File**: `crates/vestige-core/src/storage/postgres/pool.rs` +- **Depends on**: D1, D2, D9. +- **Signatures**: + +```rust +#![cfg(feature = "postgres-backend")] + +use sqlx::postgres::{PgConnectOptions, PgPoolOptions}; +use sqlx::{ConnectOptions, PgPool}; +use std::str::FromStr; +use std::time::Duration; + +use crate::config::PostgresConfig; +use crate::storage::error::{StoreError, StoreResult}; + +pub async fn build_pool(cfg: &PostgresConfig) -> StoreResult { + let mut opts = PgConnectOptions::from_str(&cfg.url)?; + opts = opts + .application_name("vestige") + .statement_cache_capacity(256) + .log_statements(tracing::log::LevelFilter::Debug); + + let pool = PgPoolOptions::new() + .max_connections(cfg.max_connections.unwrap_or(10)) + .min_connections(0) + .acquire_timeout(Duration::from_secs(cfg.acquire_timeout_secs.unwrap_or(30))) + .idle_timeout(Some(Duration::from_secs(600))) + .max_lifetime(Some(Duration::from_secs(1800))) + .test_before_acquire(false) + .connect_with(opts) + .await?; + + Ok(pool) +} +``` + +- **Behavior notes**: acquire timeout chosen to exceed the 30-second testcontainer spin-up requirement. `application_name = "vestige"` makes `pg_stat_activity` readable from `psql` during debugging. + +### D4. sqlx migrations directory + +- **File**: `crates/vestige-core/migrations/postgres/0001_init.up.sql`, `0001_init.down.sql`, `0002_hnsw.up.sql`, `0002_hnsw.down.sql`. +- **Depends on**: none (pure SQL). + +`0001_init.up.sql`: + +```sql +-- Extensions +CREATE EXTENSION IF NOT EXISTS pgcrypto; +CREATE EXTENSION IF NOT EXISTS vector; + +-- Embedding model registry +-- Mirrors the SQLite table created in Phase 1. +CREATE TABLE embedding_model ( + id SMALLINT PRIMARY KEY DEFAULT 1 CHECK (id = 1), + name TEXT NOT NULL, + dimension INTEGER NOT NULL CHECK (dimension > 0), + hash TEXT NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- Domains table (populated by Phase 4 DomainClassifier; Phase 2 only creates +-- the empty table so list/get/upsert/delete work against both backends). +CREATE TABLE domains ( + id TEXT PRIMARY KEY, + label TEXT NOT NULL, + centroid vector, + top_terms TEXT[] NOT NULL DEFAULT '{}', + memory_count INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + metadata JSONB NOT NULL DEFAULT '{}'::jsonb +); + +-- Core memories table +CREATE TABLE memories ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domains TEXT[] NOT NULL DEFAULT '{}', + domain_scores JSONB NOT NULL DEFAULT '{}'::jsonb, + content TEXT NOT NULL, + node_type TEXT NOT NULL DEFAULT 'general', + tags TEXT[] NOT NULL DEFAULT '{}', + embedding vector, + metadata JSONB NOT NULL DEFAULT '{}'::jsonb, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + search_vec TSVECTOR GENERATED ALWAYS AS ( + setweight(to_tsvector('english', coalesce(content, '')), 'A') || + setweight(to_tsvector('english', coalesce(node_type, '')), 'B') || + setweight(to_tsvector('english', coalesce(array_to_string(tags, ' '), '')), 'C') + ) STORED +); + +-- FSRS scheduling state (1:1 with memories) +CREATE TABLE scheduling ( + memory_id UUID PRIMARY KEY REFERENCES memories(id) ON DELETE CASCADE, + stability DOUBLE PRECISION NOT NULL DEFAULT 0.0, + difficulty DOUBLE PRECISION NOT NULL DEFAULT 0.0, + retrievability DOUBLE PRECISION NOT NULL DEFAULT 1.0, + last_review TIMESTAMPTZ, + next_review TIMESTAMPTZ, + reps INTEGER NOT NULL DEFAULT 0, + lapses INTEGER NOT NULL DEFAULT 0 +); + +-- Graph edges (spreading activation) +CREATE TABLE edges ( + source_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE, + target_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE, + edge_type TEXT NOT NULL DEFAULT 'related', + weight DOUBLE PRECISION NOT NULL DEFAULT 1.0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (source_id, target_id, edge_type) +); + +-- FSRS review event log (Phase 1 creates this; Phase 2 mirrors it for Postgres). +-- Append-only. Used for future federation (Phase 5). +CREATE TABLE review_events ( + id BIGSERIAL PRIMARY KEY, + memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE, + timestamp TIMESTAMPTZ NOT NULL DEFAULT now(), + rating SMALLINT NOT NULL, + prior_state JSONB NOT NULL, + new_state JSONB NOT NULL +); + +-- Indexes on memories (vector index is declared separately in 0002_hnsw.up.sql) +CREATE INDEX idx_memories_fts ON memories USING GIN (search_vec); +CREATE INDEX idx_memories_domains ON memories USING GIN (domains); +CREATE INDEX idx_memories_tags ON memories USING GIN (tags); +CREATE INDEX idx_memories_node_type ON memories (node_type); +CREATE INDEX idx_memories_created ON memories (created_at); +CREATE INDEX idx_memories_updated ON memories (updated_at); + +-- Indexes on scheduling +CREATE INDEX idx_scheduling_next_review ON scheduling (next_review); +CREATE INDEX idx_scheduling_last_review ON scheduling (last_review); + +-- Indexes on edges +CREATE INDEX idx_edges_target ON edges (target_id); +CREATE INDEX idx_edges_source ON edges (source_id); +CREATE INDEX idx_edges_type ON edges (edge_type); + +-- Indexes on review_events +CREATE INDEX idx_review_events_memory ON review_events (memory_id); +CREATE INDEX idx_review_events_ts ON review_events (timestamp); + +-- Update trigger on memories.updated_at +CREATE OR REPLACE FUNCTION memories_set_updated_at() RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at := now(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_memories_updated_at +BEFORE UPDATE ON memories +FOR EACH ROW EXECUTE FUNCTION memories_set_updated_at(); +``` + +`0001_init.down.sql`: + +```sql +DROP TRIGGER IF EXISTS trg_memories_updated_at ON memories; +DROP FUNCTION IF EXISTS memories_set_updated_at(); + +DROP INDEX IF EXISTS idx_review_events_ts; +DROP INDEX IF EXISTS idx_review_events_memory; +DROP INDEX IF EXISTS idx_edges_type; +DROP INDEX IF EXISTS idx_edges_source; +DROP INDEX IF EXISTS idx_edges_target; +DROP INDEX IF EXISTS idx_scheduling_last_review; +DROP INDEX IF EXISTS idx_scheduling_next_review; +DROP INDEX IF EXISTS idx_memories_updated; +DROP INDEX IF EXISTS idx_memories_created; +DROP INDEX IF EXISTS idx_memories_node_type; +DROP INDEX IF EXISTS idx_memories_tags; +DROP INDEX IF EXISTS idx_memories_domains; +DROP INDEX IF EXISTS idx_memories_fts; + +DROP TABLE IF EXISTS review_events; +DROP TABLE IF EXISTS edges; +DROP TABLE IF EXISTS scheduling; +DROP TABLE IF EXISTS memories; +DROP TABLE IF EXISTS domains; +DROP TABLE IF EXISTS embedding_model; +``` + +`0002_hnsw.up.sql` (separated so reembed can drop-and-recreate without touching the rest of the schema): + +```sql +-- HNSW index on memories.embedding. +-- pgvector requires the column to have a typmod (fixed dimension) for HNSW. +-- The dimension is stamped by the application at startup via ALTER TABLE +-- using the embedder's dimension() method (see PgMemoryStore::connect). +-- We express the index with the generic vector_cosine_ops operator class. +CREATE INDEX idx_memories_embedding_hnsw + ON memories USING hnsw (embedding vector_cosine_ops) + WITH (m = 16, ef_construction = 64); +``` + +`0002_hnsw.down.sql`: + +```sql +DROP INDEX IF EXISTS idx_memories_embedding_hnsw; +``` + +- **Behavior notes**: + - pgvector HNSW requires a typmod. `PgMemoryStore::connect` runs `ALTER TABLE memories ALTER COLUMN embedding TYPE vector($N)` with `$N = embedder.dimension()` exactly once, guarded by a check against `embedding_model` (first startup ever) or validated against it on subsequent starts. If `embedder.dimension()` differs from the stored one and `embedding_model` is non-empty, return `StoreError::EmbeddingDimensionMismatch` -- the user must run `vestige migrate --reembed`. + - `ALTER COLUMN ... TYPE vector($N)` on a populated column fails unless the data fits; that is the desired safety net. + - The `tsvector` GENERATED column uses `array_to_string(tags, ' ')` rather than `array_to_tsvector` from the PRD sketch, because `array_to_tsvector` is not a core function in Postgres 16 and would require an extension. The behavior is equivalent for weight C. + - `gen_random_uuid()` comes from `pgcrypto`. In Postgres 13+ it is also available from core; we keep the extension for older compatibility paths. + - MVCC: all table writes are transactional; no explicit locks. `INSERT ... ON CONFLICT DO UPDATE` is used in `upsert_domain`, `update_scheduling`, and edge idempotency. + +### D5. Hybrid search via RRF + +- **File**: `crates/vestige-core/src/storage/postgres/search.rs` +- **Depends on**: D2, D4. +- **Signatures**: + +```rust +#![cfg(feature = "postgres-backend")] + +use pgvector::Vector; +use sqlx::PgPool; +use uuid::Uuid; + +use crate::storage::error::StoreResult; +use crate::storage::types::{SearchQuery, SearchResult}; + +const RRF_K: i32 = 60; // constant from Cormack et al. 2009 +const OVERFETCH_MULT: i64 = 3; // matches Phase 1 SQLite overfetch + +pub(crate) async fn rrf_search( + pool: &PgPool, + query: &SearchQuery, +) -> StoreResult>; +``` + +SQL for the full hybrid RRF query. Placeholders: +- `$1` = text query (string, may be empty) +- `$2` = embedding (vector) +- `$3` = overfetch limit per branch (int) +- `$4` = final limit (int) +- `$5` = domain filter (text[] or NULL) +- `$6` = node_type filter (text[] or NULL) +- `$7` = tag filter (text[] or NULL) + +```sql +WITH params AS ( + SELECT + $1::text AS q_text, + $2::vector AS q_vec, + $3::int AS overfetch, + $4::int AS final_limit, + $5::text[] AS dom_filter, + $6::text[] AS nt_filter, + $7::text[] AS tag_filter +), +fts AS ( + SELECT m.id, + ts_rank_cd(m.search_vec, websearch_to_tsquery('english', p.q_text)) AS score, + ROW_NUMBER() OVER ( + ORDER BY ts_rank_cd(m.search_vec, websearch_to_tsquery('english', p.q_text)) DESC + ) AS rank + FROM memories m, params p + WHERE p.q_text <> '' + AND m.search_vec @@ websearch_to_tsquery('english', p.q_text) + AND (p.dom_filter IS NULL OR m.domains && p.dom_filter) + AND (p.nt_filter IS NULL OR m.node_type = ANY(p.nt_filter)) + AND (p.tag_filter IS NULL OR m.tags && p.tag_filter) + LIMIT (SELECT overfetch FROM params) +), +vec AS ( + SELECT m.id, + 1 - (m.embedding <=> p.q_vec) AS score, + ROW_NUMBER() OVER ( + ORDER BY m.embedding <=> p.q_vec + ) AS rank + FROM memories m, params p + WHERE m.embedding IS NOT NULL + AND p.q_vec IS NOT NULL + AND (p.dom_filter IS NULL OR m.domains && p.dom_filter) + AND (p.nt_filter IS NULL OR m.node_type = ANY(p.nt_filter)) + AND (p.tag_filter IS NULL OR m.tags && p.tag_filter) + LIMIT (SELECT overfetch FROM params) +), +fused AS ( + SELECT COALESCE(f.id, v.id) AS id, + COALESCE(1.0 / (60 + f.rank), 0.0) + + COALESCE(1.0 / (60 + v.rank), 0.0) AS rrf_score, + f.score AS fts_score, + v.score AS vector_score + FROM fts f FULL OUTER JOIN vec v ON f.id = v.id +) +SELECT m.id AS "id!: Uuid", + m.domains AS "domains!: Vec", + m.domain_scores AS "domain_scores!: serde_json::Value", + m.content AS "content!", + m.node_type AS "node_type!", + m.tags AS "tags!: Vec", + m.embedding AS "embedding?: Vector", + m.metadata AS "metadata!: serde_json::Value", + m.created_at AS "created_at!: chrono::DateTime", + m.updated_at AS "updated_at!: chrono::DateTime", + fused.rrf_score AS "rrf_score!: f64", + fused.fts_score AS "fts_score?: f64", + fused.vector_score AS "vector_score?: f64" +FROM fused +JOIN memories m ON m.id = fused.id +ORDER BY fused.rrf_score DESC +LIMIT (SELECT final_limit FROM params); +``` + +- **Behavior notes**: + - `OVERFETCH_MULT * query.limit` is passed as `$3`. Final `$4` is `query.limit`. + - Empty text query is allowed; the `fts` CTE returns zero rows (`p.q_text <> ''`) and the result degrades to pure vector search, which matches `vector_search` behavior. + - Null embedding is allowed; the `vec` CTE returns zero rows and the result degrades to pure FTS, which matches `fts_search` behavior. + - `fts_search` and `vector_search` are separate public methods on the trait. Each uses a simpler single-CTE query derived from the above by removing the other branch. Implementing them as thin wrappers over `rrf_search` with nullified inputs is acceptable but adds one extra plan per call; the explicit implementations win on latency. + - `min_retrievability` in `SearchQuery` is applied as a final filter by joining on `scheduling` in the outer `SELECT`. Adding that join unconditionally regresses simple searches; add it only when `query.min_retrievability.is_some()`. + +### D6. `embedding_model` registry impl + +- **File**: `crates/vestige-core/src/storage/postgres/registry.rs` +- **Depends on**: D1, D4 (table exists), Phase 1 `EmbeddingModelRegistry` trait. +- **Signatures**: + +```rust +#![cfg(feature = "postgres-backend")] + +use sqlx::PgPool; + +use crate::embedder::Embedder; +use crate::storage::error::{StoreError, StoreResult}; + +pub(crate) async fn ensure_registry( + pool: &PgPool, + embedder: &dyn Embedder, +) -> StoreResult<()> { + let row = sqlx::query!( + r#"SELECT name, dimension, hash FROM embedding_model WHERE id = 1"# + ) + .fetch_optional(pool) + .await?; + + match row { + None => { + sqlx::query!( + r#" + INSERT INTO embedding_model (id, name, dimension, hash) + VALUES (1, $1, $2, $3) + "#, + embedder.model_name(), + embedder.dimension() as i32, + embedder.model_hash(), + ) + .execute(pool) + .await?; + + // First-ever run: stamp the vector column typmod. + let ddl = format!( + "ALTER TABLE memories ALTER COLUMN embedding TYPE vector({})", + embedder.dimension() + ); + sqlx::query(&ddl).execute(pool).await?; + Ok(()) + } + Some(r) if r.name == embedder.model_name() + && r.dimension == embedder.dimension() as i32 + && r.hash == embedder.model_hash() => Ok(()), + Some(r) => Err(StoreError::EmbeddingMismatch { + expected: format!("{} ({}d, {})", r.name, r.dimension, r.hash), + got: format!( + "{} ({}d, {})", + embedder.model_name(), + embedder.dimension(), + embedder.model_hash() + ), + }), + } +} + +pub(crate) async fn update_registry( + pool: &PgPool, + embedder: &dyn Embedder, +) -> StoreResult<()> { + // Used only by `vestige migrate --reembed` after a full re-encode. + sqlx::query!( + r#" + UPDATE embedding_model + SET name = $1, dimension = $2, hash = $3, created_at = now() + WHERE id = 1 + "#, + embedder.model_name(), + embedder.dimension() as i32, + embedder.model_hash(), + ) + .execute(pool) + .await?; + Ok(()) +} +``` + +- **Behavior notes**: + - `StoreError::EmbeddingMismatch { expected, got }` already exists in Phase 1; Phase 2 just constructs it. + - The `ALTER TABLE ... TYPE vector(N)` DDL is only issued on first init. On subsequent inits the existing typmod already matches. + - Re-embed flow also uses this module, but the DDL path is different -- see D11. + +### D7. `VestigeConfig`: `vestige.toml` backend selection + +- **File**: `crates/vestige-core/src/config.rs` (Phase 1 may already own this file; Phase 2 extends, not replaces) +- **Depends on**: D1. +- **Signatures**: + +```rust +use std::path::{Path, PathBuf}; + +use serde::Deserialize; + +#[derive(Debug, Clone, Deserialize)] +pub struct VestigeConfig { + #[serde(default)] + pub embeddings: EmbeddingsConfig, + #[serde(default)] + pub storage: StorageConfig, + #[serde(default)] + pub server: ServerConfig, + #[serde(default)] + pub auth: AuthConfig, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct EmbeddingsConfig { + pub provider: String, // "fastembed" + pub model: String, // "BAAI/bge-base-en-v1.5" +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(tag = "backend", rename_all = "lowercase")] +pub enum StorageConfig { + Sqlite(SqliteConfig), + #[cfg(feature = "postgres-backend")] + Postgres(PostgresConfig), +} + +#[derive(Debug, Clone, Deserialize)] +pub struct SqliteConfig { + pub path: PathBuf, +} + +#[cfg(feature = "postgres-backend")] +#[derive(Debug, Clone, Deserialize)] +pub struct PostgresConfig { + pub url: String, + #[serde(default)] + pub max_connections: Option, + #[serde(default)] + pub acquire_timeout_secs: Option, +} + +#[derive(Debug, Clone, Default, Deserialize)] +pub struct ServerConfig { /* Phase 3 fills this in */ } + +#[derive(Debug, Clone, Default, Deserialize)] +pub struct AuthConfig { /* Phase 3 fills this in */ } + +impl VestigeConfig { + pub fn load(path: Option<&Path>) -> Result; + pub fn default_path() -> PathBuf; // ~/.vestige/vestige.toml +} + +#[derive(Debug, thiserror::Error)] +pub enum ConfigError { + #[error("io: {0}")] + Io(#[from] std::io::Error), + #[error("toml: {0}")] + Toml(#[from] toml::de::Error), + #[error("invalid config: {0}")] + Invalid(String), +} +``` + +- **Behavior notes**: + - The serde representation matches the PRD: `[storage]` with `backend = "sqlite"` and a matching `[storage.sqlite]` or `[storage.postgres]` subsection. + - Because `StorageConfig` is `#[serde(tag = "backend")]`, an unknown backend string returns a clear error. + - If `postgres-backend` is compiled off and the user writes `backend = "postgres"`, deserialization returns "unknown variant `postgres`" -- loud failure. Phase 2 wraps this into `ConfigError::Invalid("postgres-backend feature not compiled in")`. + - `env`-override hooks (e.g., `VESTIGE_POSTGRES_URL`) are a Phase 3 concern; not added here. + +### D8. `vestige migrate --from sqlite --to postgres` + +- **File**: `crates/vestige-core/src/storage/postgres/migrate_cli.rs` +- **Depends on**: D2, D6, D7, Phase 1 `SqliteMemoryStore`. +- **Signatures**: + +```rust +#![cfg(feature = "postgres-backend")] + +use std::path::Path; +use std::sync::Arc; + +use futures::{StreamExt, TryStreamExt}; +use indicatif::{ProgressBar, ProgressStyle}; +use uuid::Uuid; + +use crate::embedder::Embedder; +use crate::storage::error::{StoreError, StoreResult}; +use crate::storage::postgres::PgMemoryStore; +use crate::storage::sqlite::SqliteMemoryStore; + +#[derive(Debug, Clone)] +pub struct SqliteToPostgresPlan { + pub sqlite_path: std::path::PathBuf, + pub postgres_url: String, + pub max_connections: u32, + pub batch_size: usize, // default 500 +} + +pub struct MigrationReport { + pub memories_copied: u64, + pub scheduling_rows: u64, + pub edges_copied: u64, + pub review_events_copied: u64, + pub domains_copied: u64, + pub errors: Vec<(Uuid, StoreError)>, +} + +pub async fn run_sqlite_to_postgres( + plan: SqliteToPostgresPlan, + embedder: Arc, +) -> StoreResult; +``` + +Algorithm: + +1. Open source `SqliteMemoryStore` in read-only mode (`?mode=ro`). +2. Check source `embedding_model` registry; refuse if it disagrees with the supplied embedder unless the user also passed `--reembed`. +3. Open destination `PgMemoryStore` via `connect` (runs migrations, stamps dim). +4. Stream source rows in batches of `plan.batch_size` via a windowed query ordered by `created_at, id` (stable cursor; survives resume). +5. For each batch: begin a Postgres transaction, `INSERT INTO memories ... ON CONFLICT (id) DO NOTHING` for all rows, `INSERT INTO scheduling` likewise, commit. Copy domain assignments (`domains`, `domain_scores`) verbatim -- they are `[]` and `{}` for pre-Phase-4 SQLite data. +6. After memories finish, stream edges and review_events the same way. +7. Emit progress via `indicatif::ProgressBar` (one bar per table, multi-bar). Each 1000 rows log to tracing at INFO. +8. Return `MigrationReport` for the caller to print. + +- **Behavior notes**: + - Memory-bounded: batch size 500 and sqlx streams mean memory usage stays O(batch * row_size), not O(total_rows). + - Idempotent: re-running replays only the rows not already present; `ON CONFLICT DO NOTHING` means partial runs recover. + - UUID strings from SQLite are parsed via `Uuid::parse_str` -- any mangled ID pushes to `errors` instead of aborting. + - The FTS `search_vec` is regenerated by Postgres via the GENERATED column; no data to copy. + - `review_events` may not exist in Phase 1 SQLite for pre-V12 databases. The migrator detects missing tables via `SELECT name FROM sqlite_master` and skips gracefully. + - A separate `--dry-run` flag prints the counts per table without writing. + +### D9. `vestige migrate --reembed --model=` + +- **File**: `crates/vestige-core/src/storage/postgres/reembed.rs` +- **Depends on**: D2, D6, Phase 1 `Embedder`. +- **Signatures**: + +```rust +#![cfg(feature = "postgres-backend")] + +use std::sync::Arc; +use std::time::Instant; + +use futures::TryStreamExt; +use indicatif::{ProgressBar, ProgressStyle}; +use sqlx::PgPool; +use uuid::Uuid; + +use crate::embedder::Embedder; +use crate::storage::error::{StoreError, StoreResult}; +use crate::storage::postgres::PgMemoryStore; + +#[derive(Debug, Clone)] +pub struct ReembedPlan { + pub batch_size: usize, // default 128 (embedder batch) + pub drop_hnsw_first: bool, // default true + pub concurrent_index: bool, // default false; use CREATE INDEX (not CONCURRENTLY) +} + +pub struct ReembedReport { + pub rows_updated: u64, + pub duration_secs: f64, + pub index_rebuild_secs: f64, +} + +pub async fn run_reembed( + store: &PgMemoryStore, + new_embedder: Arc, + plan: ReembedPlan, +) -> StoreResult; +``` + +Algorithm: + +1. Verify `new_embedder.dimension()` != stored dimension OR `new_embedder.model_hash()` != stored hash -- otherwise no-op and return `rows_updated = 0`. +2. `BEGIN; ALTER TABLE memories ALTER COLUMN embedding DROP NOT NULL`; not actually needed (column is already nullable) but shown here for documentation. +3. If `plan.drop_hnsw_first`, execute `DROP INDEX IF EXISTS idx_memories_embedding_hnsw;` so updates are not slowed by index maintenance. This is the recommended path; `REINDEX` is kept in the Open Questions as an alternative. +4. Stream all `id, content` from `memories` ordered by `id`. +5. For each batch of `plan.batch_size`: call `new_embedder.embed_batch(&texts)` (Phase 1 trait exposes batched embedding when available; otherwise loop single `embed`). Then: + +```sql +UPDATE memories +SET embedding = v.embedding::vector +FROM UNNEST($1::uuid[], $2::real[][]) AS v(id, embedding) +WHERE memories.id = v.id; +``` + +6. After all rows updated: run `ALTER TABLE memories ALTER COLUMN embedding TYPE vector($NEW_DIM)` if dimension changed. +7. Rebuild HNSW. If `plan.concurrent_index`, execute `CREATE INDEX CONCURRENTLY idx_memories_embedding_hnsw ...`; else `CREATE INDEX idx_memories_embedding_hnsw ...`. +8. `update_registry` with the new embedder. +9. Return `ReembedReport`. + +- **Behavior notes**: + - Memory-bounded: batch_size * 2 (old + new texts) vectors in RAM at any time. + - The dimension change must happen AFTER all rows are updated (pgvector validates typmod on write when a typmod is present; we relax-then-tighten). + - `CONCURRENTLY` builds do not hold `AccessExclusiveLock`, but fail inside a transaction. That's why the outer driver runs index DDL as an autocommit statement (sqlx `execute` outside a pool transaction). + - For `--dry-run`, emit what *would* happen (row count, estimated embedder calls, estimated time using `rows / 50`-per-second baseline for local fastembed) and exit. + +### D10. CLI wiring in `vestige-mcp` + +- **File**: `crates/vestige-mcp/src/bin/cli.rs` +- **Depends on**: D8, D9, D7. Requires `vestige-mcp` Cargo feature `postgres-backend`. +- **Signatures**: + +```rust +#[derive(Subcommand)] +enum Commands { + // existing variants: Stats, Health, Consolidate, Restore, Backup, + // Export, Gc, Dashboard, Ingest, Serve ... + + /// Migrate between backends or re-embed memories. + #[cfg(feature = "postgres-backend")] + Migrate(MigrateArgs), +} + +#[derive(clap::Args)] +#[cfg(feature = "postgres-backend")] +struct MigrateArgs { + #[command(subcommand)] + action: MigrateAction, +} + +#[derive(Subcommand)] +#[cfg(feature = "postgres-backend")] +enum MigrateAction { + /// Copy all memories from SQLite to Postgres. + #[command(name = "copy")] + Copy { + #[arg(long)] + from: String, // "sqlite" + #[arg(long)] + to: String, // "postgres" + #[arg(long)] + sqlite_path: PathBuf, + #[arg(long)] + postgres_url: String, + #[arg(long, default_value = "500")] + batch_size: usize, + #[arg(long)] + dry_run: bool, + }, + /// Re-embed all memories with a new embedder. + #[command(name = "reembed")] + Reembed { + #[arg(long)] + model: String, + #[arg(long, default_value = "128")] + batch_size: usize, + #[arg(long, default_value_t = true)] + drop_hnsw_first: bool, + #[arg(long)] + concurrent_index: bool, + #[arg(long)] + dry_run: bool, + }, +} +``` + +The user-facing invocation collapses to the exact string requested by the ADR: + +``` +vestige migrate copy --from sqlite --to postgres \ + --sqlite-path ~/.vestige/vestige.db \ + --postgres-url postgresql://localhost/vestige + +vestige migrate reembed --model=BAAI/bge-large-en-v1.5 +``` + +An alternate top-level layout (single `vestige migrate` with flags `--from`, `--to`, `--reembed`) is equivalent; the subcommand split is preferred because the two flag sets are disjoint (see Open Question 1). + +- **Behavior notes**: + - `--from`/`--to` values are validated; the current Phase 2 build accepts only `sqlite` and `postgres`. + - For `reembed`, the `--model` string resolves to an `Embedder` via a factory already provided by Phase 1 (`Embedder::from_name(&str)`); Phase 2 does not invent new embedder constructors. + - Progress output on `stderr`; machine-readable summary on `stdout` as one-line JSON when `--json` is set (skipped for Phase 2 unless trivial). + +### D11. Offline query cache (`.sqlx/`) + +- **File**: `crates/vestige-core/.sqlx/` (committed directory of `query-*.json`) +- **Depends on**: all `sqlx::query!` call sites being final. +- **Procedure**: the developer runs `cargo sqlx prepare --workspace` with a live Postgres having the schema applied. Output goes into `crates/vestige-core/.sqlx/`. This directory is committed. CI enforces freshness by running `cargo sqlx prepare --workspace --check` against the same live Postgres (or failing that, any dev can reproduce by setting `SQLX_OFFLINE=true`). +- **Behavior notes**: `SQLX_OFFLINE=true` in `build.rs` or env is the default on CI and for downstream consumers. The `vestige-core` docs add a one-liner in README for contributors: "if you change any SQL in Phase 2 modules, rerun `cargo sqlx prepare` with a live DB." + +### D12. Testcontainer harness (integration) + +- **File**: `tests/phase_2/common/mod.rs` (the `common` convention used in `tests/phase_2/` crates) +- **Depends on**: D2 through D11. +- **Signatures**: + +```rust +#![cfg(feature = "postgres-backend")] + +use std::sync::Arc; + +use testcontainers_modules::postgres::Postgres; +use testcontainers::{runners::AsyncRunner, ContainerAsync}; + +use vestige_core::embedder::Embedder; +use vestige_core::storage::postgres::PgMemoryStore; + +pub struct PgHarness { + pub container: ContainerAsync, + pub store: PgMemoryStore, +} + +impl PgHarness { + pub async fn start(embedder: Arc) -> anyhow::Result { + let container = Postgres::default() + .with_tag("pg16") + .with_name("pgvector/pgvector") + .start() + .await?; + let port = container.get_host_port_ipv4(5432).await?; + let url = format!( + "postgresql://postgres:postgres@127.0.0.1:{}/postgres", port + ); + let store = PgMemoryStore::connect(&url, 4, embedder.as_ref()).await?; + Ok(Self { container, store }) + } +} +``` + +- **Behavior notes**: + - Image `pgvector/pgvector:pg16` bundles pgvector into the official postgres:16 image. + - Pool size 4 is enough for tests without starving the container's default `max_connections = 100`. + - `ContainerAsync` is held for the whole test scope; drop tears down the container. + - A fake `TestEmbedder` in `common/test_embedder.rs` provides a deterministic hash-based embedding (no ONNX dependency in CI). + +--- + +## Test Plan + +### Unit tests (colocated in `src/`) + +Under `crates/vestige-core/src/storage/postgres/`: + +- `pool.rs` -- one test per `build_pool` branch: defaults, explicit `max_connections`, invalid URL returns `StoreError::Postgres`. +- `registry.rs` -- three tests: first-init writes row and alters typmod, reopen with same embedder returns Ok, reopen with different dimension returns `EmbeddingMismatch`. +- `search.rs` -- query-builder unit tests for parameter packing: empty text, null embedding, all three filters null, all three filters populated. +- `migrate_cli.rs` -- `SqliteToPostgresPlan::default` returns sane defaults; plan validation rejects empty URL. +- `reembed.rs` -- `ReembedPlan::no_change` returns `rows_updated == 0` when embedder matches registry (no network call). +- `config.rs` -- five tests covering: valid postgres config, valid sqlite config, unknown backend string, missing subsection, feature-gated postgres without feature compiled in. + +### Integration tests (in `tests/phase_2/`) + +Each file is a full integration test crate (`[[test]]` in workspace root Cargo). + +**`tests/phase_2/pg_trait_parity.rs`** + +- Declares the same test matrix as Phase 1's SQLite trait tests, parameterized over `impl MemoryStore`. +- Runs every method: `insert`, `get`, `update`, `delete`, `search`, `fts_search`, `vector_search`, `get_scheduling`, `update_scheduling`, `get_due_memories`, `add_edge`, `get_edges`, `remove_edge`, `get_neighbors`, `list_domains`, `get_domain`, `upsert_domain`, `delete_domain`, `classify`, `count`, `get_stats`, `vacuum`, `health_check`. +- Each test is written once as `async fn roundtrip_(store: &dyn MemoryStore)` and invoked from two wrappers, one for SQLite and one for Postgres. +- Acceptance: every method returns equal results (except for `Uuid` ordering in `list_domains` where the test sorts before comparing). + +**`tests/phase_2/pg_hybrid_search_rrf.rs`** + +- Inserts 20 memories with known content ("rust async trait", "postgres hnsw vector", "fastembed onnx model", ...). +- Case 1: pure FTS. `SearchQuery { text: Some("rust trait"), embedding: None, ... }` returns the three Rust-related rows in order; `fts_score` populated, `vector_score` null. +- Case 2: pure vector. `SearchQuery { text: None, embedding: Some(embed("rust trait")), ... }` returns the same three rows via cosine; `vector_score` populated, `fts_score` null. +- Case 3: hybrid. Both set -- top hit has both scores; `rrf_score >= 1/(60+1) + 1/(60+1) = 0.0328`. +- Case 4: domain filter. 10 memories tagged with `domains = ["dev"]`, 10 with `["home"]`. Query with `domains: Some(vec!["dev"])` returns only dev memories. +- Case 5: edge case -- empty FTS query plus an embedding behaves identically to `vector_search`; empty embedding plus FTS query behaves identically to `fts_search`. + +**`tests/phase_2/pg_migration_sqlite_to_postgres.rs`** + +- Populate a fresh SQLite with 10,000 memories (seeded RNG, deterministic content), 4,000 scheduling rows, 2,000 edges. +- Run `run_sqlite_to_postgres` with a test embedder. +- Assert: `count() == 10_000` on destination; spot-check 25 memories byte-for-byte (content, tags, metadata, domains, domain_scores). +- Assert: FSRS fields (`stability`, `difficulty`, `next_review`) preserved per memory. +- Assert: edges preserved by `(source_id, target_id, edge_type)`. +- Assert: re-running the migration is a no-op (`ON CONFLICT DO NOTHING` path); row count unchanged. + +**`tests/phase_2/pg_migration_reembed.rs`** + +- Start with a fresh store using `TestEmbedder768` (768-dim, hash `h1`). Insert 500 memories. +- Swap to `TestEmbedder1024` (1024-dim, hash `h2`). Run `run_reembed(store, Arc::new(TestEmbedder1024), ReembedPlan::default())`. +- Assert: `rows_updated == 500`; `embedding_model` now has `(name=TestEmbedder1024, dimension=1024, hash=h2)`. +- Assert: `SELECT DISTINCT vector_dims(embedding) FROM memories` returns only `1024`. +- Assert: HNSW index exists after reembed (`SELECT indexrelid FROM pg_indexes WHERE indexname = 'idx_memories_embedding_hnsw'`). +- Assert: memory IDs unchanged (compare pre/post id sets). +- Assert: a hybrid search using `TestEmbedder1024` returns results (post-reembed vectors are queryable). + +**`tests/phase_2/pg_config_parsing.rs`** + +- Parse six `vestige.toml` snippets: + - sqlite + fastembed -> `StorageConfig::Sqlite`. + - postgres + fastembed -> `StorageConfig::Postgres` with `max_connections = 10`. + - postgres with custom `max_connections = 25` and `acquire_timeout_secs = 60`. + - unknown backend `"mysql"` -> `ConfigError`. + - missing subsection `[storage.postgres]` while `backend = "postgres"` -> `ConfigError`. + - malformed URL (empty) -> `ConfigError::Invalid`. + +**`tests/phase_2/pg_concurrency.rs`** + +- Spawn 16 tasks, each inserting 100 memories in parallel for 1,600 total. +- Spawn 4 tasks concurrently running `search` queries; none should fail. +- Spawn 2 tasks concurrently running `update_scheduling` on overlapping IDs -- last write wins (MVCC), neither errors. +- Assert: all 1,600 rows present, no deadlocks, every task returns `Ok`. +- Run time < 10 seconds on a cold container. + +### Compile-time query verification + +- CI step: `cargo sqlx prepare --workspace --check` against a CI-provisioned Postgres (GitHub Actions / Forgejo Actions services block). Fails CI if any `query!` macro goes stale. +- Alternative offline run for contributors: `SQLX_OFFLINE=true cargo check -p vestige-core --features postgres-backend`. CI runs both forms to ensure `.sqlx/` is up to date. +- `.sqlx/` is committed to the repo. A `.gitattributes` entry marks it as `linguist-generated=true` so it doesn't inflate language stats. + +### Benchmarks + +Under `crates/vestige-core/benches/pg_hybrid_search.rs` (Criterion), gated by `postgres-backend`. + +- `pg_search_1k` -- populate 1,000 memories once per bench suite, measure `rrf_search` p50/p99 over 500 iterations. Target: p50 < 10ms, p99 < 30ms on a local container. +- `pg_search_100k` -- 100,000 memories. Target: p50 < 50ms, p99 < 150ms. Validates HNSW scaling. +- Testcontainer shared across both benches via `once_cell`. +- Bench entry in `vestige-core/Cargo.toml`: + +``` +[[bench]] +name = "pg_hybrid_search" +harness = false +required-features = ["postgres-backend"] +``` + +--- + +## Acceptance Criteria + +- [ ] `cargo build -p vestige-core --features postgres-backend` -- zero warnings. +- [ ] `cargo build -p vestige-core` (SQLite-only, default features) -- zero warnings; no Postgres symbols referenced. +- [ ] `cargo build -p vestige-mcp --features postgres-backend` -- zero warnings; `vestige` binary exposes the `migrate` subcommand. +- [ ] `cargo clippy --workspace --all-targets --all-features -- -D warnings` -- clean. +- [ ] `cargo sqlx prepare --workspace --check` -- returns success; `.sqlx/` is current. +- [ ] `cargo test -p vestige-core --features postgres-backend --test pg_trait_parity --test pg_hybrid_search_rrf --test pg_migration_sqlite_to_postgres --test pg_migration_reembed --test pg_config_parsing --test pg_concurrency` -- all green. +- [ ] Testcontainer spin-up p50 under 30 seconds on a developer laptop with a warm Docker daemon. +- [ ] `pg_search_100k` Criterion bench reports p50 < 50ms on reference hardware (logged in the ADR comment trail). +- [ ] `vestige migrate copy --from sqlite --to postgres` on a 10,000-memory corpus completes without data loss: row count parity, content byte-parity on a 1 percent sample, FSRS state preserved (stability, difficulty, reps, lapses, next_review), edge count parity. +- [ ] `vestige migrate reembed` with a dimension-changing embedder returns to a fully queryable state: HNSW present, `embedding_model` updated, no stale vectors, memory IDs untouched. +- [ ] Trait parity: every method on `MemoryStore` has at least one passing test against `PgMemoryStore`. +- [ ] Phase 1's existing SQLite suite continues to pass with zero changes required (Phase 2 is additive). +- [ ] The `postgres-backend` feature does not compile in SQLCipher (`encryption`) simultaneously (mutually exclusive at compile time, per project rule). + +--- + +## Rollback Notes + +- Every `*.up.sql` has a matching `*.down.sql` in `crates/vestige-core/migrations/postgres/`. `sqlx migrate revert` walks them in reverse order. Manual operator procedure: `sqlx migrate revert --database-url $URL --source crates/vestige-core/migrations/postgres`. +- `vestige migrate copy` is a one-way operation. The source SQLite DB is read-only during the run and untouched afterward; users retain their original file indefinitely. Recommended discipline: copy the SQLite file aside before starting, retain for 30 days. +- `vestige migrate reembed` is destructive to the `embedding` column. Recommended discipline: take a logical backup (`pg_dump --table=memories --table=embedding_model --table=scheduling`) before a reembed run. The tool prints that recommendation before starting and exits non-zero unless `--yes` is passed or the user is on a TTY that confirms. +- Feature-gate strategy: the default build remains SQLite-only. Downstream users pull `postgres-backend` explicitly: `cargo install --features postgres-backend vestige-mcp`. If the Postgres implementation fails in the field, users fall back to SQLite simply by flipping `vestige.toml`'s `[storage] backend = "sqlite"` and restarting. No data re-migration is needed if they retained their SQLite file. +- The `docs/runbook/postgres.md` deliverable (D16) captures this discipline as a one-page ops note. + +--- + +## Open Implementation Questions + +Each item has a recommendation. Ship that unless a reviewer objects. + +### Q1. CLI shape: subcommand split vs flag union + +- **Options**: (a) `vestige migrate copy --from sqlite --to postgres ...` and `vestige migrate reembed --model=...` (subcommand split); (b) `vestige migrate --from sqlite --to postgres ...` and `vestige migrate --reembed --model=...` under one `clap` command with disjoint flag groups (flag union). +- **RECOMMENDATION**: (a) subcommand split. The flag sets do not overlap and clap expresses the constraint more cleanly. The ADR string `vestige migrate --from sqlite --to postgres` can still be documented as a canonical alias by having `copy` accept it verbatim when `--from` is present. + +### Q2. Feature flag name + +- **Options**: `postgres-backend`, `postgres`, `backend-postgres`, `pg`. +- **RECOMMENDATION**: `postgres-backend`. Matches the ADR text and is explicit in `Cargo.toml` feature listings. + +### Q3. sqlx offline mode strategy + +- **Options**: (a) commit `.sqlx/` so downstream builds never need DATABASE_URL; (b) require `DATABASE_URL` at build time. +- **RECOMMENDATION**: (a). The repo already ships as a library; many downstream users will build from crates.io with no Postgres available. Committing `.sqlx/` costs ~100 kB. + +### Q4. HNSW rebuild strategy during reembed + +- **Options**: (a) `DROP INDEX; CREATE INDEX`; (b) `REINDEX INDEX CONCURRENTLY`; (c) `CREATE INDEX CONCURRENTLY` on a new name then swap. +- **RECOMMENDATION**: (a) by default for speed on empty / near-empty tables; expose `--concurrent-index` for large production corpora where locking the table is unacceptable. `REINDEX CONCURRENTLY` on pgvector HNSW is supported in pgvector 0.6+ but the community still reports edge cases with `maintenance_work_mem` -- skip unless a user explicitly opts in. + +### Q5. Connection pool sizing default + +- **Options**: 4, 10, 20, `cpus() * 2`. +- **RECOMMENDATION**: 10. Matches the PRD example, covers a single-operator load, and does not exhaust the default Postgres `max_connections = 100`. Configurable via `vestige.toml`. + +### Q6. Testcontainer image pinning + +- **Options**: (a) `pgvector/pgvector:pg16`; (b) `pgvector/pgvector:pg16.2-0.7.4` (exact tag); (c) maintain local Dockerfile. +- **RECOMMENDATION**: (b) pin exact. The float tag `pg16` has shipped breaking changes in the past (e.g., pg 16.0 to 16.1 interop). Pin to a specific pgvector minor and Postgres patch. CI bumps the tag via a single-line change. + +### Q7. Empty-text and null-embedding behavior in `search` + +- **Options**: (a) return an error if both are missing; (b) return an empty result; (c) return all memories sorted by `created_at DESC`. +- **RECOMMENDATION**: (a). A `search` call with no query is a bug in the caller; returning empty silently would hide the bug. The existing Phase 1 SQLite behavior (TBD but likely errors) is the tiebreaker. + +### Q8. `classify()` SQL vs Rust + +- **Options**: (a) compute cosine to all centroids in SQL (`SELECT id, 1 - (centroid <=> $1::vector) FROM domains ORDER BY ...`); (b) load centroids, compute in Rust. +- **RECOMMENDATION**: (a). Leverages pgvector's SIMD paths and avoids round-tripping centroid vectors. At Phase 4 scale (tens of centroids) the difference is marginal, but the SQL path is simpler and matches the rest of the backend. + +### Q9. FSRS `review_events` writes: trait method vs implicit on `update_scheduling` + +- **Options**: (a) add an explicit `record_review(memory_id, rating, prior, new)` method to the Phase 1 trait; (b) have `update_scheduling` write the event atomically. +- **RECOMMENDATION**: this is a Phase 1 question, not Phase 2. Phase 2 implements whichever Phase 1 chose. If Phase 1 missed it, Phase 2 raises a blocker rather than deciding alone. + +### Q10. `tsvector` weight for tags -- PRD used `array_to_tsvector`, we used `array_to_string` + +- **Options**: (a) `array_to_tsvector(tags)` (requires the `tsvector_extra` extension or similar); (b) `to_tsvector('english', array_to_string(tags, ' '))` (plain core Postgres). +- **RECOMMENDATION**: (b). Equivalent ranking, zero extra extensions. If a future tag matches a stopword (`"the"`), it gets dropped, but that is correct behavior for ranking. + +### Q11. `PgMemoryStore::connect` runs migrations automatically? + +- **Options**: (a) always run `sqlx::migrate!` on connect; (b) require the user to run `vestige migrate-schema` explicitly before starting the server. +- **RECOMMENDATION**: (a) during Phase 2; revisit in Phase 3 when the server binary exists. Developer ergonomics win now, and the migrations are idempotent. + +### Q12. Offline query cache freshness vs `sqlx-cli` version skew + +- **Options**: (a) pin `sqlx-cli` version in CI `actions/cache` step; (b) let CI install whatever version `sqlx` depends on. +- **RECOMMENDATION**: (a) pin to the same 0.8.x as the crate. `sqlx prepare` output changes between 0.7 and 0.8 and must match the runtime. + +--- + +## Sequencing + +The Phase 2 agent executes deliverables in this order; deliverables not listed can run in any order relative to each other. + +1. D1 (feature gate + Cargo deps) -- unblocks everything. +2. D7 (config) -- required to construct `PgMemoryStore`. +3. D4 (migrations SQL) -- required before any `query!` compiles. +4. D3 (pool) + D6 (registry) -- small, used by D2. +5. D2 (`PgMemoryStore` core + trait impl) -- the bulk of Phase 2. +6. D5 (RRF search) -- after D2; requires the trait to exist. +7. D12 (test harness) + parity and search tests -- validates D2 and D5 in isolation. +8. D8 (sqlite->pg migrate) + its integration test. +9. D9 (reembed) + its integration test. +10. D10 (CLI wiring). +11. D11 (`.sqlx/` offline cache) -- last, after SQL is frozen. +12. D15 (benches) + D16 (runbook) -- after acceptance tests pass. + +Each deliverable PR includes its own tests; the final Phase 2 PR stacks them (or lands as a single branch if the Phase 1 trait is stable enough to avoid rebase churn). + +### Critical Files for Implementation + +- /home/delandtj/prppl/vestige/crates/vestige-core/src/storage/postgres/mod.rs +- /home/delandtj/prppl/vestige/crates/vestige-core/migrations/postgres/0001_init.up.sql +- /home/delandtj/prppl/vestige/crates/vestige-core/src/storage/postgres/search.rs +- /home/delandtj/prppl/vestige/crates/vestige-core/src/storage/postgres/migrate_cli.rs +- /home/delandtj/prppl/vestige/crates/vestige-mcp/src/bin/cli.rs diff --git a/docs/plans/0003-phase-3-network-access.md b/docs/plans/0003-phase-3-network-access.md new file mode 100644 index 0000000..500fd5a --- /dev/null +++ b/docs/plans/0003-phase-3-network-access.md @@ -0,0 +1,1435 @@ +# Phase 3 Plan: Network Access and Authentication + +**Status**: Draft +**Depends on**: Phase 1 (MemoryStore trait), Phase 2 (PgMemoryStore, backend config) +**Related**: docs/adr/0001-pluggable-storage-and-network-access.md (Phase 3) + +--- + +## Scope + +### In scope + +- HTTP MCP Streamable endpoint at `POST /mcp` (JSON-RPC body, keep existing + session semantics) and `GET /mcp` (Server-Sent Events for long-running + operations: dream, consolidate, discover, reassign). +- REST API under `/api/v1/` for direct HTTP clients that do not speak MCP + (memories CRUD, search, consolidate trigger, stats, domains + list/rename/merge/discover). +- `api_keys` table + enforcement (blake3-hashed, scopes `read`/`write`, optional + `domain_filter` TEXT[], `last_used` timestamp, `active` flag, revocation). +- Auth middleware with three resolution paths in priority order: + `Authorization: Bearer ` then `X-API-Key: ` then signed session + cookie. All three resolve to the same `ApiKeyIdentity`. +- Signed session cookie: `vestige_session`, SameSite=Strict, HttpOnly, + Secure-when-TLS, Path=/, Max-Age 8 hours. Signed with HMAC-SHA256 using a + key derived from `VESTIGE_SESSION_SECRET` (env) or generated + persisted to + `/session_secret` on first boot. +- `vestige keys create|list|revoke` CLI subcommand (plus `keys rotate` as a + convenience alias of `revoke` + `create`). +- Startup-time refusal to bind non-loopback with `auth.enabled = false` (hard + error, non-zero exit, stderr message, no fallback). +- Dashboard login flow: `POST /dashboard/login` with `{"api_key":"vst_..."}` + JSON body, `X-API-Key` header, or form body; sets signed cookie; returns 200 + JSON `{"ok":true}` for XHR or 303 to `/` if form. Logout at + `POST /dashboard/logout` clears cookie. +- Per-key `domain_filter` enforced inside the auth layer: if the key has + `domain_filter = ["dev","infra"]`, every handler that searches or lists sees + the filter pre-applied via a request extension. Optional + `X-Vestige-Domain: home` header may narrow further but may never escape the + key's filter. +- `[server]` and `[auth]` sections in `vestige.toml`, plus backward-compatible + env var bridges. +- `VESTIGE_AUTH_TOKEN` continues to work for one minor release as a synthetic + single-key fallback, but logs a deprecation warning. +- Per-request request IDs and structured tracing; `last_used` write-back on + successful auth. + +### Out of scope + +- Phase 4 HDBSCAN domain classifier itself. The REST surface exposes domain + endpoints but they may stub to empty results until Phase 4 lands. +- Real TLS termination. Assumed handled by a reverse proxy (nginx, Caddy, + Mycelium). An optional `tls_cert` / `tls_key` pair is documented but its + implementation may be deferred behind a `tls` Cargo feature. +- OAuth / OIDC / SSO. Future work. +- Rate limiting per key (documented in Open Questions, not implemented here). +- WebAuthn / passkey dashboard login. Future work. +- Fine-grained RBAC beyond `read` / `write` scopes. + +## Prerequisites + +Phase 1 artifacts: + +- `vestige_core::storage::MemoryStore` trait (with `Send` variant via + `trait_variant::make`). +- `Embedder` trait. +- `SqliteMemoryStore` implementing `MemoryStore`. + +Phase 2 artifacts: + +- `PgMemoryStore` implementing `MemoryStore`. +- `crates/vestige-core/migrations/postgres/` sqlx migrations; `api_keys` table + schema present but enforcement path is Phase 3's job. +- Runtime backend selection via `vestige.toml` `[storage]` section returning + an `Arc`. + +Assumed already available in workspace: + +- `axum = 0.8` (currently pinned in `crates/vestige-mcp/Cargo.toml`). +- `tower = 0.5`, `tower-http = 0.6` (`cors`, `set-header` features already on). +- `tokio`, `serde`, `serde_json`, `uuid`, `chrono`, `tracing`, + `tracing-subscriber`, `thiserror`, `anyhow`, `subtle`, `clap`, `directories`. + +New crates required (add via `cargo add -p vestige-mcp`): + +- `blake3 = "1"` -- key hashing. +- `rand = "0.9"` with `std_rng` (for key bytes; prefer `rand::rngs::OsRng`). +- `axum-extra = { version = "0.10", features = ["cookie-signed", "typed-header"] }` + -- `SignedCookieJar`, `Cookie`, `Key`. +- `hmac = "0.12"` + `sha2 = "0.10"` -- HMAC-SHA256 for the session secret + derivation (not required if `axum-extra`'s `SignedCookieJar` is used, but + retained for the pure-token-signing path). RECOMMENDATION: rely solely on + `axum-extra::extract::cookie::{Key, SignedCookieJar}`. +- `tower-http` features bump: add `trace` and `request-id`. +- `async-stream = "0.3"` -- emitting SSE events from async closures. +- `futures-util` already present -- for `Stream` adapters. +- `base64 = "0.22"` -- emitting / parsing the random bytes in the `vst_...` + prefix. Use the `URL_SAFE_NO_PAD` alphabet. +- `zeroize = "1"` (optional, recommended) -- scrub the plaintext key in RAM + after hashing. + +`cargo add` commands (do not execute here, leave to implementation): + + cargo add -p vestige-mcp blake3 rand base64 zeroize async-stream + cargo add -p vestige-mcp axum-extra --features cookie-signed,typed-header + cargo add -p vestige-mcp tower-http --features trace,request-id,cors,set-header + +JSON-RPC library: the project uses a hand-rolled `JsonRpcRequest` / +`JsonRpcResponse` pair in `crates/vestige-mcp/src/protocol/types.rs`. Keep it +in Phase 3 (no jsonrpsee migration). Streamable HTTP remains implemented as +`POST /mcp` + session header + `GET /mcp` SSE. See Open Questions for rationale. + +## Deliverables + +1. `crates/vestige-mcp/src/auth/` module (new). Houses key generation, key + verification, identity resolution, scopes, domain-filter extractor, session + key type, and error types. + +2. `crates/vestige-mcp/src/auth/keys.rs` -- key format, generation, + blake3 hashing, store-facing trait methods for list / create / revoke / + verify. + +3. `crates/vestige-mcp/src/auth/middleware.rs` -- axum `from_fn` middleware + that populates `Extension` on the request, rejects unauthenticated + requests with 401, insufficient scope with 403. + +4. `crates/vestige-mcp/src/auth/session.rs` -- `SignedCookieJar` integration, + `session_key()` loader (env or persisted file), `issue_session()` and + `revoke_session()` helpers. + +5. `crates/vestige-mcp/src/http/` module split out of `protocol/http.rs`: + - `http/mcp.rs` -- MCP JSON-RPC endpoint (adapted from the current + `post_mcp` / `delete_mcp`, with auth middleware now gating). + - `http/mcp_sse.rs` -- SSE handler for `GET /mcp` long-running ops. + - `http/rest.rs` -- `/api/v1/*` handlers. + - `http/mod.rs` -- `build_router()`, `start_server()`, bind-safety check, + layer stack assembly. + +6. `crates/vestige-mcp/src/http/errors.rs` -- uniform `ApiError` enum and + `IntoResponse` implementation. Maps to RFC 7807 problem+json for REST and + plain JSON for `/mcp`. + +7. Dashboard patch: `crates/vestige-mcp/src/dashboard/mod.rs` -- add the auth + middleware to the dashboard router, add `/dashboard/login` + `/dashboard/logout` + endpoints, keep `/api/health` unauthenticated. + +8. `crates/vestige-mcp/src/bin/cli.rs` -- new `Keys` subcommand group (`create`, + `list`, `revoke`, `rotate`). + +9. `crates/vestige-mcp/src/config.rs` (new file) -- typed `ServerConfig`, + `AuthConfig`, `StorageConfig` loader from `vestige.toml`, merging env var + overrides, validating the non-loopback + auth-disabled combination. + +10. SQL migration `crates/vestige-core/migrations/postgres/0300_api_keys_enforcement.sql` + and SQLite equivalent `crates/vestige-core/migrations/sqlite/0300_api_keys.sql`: + - `api_keys` table (if not already created in Phase 2), with `key_hash` + UNIQUE, `label` NOT NULL, `scopes` TEXT[] default `{read,write}`, + `domain_filter` TEXT[] default `{}`, `created_at`, `last_used`, + `active BOOLEAN DEFAULT true`. + - Index on `key_hash` (unique already), and on `active WHERE active`. + +11. `MemoryStore` trait extension (Phase 2 may already cover this; if not, + finalize in Phase 3): `list_api_keys`, `create_api_key`, + `revoke_api_key`, `find_api_key_by_hash`, `touch_api_key_last_used`. + +12. Docs updates: + - `docs/env-vars.md` (new) -- one sheet for all runtime env vars. + - `README.md` server-mode section. + - `docs/adr/0001-*.md` -- mark Phase 3 as Implemented when merged. + +## Detailed Task Breakdown + +### D1. Auth module skeleton + +Files: + +- `crates/vestige-mcp/src/auth/mod.rs` +- `crates/vestige-mcp/src/auth/keys.rs` +- `crates/vestige-mcp/src/auth/session.rs` +- `crates/vestige-mcp/src/auth/middleware.rs` +- `crates/vestige-mcp/src/auth/errors.rs` + +`auth/mod.rs`: + + pub mod errors; + pub mod keys; + pub mod middleware; + pub mod session; + + pub use errors::AuthError; + pub use keys::{ApiKey, ApiKeyPlaintext, ApiKeyRecord, Scope}; + pub use middleware::{Identity, auth_layer}; + pub use session::{SessionConfig, session_key}; + +`auth/errors.rs`: + + use axum::http::StatusCode; + use axum::response::{IntoResponse, Response}; + use serde::Serialize; + use thiserror::Error; + + #[derive(Debug, Error)] + pub enum AuthError { + #[error("missing credentials")] + MissingCredentials, + #[error("invalid credentials")] + InvalidCredentials, + #[error("key revoked")] + Revoked, + #[error("insufficient scope: required {required}")] + InsufficientScope { required: &'static str }, + #[error("domain not permitted for this key: {domain}")] + DomainNotAllowed { domain: String }, + #[error("internal auth error")] + Internal, + } + + #[derive(Serialize)] + struct Problem<'a> { + #[serde(rename = "type")] + kind: &'a str, + title: &'a str, + status: u16, + detail: &'a str, + } + + impl IntoResponse for AuthError { + fn into_response(self) -> Response { + let (status, title) = match self { + AuthError::MissingCredentials => (StatusCode::UNAUTHORIZED, "unauthorized"), + AuthError::InvalidCredentials => (StatusCode::UNAUTHORIZED, "unauthorized"), + AuthError::Revoked => (StatusCode::UNAUTHORIZED, "unauthorized"), + AuthError::InsufficientScope { .. } => (StatusCode::FORBIDDEN, "forbidden"), + AuthError::DomainNotAllowed { .. } => (StatusCode::FORBIDDEN, "forbidden"), + AuthError::Internal => (StatusCode::INTERNAL_SERVER_ERROR, "internal"), + }; + let detail = self.to_string(); + let body = axum::Json(Problem { + kind: "about:blank", + title, + status: status.as_u16(), + detail: &detail, + }); + let mut r = (status, body).into_response(); + r.headers_mut().insert( + axum::http::header::CONTENT_TYPE, + axum::http::HeaderValue::from_static("application/problem+json"), + ); + r + } + } + +### D2. Key format and generation + +File: `crates/vestige-mcp/src/auth/keys.rs` + +- Key on wire: `vst_<22-byte base64url-no-pad>`. 22 bytes = 176 bits entropy. + Encoded length ~30 chars. Full string ~34 chars including the `vst_` prefix. +- Hash stored in DB: `blake3(key_plaintext)` hex lowercase (32 bytes -> 64 + hex chars). +- Hash prefix on list: first 12 hex characters, e.g. `key_hash[..12]` for + human display. + +Signatures: + + use blake3::Hasher; + use rand::rngs::OsRng; + use rand::TryRngCore; + use base64::engine::general_purpose::URL_SAFE_NO_PAD; + use base64::Engine; + use zeroize::Zeroize; + + const KEY_PREFIX: &str = "vst_"; + const KEY_RANDOM_BYTES: usize = 22; + + #[derive(Clone, Debug, PartialEq, Eq)] + pub enum Scope { + Read, + Write, + } + + impl Scope { + pub fn as_str(&self) -> &'static str { + match self { + Scope::Read => "read", + Scope::Write => "write", + } + } + pub fn from_str(s: &str) -> Option { + match s { + "read" => Some(Scope::Read), + "write" => Some(Scope::Write), + _ => None, + } + } + } + + /// The plaintext key. Shown to the user exactly once. + /// Zeroed on drop. + pub struct ApiKeyPlaintext(String); + + impl ApiKeyPlaintext { + pub fn as_str(&self) -> &str { &self.0 } + pub fn into_inner(mut self) -> String { + std::mem::take(&mut self.0) + } + } + + impl Drop for ApiKeyPlaintext { + fn drop(&mut self) { self.0.zeroize(); } + } + + #[derive(Clone, Debug)] + pub struct ApiKeyRecord { + pub id: uuid::Uuid, + pub key_hash: String, // hex-encoded blake3(plaintext) + pub label: String, + pub scopes: Vec, + pub domain_filter: Vec, + pub created_at: chrono::DateTime, + pub last_used: Option>, + pub active: bool, + } + + pub fn generate_key() -> ApiKeyPlaintext { + let mut bytes = [0u8; KEY_RANDOM_BYTES]; + OsRng.try_fill_bytes(&mut bytes).expect("OsRng"); + let encoded = URL_SAFE_NO_PAD.encode(&bytes); + bytes.zeroize(); + ApiKeyPlaintext(format!("{}{}", KEY_PREFIX, encoded)) + } + + pub fn hash_key(plaintext: &str) -> String { + let mut hasher = Hasher::new(); + hasher.update(plaintext.as_bytes()); + hasher.finalize().to_hex().to_string() + } + + pub fn verify_key(plaintext: &str, stored_hash_hex: &str) -> bool { + use subtle::ConstantTimeEq; + let computed = hash_key(plaintext); + computed.as_bytes().ct_eq(stored_hash_hex.as_bytes()).unwrap_u8() == 1 + } + +Helpers on a thin repository trait that both backends implement through +`MemoryStore` (Phase 2 already adds the required columns; Phase 3 wires the +methods): + + #[async_trait::async_trait] + pub trait ApiKeyStore: Send + Sync + 'static { + async fn create_api_key(&self, rec: &ApiKeyRecord) -> anyhow::Result<()>; + async fn find_api_key_by_hash(&self, hash: &str) -> anyhow::Result>; + async fn list_api_keys(&self) -> anyhow::Result>; + async fn revoke_api_key(&self, id: uuid::Uuid) -> anyhow::Result; + async fn touch_api_key_last_used(&self, id: uuid::Uuid) -> anyhow::Result<()>; + } + +(If Phase 2 already bolted these onto `MemoryStore`, `ApiKeyStore` is simply a +re-export of the relevant subset.) + +### D3. Session cookie + +File: `crates/vestige-mcp/src/auth/session.rs` + +- Cookie name: `vestige_session`. +- Cookie attributes: `HttpOnly`, `SameSite=Strict`, `Path=/`, `Max-Age=28800` + (8h), `Secure` when the server is running behind TLS (detected from + `config.server.tls_cert.is_some()` or the `X-Forwarded-Proto` trusted header; + default: set `Secure` whenever `config.server.bind` is non-loopback). +- Payload: serialized `SessionClaims { key_id: Uuid, issued_at: i64, + expires_at: i64 }` encoded as `serde_json` then base64url. The signing is + handled by `axum-extra::extract::cookie::SignedCookieJar` (HMAC via a 64-byte + `Key`). Any tampering or truncation is rejected by the jar automatically. +- Key material: 64 random bytes, stored at `/session_secret` (mode + 0600) or overridden by `VESTIGE_SESSION_SECRET` (base64url-encoded 64 bytes, + reject if shorter). + +Signatures: + + use axum_extra::extract::cookie::{Cookie, Key, SameSite, SignedCookieJar}; + use chrono::{Duration, Utc}; + use serde::{Deserialize, Serialize}; + + const COOKIE_NAME: &str = "vestige_session"; + const DEFAULT_TTL: Duration = Duration::hours(8); + + #[derive(Clone, Serialize, Deserialize)] + pub struct SessionClaims { + pub key_id: uuid::Uuid, + pub iat: i64, + pub exp: i64, + } + + pub fn session_key(data_dir: &std::path::Path) -> anyhow::Result { + // 1) env override + if let Ok(env_val) = std::env::var("VESTIGE_SESSION_SECRET") { + let raw = base64::engine::general_purpose::URL_SAFE_NO_PAD + .decode(env_val.trim())?; + anyhow::ensure!(raw.len() >= 64, "VESTIGE_SESSION_SECRET must be >= 64 bytes"); + return Ok(Key::from(&raw)); + } + // 2) persisted file + let path = data_dir.join("session_secret"); + if path.exists() { + let bytes = std::fs::read(&path)?; + return Ok(Key::from(&bytes)); + } + // 3) generate + use rand::TryRngCore; + let mut bytes = [0u8; 64]; + rand::rngs::OsRng.try_fill_bytes(&mut bytes)?; + #[cfg(unix)] + { + use std::io::Write; + use std::os::unix::fs::OpenOptionsExt; + std::fs::create_dir_all(data_dir).ok(); + let mut f = std::fs::OpenOptions::new() + .create_new(true).write(true).mode(0o600).open(&path)?; + f.write_all(&bytes)?; + f.sync_all()?; + } + #[cfg(not(unix))] + std::fs::write(&path, &bytes)?; + Ok(Key::from(&bytes)) + } + + pub fn issue_session( + jar: SignedCookieJar, + key_id: uuid::Uuid, + secure: bool, + ) -> SignedCookieJar { + let now = Utc::now(); + let claims = SessionClaims { + key_id, + iat: now.timestamp(), + exp: (now + DEFAULT_TTL).timestamp(), + }; + let value = serde_json::to_string(&claims).expect("serialize claims"); + let mut cookie = Cookie::new(COOKIE_NAME, value); + cookie.set_http_only(true); + cookie.set_same_site(SameSite::Strict); + cookie.set_path("/"); + cookie.set_max_age(cookie::time::Duration::seconds(DEFAULT_TTL.num_seconds())); + cookie.set_secure(secure); + jar.add(cookie) + } + + pub fn revoke_session(jar: SignedCookieJar) -> SignedCookieJar { + jar.remove(Cookie::from(COOKIE_NAME)) + } + + pub fn claims_from(jar: &SignedCookieJar) -> Option { + let c = jar.get(COOKIE_NAME)?; + let claims: SessionClaims = serde_json::from_str(c.value()).ok()?; + if claims.exp < Utc::now().timestamp() { return None; } + Some(claims) + } + +### D4. Auth middleware + +File: `crates/vestige-mcp/src/auth/middleware.rs` + +Identity carried through the request: + + #[derive(Clone, Debug)] + pub struct Identity { + pub key_id: uuid::Uuid, + pub label: String, + pub scopes: Vec, + pub domain_filter: Vec, + pub via: AuthVia, + } + + #[derive(Clone, Copy, Debug)] + pub enum AuthVia { + Bearer, + ApiKeyHeader, + SessionCookie, + } + +Middleware (axum 0.8): + + use axum::extract::{Request, State}; + use axum::http::{header, StatusCode}; + use axum::middleware::Next; + use axum::response::{IntoResponse, Response}; + use axum_extra::extract::cookie::SignedCookieJar; + use std::sync::Arc; + + pub async fn auth_layer( + State(state): State>, + jar: SignedCookieJar, + mut request: Request, + next: Next, + ) -> Response { + // Allowlist endpoints that never require auth: + let path = request.uri().path(); + if path == "/api/health" || path == "/api/v1/health" || + path == "/dashboard/login" { + return next.run(request).await; + } + + let via_and_key = extract_credentials(request.headers(), &jar); + let outcome = match via_and_key { + Some((AuthVia::Bearer, key)) | Some((AuthVia::ApiKeyHeader, key)) => { + resolve_by_plaintext(&state, &key).await.map(|id| (id, via_and_key.unwrap().0)) + } + Some((AuthVia::SessionCookie, key_id_str)) => { + let id = uuid::Uuid::parse_str(&key_id_str).map_err(|_| AuthError::InvalidCredentials)?; + resolve_by_key_id(&state, id).await.map(|id| (id, AuthVia::SessionCookie)) + } + None => Err(AuthError::MissingCredentials), + }; + + let identity = match outcome { + Ok((id, via)) => Identity { via, ..id }, + Err(e) => return e.into_response(), + }; + + // touch last_used asynchronously; do not block request path + let st2 = state.clone(); + let kid = identity.key_id; + tokio::spawn(async move { let _ = st2.store.touch_api_key_last_used(kid).await; }); + + request.extensions_mut().insert(identity); + next.run(request).await + } + +Credential extraction (priority: Bearer > X-API-Key > cookie): + + fn extract_credentials( + headers: &axum::http::HeaderMap, + jar: &SignedCookieJar, + ) -> Option<(AuthVia, String)> { + if let Some(v) = headers.get(header::AUTHORIZATION).and_then(|h| h.to_str().ok()) { + if let Some(rest) = v.strip_prefix("Bearer ") { + return Some((AuthVia::Bearer, rest.trim().to_string())); + } + } + if let Some(v) = headers.get("x-api-key").and_then(|h| h.to_str().ok()) { + return Some((AuthVia::ApiKeyHeader, v.trim().to_string())); + } + if let Some(claims) = crate::auth::session::claims_from(jar) { + return Some((AuthVia::SessionCookie, claims.key_id.to_string())); + } + None + } + +Resolution helpers: + + async fn resolve_by_plaintext(st: &AppCtx, key: &str) -> Result { + let hash = crate::auth::keys::hash_key(key); + let rec = st.store.find_api_key_by_hash(&hash).await + .map_err(|_| AuthError::Internal)? + .ok_or(AuthError::InvalidCredentials)?; + if !rec.active { return Err(AuthError::Revoked); } + Ok(Identity { + key_id: rec.id, label: rec.label, scopes: rec.scopes, + domain_filter: rec.domain_filter, via: AuthVia::Bearer, + }) + } + + async fn resolve_by_key_id(st: &AppCtx, id: uuid::Uuid) -> Result { + let rec = st.store.find_api_key_by_id(id).await + .map_err(|_| AuthError::Internal)? + .ok_or(AuthError::InvalidCredentials)?; + if !rec.active { return Err(AuthError::Revoked); } + Ok(Identity { + key_id: rec.id, label: rec.label, scopes: rec.scopes, + domain_filter: rec.domain_filter, via: AuthVia::SessionCookie, + }) + } + +Scope guard extractor (per-handler opt-in): + + pub struct RequireScope; + impl axum::extract::FromRequestParts for RequireScope + where S: Send + Sync, + { + type Rejection = AuthError; + async fn from_request_parts( + parts: &mut axum::http::request::Parts, _state: &S, + ) -> Result { + let id = parts.extensions.get::().ok_or(AuthError::MissingCredentials)?; + let need = if WRITE { Scope::Write } else { Scope::Read }; + if !id.scopes.contains(&need) { + return Err(AuthError::InsufficientScope { + required: if WRITE { "write" } else { "read" }, + }); + } + Ok(RequireScope) + } + } + +Domain scoping: + + /// Returns the effective domain filter for the request: + /// - Intersect the key's domain_filter with any X-Vestige-Domain header. + /// - Empty key filter means "all domains", so the header is authoritative. + /// - A header that names a domain outside the key filter returns + /// `Err(DomainNotAllowed)`. + pub fn effective_domain_filter( + id: &Identity, header: Option<&str>, + ) -> Result>, AuthError> { + let header_dom = header.map(|s| s.trim().to_string()).filter(|s| !s.is_empty()); + match (id.domain_filter.as_slice(), header_dom) { + ([], None) => Ok(None), + ([], Some(h)) => Ok(Some(vec![h])), + (filter, None) => Ok(Some(filter.to_vec())), + (filter, Some(h)) => { + if filter.iter().any(|d| d == &h) { + Ok(Some(vec![h])) + } else { + Err(AuthError::DomainNotAllowed { domain: h }) + } + } + } + } + +### D5. Layer ordering + +Router assembly in `http/mod.rs::build_router`: + + let trace = tower_http::trace::TraceLayer::new_for_http(); + let request_id = tower_http::request_id::SetRequestIdLayer::x_request_id( + tower_http::request_id::MakeRequestUuid); + let propagate_id = tower_http::request_id::PropagateRequestIdLayer::x_request_id(); + + let cors = CorsLayer::new() + .allow_origin(cfg.server.allowed_origins()) + .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE, Method::OPTIONS]) + .allow_headers([header::CONTENT_TYPE, header::AUTHORIZATION, + HeaderName::from_static("x-api-key"), + HeaderName::from_static("x-vestige-domain"), + HeaderName::from_static("mcp-session-id")]) + .allow_credentials(true); + + let app = Router::new() + // Unauth routes first (not subjected to auth_layer by path allowlist) + .route("/api/health", get(health)) + .route("/dashboard/login", post(login)) + .route("/dashboard/logout", post(logout)) + // MCP + REST + dashboard + .route("/mcp", post(http::mcp::post_mcp).get(http::mcp_sse::get_mcp_sse) + .delete(http::mcp::delete_mcp)) + .nest("/api/v1", http::rest::router()) + .merge(dashboard::router()) + // Auth middleware applied via from_fn_with_state (allowlist inside) + .layer(axum::middleware::from_fn_with_state(ctx.clone(), auth_layer)) + // Outermost: tracing, request-id, cors, body limit, concurrency + .layer( + ServiceBuilder::new() + .layer(trace) + .layer(request_id) + .layer(propagate_id) + .layer(cors) + .layer(DefaultBodyLimit::max(MAX_BODY_SIZE)) + .layer(ConcurrencyLimitLayer::new(CONCURRENCY_LIMIT)) + ) + .with_state(ctx); + +Axum applies `layer()` calls outermost-first in the order they are declared. +The result here: request -> trace -> request-id -> CORS -> body-limit -> +concurrency -> auth -> handler. Auth must wrap the handlers but be inside +tracing so its spans can log auth outcomes. + +### D6. MCP endpoints + +File: `crates/vestige-mcp/src/http/mcp.rs` + +`POST /mcp` -- keep the session-based structure already in `protocol/http.rs` +but use the `Identity` injected by the auth layer instead of a shared +`auth_token`: + + pub async fn post_mcp( + State(ctx): State>, + Extension(id): Extension, + headers: HeaderMap, + Json(request): Json, + ) -> Response { ... } + +Auth happens in the layer, so this handler cannot be reached without a valid +`Identity`. Scope check: all MCP writes (tools that mutate) require +`RequireScope`. Use an enum of MCP methods or a method -> required-scope +map. `tools/list`, `resources/list`, `initialize`, `ping` are read-only. +`tools/call` is conservatively classified as write; the per-tool dispatch +inside `McpServer::handle_tools_call` may further reject writes when the tool +name is read-only and the key lacks write. + +`DELETE /mcp` -- unchanged semantics, drops the session. + +`GET /mcp` -- SSE. Implementation in `http/mcp_sse.rs`: + + use axum::response::sse::{Event, KeepAlive, Sse}; + use axum::extract::Query; + use futures_util::stream::Stream; + use async_stream::stream; + use std::time::Duration; + + #[derive(serde::Deserialize)] + pub struct SseParams { + pub op: String, // "dream" | "consolidate" | "discover" | "reassign" + pub session: Option, // optional operation correlation id + } + + pub async fn get_mcp_sse( + State(ctx): State>, + Extension(_id): Extension, + Query(params): Query, + ) -> Result>>, AuthError> { + let op = params.op.clone(); + let ctx2 = ctx.clone(); + let s = stream! { + yield Ok(Event::default().event("start").data(format!("{{\"op\":\"{}\"}}", op))); + match op.as_str() { + "dream" => { + let mut rx = ctx2.cognitive.lock().await.begin_dream_stream().await; + while let Some(ev) = rx.recv().await { + yield Ok(Event::default().event("progress").json_data(ev)?); + } + yield Ok(Event::default().event("done").data("{}")); + } + "consolidate" => { /* same pattern over Storage::run_consolidation_stream */ } + "discover" => { /* Phase 4 */ } + "reassign" => { /* Phase 4 */ } + other => { + yield Ok(Event::default().event("error") + .data(format!("{{\"message\":\"unknown op {}\"}}", other))); + } + } + }; + Ok(Sse::new(s).keep_alive(KeepAlive::new().interval(Duration::from_secs(15)))) + } + +SSE event shape (stable contract, document in `docs/http-api.md`): + + event: start + data: {"op":"dream"} + + event: progress + data: {"stage":"replay","processed":12,"total":50} + + event: progress + data: {"stage":"cross_reference","processed":25,"total":50} + + event: done + data: {"nodes_processed":50,"duration_ms":14320} + +The `keep-alive` hint is 15s to survive most proxy timeouts. + +### D7. REST API + +File: `crates/vestige-mcp/src/http/rest.rs` + +Routes: + + pub fn router() -> Router> { + Router::new() + .route("/health", get(health)) + .route("/memories", post(create_memory).get(list_memories)) + .route("/memories/{id}", get(get_memory).put(update_memory).delete(delete_memory)) + .route("/memories/{id}/promote", post(promote_memory)) + .route("/memories/{id}/demote", post(demote_memory)) + .route("/search", post(search_memories)) + .route("/consolidate", post(trigger_consolidation)) + .route("/stats", get(get_stats)) + .route("/domains", get(list_domains)) + .route("/domains/discover", post(trigger_discovery)) + .route("/domains/{id}", put(rename_domain).delete(delete_domain)) + .route("/domains/{id}/merge", post(merge_domain)) + .route("/keys", post(create_key).get(list_keys)) + .route("/keys/{id}", delete(revoke_key)) + } + +Representative signatures: + + #[derive(serde::Deserialize)] + pub struct CreateMemoryReq { + pub content: String, + pub node_type: Option, + pub tags: Option>, + pub source: Option, + pub metadata: Option, + } + + #[derive(serde::Serialize)] + pub struct MemoryView { /* flat projection of MemoryRecord */ } + + pub async fn create_memory( + State(ctx): State>, + Extension(id): Extension, + _: RequireScope, + Json(req): Json, + ) -> Result<(StatusCode, Json), ApiError> { + let effective = effective_domain_filter(&id, None)?; + let rec = ctx.store.insert_from_rest(req, effective).await?; + Ok((StatusCode::CREATED, Json(MemoryView::from(rec)))) + } + + pub async fn search_memories( + State(ctx): State>, + Extension(id): Extension, + _: RequireScope, + headers: HeaderMap, + Json(req): Json, + ) -> Result, ApiError> { + let dom_header = headers.get("x-vestige-domain").and_then(|h| h.to_str().ok()); + let effective = effective_domain_filter(&id, dom_header)?; + let q = SearchQuery { domains: effective, ..req.into() }; + let res = ctx.store.search(&q).await?; + Ok(Json(SearchResp::from(res))) + } + +`trigger_consolidation` returns 202 Accepted + a JSON body with a `session_id` +the client may pass to `GET /mcp?op=consolidate&session=...` to stream +progress. + +### D8. Error mapping + +File: `crates/vestige-mcp/src/http/errors.rs` + + #[derive(Debug, thiserror::Error)] + pub enum ApiError { + #[error(transparent)] Auth(#[from] AuthError), + #[error("bad request: {0}")] BadRequest(String), + #[error("not found")] NotFound, + #[error("conflict: {0}")] Conflict(String), + #[error(transparent)] Store(#[from] anyhow::Error), + } + + impl IntoResponse for ApiError { + fn into_response(self) -> Response { + match self { + ApiError::Auth(a) => a.into_response(), + ApiError::BadRequest(m) => (StatusCode::BAD_REQUEST, problem(400, "bad_request", &m)).into_response(), + ApiError::NotFound => (StatusCode::NOT_FOUND, problem(404, "not_found", "")).into_response(), + ApiError::Conflict(m) => (StatusCode::CONFLICT, problem(409, "conflict", &m)).into_response(), + ApiError::Store(e) => { + tracing::error!(err = %e, "store error"); + (StatusCode::INTERNAL_SERVER_ERROR, problem(500, "internal", "internal error")).into_response() + } + } + } + } + +All MCP JSON-RPC error mapping is unchanged (done in `McpServer`); only +transport-level errors (401/403) leave that path. + +### D9. Config loader and bind-safety check + +File: `crates/vestige-mcp/src/config.rs` + + #[derive(Debug, Clone, serde::Deserialize)] + pub struct ServerConfig { + #[serde(default = "default_bind")] + pub bind: String, // "127.0.0.1:3928" + #[serde(default = "default_dashboard_port")] + pub dashboard_port: u16, + #[serde(default)] pub tls_cert: Option, + #[serde(default)] pub tls_key: Option, + #[serde(default)] pub allowed_origins: Vec, + } + + #[derive(Debug, Clone, serde::Deserialize)] + pub struct AuthConfig { + #[serde(default = "default_true")] + pub enabled: bool, + #[serde(default)] pub session_secret_file: Option, + } + + impl ServerConfig { + pub fn parsed_bind(&self) -> anyhow::Result { + self.bind.parse().map_err(|e: std::net::AddrParseError| + anyhow::anyhow!("invalid bind {}: {}", self.bind, e)) + } + } + +Bind-safety check (called during `start_server`): + + pub fn enforce_bind_safety(server: &ServerConfig, auth: &AuthConfig) -> anyhow::Result<()> { + let addr = server.parsed_bind()?; + let is_loopback = match addr.ip() { + std::net::IpAddr::V4(v) => v.is_loopback(), + std::net::IpAddr::V6(v) => v.is_loopback(), + }; + if !is_loopback && !auth.enabled { + anyhow::bail!( + "refusing to bind {} with auth disabled; \ + set [auth] enabled = true in vestige.toml or \ + change [server] bind to a loopback address", + addr + ); + } + Ok(()) + } + +`main.rs` and the `serve` CLI both call `enforce_bind_safety` before +`TcpListener::bind`. On failure: `eprintln!` the error, `std::process::exit(2)`. + +Env bridge: + +- `VESTIGE_HTTP_BIND` (existing) -> `server.bind` host part. +- `VESTIGE_HTTP_PORT` (existing) -> `server.bind` port part. +- `VESTIGE_DASHBOARD_PORT` (existing) -> `server.dashboard_port`. +- `VESTIGE_AUTH_TOKEN` (deprecated) -- when set, synthesize a virtual + `ApiKeyRecord` with `id = all-zero UUID`, `scopes = [read, write]`, + `domain_filter = []`, `active = true`, hash stored in memory only. Log a + warning on every startup: `VESTIGE_AUTH_TOKEN is deprecated; use 'vestige + keys create' and set auth.enabled=true instead. Will be removed in v2.2.0.` +- `VESTIGE_SESSION_SECRET` -- see D3. + +### D10. Dashboard login + logout + +File: `crates/vestige-mcp/src/dashboard/handlers.rs` (additions). + + #[derive(serde::Deserialize)] + pub struct LoginBody { + pub api_key: String, + } + + pub async fn login( + State(state): State, + jar: SignedCookieJar, + headers: HeaderMap, + body: Option>, + ) -> Result<(SignedCookieJar, Json), AuthError> { + // Accept key in either JSON body or X-API-Key header + let plaintext = body.map(|b| b.0.api_key) + .or_else(|| headers.get("x-api-key").and_then(|h| h.to_str().ok()).map(String::from)) + .ok_or(AuthError::MissingCredentials)?; + + let hash = crate::auth::keys::hash_key(&plaintext); + let rec = state.store.find_api_key_by_hash(&hash).await + .map_err(|_| AuthError::Internal)? + .ok_or(AuthError::InvalidCredentials)?; + if !rec.active { return Err(AuthError::Revoked); } + + let secure = state.config.server.tls_cert.is_some(); + let jar = crate::auth::session::issue_session(jar, rec.id, secure); + + Ok((jar, Json(serde_json::json!({ + "ok": true, "key_id": rec.id, "label": rec.label, + "scopes": rec.scopes.iter().map(|s| s.as_str()).collect::>(), + "domains": rec.domain_filter, + })))) + } + + pub async fn logout(jar: SignedCookieJar) + -> (SignedCookieJar, Json) + { + (crate::auth::session::revoke_session(jar), + Json(serde_json::json!({"ok": true}))) + } + +Dashboard router integration: login/logout are appended before `auth_layer` +is applied, so they are reachable unauthenticated. The dashboard SPA asset +routes (`/dashboard`, `/dashboard/{*path}`) remain publicly readable so the +login page can load; the `/api/*` dashboard endpoints are gated by +`auth_layer`. (The existing health endpoint keeps its current behaviour.) + +### D11. `vestige keys` CLI + +File: `crates/vestige-mcp/src/bin/cli.rs` additions. + + #[derive(Subcommand)] + enum Commands { + // ... existing + /// Manage API keys + Keys { + #[command(subcommand)] + sub: KeyCmd, + }, + } + + #[derive(Subcommand)] + enum KeyCmd { + /// Create a new API key + Create { + #[arg(long)] label: String, + #[arg(long, value_delimiter = ',', default_values_t = ["read".to_string(), "write".to_string()])] + scopes: Vec, + /// Restrict the key to listed domains (comma-separated). Empty = all domains. + #[arg(long, value_delimiter = ',')] + domains: Vec, + }, + /// List existing keys (never shows plaintext) + List { + /// Include revoked keys in the output + #[arg(long)] all: bool, + }, + /// Revoke a key by id or by hash prefix + Revoke { + /// Id (UUID) or hash prefix (first 12 hex chars) + id_or_prefix: String, + }, + /// Revoke and re-create with the same scopes/label + Rotate { + id_or_prefix: String, + }, + } + +`Create` outputs the plaintext exactly once on stdout (for piping into env +files) and a confirmation on stderr. Use colored output only on stderr to keep +stdout machine-readable. + + fn run_keys_create(...) -> anyhow::Result<()> { + let store = open_store()?; // Arc + let plaintext = crate::auth::keys::generate_key(); + let hash = crate::auth::keys::hash_key(plaintext.as_str()); + let rec = ApiKeyRecord { + id: uuid::Uuid::new_v4(), + key_hash: hash, label, scopes, domain_filter: domains, + created_at: chrono::Utc::now(), + last_used: None, active: true, + }; + block_on(store.create_api_key(&rec))?; + + // stderr: human-readable + eprintln!("{} {}", "Created key:".green().bold(), rec.label); + eprintln!(" id: {}", rec.id); + eprintln!(" scopes: {}", rec.scopes.iter().map(|s| s.as_str()).collect::>().join(",")); + eprintln!(" domains: {}", if rec.domain_filter.is_empty() { "all".to_string() } else { rec.domain_filter.join(",") }); + eprintln!(); + eprintln!("{}", "Store the plaintext key now. It will not be shown again.".yellow()); + // stdout: ONLY the plaintext, for scripting + println!("{}", plaintext.as_str()); + Ok(()) + } + +`List`: + + kid label scopes domains last_used hash + d3a8... macbook read,write all 2026-04-20 11:02 a1b2c3d4e5f6 + ... + +Never print the plaintext. Show only `hash[..12]`. + +### D12. Migrations + +Postgres `0300_api_keys.sql` (idempotent; Phase 2 may have already created the +table, in which case this migration is a no-op `CREATE TABLE IF NOT EXISTS`): + + CREATE TABLE IF NOT EXISTS api_keys ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + key_hash TEXT NOT NULL UNIQUE, + label TEXT NOT NULL, + scopes TEXT[] NOT NULL DEFAULT ARRAY['read','write'], + domain_filter TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + last_used TIMESTAMPTZ, + active BOOLEAN NOT NULL DEFAULT true + ); + + CREATE INDEX IF NOT EXISTS idx_api_keys_active + ON api_keys (active) WHERE active; + +SQLite `0300_api_keys.sql`: + + CREATE TABLE IF NOT EXISTS api_keys ( + id TEXT PRIMARY KEY, + key_hash TEXT NOT NULL UNIQUE, + label TEXT NOT NULL, + scopes TEXT NOT NULL DEFAULT 'read,write', -- comma-joined + domain_filter TEXT NOT NULL DEFAULT '', -- comma-joined, '' = all + created_at TEXT NOT NULL DEFAULT (datetime('now')), + last_used TEXT, + active INTEGER NOT NULL DEFAULT 1 + ); + + CREATE INDEX IF NOT EXISTS idx_api_keys_active + ON api_keys (active) WHERE active = 1; + +Both backends' trait impls convert to/from `ApiKeyRecord`. + +### D13. Wiring main.rs and the `serve` CLI path + +`main.rs` refactor: + +1. `Config::load()` reads `vestige.toml` (if present) and overlays env vars. +2. Run `enforce_bind_safety(&cfg.server, &cfg.auth)` before spawning any + listener. On failure, print to stderr and exit 2. +3. Build `AppCtx` with `Arc`, `CognitiveEngine`, + event bus, `session_key`, `config`. +4. `build_router(ctx)` returns a single Axum `Router` that covers MCP, REST, + and dashboard. +5. `axum::serve(listener, app).await`. +6. The stdio MCP transport continues to run in parallel (unchanged) for + desktop / Claude Code single-user scenarios. + +`serve` CLI subcommand: identical flow minus stdio. + +### D14. Docs + +- `docs/env-vars.md` new: table of every supported env var, default, purpose, + deprecation status. +- Section in `README.md`: "Running Vestige as a network server". +- Cheat-sheet section in `CLAUDE.md` for: create a key, start the server, + curl smoke test. + +## Test Plan + +### Unit tests (colocated under `#[cfg(test)]`) + +- `auth/keys.rs`: + - `generate_key_has_prefix_and_length()` -- asserts `vst_` prefix and 34-ish + char total, regex `^vst_[A-Za-z0-9_-]{29}$`. + - `hash_key_blake3_is_stable_and_hex()` -- fixed vector test. + - `verify_key_accepts_same_input()` / `verify_key_rejects_tampered()` / + `verify_key_rejects_length_mismatch()`. + - `keys_are_unique_in_a_loop()` -- 10_000 iterations, no collisions. + - `plaintext_zeroed_on_drop()` -- unsafe peek into the backing buffer + through a wrapper that exposes bytes for the test only. + +- `auth/session.rs`: + - `round_trip_claims_through_signed_jar()`. + - `expired_cookie_is_rejected()` -- mint a cookie with `exp = iat - 60` and + confirm `claims_from` returns `None`. + - `tampered_cookie_is_rejected()` -- flip one byte in the signed segment, + confirm the jar drops it. + - `session_key_env_overrides_file()`. + - `session_key_generated_file_has_mode_0600_on_unix()`. + +- `auth/middleware.rs`: + - `extract_credentials_prefers_bearer_over_api_key_header()`. + - `extract_credentials_falls_back_to_cookie()`. + - `effective_domain_filter_empty_means_all()`. + - `effective_domain_filter_header_narrows_within_key_filter()`. + - `effective_domain_filter_rejects_header_outside_key_filter()`. + - `missing_credentials_returns_401()`. + - `revoked_key_returns_401()`. + - `insufficient_scope_returns_403()`. + +- `config.rs`: + - `parse_vestige_toml_with_server_and_auth_sections()`. + - `env_vars_override_toml_bind()`. + - `enforce_bind_safety_rejects_0_0_0_0_with_auth_disabled()`. + - `enforce_bind_safety_allows_0_0_0_0_with_auth_enabled()`. + - `enforce_bind_safety_allows_loopback_with_auth_disabled()`. + +- `http/errors.rs`: + - `not_found_emits_problem_json_with_correct_content_type()`. + - `bad_request_includes_detail_field()`. + +- `http/mcp.rs`: + - `post_mcp_unauth_returns_401()` (this would normally be caught by the + middleware; kept as a unit test by constructing the Router minus the + middleware to exercise the handler's own error paths). + +### Integration tests (`tests/phase_3/`) + +All tests spin up the full Axum stack in-process on a random port via +`tokio::net::TcpListener::bind("127.0.0.1:0")`, wire a `SqliteMemoryStore` in +a `TempDir`, and issue HTTP calls with `reqwest`. + +Files (each one a standalone binary test file): + +- `phase_3/common/mod.rs` -- shared harness (`spawn_server()`, + `create_test_key()`, `client()`). + +- `phase_3/http_mcp_round_trip.rs` -- boot server, mint a key, send + `initialize` over `POST /mcp` with `Authorization: Bearer vst_...`, follow + with `tools/list`, assert we see the expected tool count (greater than 20). + +- `phase_3/http_sse_stream.rs` -- `POST /api/v1/consolidate` returns 202 + + `session_id`. `GET /mcp?op=consolidate&session=...` streams at least one + `progress` and one `done` event. Use `eventsource-client` dev dep, or parse + the stream manually. + +- `phase_3/rest_api_crud.rs` -- exercises each REST endpoint in turn: + - `POST /api/v1/memories` -> 201 + body. + - `GET /api/v1/memories/{id}` -> 200. + - `PUT /api/v1/memories/{id}` -> 200. + - `POST /api/v1/search` -> 200 with the new memory in results. + - `POST /api/v1/memories/{id}/promote` -> 200. + - `GET /api/v1/stats` -> 200. + - `GET /api/v1/domains` -> 200 (likely empty). + - `DELETE /api/v1/memories/{id}` -> 204. + +- `phase_3/auth_bearer_token.rs`: + - unauth: `GET /api/v1/stats` returns 401 and `Content-Type: + application/problem+json`. + - valid Bearer: same call returns 200. + - revoked key: `POST /api/v1/keys/{id}` DELETE then reuse -> 401. + - tampered Bearer (last char flipped) -> 401. + +- `phase_3/auth_api_key_header.rs`: + - `X-API-Key: vst_...` alone -> 200. + - Both Bearer and X-API-Key with different values -> Bearer wins (asserted + via a key that is read-only in Bearer + full-scope X-API-Key, then + confirming a write 403s). + +- `phase_3/auth_session_cookie.rs`: + - `POST /dashboard/login` with valid key -> 200 + `Set-Cookie: + vestige_session=...; HttpOnly; SameSite=Strict; Path=/`. + - reuse cookie: `GET /api/v1/stats` returns 200. + - tampered cookie (change one char): -> 401. + - `POST /dashboard/logout` -> `Set-Cookie: vestige_session=; Max-Age=0`. + +- `phase_3/auth_domain_filter.rs`: + - Key with `domain_filter = ["dev"]`: + - `POST /api/v1/search` without header -> search is scoped to `["dev"]` + (insert fixtures with two domains, assert only `dev` rows returned). + - `X-Vestige-Domain: dev` -> same. + - `X-Vestige-Domain: home` -> 403 with detail `domain not permitted`. + - Key with empty filter + `X-Vestige-Domain: dev` -> scoped to `["dev"]`. + - Key with empty filter + no header -> no scoping. + +- `phase_3/auth_scope_enforcement.rs`: + - read-only key cannot call `POST /api/v1/memories` -> 403. + - read-only key CAN call `POST /api/v1/search` -> 200. + +- `phase_3/bind_safety_nonlocalhost_without_auth.rs`: + - Spawn `vestige serve --bind 0.0.0.0:0` as a subprocess with `auth.enabled + = false` via a temp `vestige.toml`. + - Assert: non-zero exit, stderr contains `refusing to bind`, no listener + ever opens (confirm by trying to connect to the configured port and + expecting connection refused after a short timeout). + +- `phase_3/cli_keys_create_list_revoke.rs`: + - Spawn the `vestige` CLI binary with `--data-dir `. + - Run `vestige keys create --label test --scopes read,write`; capture + stdout (the plaintext) and stderr (the human summary). Assert `vst_` + prefix in stdout. + - Run `vestige keys list`; assert no plaintext, label `test` present. + - Run `vestige keys revoke `; confirm exit 0. + - Run `vestige keys list`; assert label no longer visible without `--all`. + +- `phase_3/dashboard_login_flow.rs`: + - Full loop: login -> fetch `/dashboard` (gets SPA index, unauthed ok) -> + fetch `/api/memories` (authed via cookie) -> logout -> fetch `/api/memories` + (401). + +- `phase_3/deprecation_auth_token.rs`: + - Start the server with `VESTIGE_AUTH_TOKEN=test12345...` and no created + keys. Send a Bearer request with that token -> 200. Assert stderr log + contains `deprecated`. + +### Smoke test (`tests/phase_3/smoke/`) + +- `remote_mcp_client.sh`: + + #!/usr/bin/env bash + set -euo pipefail + KEY="${VESTIGE_TEST_KEY:?set me}" + HOST="${VESTIGE_HOST:-http://127.0.0.1:3928}" + # Initialize a session + RESP=$(curl -sS -D /tmp/h -H "Authorization: Bearer $KEY" \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","id":1,"method":"initialize", + "params":{"protocolVersion":"2025-11-25", + "clientInfo":{"name":"smoke","version":"0"}, + "capabilities":{}}}' \ + "$HOST/mcp") + SID=$(grep -i 'mcp-session-id:' /tmp/h | awk '{print $2}' | tr -d '\r') + # tools/list + curl -sS -H "Authorization: Bearer $KEY" \ + -H "Mcp-Session-Id: $SID" \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \ + "$HOST/mcp" | jq '.result.tools | length' + echo "smoke ok" + +## Acceptance Criteria + +- [ ] `cargo build -p vestige-mcp` -- zero warnings, all feature combinations + (`--no-default-features`, default, `--features ort-dynamic`). +- [ ] `cargo clippy --workspace --all-targets --all-features -- -D warnings`. +- [ ] `cargo fmt --all --check`. +- [ ] All `tests/phase_3/*.rs` pass, plus phase_1 and phase_2 remain green. +- [ ] Unauth request to `POST /mcp` returns 401 with + `Content-Type: application/problem+json` and a body containing `status`, + `title`, `detail`. +- [ ] Binding `0.0.0.0:` with `[auth].enabled = false` makes the + process exit with code 2 and print `refusing to bind` to stderr. +- [ ] `vestige keys create --label X` prints exactly one line on stdout + matching `^vst_[A-Za-z0-9_-]+$`; `vestige keys list` never prints that + line back. +- [ ] Dashboard login from a browser-like client (tested via the reqwest + `Client::cookie_store(true)` harness) yields a `Set-Cookie` with + `HttpOnly`, `SameSite=Strict`, `Path=/`, and Max-Age present. +- [ ] A second machine can run a curl-based MCP client against the server + (smoke test) and receive successful `tools/list` responses. +- [ ] `VESTIGE_AUTH_TOKEN` still works and emits the deprecation warning. +- [ ] `tests/phase_3/auth_domain_filter.rs` demonstrates that a key scoped to + `dev` cannot read `home`-domain memories via any of the three auth modes + and cannot escape with `X-Vestige-Domain`. + +## Rollback Notes + +- Ship behind an on-by-default Cargo feature `http-server` on + `vestige-mcp`. Disabling it reverts to stdio + existing localhost HTTP + (`protocol/http.rs` in its current form) with zero behaviour change. +- SQL: migration `0300_api_keys.sql` is additive only; rollback is a single + `DROP TABLE api_keys;` in `0300_api_keys.down.sql` for both backends. Keep a + row count safety check in the down migration and log the deletion. +- Session secret file: deleting `/session_secret` invalidates every + outstanding cookie; users simply log in again. Safe to rotate. +- Env var sunset schedule: + - v2.1.x: `VESTIGE_AUTH_TOKEN` emits a warning, still works. + - v2.2.0: `VESTIGE_AUTH_TOKEN` refused with an error pointing at + `vestige keys create`. +- Downgrade procedure: `git revert` the Phase 3 merge, then run the down + migration. No data loss; plaintext keys were only ever in user-side + secret managers. + +## Open Implementation Questions + +1. JSON-RPC library: hand-rolled vs jsonrpsee? + + - Candidate A: keep the hand-rolled types in `protocol/types.rs` plus the + session-aware `post_mcp` handler already in `protocol/http.rs`. + - Candidate B: switch to `jsonrpsee = "0.24"` with the `server` feature + and adapt it to Axum via `jsonrpsee::server::Server`. + + RECOMMENDATION: A. Phase 3 is about auth and transport surfaces, not + library rewrites. The existing types are already correct, tested, and + compatible with Streamable HTTP; the 29 cognitive modules depend on + `McpServer::handle_request`, which does not map 1:1 to jsonrpsee's + `RpcModule` trait. Re-evaluate in a future phase only if we need subscription + notifications beyond SSE. + +2. Streamable HTTP vs plain POST-with-JSON? + + - The MCP spec titled "Streamable HTTP" defines: `POST /mcp` for + request/response, `GET /mcp` for SSE where the client subscribes to + server-initiated messages, and an `Mcp-Session-Id` header for session + correlation. The current implementation already covers POST + session + header + DELETE; Phase 3 adds the GET/SSE half. + + RECOMMENDATION: implement the full Streamable HTTP transport. Long-running + tools (dream, consolidate, discover) benefit from SSE progress events, and + Claude Desktop / Claude Code both speak Streamable HTTP natively. Keeping + POST-only would work for short calls but block the UX we want for + background jobs. + +3. Session cookie crate? + + - Candidate A: `axum-extra::extract::cookie::SignedCookieJar` with a 64-byte + `Key`. + - Candidate B: `tower-sessions = "0.13"` with the `MemoryStore` or + `PostgresStore` session backend. + - Candidate C: stateless JWT via `jsonwebtoken`. + + RECOMMENDATION: A. We do not need server-side session state (the `api_keys` + row is the state; the cookie is merely a signed pointer to it). B adds a + whole storage backend we do not need. C adds signing-algorithm surface area + and revocation becomes awkward ("revoked key" with a long-lived JWT). + `SignedCookieJar` gives us HMAC-signed cookies for free, integrates with + axum extractors, and the payload is tiny. + +4. Key format and length? + + - 22 random bytes base64url-no-pad = 176 bits entropy, encoded ~30 chars, + full key ~34 chars with the `vst_` prefix. Long enough to make + brute-force infeasible, short enough to paste into config files. + - Alternatives: 32 bytes (40 chars, overkill), 16 bytes (128 bits, marginal + for secret material shared over networks). + + RECOMMENDATION: 22 bytes. Prefix `vst_` is already documented in the PRD + and gives grep-ability. + +5. Rate limiting: in scope for Phase 3? + + - Useful: mitigates slow brute force, runaway agents. + - Expensive to design well (per-key, per-IP, per-endpoint). + + RECOMMENDATION: OUT of scope. Track as `docs/adr/0002-rate-limiting.md` + follow-up. Axum + `tower` has `ConcurrencyLimitLayer` (already used); a + follow-up can add `governor` or `tower_governor` behind the auth layer so + identity is available. + +6. CORS policy defaults for dashboard in server mode? + + - Candidate A: allow only origins derived from `server.bind` host + the + dashboard port. + - Candidate B: allow user-listed origins via `server.allowed_origins` + config, with A as fallback. + - Candidate C: open CORS to `*` when TLS is configured. + + RECOMMENDATION: B. Auto-populate `allowed_origins` from the bind address + and dashboard port at start time; if the operator sets the config list, + use that list verbatim. Never `*` (`allow_credentials = true` is + incompatible with `*` anyway). + +7. Dashboard session lifetime? + + - 8 hours for default; configurable via `auth.session_ttl_hours`. + - Rotate on each write? (Rolling sessions.) + + RECOMMENDATION: 8 hours fixed, non-rolling. Revisit if users complain. + +8. Handling `tools/call` scope granularity? + + - Today, `tools/call` is a single MCP method. Read-only tools like + `search`, `deep_reference`, `predict` should be callable with a + read-only key. + + RECOMMENDATION: map tool names to scopes in `McpServer::handle_tools_call`. + Read-only names: `search`, `session_context`, `memory` with action in + `{get, state, get_batch}`, `deep_reference`, `cross_reference`, `predict`, + `explore_connections`, `find_duplicates`, `memory_timeline`, + `memory_changelog`, `memory_health`, `memory_graph`, `importance_score`, + `system_status`. Everything else requires `write`. If a read-only key + calls a write tool, return a JSON-RPC error with code `-32003` + ("server not initialized" is close but wrong; reuse `-32603 internal` with + a descriptive message or add a new `-32004 UnauthorizedTool`). RECOMMEND + adding `-32004`. + +9. How to bridge `MemoryStore` trait with dashboard state (`AppState`)? + + - Today `AppState.storage: Arc` is a concrete type. + - Phase 2 introduces `Arc`. + + RECOMMENDATION: in Phase 3, introduce `AppCtx { store: Arc, + cognitive, config, event_tx }` as the single state type for the unified + router. Keep `AppState` as a thin wrapper (or alias) if the dashboard + handlers need to stay untouched in this phase. Migrate the dashboard + handlers to the trait in a follow-up refactor to contain the blast radius. + +10. Windows support for `session_secret` and `auth_token` file modes? + + - Unix gets `0600` via `OpenOptionsExt`. + - Windows has no direct equivalent; ACLs differ. + + RECOMMENDATION: document the limitation; use default permissions on + Windows. Add a `#[cfg(windows)]` placeholder to set owner-only ACLs via + `windows-acl` in a follow-up, not Phase 3. + +### Critical Files for Implementation + +- /home/delandtj/prppl/vestige/crates/vestige-mcp/src/protocol/http.rs +- /home/delandtj/prppl/vestige/crates/vestige-mcp/src/dashboard/mod.rs +- /home/delandtj/prppl/vestige/crates/vestige-mcp/src/main.rs +- /home/delandtj/prppl/vestige/crates/vestige-mcp/src/bin/cli.rs +- /home/delandtj/prppl/vestige/crates/vestige-mcp/Cargo.toml diff --git a/docs/plans/0004-phase-4-emergent-domain-classification.md b/docs/plans/0004-phase-4-emergent-domain-classification.md new file mode 100644 index 0000000..d9f2355 --- /dev/null +++ b/docs/plans/0004-phase-4-emergent-domain-classification.md @@ -0,0 +1,883 @@ +# Phase 4 Plan: Emergent Domain Classification + +**Status**: Draft +**Depends on**: Phase 1 (domain columns on memories, `Domain` struct + `DomainStore` methods on `MemoryStore`, `Embedder` trait), Phase 2 (Postgres JSONB + TEXT[] support for domain fields, `embedding_model` registry parity), Phase 3 (Axum HTTP server, REST `/api/v1/` scaffolding, API key auth middleware, signed dashboard session cookies) +**Related**: docs/adr/0001-pluggable-storage-and-network-access.md (Phase 4), docs/prd/001-getting-centralized-vestige.md (Emergent Domain Model) + +--- + +## Scope + +### In scope + +- `DomainClassifier` cognitive module under `crates/vestige-core/src/neuroscience/domain_classifier.rs`, alongside existing neuroscience modules (spreading_activation, synaptic_tagging, ...). +- HDBSCAN discovery pipeline using the `hdbscan` crate (v0.10): load all embeddings, cluster, extract centroids, extract top-terms via TF-IDF over cluster members, persist via the trait's `DomainStore` methods. +- Soft-assignment pipeline: for each memory, compute `cosine_similarity(memory.embedding, domain.centroid)` for every domain, store raw scores in `domain_scores` JSONB, threshold into `domains[]` using `assign_threshold` (default 0.65). +- Automatic classification on ingest: run through `CognitiveEngine` / `smart_ingest` so new memories get classified against existing centroids immediately; skip when `domain_count == 0` (Phase 0 accumulation). +- Re-cluster hook in dream consolidation: every Nth four-phase dream cycle (N=5 default) triggers a discovery pass and generates proposals (split / merge / none). Proposals land in a new `domain_proposals` table, surface in the dashboard, and are never auto-applied (conservative drift, ADR Q7). +- Context signals: `SignalSource` trait with `GitRepoSignal` (detects `.git` in CWD or `metadata.cwd`) and `IdeHintSignal` (reads `metadata.editor` / `metadata.ide`). Each returns a `boost_map` of `domain_id -> additive delta` (typical +0.05). Injected as a `signal_boost: Option>` parameter into `DomainClassifier::classify`. +- Cross-domain spreading activation decay: `ActivationNetwork` traversal multiplies the edge's effective weight by `cross_domain_decay` (default 0.5) when `target.domains` and `source.domains` are disjoint. Strict "no overlap" policy, not graded. +- CLI subcommands (in `crates/vestige-mcp/src/bin/cli.rs`, under a new `Domains` command group): `list`, `discover [--min-cluster-size N] [--force]`, `rename `, `merge [--into ]`. Human-readable tables on stdout; JSON via `--json`. +- Dashboard UI additions (`apps/dashboard/src/routes/(app)/domains/`): list page, per-domain detail (memories, centroid top_terms, score histogram, proposal review controls). +- REST endpoints under `/api/v1/domains` (introduced by Phase 3 skeleton, implemented in Phase 4): list, discover, rename, merge, proposal list / accept / reject. +- Config additions: `[domains]` section in `vestige.toml` covering `assign_threshold`, `recluster_interval`, `min_cluster_size`, `cross_domain_decay`, `discovery_threshold`, `merge_threshold`, `signal_boost` (per-signal toggle). + +### Out of scope + +- Phase 5 federation (explicit separate ADR). Domain centroids are installation-local; no sync. +- Learned re-weighting of domain scores (future, only if retrieval-quality metrics show a need). +- Interactive cluster-membership editing in the UI (drag-and-drop reassign) -- future enhancement. +- Multi-user domain namespaces. One domain set per installation; API keys that carry `domain_filter` just restrict access, they do not create namespaces. +- Auto-sweep of `min_cluster_size` / auto-tuned `assign_threshold` (ADR resolution Q6 + Q9: static defaults, user tunes). +- Graded cross-domain decay (`|A intersect B| / max(|A|,|B|)`) -- strict "no overlap" is the Phase 4 rule. + +--- + +## Prerequisites + +Artifacts that Phases 1-3 are expected to have landed: + +- In `vestige-core`: + - `Embedder` trait (`crates/vestige-core/src/embedder/`). + - `MemoryStore` trait (`crates/vestige-core/src/storage/trait.rs` or similar) including `DomainStore` methods: `list_domains`, `get_domain`, `upsert_domain`, `delete_domain`, `classify(&[f32]) -> Vec<(String, f64)>`, plus a bulk accessor such as `all_embeddings()` (already present in sqlite.rs as `get_all_embeddings`) and a `get_all_memories_with_embeddings()` iterator for discovery. The trait must expose a method to batch-update `(domains, domain_scores)` for a memory id. + - `Domain` struct: `{ id: String, label: String, centroid: Vec, top_terms: Vec, memory_count: usize, created_at: DateTime }`. + - Columns on memories in both SQLite and Postgres: `domains TEXT[]` (or JSON array on SQLite) and `domain_scores JSONB` (or TEXT JSON on SQLite). + - The `domains` table in both backends (see PRD schema sketch). +- In `vestige-mcp`: + - Axum `/api/v1/` router prefix with auth middleware. + - CLI skeleton (`bin/cli.rs`) using `clap`; Phase 4 adds a `Domains` subcommand tree. + - REST handlers file structure ready under `crates/vestige-mcp/src/dashboard/handlers.rs` (legacy) and a dedicated REST handler under `/api/v1/`; Phase 4 adds `domains.rs` handler module. + - SvelteKit dashboard (`apps/dashboard/`) with existing `(app)/memories`, `(app)/timeline`, `(app)/stats`, etc. Phase 4 adds `(app)/domains/`. + +New workspace crate additions required (added manually to `Cargo.toml`, since `cargo add` is not run from the plan): + +- `hdbscan = "0.10"` in `crates/vestige-core/Cargo.toml` (feature-gated behind `domain-classification`). +- Optional: a lightweight stop-word constant inline; no external stop-word crate -- the neuroscience modules already do tokenization on whitespace + length>3 (see `dreams.rs::content_similarity`). Reuse that style; no `ndarray` needed because `hdbscan` v0.10 accepts `&[Vec]` directly (verified from PRD snippet). +- No new deps in `vestige-mcp` for Phase 4 -- CLI reuses `clap` / `colored` / `comfy-table` if already present, otherwise a hand-rolled padded print. We pick hand-rolled to avoid adding a table crate; this matches the existing style of `run_stats` in `cli.rs`. + +Test fixtures: + +- A JSON seed corpus checked into `tests/phase_4/fixtures/seed_500.json` containing >= 500 memories drawn from three plausible clusters. A builder function `tests/phase_4/support/fixtures.rs::build_seed_corpus()` deterministically generates or loads this corpus. Each record has `content`, `tags`, `embedding` (768D bge-base-en-v1.5; use a committed vector or a deterministic mock embedder in tests). For deterministic tests we fake embeddings by hashing content -- acceptable as long as the fake preserves cluster separability (prefix-based: "DEV-...", "INFRA-...", "HOME-..." seeds three Gaussian blobs). +- Reuse `Embedder` mock from Phase 1 tests (`MockEmbedder`) for discovery tests that need real cosine similarity. +- A minimal git-repo fixture created in a tempdir (`tempfile::tempdir` + `std::process::Command::new("git").arg("init")`) for context-signal tests. + +--- + +## Deliverables + +1. `DomainClassifier` cognitive module: struct, defaults, `classify`, `classify_with_boost`, `reassign_all`, `discover`. +2. `domain_terms` helper (TF-IDF over cluster members, returning `top_k` terms). +3. `cli domains discover` subcommand. +4. `cli domains list` / `rename` / `merge` subcommands. +5. Auto-classify hook on ingest (wired into the cognitive engine's ingest pipeline before persistence). +6. Re-cluster hook in dream consolidation (`DreamEngine::run` orchestrator gets an optional `DomainReClusterHook`; triggers every Nth dream). +7. Context signal extractor module (`crates/vestige-core/src/neuroscience/context_signals.rs`) with `SignalSource` trait + `GitRepoSignal` + `IdeHintSignal`. +8. Cross-domain spreading activation decay in `ActivationNetwork::activate` (config-driven). +9. `vestige.toml` `[domains]` section + defaults loader. +10. Dashboard UI: SvelteKit routes `(app)/domains/+page.svelte` (list), `(app)/domains/[id]/+page.svelte` (detail), `(app)/domains/proposals/+page.svelte` (review). +11. REST endpoints under `/api/v1/domains` + `/api/v1/domains/proposals`. +12. `domain_proposals` table + migration + `DomainProposal` trait methods on `MemoryStore`. +13. WebSocket event `VestigeEvent::DomainProposalCreated` so the dashboard gets a live notification after a re-cluster fires. + +--- + +## Detailed Task Breakdown + +### 1. `DomainClassifier` cognitive module + +**File**: `crates/vestige-core/src/neuroscience/domain_classifier.rs` +**Export**: in `crates/vestige-core/src/neuroscience/mod.rs`, add `pub mod domain_classifier;` and re-export `pub use domain_classifier::{DomainClassifier, ClassificationResult, DomainProposal, ProposalKind};` +**Deps**: `hdbscan = "0.10"`, `serde`, `serde_json`, `chrono`, `tracing`, existing `crate::storage::Domain`, `crate::storage::MemoryStore` trait. + +Struct and defaults (match PRD exactly): + +```rust +pub struct DomainClassifier { + pub assign_threshold: f64, // default 0.65 + pub discovery_threshold: usize, // default 150 + pub recluster_interval: usize, // default 5 (every 5th dream) + pub min_cluster_size: usize, // default 10 + pub min_samples: usize, // default 5 (HDBSCAN) + pub cross_domain_decay: f64, // default 0.5 + pub merge_threshold: f64, // default 0.90 (centroid cosine) + pub top_terms_k: usize, // default 10 +} + +impl Default for DomainClassifier { ... } +``` + +Result types: + +```rust +#[derive(Debug, Clone)] +pub struct ClassificationResult { + pub scores: HashMap, // raw per-domain similarities + pub domains: Vec, // above assign_threshold +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ProposalKind { + Split { parent: String, children: Vec }, + Merge { targets: Vec, suggested_label: String }, + NewCluster { top_terms: Vec }, +} + +#[derive(Debug, Clone)] +pub struct DomainProposal { + pub id: String, // uuid v4 + pub kind: ProposalKind, + pub rationale: String, + pub confidence: f64, + pub created_at: DateTime, + pub status: ProposalStatus, // Pending | Accepted | Rejected +} +``` + +Key methods (all pure where possible; all pub): + +```rust +impl DomainClassifier { + pub fn classify(&self, embedding: &[f32], domains: &[Domain]) -> ClassificationResult; + + pub fn classify_with_boost( + &self, + embedding: &[f32], + domains: &[Domain], + boost: Option<&HashMap>, + ) -> ClassificationResult; + + pub async fn reassign_all( + &self, + store: &dyn MemoryStore, + domains: &[Domain], + ) -> Result; + + pub async fn discover( + &self, + store: &dyn MemoryStore, + ) -> Result, StorageError>; + + pub async fn propose_changes( + &self, + store: &dyn MemoryStore, + existing: &[Domain], + newly_discovered: &[Domain], + ) -> Result, StorageError>; + + pub async fn apply_proposal( + &self, + store: &dyn MemoryStore, + proposal: &DomainProposal, + ) -> Result<(), StorageError>; +} +``` + +Behavior notes: + +- `classify` returns empty `{ scores: {}, domains: [] }` iff `domains.is_empty()` (accumulation phase). This matches the PRD snippet verbatim. +- `classify_with_boost` adds the boost delta to each score AFTER cosine, before thresholding. It clamps to `[0.0, 1.0]`. Boost keys not present in `domains` are ignored. +- `reassign_all` streams memories in batches of 500 (iterator on the store) to keep memory bounded; for each memory issues a single `UPDATE memories SET domains = ?, domain_scores = ? WHERE id = ?` call. Returns count of memories whose `domains` vector actually changed. +- `discover` loads all `(id, embedding)` pairs via an `all_embeddings()` method on the store (exists under `#[cfg(all(feature = "embeddings", feature = "vector-search"))]` in `sqlite.rs::get_all_embeddings`; Phase 1 should promote this onto the trait -- if not yet promoted, add the method). Then: + 1. Build `Vec>` and index -> id map. + 2. `Hdbscan::default_hyper_params(&embeddings).min_cluster_size(self.min_cluster_size).min_samples(self.min_samples).build()` (exact builder depends on hdbscan 0.10 surface; see Open Question). + 3. `let labels = clusterer.cluster()?;` + 4. `let centers = clusterer.calc_centers(Center::Centroid, &labels)?;` + 5. Group indices by label ignoring -1 (noise). For each cluster compute `top_terms` via `compute_top_terms`. + 6. Preserve stable IDs where possible: match each new cluster centroid to the closest existing domain by cosine; if similarity > 0.85, reuse the existing domain id + label. Otherwise generate a fresh id `cluster_{n}` with a label derived from the first 2 terms. + 7. Upsert all resulting `Domain`s via the store. +- `propose_changes` compares old vs new clusters: + - **Split**: an old domain that best-matches two or more new domains each with >= `min_cluster_size` members. Rationale: "domain `dev` is now 2 clusters of >=10 memories: `systems` and `networking`". + - **Merge**: two old domains whose centroids now satisfy `cosine > merge_threshold` get a merge proposal. + - **NewCluster**: a new cluster that doesn't match any old domain above 0.85 similarity. +- `apply_proposal` runs the split or merge against the store (reassign memberships via `reassign_all`), then marks the proposal `Accepted`. It never runs automatically -- only via the CLI or dashboard. + +Helper: + +```rust +fn compute_top_terms(documents: &[&str], k: usize) -> Vec; +``` + +Uses TF-IDF with IDF computed over the entire passed-in corpus (the `documents` slice), tokenization = whitespace split, lowercase, strip non-alphanumeric, drop tokens shorter than 4 chars and a small built-in stop-word list (`the`, `and`, `for`, `that`, `with`, ...). Matches the tokenizer used in `dreams.rs::content_similarity` and `dreams.rs::extract_patterns` so behavior is predictable. + +Cosine similarity helper: + +```rust +fn cosine_similarity(a: &[f32], b: &[f32]) -> f64; +``` + +Keep the existing crate-level `cosine_similarity` if already present (check `embeddings::` or `search::`); otherwise add a private one. Returns 0.0 on dimension mismatch, panics would be a bug. + +### 2. Top-terms computation helper + +**File**: same module, private section. + +- `fn tokenize(text: &str) -> Vec`: lowercase, split on non-alphanumeric, filter len >= 4, drop stop-words. +- `fn tfidf_top_k(docs: &[&str], k: usize) -> Vec`: + 1. `tf[doc_idx][term] = count / total_terms`. + 2. `df[term] = docs containing term`. + 3. `idf[term] = log((N + 1) / (df[term] + 1)) + 1` (smoothed). + 4. For each term, average `tf` across docs in the cluster; multiply by `idf`; sort desc; return top `k`. + +Cluster top-terms are computed over cluster members only, with IDF over the **whole corpus** (all memory contents), not the cluster, so common words get penalized globally. Recompute global IDF once per `discover` call. + +### 3. CLI subcommand: `vestige domains discover` + +**File**: `crates/vestige-mcp/src/bin/cli.rs` + +Add to `enum Commands`: + +```rust +/// Emergent domain management +Domains { + #[command(subcommand)] + action: DomainAction, +}, +``` + +```rust +#[derive(clap::Subcommand)] +enum DomainAction { + /// List all discovered domains + List { + #[arg(long)] json: bool, + }, + /// Run HDBSCAN discovery on all embeddings and propose domains + Discover { + #[arg(long, default_value_t = 10)] min_cluster_size: usize, + /// Skip the proposal flow and write new domains directly (first-time use) + #[arg(long)] force: bool, + #[arg(long)] json: bool, + }, + /// Rename a domain (by id) + Rename { + id: String, + new_label: String, + }, + /// Merge two domains + Merge { + a: String, + b: String, + #[arg(long)] into: Option, // default: `a` + }, +} +``` + +Handler plumbing lives in `run_domains(action)` dispatching to `run_domains_list`, `run_domains_discover`, `run_domains_rename`, `run_domains_merge`. Each opens the default `Storage`, constructs a `DomainClassifier::default()`, and invokes the appropriate method. + +Output format for `list`: + +``` +ID LABEL MEMORIES TOP TERMS +dev Development 87 rust, trait, async, tokio, zinit +infra Infrastructure 47 bgp, sonic, vlan, frr, peering +home Home 31 solar, kwh, battery, pool, esphome +(unclassified) 12 +``` + +Produced via plain `print!` with `%-15s %-18s %-10d %s` style padding. `--json` emits `serde_json::to_string_pretty(&domains)`. + +Output format for `discover` with `--force`: + +``` +HDBSCAN: 500 embeddings, min_cluster_size=10, min_samples=5 +Found 3 clusters (ignoring 14 noise points) + cluster_0 (N=47) top: bgp, sonic, vlan, frr, peering + cluster_1 (N=31) top: solar, kwh, battery, pool, esphome + cluster_2 (N=22) top: rust, trait, async, tokio, zinit + +Writing 3 domains to the store... +Soft-assigning 500 memories against centroids... + multi-domain: 43 + single-domain: 412 + unclassified (below threshold 0.65): 45 +Done in 7.4s. +``` + +Output format for `discover` without `--force` (post-Phase-0): + +``` +HDBSCAN: 623 embeddings, min_cluster_size=10 +Comparing to existing 3 domains... + +Proposals (pending, accept via dashboard or `vestige domains proposals`): + [split] dev -> (systems:34, networking:28) confidence 0.82 + [new] cluster_5 (books, novels, reading) confidence 0.71 + +Run `vestige domains proposals` to review, or open the dashboard. +``` + +### 4. CLI: `list`, `rename`, `merge` + +- `list`: calls `store.list_domains()`, fetches unclassified count via `store.count_memories_without_domains()` (Phase 1 should have provided this; if not, Phase 4 adds it to the trait and both backends). +- `rename`: `store.get_domain(id)` -> mutate `label` -> `store.upsert_domain`. No memory touch. +- `merge`: load both, compute blended centroid (weighted by `memory_count`), merge `top_terms` (union, recompute TF-IDF rank if both sides share the corpus), delete the non-`into` domain, call `reassign_all`. Wrapped in a transaction on Postgres; on SQLite rely on the existing writer-lock pattern. + +### 5. Auto-classify on ingest + +**File**: `crates/vestige-core/src/cognitive.rs` (or equivalent ingest entry in `vestige-mcp/src/tools/smart_ingest.rs`). + +Integration point: just before the record is persisted in the smart-ingest path, after the embedder has produced `embedding` and before `storage.insert(...)`. Trace the current call site -- today `Storage::ingest(IngestInput)` computes embedding inside storage; in Phase 1 the embedder becomes external (ADR decision Q2), so classification can hook right there in the cognitive engine. + +Pseudocode: + +```rust +let embedding = embedder.embed(&input.content).await?; +let domains = store.list_domains().await?; + +let (domains_assigned, domain_scores) = if domains.is_empty() { + (Vec::new(), HashMap::new()) +} else { + let boost = context_signals.gather_boost(&input.metadata, &domains); + let result = classifier.classify_with_boost(&embedding, &domains, boost.as_ref()); + (result.domains, result.scores) +}; + +record.embedding = Some(embedding); +record.domains = domains_assigned; +record.domain_scores = domain_scores; +store.insert(&record).await?; +``` + +Edge cases: + +- Accumulation phase (`domains.is_empty()`): skip classification entirely. Zero overhead. +- Embedding failed / skipped: leave `domains = []`, `domain_scores = {}`. Never fail ingest because of classification. +- Metric: emit `VestigeEvent::MemoryClassified { id, domains, top_score }` on the WebSocket bus so the dashboard sees it live. + +### 6. Re-cluster hook in dream consolidation + +**File**: `crates/vestige-core/src/advanced/dreams.rs` (long file, 1131-line `dream()` entry on the `MemoryDreamer` impl) plus `crates/vestige-core/src/consolidation/phases.rs` (the `DreamEngine::run` orchestrator). + +Design: the `DreamEngine::run(...)` returns `FourPhaseDreamResult`. It does not currently know how many times it has run. Phase 4 introduces a persistent counter on disk (column `dream_cycle_count` on a new singleton `system_state` table, or a simple row in the existing `metadata` / `embedding_model` registry). After the Integration phase finishes, the cognitive engine increments the counter and, if `counter % recluster_interval == 0`, launches discovery asynchronously: + +Extension struct in `phases.rs`: + +```rust +pub struct DreamReClusterHook<'a> { + pub classifier: &'a DomainClassifier, + pub store: &'a dyn MemoryStore, + pub event_tx: Option<&'a tokio::sync::mpsc::UnboundedSender>, +} + +impl<'a> DreamReClusterHook<'a> { + pub async fn tick(&self, cycle_count: usize) -> Result, StorageError> { + if cycle_count == 0 || cycle_count % self.classifier.recluster_interval != 0 { + return Ok(vec![]); + } + let existing = self.store.list_domains().await?; + let rediscovered = self.classifier.discover(self.store).await?; + let proposals = self + .classifier + .propose_changes(self.store, &existing, &rediscovered) + .await?; + for p in &proposals { + self.store.insert_domain_proposal(p).await?; + if let Some(tx) = self.event_tx { + let _ = tx.send(VestigeEvent::DomainProposalCreated { + id: p.id.clone(), + kind: format!("{:?}", p.kind), + confidence: p.confidence, + timestamp: Utc::now(), + }); + } + } + Ok(proposals) + } +} +``` + +Caller wires `tick()` after `DreamEngine::run()` returns, at the ingest/consolidation orchestrator level. The hook never mutates existing domains -- it only writes proposals. The acceptance path is manual (CLI or dashboard). + +Counter storage: add method `store.bump_dream_cycle_count() -> Result` returning the new count. Single-row table: + +```sql +CREATE TABLE IF NOT EXISTS system_state ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL +); +-- seed: ('dream_cycle_count', '0') +``` + +### 7. Context signal extractor + +**File**: `crates/vestige-core/src/neuroscience/context_signals.rs` + +```rust +pub trait SignalSource: Send + Sync { + /// Returns domain_id -> additive boost (positive or negative, typically in [-0.1, +0.1]). + fn boost_map( + &self, + input_metadata: &serde_json::Value, + domains: &[Domain], + ) -> HashMap; + + fn name(&self) -> &'static str; +} + +pub struct GitRepoSignal { + pub boost: f64, // default +0.05 +} + +pub struct IdeHintSignal { + pub boost: f64, +} + +pub struct ContextSignals { + sources: Vec>, +} + +impl ContextSignals { + pub fn gather_boost( + &self, + input_metadata: &serde_json::Value, + domains: &[Domain], + ) -> Option>; +} +``` + +Signal encoding convention (document in the module header): + +- A signal is a **soft prior**. It nudges the post-cosine score by a small additive delta, clamped to `[-0.10, +0.10]` per signal. +- Multiple signals sum, then the final boost per domain is clamped to `[-0.15, +0.15]` so signals cannot by themselves push a memory into or out of a domain; the embedding similarity dominates. +- Signals target domains by heuristic: `GitRepoSignal` boosts any domain whose `top_terms` overlaps `{"rust","async","trait","function","class","def","git","commit","fn","code"}`. `IdeHintSignal` does the same for `{"file","line","editor","vscode","neovim","rust-analyzer","lsp"}`. +- All signal boosts are logged via `tracing::debug!` so users can audit why a memory picked up a domain. + +`GitRepoSignal::boost_map` implementation: + +```rust +fn boost_map(&self, meta: &Value, domains: &[Domain]) -> HashMap { + let is_git = meta.get("cwd") + .and_then(|v| v.as_str()) + .map(|cwd| std::path::Path::new(cwd).join(".git").exists()) + .unwrap_or(false) + || meta.get("git_repo").is_some(); + if !is_git { return HashMap::new(); } + let mut out = HashMap::new(); + for d in domains { + let code_hits = d.top_terms.iter() + .filter(|t| CODE_TERMS.contains(t.as_str())) + .count(); + if code_hits > 0 { out.insert(d.id.clone(), self.boost); } + } + out +} +``` + +Config knob in `[domains.signals]`: `git = true`, `ide = true`, `git_boost = 0.05`, `ide_boost = 0.05`. + +### 8. Cross-domain spreading activation decay + +**File**: `crates/vestige-core/src/neuroscience/spreading_activation.rs` + +Modify `ActivationConfig`: + +```rust +pub struct ActivationConfig { + pub decay_factor: f64, + pub max_hops: u32, + pub min_threshold: f64, + pub allow_cycles: bool, + pub cross_domain_decay: f64, // NEW, default 0.5 +} +``` + +Domain metadata on nodes: the current `ActivationNode` has `id`, `activation`, `last_activated`, `edges: Vec`. Phase 4 adds `pub domains: Vec`. Populated when nodes get added (propagated from the memory's `domains` field). The network is rebuilt on each search from the store; if the in-memory network is persisted (check `ActivationNetwork` lifetime in `CognitiveEngine`), the population happens in the engine at boot and on insert. + +Traversal change, in `ActivationNetwork::activate` loop, replacing the single line `let propagated = current_activation * edge.strength * self.config.decay_factor;`: + +```rust +let cross_penalty = { + let src_doms = self.nodes.get(¤t_id).map(|n| &n.domains); + let tgt_doms = self.nodes.get(&target_id).map(|n| &n.domains); + match (src_doms, tgt_doms) { + (Some(s), Some(t)) if !s.is_empty() && !t.is_empty() => { + let overlap = s.iter().any(|d| t.contains(d)); + if overlap { 1.0 } else { self.config.cross_domain_decay } + } + _ => 1.0, // unclassified on either side: no penalty + } +}; +let propagated = current_activation * edge.strength * self.config.decay_factor * cross_penalty; +``` + +Rationale for "unclassified -> no penalty": unclassified memories are Phase-0 or low-confidence corpus members; penalizing them would block useful cross-pollination during the accumulation ramp. + +API to update a node's domains after reclassification: + +```rust +pub fn set_node_domains(&mut self, id: &str, domains: Vec); +``` + +Called by the reassignment pipeline after `reassign_all`. + +### 9. `vestige.toml` `[domains]` section + +**File**: wherever `vestige.toml` is loaded (search for `[storage]` / `[server]` loaders). Add: + +```toml +[domains] +assign_threshold = 0.65 +discovery_threshold = 150 +recluster_interval = 5 +min_cluster_size = 10 +min_samples = 5 +cross_domain_decay = 0.5 +merge_threshold = 0.90 +top_terms_k = 10 + +[domains.signals] +git = true +ide = true +git_boost = 0.05 +ide_boost = 0.05 +``` + +Rust-side: `DomainsConfig { ... }` struct with `serde(default)` so `vestige.toml` without a `[domains]` section falls back to hard-coded defaults. `DomainClassifier::from_config(cfg: &DomainsConfig) -> Self`. + +### 10. Dashboard UI additions + +**SvelteKit routes** (`apps/dashboard/src/routes/(app)/domains/`): + +- `+page.svelte` (list): fetches `GET /api/v1/domains` and `GET /api/v1/domains/unclassified-count`. Renders a table: `label`, `memories`, `top_terms` chips, `created_at`. Each row links to `/domains/[id]`. A "Discover" button posts `POST /api/v1/domains/discover`. +- `[id]/+page.svelte` (detail): fetches `GET /api/v1/domains/:id`, `GET /api/v1/domains/:id/memories?limit=100`, `GET /api/v1/domains/:id/score-histogram`. Renders: + - Header: label (editable, triggers `PUT /api/v1/domains/:id`), top-terms chips, memory count, created_at. + - Histogram: a vertical bar chart of `domain_scores[:id]` buckets 0-0.1, 0.1-0.2, ..., 0.9-1.0 across all memories. Data source: server precomputes buckets so the client does not need to fetch all scores. + - Memory list: paginated, each row shows the raw score for this domain. +- `proposals/+page.svelte`: fetches `GET /api/v1/domains/proposals?status=pending`. Each pending proposal card shows `kind`, `rationale`, `confidence`, `created_at`, buttons "Accept" (posts `POST /api/v1/domains/proposals/:id/accept`) and "Reject" (`POST .../reject`). Live updates via the existing WebSocket channel (`/ws`) reacting to `DomainProposalCreated` events. + +Styling reuses the existing Tailwind + shadcn-svelte conventions in `apps/dashboard/src/lib/components/`. + +Existing `(app)/stats` and `(app)/feed` pages get a small "Domains" summary panel that links to `/domains`. + +### 11. REST endpoints + +**File**: `crates/vestige-mcp/src/protocol/http.rs` or a new `crates/vestige-mcp/src/api/domains.rs` module, wired into the `/api/v1/` router. + +| Method | Path | Handler | +|--------|------|---------| +| GET | `/api/v1/domains` | `list_domains` -- returns `[Domain...]` + unclassified count | +| POST | `/api/v1/domains/discover` | `trigger_discover` -- body `{ min_cluster_size?: usize, force?: bool }`, returns proposals or applied domains | +| GET | `/api/v1/domains/:id` | `get_domain` | +| PUT | `/api/v1/domains/:id` | `update_domain` -- rename | +| DELETE | `/api/v1/domains/:id` | `delete_domain` -- with `?merge_into=other_id` | +| GET | `/api/v1/domains/:id/memories` | paginated memories in this domain | +| GET | `/api/v1/domains/:id/score-histogram` | precomputed buckets | +| GET | `/api/v1/domains/proposals` | `list_proposals?status=pending` | +| POST | `/api/v1/domains/proposals/:id/accept` | `accept_proposal` | +| POST | `/api/v1/domains/proposals/:id/reject` | `reject_proposal` | + +All handlers go through the Phase 3 auth middleware (Bearer / X-API-Key / session cookie). Responses are JSON; error paths use `StatusCode::*` with a small `{"error": "..."}` body. + +### 12. `domain_proposals` table + trait methods + +Postgres migration (`crates/vestige-core/migrations/postgres/00XX_domain_proposals.sql`): + +```sql +CREATE TABLE domain_proposals ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + kind TEXT NOT NULL, -- 'split' | 'merge' | 'new_cluster' + payload JSONB NOT NULL, -- serialized ProposalKind body + rationale TEXT NOT NULL, + confidence DOUBLE PRECISION NOT NULL, + status TEXT NOT NULL DEFAULT 'pending', -- pending|accepted|rejected + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + resolved_at TIMESTAMPTZ +); +CREATE INDEX idx_domain_proposals_status ON domain_proposals (status, created_at DESC); +``` + +SQLite migration: same table, `UUID` -> `TEXT`, `JSONB` -> `TEXT` with JSON-encoded bodies, `TIMESTAMPTZ` -> `TEXT` ISO-8601. + +`MemoryStore` trait additions: + +```rust +async fn insert_domain_proposal(&self, p: &DomainProposal) -> Result<()>; +async fn list_domain_proposals(&self, status: Option<&str>) -> Result>; +async fn get_domain_proposal(&self, id: &str) -> Result>; +async fn set_proposal_status(&self, id: &str, status: &str) -> Result<()>; +``` + +### 13. WebSocket event for proposals + +**File**: `crates/vestige-mcp/src/dashboard/events.rs` + +Add variant: + +```rust +pub enum VestigeEvent { + // ... existing ... + DomainProposalCreated { + id: String, + kind: String, + confidence: f64, + timestamp: DateTime, + }, + MemoryClassified { + id: String, + domains: Vec, + top_score: f64, + timestamp: DateTime, + }, +} +``` + +The SvelteKit dashboard's WS client reacts to both events: classified events refresh any open domain-detail page; proposal events push a toast and a badge on the navbar. + +--- + +## Test Plan + +Test root: `tests/phase_4/` (a new member of the workspace; mirror the `tests/e2e` layout). + +`tests/phase_4/Cargo.toml`: + +```toml +[package] +name = "vestige-phase4-tests" +version = "0.0.0" +edition = "2024" +publish = false + +[dependencies] +vestige-core = { path = "../../crates/vestige-core", features = ["embeddings", "vector-search", "domain-classification"] } +vestige-mcp = { path = "../../crates/vestige-mcp" } +tokio = { workspace = true } +anyhow = "1" +tempfile = "3" +serde_json = { workspace = true } +uuid = { workspace = true } +``` + +### Unit tests (colocated in `domain_classifier.rs::tests`, `context_signals.rs::tests`, `spreading_activation.rs::tests`) + +Each public function must have at least one test: + +- `classify_empty_domains_returns_empty`: `classify(&[0.0; 768], &[])` returns `ClassificationResult { scores: {}, domains: [] }`. +- `classify_single_domain_scores`: one `Domain` with a known centroid; input embedding equal to centroid; expect score 1.0 and `domains == [id]`. +- `classify_multi_domain_overlap`: two domains A, B; input halfway between centroids; expect both scores >= `assign_threshold`; expect `domains == [A, B]` (order not guaranteed). +- `classify_below_threshold_returns_empty_domains_but_scores_filled`: input orthogonal to all centroids; expect `scores` populated, `domains` empty. +- `classify_with_boost_adds_delta`: same input as above, with `boost = {A: 0.4}`; expect A now above threshold, B unchanged. +- `classify_boost_clamps_to_unit`: `boost = {A: 5.0}`; resulting `scores[A]` must be <= 1.0. +- `tfidf_top_k_returns_distinct_terms`: given three fake docs, `top_k=3` returns three non-duplicate strings, in descending TF-IDF order. +- `tfidf_top_k_drops_stopwords`: `["the and for"]` + real content -> stop-words absent. +- `compute_top_terms_handles_empty_cluster`: returns `vec![]` (no panic). +- `signal_git_present_vs_absent`: `GitRepoSignal` given metadata with `.git` in cwd returns non-empty map; without it returns empty. +- `signal_ide_present_vs_absent`: `IdeHintSignal` ditto for `metadata.editor == "vscode"`. +- `signal_combined_clamped`: two signals both firing each at +0.10 -> combined map values <= +0.15. +- `cross_domain_decay_full_weight_on_overlap`: graph with node A in domain `dev`, node B in domain `dev`, edge A->B strength 1.0; after `activate`, B's activation equals the standard `initial * strength * decay_factor` (no extra penalty). +- `cross_domain_decay_half_weight_no_overlap`: A in `dev`, B in `infra`, same edge -> B's activation is 0.5x that of the overlap case. +- `cross_domain_decay_unclassified_no_penalty`: A classified, B unclassified -> full weight. +- `propose_changes_detects_split`: existing domain `dev`; new discovery returns two clusters whose centroids both sit close to old `dev` centroid, each >= min_cluster_size members -> proposal of kind `Split { parent: "dev", children: [a, b] }`. +- `propose_changes_detects_merge`: two existing domains whose new centroids now have cosine > `merge_threshold` -> proposal of kind `Merge`. +- `propose_changes_detects_new_cluster`: a new cluster with no match >= 0.85 to any existing -> `NewCluster`. +- `apply_proposal_split_updates_memberships`: after accept, memories previously in `dev` get reassigned (some to child a, some to child b) via `reassign_all`. + +### Integration tests (`tests/phase_4/tests/`) + +One file per behavior listed in the Phase 4 acceptance sheet. + +- `discover_seed_corpus.rs` -- loads the 500-memory fixture, runs `classifier.discover(&store).await`, asserts at least 3 clusters, asserts per-cluster intra-similarity mean > 0.6, asserts discovery wall time < 10s in release. Also asserts `top_terms` for each cluster contains at least one expected keyword per cluster (dev: contains any of `rust/trait/async`; infra: `bgp/vlan/network`; home: `solar/battery/pool`). +- `soft_assign_multi_domain.rs` -- inserts a memory "deploy zinit containers over BGP network"; after classify, `domains` contains both `dev` and `infra` (from a known centroid setup). +- `auto_classify_on_ingest.rs` -- with three existing domains, a fresh `smart_ingest` of a dev-ish sentence ends up with `domains == ["dev"]` and non-empty `domain_scores`. +- `reembed_triggers_recluster.rs` -- after `vestige migrate --reembed`, centroids must be recomputed; verify `list_domains()` returns fresh `centroid` values (different from pre-reembed). +- `dream_consolidation_recluster_hook.rs` -- run 5 dream cycles with heavy synthetic memory insertion; after the 5th, assert `list_domain_proposals("pending")` has at least one proposal. +- `proposal_accept_applies_changes.rs` -- accept a split proposal via `apply_proposal`; verify that memories in `dev` are now distributed across the new children and that the old `dev` domain is removed. +- `proposal_reject_leaves_state.rs` -- reject a proposal; verify all domains and memberships unchanged. +- `drift_is_proposal_only.rs` -- over 5 dream cycles with new inserts, never call accept; verify every memory's `domains` field equals its initial post-discovery value. No auto-apply. +- `cross_domain_activation_decay.rs` -- build a `ActivationNetwork` with two memories linked by a strength-1.0 edge, one in `dev`, one in `infra`; activate `dev` memory with 1.0; assert `infra` memory's activation == `0.5 * decay_factor` (0.35 with default decay_factor 0.7). Then set both to `dev` and reassert activation == `0.7`. +- `cli_domains_discover.rs` -- spawn `cargo run -- domains discover --force --json`, parse stdout, assert at least 3 clusters and valid JSON shape. +- `cli_domains_rename_merge.rs` -- happy-path rename then merge, with stdout assertions. +- `context_signal_git_repo.rs` -- ingest the same sentence from inside a tempdir with `.git` vs outside; assert the git-run produces slightly higher `domain_scores` for the code-related domain (diff >= 0.04, matches `git_boost = 0.05`). +- `threshold_tunable.rs` -- same memory, two runs with `assign_threshold = 0.40` vs `0.85`; the low-threshold run assigns more domains than the high-threshold run for the same content. +- `signal_boost_clamped.rs` -- artificially configure `git_boost = 5.0` and assert the resulting per-domain score is still <= 1.0. +- `discover_preserves_stable_ids.rs` -- run discover twice with no new memories; the second run's domain ids match the first's (via centroid-similarity stable-ID matching above 0.85). + +### Dashboard UI tests (`tests/phase_4/ui/`) + +Use curl-driven smoke tests (avoids adding Playwright as a new hard dep; Playwright already exists at `apps/dashboard/playwright.config.ts` and can be extended later). + +- `domains_list_renders.sh` -- `curl -H "X-API-Key: $KEY" http://localhost:3927/api/v1/domains` returns 200 + JSON array with expected keys. +- `domain_detail_histogram.sh` -- `curl .../api/v1/domains/dev/score-histogram` returns 10 buckets. +- `proposal_review_flow.sh` -- create a pending proposal via SQL insert; `curl POST .../api/v1/domains/proposals//accept`; `curl GET .../proposals?status=accepted` shows it. +- `unauth_domain_list_rejected.sh` -- no auth header -> 401. + +### Benchmarks (`tests/phase_4/benches/`) + +Criterion benches: + +- `bench_discover_10k.rs` -- synthetic 10k x 768D embeddings drawn from 5 blobs; assert `discover` wall p95 < 30s on a warm release build. +- `bench_auto_classify_single.rs` -- 20 domains in memory, classify one 768D vector; assert p99 < 5ms. +- `bench_reassign_all.rs` -- 10k memories, 5 domains; assert full `reassign_all` wall time < 90s (100 rows/ms baseline). + +--- + +## Acceptance Criteria + +- [ ] `cargo build -p vestige-core --features domain-classification` zero warnings. +- [ ] `cargo build -p vestige-mcp` zero warnings. +- [ ] `cargo clippy --workspace --all-targets --all-features -- -D warnings` clean. +- [ ] `cargo test -p vestige-phase4-tests` -- all tests in `tests/phase_4/` pass. +- [ ] On a 500+ memory seed corpus covering three natural clusters (dev / infra / home), `vestige domains discover --force` produces sensible top-terms matching the expected keyword sets and labels are stable on a second run. +- [ ] `vestige search` with domain filter `["dev"]` excludes any memory whose `domains` array does not include `dev`. +- [ ] After 5 dream cycles with ongoing inserts, no existing memory's `domains` has silently changed; proposals exist in `domain_proposals` table; accepting a proposal reassigns as described. +- [ ] Cross-domain spreading activation: a query in `dev` that crosses a single edge into an `infra`-only memory still returns the memory but with activation `cross_domain_decay * in-domain_activation`. +- [ ] `vestige domains discover --min-cluster-size 20` produces strictly fewer or equal clusters than the default, and with larger per-cluster membership. +- [ ] Dashboard `/dashboard/domains` route renders all domains within 2 seconds on the seed corpus. +- [ ] Proposal UI flow (open pending, accept, confirmed in store) works end-to-end. +- [ ] Benchmarks meet targets (discover 10k p95 < 30s, auto-classify p99 < 5ms). + +--- + +## Rollback Notes + +- **Feature gate**: add `domain-classification` to `crates/vestige-core/Cargo.toml`'s `[features]`. When disabled, the `DomainClassifier` module is not compiled, the classification call in the ingest path is a no-op (`#[cfg]`-guarded), and cross-domain decay collapses to `1.0`. The CLI `domains` subcommand emits "domain classification is disabled in this build". +- **Revert strategy**: drop the two new tables `domains` (if created in Phase 1 is retained) or `domain_proposals` (Phase 4). A DOWN migration clears `memories.domains` and `memories.domain_scores`. Existing memories simply lose their domain assignments; all search and retrieval paths work unchanged because `domains = []` is the documented "unclassified" state. +- **Idempotency**: rerunning `discover` is always safe. Cluster numeric IDs may differ between runs, but the stable-ID match by centroid similarity preserves user-assigned labels. Do not persist cluster ids in client-side bookmarks; link via the user-assigned label. +- **Data-loss risk**: `apply_proposal` is a destructive operation (it deletes the old parent domain in a split or merges two). The dashboard's accept button double-confirms with a modal that shows the number of affected memories. + +--- + +## Open Implementation Questions + +Each question + candidates + RECOMMENDATION. + +### OQ1. Top-terms extraction: TF-IDF vs BM25 vs frequency? +- TF-IDF with smoothed IDF -- standard, cheap, good-enough. +- BM25 -- better for long-document discrimination, overkill for short memory contents. +- Raw frequency -- noisy; stop-words dominate. +**RECOMMENDATION**: TF-IDF with global IDF over the entire memory corpus (not just cluster members), recomputed once per `discover` call. Same tokenizer as the `dreams.rs::content_similarity` Jaccard for consistency. + +### OQ2. Proposal persistence: DB table vs in-memory with dashboard notification? +- DB table (`domain_proposals`) -- durable, surfaces across restarts, enables audit. +- In-memory only -- simpler, but loses proposals on server restart. +**RECOMMENDATION**: DB table. Proposals are rare (every 5th dream) and valuable user-facing artifacts; durability is mandatory. + +### OQ3. `hdbscan` crate: f32 vs f64 input, exact API surface? +- v0.10 historically takes `&[Vec]`; embeddings are `Vec`. +- Cost of converting f32 -> f64 at discovery time: `10k * 768 = 7.68M` f64 doubles ~ 60MB transient, acceptable. +**RECOMMENDATION**: verify v0.10's type signature at implementation time; if it requires f64, perform the conversion in `discover()` behind a single allocation. Document in module header. If the crate API diverged from the PRD snippet, fall back to the manual builder style (`HdbscanHyperParams::builder().min_cluster_size(n).min_samples(s).build()`). + +### OQ4. Stable domain IDs across discover re-runs? +- Option A: numeric IDs from HDBSCAN labels -- unstable, re-runs shuffle them. +- Option B: hash(top_terms) -- stable if top-terms stable, but top-terms drift. +- Option C (recommended): after computing new centroids, match each to the closest existing domain by centroid cosine; if similarity > 0.85, reuse the existing domain's `id` and `label`. Otherwise mint a fresh `id = "cluster_"`. +**RECOMMENDATION**: Option C. Preserves user-assigned labels across drift. Threshold 0.85 is config-tunable via `stable_id_threshold` if needed later. + +### OQ5. Context signal injection site: ingest handler vs embedder vs classifier? +- Embedder -- would alter embedding; signals are not about embedding quality. +- Ingest handler -- signals known there, but then `DomainClassifier` cannot be tested in isolation. +- Classifier as a `classify_with_boost(boost: Option<&HashMap>)` parameter -- pure, testable, composable. +**RECOMMENDATION**: classifier parameter. The cognitive engine constructs the boost map via `ContextSignals::gather_boost(&metadata, &domains)` and hands it to the classifier. Keeps the classifier stateless w.r.t. signals. + +### OQ6. Re-cluster proposal cadence: event-based (every Nth dream) vs time-based (weekly)? +- ADR resolution Q7: every Nth dream (N=5 default). +- Alternative: once per week regardless of dream cadence. +**RECOMMENDATION**: stick with every Nth dream. Users who dream rarely re-cluster rarely -- that matches the philosophy ("memory work triggers memory bookkeeping"). Note the alternative as future consideration; if users complain about never seeing proposals, add a time-based fallback. + +### OQ7. Minimum corpus size for first discover? +- PRD default: 150. +- Too low -> noisy initial clusters, proposals every dream. +- Too high -> user waits forever for domains to appear. +**RECOMMENDATION**: 150 as the default discovery gate; HDBSCAN's `min_cluster_size=10` will produce 0 clusters for < 100 memories, so the system gracefully produces no domains until the corpus is large enough. Test with `N=80, 150, 500` in `threshold_tunable.rs` to confirm sensible behavior. + +### OQ8. Cross-domain decay: strict no-overlap vs graded? +- Strict: `1.0` if any overlap, `cross_domain_decay` otherwise. +- Graded: `max(cross_domain_decay, |A intersect B| / max(|A|, |B|))`. +**RECOMMENDATION**: strict for Phase 4. Easier to reason about, easier to tune, easier to test. Graded is a marked future enhancement; file an issue if retrieval-quality metrics justify it. + +### OQ9. Classifier invocation from remote HTTP clients? +- In server mode, an agent posts `smart_ingest` -> server embeds -> server classifies. +- All the work stays server-side; MCP clients never do classification. +**RECOMMENDATION**: confirmed server-side-only. Document in the MCP tool schema that `smart_ingest` now returns `domains` and `domain_scores` in its response so clients can display the classification to the user. + +### OQ10. Where to store the dream-cycle counter? +- In-memory on `CognitiveEngine` -- lost on restart, miscounts cadence. +- New `system_state` singleton table. +**RECOMMENDATION**: `system_state` table. Survives restarts. Also useful for future metrics (total memories ever, total dreams ever). + +### OQ11. Scope of `reassign_all` after a proposal accept vs a normal discover? +- On discover --force (first-time), run `reassign_all` against all memories. +- On proposal accept (split / merge), run `reassign_all` only on affected memories (parent's members for split; both parents' members for merge) to avoid touching unrelated records. +**RECOMMENDATION**: scoped reassignment where possible; fall back to full `reassign_all` only on `discover --force` or when the set of domains has fundamentally changed. Reduces write amplification on large corpora. + +### OQ12. Proposal freshness? +- Multiple re-clusters could stack up pending proposals. +**RECOMMENDATION**: before inserting a new proposal, check for existing pending proposals with the same `kind + targets`; if present, bump `created_at` and `confidence` instead of creating a duplicate. Add a `confidence_history` array in the `payload` JSONB for audit. + +--- + +## Implementation Sequencing (suggested order) + +1. Land the `DomainClassifier` struct, `classify` / `classify_with_boost`, unit tests. (Day 1) +2. Add `compute_top_terms` + TF-IDF helper, tests. (Day 1) +3. Wire `discover` end-to-end against SQLite; `discover_seed_corpus` integration test. (Day 2) +4. Add `domain_proposals` table migrations + trait methods; both backends. (Day 2) +5. Implement `propose_changes` + `apply_proposal`; proposal unit tests. (Day 3) +6. Context signals module + tests. (Day 3) +7. Hook classifier into ingest path; `auto_classify_on_ingest` integration test. (Day 4) +8. Cross-domain decay in spreading activation; unit + integration tests. (Day 4) +9. Dream re-cluster hook + `system_state` counter; integration tests for drift-only behavior. (Day 5) +10. CLI subcommands. (Day 6) +11. REST endpoints. (Day 6) +12. SvelteKit dashboard routes + WebSocket event wiring. (Day 7-8) +13. Benchmarks + acceptance sweep on the 500-memory seed. (Day 9) + +--- + +## File Map (everything Phase 4 touches or creates) + +Creates: + +- `crates/vestige-core/src/neuroscience/domain_classifier.rs` +- `crates/vestige-core/src/neuroscience/context_signals.rs` +- `crates/vestige-core/migrations/postgres/00XX_domain_proposals.sql` +- `crates/vestige-core/migrations/sqlite/00XX_domain_proposals.sql` (or inline in `storage/migrations.rs`) +- `crates/vestige-mcp/src/api/domains.rs` (REST handlers) +- `apps/dashboard/src/routes/(app)/domains/+page.svelte` +- `apps/dashboard/src/routes/(app)/domains/[id]/+page.svelte` +- `apps/dashboard/src/routes/(app)/domains/proposals/+page.svelte` +- `apps/dashboard/src/lib/api/domains.ts` +- `tests/phase_4/Cargo.toml` +- `tests/phase_4/tests/*.rs` (per the Integration test list) +- `tests/phase_4/fixtures/seed_500.json` +- `tests/phase_4/support/fixtures.rs` + +Modifies: + +- `crates/vestige-core/Cargo.toml` -- add `hdbscan = "0.10"` under a new `domain-classification` feature. +- `crates/vestige-core/src/neuroscience/mod.rs` -- register new modules, re-exports. +- `crates/vestige-core/src/neuroscience/spreading_activation.rs` -- `cross_domain_decay` field in `ActivationConfig`, `domains` field on `ActivationNode`, decay math in `activate`. +- `crates/vestige-core/src/consolidation/phases.rs` -- `DreamReClusterHook`. +- `crates/vestige-core/src/advanced/dreams.rs` -- accept a hook callback from the orchestrator (if the orchestration is done at this level). +- `crates/vestige-core/src/storage/trait.rs` -- add proposal + system_state methods. +- `crates/vestige-core/src/storage/sqlite.rs` -- implement proposal + system_state methods + `all_embeddings_with_meta` if not already on the trait. +- `crates/vestige-core/src/storage/postgres.rs` (Phase 2) -- same. +- `crates/vestige-core/src/lib.rs` -- re-exports. +- `crates/vestige-core/src/cognitive.rs` (or equivalent ingest orchestrator) -- auto-classify injection. +- `crates/vestige-mcp/src/bin/cli.rs` -- `Domains` subcommand + dispatch. +- `crates/vestige-mcp/src/dashboard/mod.rs` -- wire new REST routes. +- `crates/vestige-mcp/src/dashboard/events.rs` -- new event variants. +- `crates/vestige-mcp/src/dashboard/handlers.rs` -- if legacy dashboard gets a domains panel (optional). +- `vestige.toml` config loader -- `[domains]` section + struct + defaults. +- Root `Cargo.toml` workspace members -- add `tests/phase_4`. + +--- + +## Risks + +- **HDBSCAN determinism**: HDBSCAN is deterministic given input order; sorting embeddings by memory id before feeding the clusterer guarantees reproducibility across runs -- do this in `discover()` and document it. +- **Embedding dimension drift**: Phase 1's `embedding_model` registry blocks writes from mismatched embedders. If `discover()` ever sees two dimensions, it bails with a clear error and points at `vestige migrate --reembed`. +- **Classification latency on ingest**: for users with thousands of domains (unlikely but possible), `classify` is O(n_domains * dim). 20 domains * 768 f32 = 15k flops per classification, trivial. Still, expose a `classify_budget_ms` config knob for paranoia. +- **Re-cluster proposal storms**: if the corpus is borderline-stable, small changes can produce conflicting proposals on consecutive dreams. Mitigation: OQ12 (dedup by target set, bump confidence instead of stacking). +- **Dashboard feature gap**: if the SvelteKit app lands with the domains route but the REST endpoints are not yet deployed, the route 404s. Mitigation: ship the REST endpoints in the same release; a feature flag on the client toggles the nav entry. + +--- + +## Non-Goals Reminder + +- No Phase 5 federation concerns in this plan. +- No cross-installation domain sync. +- No automatic accept of proposals, ever. +- No graded cross-domain decay; strict only. +- No ML-based domain label suggestion (top-terms are enough for v1). +- No editing individual memory memberships from the UI in this phase. diff --git a/docs/prd/001-getting-centralized-vestige.md b/docs/prd/001-getting-centralized-vestige.md new file mode 100644 index 0000000..9d86087 --- /dev/null +++ b/docs/prd/001-getting-centralized-vestige.md @@ -0,0 +1,751 @@ +# RFC: Pluggable Storage Backend + Network Access for Vestige + +**Status**: Draft / Discussion +**Author**: Jan +**Date**: 2026-02-26 +**Vestige version**: v2.x (current main) + +## Summary + +Add a pluggable storage backend trait to Vestige, enabling PostgreSQL (+pgvector) as an alternative to the current SQLite+FTS5+USearch stack. Simultaneously add HTTP MCP transport with API key authentication to enable centralized/remote deployment. + +This keeps the existing local-first SQLite mode fully intact while opening up a server deployment model. + +## Motivation + +Vestige currently runs as a local process per machine (MCP via stdio, SQLite in `~/.vestige/`). This works great for single-machine use but doesn't support: + +- **Multi-machine access**: Same memory brain from laptop, desktop, and server +- **Multi-agent access**: Multiple AI clients hitting one memory store concurrently +- **Future federation**: Syncing memory between decentralized nodes (e.g., MOS/Threefold grid) + +SQLite's single-writer model and lack of native network protocol make it unsuitable as a centralized server. PostgreSQL is a natural fit: built-in concurrency (MVCC), authentication, replication, and with `pgvector` + built-in FTS it collapses three separate storage layers into one. + +## Design + +### Storage Trait + +The core abstraction. All 29 cognitive modules interact with storage exclusively through this trait (or a small family of traits). + +```rust +use std::collections::HashMap; +use uuid::Uuid; + +/// Core memory record, backend-agnostic +#[derive(Debug, Clone)] +pub struct MemoryRecord { + pub id: Uuid, + pub domains: Vec, // [] = unclassified, ["dev"], ["dev", "infra"], etc. + pub domain_scores: HashMap, // raw similarities: {"dev": 0.82, "infra": 0.71} + pub content: String, + pub node_type: String, + pub tags: Vec, + pub embedding: Option>, // dimensionality is runtime config + pub created_at: chrono::DateTime, + pub updated_at: chrono::DateTime, + pub metadata: serde_json::Value, +} + +/// FSRS scheduling state, stored alongside each memory +#[derive(Debug, Clone)] +pub struct SchedulingState { + pub memory_id: Uuid, + pub stability: f64, + pub difficulty: f64, + pub retrievability: f64, + pub last_review: Option>, + pub next_review: Option>, + pub reps: u32, + pub lapses: u32, +} + +/// Hybrid search request +#[derive(Debug, Clone)] +pub struct SearchQuery { + pub domains: Option>, // None = search all domains + pub text: Option, // FTS query + pub embedding: Option>, // vector similarity + pub tags: Option>, // tag filter + pub node_types: Option>, + pub limit: usize, + pub min_retrievability: Option, // filter by FSRS state +} + +#[derive(Debug, Clone)] +pub struct SearchResult { + pub record: MemoryRecord, + pub score: f64, // combined/fused score + pub fts_score: Option, + pub vector_score: Option, +} + +/// Connection/edge between memories (for spreading activation) +#[derive(Debug, Clone)] +pub struct MemoryEdge { + pub source_id: Uuid, + pub target_id: Uuid, + pub edge_type: String, + pub weight: f64, + pub created_at: chrono::DateTime, +} + +/// Main storage trait — one impl per backend +/// trait_variant generates a Send-bound `MemoryStore` alias, +/// enabling Arc without manual boxing. +#[trait_variant::make(MemoryStore: Send)] +pub trait LocalMemoryStore: Sync + 'static { + // --- Lifecycle --- + async fn init(&self) -> Result<()>; + async fn health_check(&self) -> Result; + + // --- CRUD --- + async fn insert(&self, record: &MemoryRecord) -> Result; + async fn get(&self, id: Uuid) -> Result>; + async fn update(&self, record: &MemoryRecord) -> Result<()>; + async fn delete(&self, id: Uuid) -> Result<()>; + + // --- Search --- + async fn search(&self, query: &SearchQuery) -> Result>; + async fn fts_search(&self, text: &str, limit: usize) -> Result>; + async fn vector_search(&self, embedding: &[f32], limit: usize) -> Result>; + + // --- FSRS Scheduling --- + async fn get_scheduling(&self, memory_id: Uuid) -> Result>; + async fn update_scheduling(&self, state: &SchedulingState) -> Result<()>; + async fn get_due_memories(&self, before: chrono::DateTime, limit: usize) -> Result>; + + // --- Graph (spreading activation) --- + async fn add_edge(&self, edge: &MemoryEdge) -> Result<()>; + async fn get_edges(&self, node_id: Uuid, edge_type: Option<&str>) -> Result>; + async fn remove_edge(&self, source: Uuid, target: Uuid) -> Result<()>; + async fn get_neighbors(&self, node_id: Uuid, depth: usize) -> Result>; + + // --- Bulk / Maintenance --- + async fn count(&self) -> Result; + async fn get_stats(&self) -> Result; + async fn vacuum(&self) -> Result<()>; +} +``` + +**Design notes:** + +- `trait_variant::make` generates a `MemoryStore` trait alias with `Send`-bound futures, allowing `Arc` for runtime backend selection. `LocalMemoryStore` is the base (usable in single-threaded contexts), `MemoryStore` is the Send variant for Axum/tokio. +- `embedding: Option>` — dimensions determined at runtime by the configured fastembed model. The backend stores whatever it gets. +- The trait is intentionally flat. The cognitive modules (FSRS-6, spreading activation, synaptic tagging, prediction error gating, etc.) sit *above* this trait and don't need to know about the backend. +- `search()` does hybrid RRF fusion at the backend level — both SQLite and Postgres implementations handle this internally. + +### Backend: SQLite (existing, refactored) + +Wraps the current implementation behind the trait: + +``` +SqliteMemoryStore +├── rusqlite connection pool (r2d2 or deadpool) +├── FTS5 virtual table (keyword search) +├── USearch HNSW index (vector search, behind RwLock) +└── WAL mode + busy timeout for concurrent readers +``` + +No behavioral changes — just the trait boundary. + +### Backend: PostgreSQL (new) + +``` +PgMemoryStore +├── sqlx::PgPool (connection pool, compile-time checked queries) +├── tsvector + GIN index (keyword search) +├── pgvector + HNSW index (vector search) +└── Standard PostgreSQL MVCC concurrency +``` + +**Schema sketch:** + +```sql +CREATE EXTENSION IF NOT EXISTS vector; + +-- Domain registry — populated by clustering, not by user +CREATE TABLE domains ( + id TEXT PRIMARY KEY, -- auto-generated or user-named + label TEXT NOT NULL, -- human label (suggested or user-provided) + centroid vector, -- mean embedding of domain members + top_terms TEXT[] NOT NULL DEFAULT '{}', -- top keywords for display + memory_count INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + metadata JSONB NOT NULL DEFAULT '{}' +); + +CREATE TABLE memories ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + domains TEXT[] NOT NULL DEFAULT '{}', -- [] = unclassified + domain_scores JSONB NOT NULL DEFAULT '{}', -- {"dev": 0.82, "infra": 0.71} raw similarities + content TEXT NOT NULL, + node_type TEXT NOT NULL DEFAULT 'general', + tags TEXT[] NOT NULL DEFAULT '{}', + embedding vector, -- dimension set at table creation or unconstrained + metadata JSONB NOT NULL DEFAULT '{}', + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + + -- FTS: auto-maintained tsvector column + search_vec TSVECTOR GENERATED ALWAYS AS ( + setweight(to_tsvector('english', content), 'A') || + setweight(to_tsvector('english', coalesce(node_type, '')), 'B') || + setweight(array_to_tsvector(tags), 'C') + ) STORED +); + +-- FTS index +CREATE INDEX idx_memories_fts ON memories USING GIN (search_vec); + +-- Vector similarity (HNSW) +CREATE INDEX idx_memories_embedding ON memories + USING hnsw (embedding vector_cosine_ops) + WITH (m = 16, ef_construction = 64); + +-- Common filters +CREATE INDEX idx_memories_domains ON memories USING GIN (domains); +CREATE INDEX idx_memories_node_type ON memories (node_type); +CREATE INDEX idx_memories_tags ON memories USING GIN (tags); +CREATE INDEX idx_memories_created ON memories (created_at); + +-- FSRS scheduling state +CREATE TABLE scheduling ( + memory_id UUID PRIMARY KEY REFERENCES memories(id) ON DELETE CASCADE, + stability DOUBLE PRECISION NOT NULL DEFAULT 0.0, + difficulty DOUBLE PRECISION NOT NULL DEFAULT 0.0, + retrievability DOUBLE PRECISION NOT NULL DEFAULT 1.0, + last_review TIMESTAMPTZ, + next_review TIMESTAMPTZ, + reps INTEGER NOT NULL DEFAULT 0, + lapses INTEGER NOT NULL DEFAULT 0 +); + +CREATE INDEX idx_scheduling_next ON scheduling (next_review); + +-- Graph edges (spreading activation) +-- Edges can cross domain boundaries — spreading activation respects +-- domain filters when provided, traverses freely when searching all domains. +CREATE TABLE edges ( + source_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE, + target_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE, + edge_type TEXT NOT NULL DEFAULT 'related', + weight DOUBLE PRECISION NOT NULL DEFAULT 1.0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (source_id, target_id, edge_type) +); + +CREATE INDEX idx_edges_target ON edges (target_id); + +-- API keys +CREATE TABLE api_keys ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + key_hash TEXT NOT NULL UNIQUE, -- blake3 + label TEXT NOT NULL, + scopes TEXT[] NOT NULL DEFAULT '{read,write}', + domain_filter TEXT[] NOT NULL DEFAULT '{}', -- {} = access all domains + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + last_used TIMESTAMPTZ, + active BOOLEAN NOT NULL DEFAULT true +); +``` + +**Hybrid search in SQL:** + +```sql +-- RRF (Reciprocal Rank Fusion) combining FTS + vector +-- $1 = query text, $2 = embedding, $3 = limit, $4 = domain filter (NULL for all) +WITH fts AS ( + SELECT id, ts_rank_cd(search_vec, websearch_to_tsquery('english', $1)) AS score, + ROW_NUMBER() OVER (ORDER BY ts_rank_cd(search_vec, websearch_to_tsquery('english', $1)) DESC) AS rank + FROM memories + WHERE search_vec @@ websearch_to_tsquery('english', $1) + AND ($4::text[] IS NULL OR domains && $4) -- array overlap: any match + LIMIT 50 +), +vec AS ( + SELECT id, 1 - (embedding <=> $2::vector) AS score, + ROW_NUMBER() OVER (ORDER BY embedding <=> $2::vector) AS rank + FROM memories + WHERE embedding IS NOT NULL + AND ($4::text[] IS NULL OR domains && $4) + LIMIT 50 +) +SELECT COALESCE(f.id, v.id) AS id, + COALESCE(1.0 / (60 + f.rank), 0) + COALESCE(1.0 / (60 + v.rank), 0) AS rrf_score, + f.score AS fts_score, + v.score AS vector_score +FROM fts f FULL OUTER JOIN vec v ON f.id = v.id +ORDER BY rrf_score DESC +LIMIT $3; +``` + +### Embedding Configuration + +The embedding layer stays external to the storage backend. fastembed runs locally and produces vectors that get passed into `MemoryRecord.embedding`. + +```toml +# vestige.toml +[embeddings] +provider = "fastembed" # only local for now +model = "BAAI/bge-base-en-v1.5" # 768 dimensions +# model = "BAAI/bge-large-en-v1.5" # 1024 dimensions +# model = "BAAI/bge-small-en-v1.5" # 384 dimensions + +[storage] +backend = "postgres" # or "sqlite" + +[storage.sqlite] +path = "~/.vestige/vestige.db" + +[storage.postgres] +url = "postgresql://vestige:secret@localhost:5432/vestige" +max_connections = 10 +``` + +On init, the backend reads the embedding dimension from the first stored vector (or from config) and validates consistency. + +For pgvector: you can either create the column as `vector(768)` (fixed, faster) or unconstrained `vector` (flexible, slightly slower). Recommendation: fixed dimension derived from config, with a migration path if the model changes. + +### Emergent Domain Model + +Instead of user-defined tenants, domains emerge automatically from the data via clustering. The user never has to decide where a memory belongs — the system figures it out. + +#### Pipeline + +``` +Phase 1: Accumulate (cold start, 0 → N memories) +│ All memories stored with domains = [] (unclassified) +│ No classification overhead, just embed and store +│ Threshold N is configurable, default ~150 memories +│ +Phase 2: Discover (triggered once at threshold, or manually) +│ Run HDBSCAN on all embeddings: +│ - min_cluster_size: ~10 +│ - min_samples: ~5 +│ - No eps parameter needed (unlike DBSCAN) +│ - Automatically determines number of clusters +│ - Handles variable-density clusters +│ - Border points between clusters flagged naturally +│ +│ For each cluster, extract: +│ - Centroid (mean embedding) +│ - Top terms (TF-IDF or frequency over cluster members) +│ - Suggested label from top terms +│ +│ Present to user (via dashboard or CLI): +│ "I found 3 natural groupings in your memories: +│ ● cluster_0 (47 memories): BGP, SONiC, VLAN, FRR, peering... +│ ● cluster_1 (31 memories): solar, kWh, battery, pool, ESPHome... +│ ● cluster_2 (22 memories): Rust, trait, async, zinit, tokio..." +│ +│ User can: +│ - Name them: cluster_0 → "infra", cluster_1 → "home", cluster_2 → "dev" +│ - Accept suggested names +│ - Merge clusters +│ - Do nothing (auto-names stick) +│ +Phase 3: Soft-assign all existing memories +│ Now that centroids exist, re-score every memory (including +│ those from discovery) against all centroids. +│ This replaces HDBSCAN's hard labels with continuous scores: +│ +│ For each memory: +│ similarities = [(domain, cosine_sim(embedding, centroid)) for each domain] +│ domains = [id for (id, score) in similarities if score >= threshold] +│ +│ Memories in overlap zones get multiple domains. +│ Memories far from all centroids stay unclassified. +│ +Phase 4: Classify (ongoing, after discovery) +│ New memory ingested: +│ 1. Compute embedding +│ 2. Compute similarity to ALL domain centroids +│ 3. Store raw scores in domain_scores JSONB +│ 4. Threshold into domains[] array +│ 5. Update domain centroids incrementally (running mean) +│ +│ Context signals as soft priors: +│ - Git repo / IDE metadata → boost similarity to code-related domains +│ - No workspace context → slight boost toward non-technical domains +│ - These shift the score, never override the embedding distance +│ +Phase 5: Re-cluster (periodic, during dream consolidation) + Re-run HDBSCAN on all embeddings including new ones + Detect: + - New clusters forming from previously unclassified memories + - Existing clusters splitting (domain grew too broad) + - Clusters merging (domains that were artificially separate) + Propose changes to user: + "Your 'dev' domain may have split into two groups: + - systems (zinit, MOS, containers, VMs) — 34 memories + - networking (BGP, SONiC, VLANs, MLAG) — 28 memories + Split them? [yes / no / later]" + Re-run soft assignment on all memories after structural changes + Centroid vectors are updated regardless +``` + +#### Domain Storage + +```rust +#[derive(Debug, Clone)] +pub struct Domain { + pub id: String, + pub label: String, + pub centroid: Vec, + pub top_terms: Vec, + pub memory_count: usize, + pub created_at: chrono::DateTime, +} +``` + +Added to the `MemoryStore` trait: + +```rust + // --- Domains --- + async fn list_domains(&self) -> Result>; + async fn get_domain(&self, id: &str) -> Result>; + async fn upsert_domain(&self, domain: &Domain) -> Result<()>; + async fn delete_domain(&self, id: &str) -> Result<()>; + async fn classify(&self, embedding: &[f32]) -> Result>; + // Returns [(domain_id, similarity)] sorted by similarity desc. + // Caller decides threshold for assignment. +``` + +#### Classification Module + +A new cognitive module alongside FSRS, spreading activation, etc.: + +```rust +pub struct DomainClassifier { + /// Similarity threshold — domains scoring above this are assigned + pub assign_threshold: f64, // default: 0.65 + /// Minimum memories before running initial discovery + pub discovery_threshold: usize, // default: 150 + /// How often to re-cluster (in dream consolidation passes) + pub recluster_interval: usize, // default: every 5th consolidation + /// HDBSCAN min_cluster_size + pub min_cluster_size: usize, // default: 10 +} + +/// Raw classification result — all scores, before thresholding +#[derive(Debug, Clone)] +pub struct ClassificationResult { + /// Similarity to every known domain centroid + pub scores: HashMap, // {"dev": 0.82, "infra": 0.71, "home": 0.34} + /// Domains above assign_threshold + pub domains: Vec, // ["dev", "infra"] +} + +impl DomainClassifier { + /// Score a memory against all domain centroids. + /// Returns raw scores AND thresholded domain list. + pub fn classify( + &self, + embedding: &[f32], + domains: &[Domain], + ) -> ClassificationResult { + if domains.is_empty() { + return ClassificationResult { + scores: HashMap::new(), + domains: vec![], // still in accumulation phase + }; + } + + let scores: HashMap = domains.iter() + .map(|d| (d.id.clone(), cosine_similarity(embedding, &d.centroid))) + .collect(); + + let assigned: Vec = scores.iter() + .filter(|(_, &s)| s >= self.assign_threshold) + .map(|(id, _)| id.clone()) + .collect(); + + ClassificationResult { scores, domains: assigned } + } + + /// Soft-assign all existing memories after discovery or re-clustering. + /// Returns number of memories whose domains changed. + pub async fn reassign_all( + &self, + store: &dyn MemoryStore, + domains: &[Domain], + ) -> Result { + // Load all memories, re-score, update domains + domain_scores + // Batched to avoid loading everything into memory at once + todo!() + } +} +``` + +**Key distinction from the previous design:** there's no "closest wins" or "margin" logic. Every domain gets a score, and *all* domains above threshold are assigned. A memory about "deploying zinit containers via BGP-routed network" might score 0.78 on "dev" and 0.72 on "infra" — it gets both. A memory about "solar panel output today" scores 0.85 on "home" and 0.31 on everything else — it only gets "home". + +The raw `domain_scores` are always stored, so you (or the dashboard) can see *why* a memory was classified the way it was, and the threshold can be adjusted retroactively without re-computing embeddings. + +#### Search Behavior + +- **Default (no domain filter)**: searches all memories across all domains +- **Domain-scoped**: `domains: Some(vec!["dev"])` — only memories tagged with `dev` +- **Multi-domain**: `domains: Some(vec!["dev", "infra"])` — memories in either +- **MCP clients can set `X-Vestige-Domain` header** for default scoping, but the system works fine without it + +#### HDBSCAN Implementation + +HDBSCAN (Hierarchical DBSCAN) over the embedding vectors. Advantages over plain DBSCAN: + +- **No `eps` parameter** — the hardest thing to tune in DBSCAN. HDBSCAN determines density thresholds from the data hierarchy. +- **Variable-density clusters** — a tight cluster of networking memories and a spread-out cluster of personal memories are both detected correctly. +- **Border points** — memories between clusters are identified as low-confidence members, which aligns perfectly with soft assignment. + +Implementation: the `hdbscan` crate in Rust. Load all embeddings into memory (at 768d × f32 × 10k memories ≈ 30MB — fine), cluster, compute centroids, soft-assign all memories against the centroids. + +```rust +use hdbscan::{Center, Hdbscan}; + +fn discover_domains( + embeddings: &[Vec], + min_cluster_size: usize, +) -> (Vec>, Vec>) { // (cluster → member indices, centroids) + let clusterer = Hdbscan::default(embeddings); + let labels = clusterer.cluster().unwrap(); + let centroids = clusterer.calc_centers(Center::Centroid, &labels).unwrap(); + + // Group indices by label, ignoring noise (-1) + let mut clusters: HashMap> = HashMap::new(); + for (i, &label) in labels.iter().enumerate() { + if label >= 0 { + clusters.entry(label).or_default().push(i); + } + } + (clusters.into_values().collect(), centroids) +} +``` + +After HDBSCAN produces hard clusters, the soft-assignment pass (Phase 3) immediately re-scores all memories — including the ones HDBSCAN assigned — against the computed centroids. So HDBSCAN's hard labels are only used to *define* the centroids. The actual domain assignments always come from the continuous similarity scores. + +This works identically for both SQLite and Postgres backends — clustering runs in Rust application code, results are written back to the storage layer. + +### Network Transport + +#### MCP over Streamable HTTP + +Extend the existing Axum server: + +```rust +// Alongside existing dashboard routes +let app = Router::new() + // Existing dashboard + .route("/api/health", get(health_handler)) + .route("/dashboard/*path", get(dashboard_handler)) + // New: MCP over HTTP + .route("/mcp", post(mcp_handler).get(mcp_sse_handler)) + // New: REST API + // X-Vestige-Domain header optionally scopes to a domain + .route("/api/v1/memories", post(create_memory).get(list_memories)) + .route("/api/v1/memories/:id", get(get_memory).put(update_memory).delete(delete_memory)) + .route("/api/v1/search", post(search_memories)) + .route("/api/v1/consolidate", post(trigger_consolidation)) + .route("/api/v1/stats", get(get_stats)) + .route("/api/v1/domains", get(list_domains)) + .route("/api/v1/domains/discover", post(trigger_discovery)) + .route("/api/v1/domains/:id", put(rename_domain).delete(merge_domain)) + // Auth on everything except health + .layer(middleware::from_fn(api_key_auth)); +``` + +#### Auth Middleware + +```rust +async fn api_key_auth( + State(store): State>, + request: axum::extract::Request, + next: middleware::Next, +) -> Result { + // Skip auth for health endpoint + if request.uri().path() == "/api/health" { + return Ok(next.run(request).await); + } + + let key = request.headers() + .get("Authorization") + .and_then(|v| v.to_str().ok()) + .and_then(|v| v.strip_prefix("Bearer ")) + .or_else(|| request.headers() + .get("X-API-Key") + .and_then(|v| v.to_str().ok())); + + match key { + Some(k) if verify_api_key(store.as_ref(), k).await => { + Ok(next.run(request).await) + } + _ => Err(StatusCode::UNAUTHORIZED), + } +} +``` + +#### Client Configuration + +```json +// Claude Desktop / Claude Code — single key, all domains +{ + "mcpServers": { + "vestige": { + "url": "http://vestige.local:3927/mcp", + "headers": { + "Authorization": "Bearer vst_a1b2c3..." + } + } + } +} +``` + +No domain header needed — searches all domains by default. The MCP tools include an optional `domain` parameter for scoped queries if the LLM or user wants to narrow down. + +Alternatively, scope a connection to a specific domain: + +```json +// Domain-scoped connection (e.g., for a home automation agent) +{ + "mcpServers": { + "vestige-home": { + "url": "http://vestige.local:3927/mcp", + "headers": { + "Authorization": "Bearer vst_e5f6g7...", + "X-Vestige-Domain": "home" + } + } + } +} +``` + +### Server Configuration + +```toml +# vestige.toml — full example for server mode +[server] +bind = "0.0.0.0:3927" # or mycelium IPv6 address +# tls_cert = "/path/to/cert.pem" # optional +# tls_key = "/path/to/key.pem" + +[auth] +enabled = true +# If false, no key required (local-only mode) + +[storage] +backend = "postgres" + +[storage.postgres] +url = "postgresql://vestige:secret@localhost:5432/vestige" +max_connections = 10 + +[embeddings] +provider = "fastembed" +model = "BAAI/bge-base-en-v1.5" +``` + +### CLI Extensions + +```bash +# Domain management (mostly automatic, but user can inspect/rename) +vestige domains list +# → dev Development (auto) memories: 87 top: Rust, trait, async, tokio +# → infra Infrastructure (auto) memories: 47 top: BGP, SONiC, VLAN, FRR +# → home Home (auto) memories: 31 top: solar, kWh, pool, ESPHome +# → (unclassified) memories: 12 + +vestige domains rename cluster_0 infra --label "Infrastructure" +vestige domains merge home personal --into home +vestige domains discover --force # re-run HDBSCAN now + +# Key management +vestige keys create --label "macbook" +# → Created key: vst_a1b2c3d4... (store this, shown once) + +vestige keys create --label "home-assistant" --scopes read --domains home +# → Created key: vst_e5f6g7h8... (read-only, home domain only) + +vestige keys list +# → macbook vst_a1b2... scopes: [read,write] domains: [all] +# → home-assistant vst_e5f6... scopes: [read] domains: [home] + +vestige keys revoke vst_a1b2c3d4... + +# Migration +vestige migrate --from sqlite --to postgres \ + --sqlite-path ~/.vestige/vestige.db \ + --postgres-url postgresql://localhost/vestige +``` + +## Implementation Plan + +### Phase 1: Storage Trait Extraction +- Define the `MemoryStore` trait (including domain methods) +- Refactor current SQLite code to implement it +- Add `domains TEXT[]` column to existing SQLite schema +- Verify all 29 modules work through the trait (no direct SQLite access) +- **No behavioral changes** — all memories start as unclassified + +### Phase 2: PostgreSQL Backend +- Implement `PgMemoryStore` +- Schema migrations (sqlx or refinery) +- `vestige migrate` command for SQLite → Postgres +- Config file support for backend selection + +### Phase 3: Network Access +- MCP Streamable HTTP endpoint on existing Axum server +- API key auth middleware + CLI management +- REST API endpoints +- Feature flags for stdio vs HTTP mode + +### Phase 4: Emergent Domain Classification +- `DomainClassifier` cognitive module +- HDBSCAN clustering via `hdbscan` crate (runs on both backends) +- Soft assignment pass: score all memories against centroids, threshold into domains +- `domain_scores` JSONB stored per memory for transparency / retroactive re-thresholding +- Domain discovery CLI and dashboard UI +- Auto-classification on ingest (once domains exist) +- Re-clustering during dream consolidation passes +- Domain management CLI (rename, merge, inspect) + +### Phase 5: Federation (future) +- Node discovery via Mycelium / mDNS +- Memory sync protocol (UUID-based, last-write-wins) +- Possibly Iroh for content-addressed replication +- FSRS state merge (review history append, not overwrite) + +## Crate Dependencies (new) + +```toml +# Phase 1 — trait abstraction +trait-variant = "0.1" + +# Phase 2 — Postgres +sqlx = { version = "0.8", features = ["runtime-tokio", "postgres", "uuid", "chrono", "json"] } +pgvector = "0.4" # sqlx integration for vector type + +# Phase 3 — Auth +blake3 = "1" # key hashing +rand = "0.8" # key generation + +# Phase 4 — Domain clustering +hdbscan = "0.10" # HDBSCAN — no eps tuning, variable density, built-in centroid calc +``` + +## Open Questions + +1. **Trait granularity**: One big `MemoryStore` trait or split into `MemoryStore + SchedulingStore + GraphStore + DomainStore`? Splitting is cleaner but means more `dyn` parameters threading through handlers. + +2. **Embedding on insert**: Should the storage backend call fastembed, or should the caller always provide the embedding? Current design says caller provides it, keeping the backend pure storage. But this means every client needs fastembed locally even if the DB is remote. For the server model, having the server compute embeddings makes more sense. + +3. **pgvector dimension**: Fixed (e.g., `vector(768)`) or unconstrained (`vector`)? Fixed is faster for HNSW but requires migration if model changes. + +4. **Sync conflict resolution for federation**: LWW per-UUID is simple but lossy. CRDTs would be more correct but massively more complex. For FSRS state specifically, merging review event logs would be ideal. + +5. **Dashboard auth**: The 3D dashboard currently runs unauthenticated on localhost. With remote access, it needs the same auth. Should it use the same API keys or have a separate session/cookie mechanism? + +6. **HDBSCAN `min_cluster_size`**: The main tuning knob. Too small → noisy micro-clusters. Too large → distinct topics get merged. Default of 10 should work for most cases, but may need a manual override or auto-sweep (run with several values, pick the one with best silhouette score). + +7. **Domain drift**: Over time, the character of a domain changes. How aggressively should re-clustering reshape existing domains? Conservative (only propose splits/merges, never auto-apply) vs. aggressive (auto-reassign memories whose scores drifted below threshold)? + +8. **Spreading activation across domains**: When searching within a single domain, should graph edges that cross into other domains be followed? Probably yes for recall quality, but with decaying weight as you cross boundaries. + +9. **Threshold tuning**: The `assign_threshold` (0.65 default) determines how many memories are multi-domain vs single-domain vs unclassified. Too low → everything is multi-domain (useless). Too high → too many unclassified. Could be auto-tuned per dataset by targeting a specific unclassified ratio (e.g., "keep fewer than 10% unclassified"). From 9c633c172b346980eacd5173e5aa66eea767836a Mon Sep 17 00:00:00 2001 From: Jan De Landtsheer Date: Wed, 22 Apr 2026 10:28:59 +0200 Subject: [PATCH 02/31] Added postgres admin added amends to the postgres backend/phase2 --- .gitignore | 3 + docs/plans/0002-phase-2-postgres-backend.md | 3 +- docs/plans/local-dev-postgres-setup.md | 153 ++++++++++++++++++++ 3 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 docs/plans/local-dev-postgres-setup.md diff --git a/.gitignore b/.gitignore index 4236e68..41e352a 100644 --- a/.gitignore +++ b/.gitignore @@ -137,3 +137,6 @@ apps/dashboard/node_modules/ # ============================================================================= fastembed-rs/ .mcp.json + +.claude/ +.codebase-memory/ diff --git a/docs/plans/0002-phase-2-postgres-backend.md b/docs/plans/0002-phase-2-postgres-backend.md index a372e27..3fe28f2 100644 --- a/docs/plans/0002-phase-2-postgres-backend.md +++ b/docs/plans/0002-phase-2-postgres-backend.md @@ -2,7 +2,7 @@ **Status**: Draft **Depends on**: Phase 1 (MemoryStore + Embedder traits, embedding_model registry, domain columns) -**Related**: docs/adr/0001-pluggable-storage-and-network-access.md (Phase 2), docs/prd/001-getting-centralized-vestige.md +**Related**: docs/adr/0001-pluggable-storage-and-network-access.md (Phase 2), docs/prd/001-getting-centralized-vestige.md, docs/plans/local-dev-postgres-setup.md (local cluster provisioning) --- @@ -85,6 +85,7 @@ postgres-backend = ["dep:sqlx", "dep:pgvector", "dep:tokio-stream", "dep:futures - The `pgvector` extension installed in the target database (our migration issues `CREATE EXTENSION IF NOT EXISTS vector`). - `sqlx-cli@0.8` installed on the developer machine for `cargo sqlx prepare --workspace` and `cargo sqlx migrate add` (not a build-time requirement once `.sqlx/` is committed). - Docker or Podman reachable by the test harness for `testcontainers-modules::postgres` to spin up `pgvector/pgvector:pg16`. +- A local Postgres cluster for `sqlx prepare`, manual migration work, and `vestige migrate --to postgres` smoke runs. The recipe for standing one up on Arch/CachyOS (install, initdb, role + db, pgvector, connection string at `~/.vestige_pg_pw`) lives in `docs/plans/local-dev-postgres-setup.md`. Postgres 18 from the Arch repo satisfies the "16 or newer" requirement above. Phase 2 work assumes `DATABASE_URL` points at that cluster once migrations are applied. ### Assumed Rust toolchain diff --git a/docs/plans/local-dev-postgres-setup.md b/docs/plans/local-dev-postgres-setup.md new file mode 100644 index 0000000..6250a55 --- /dev/null +++ b/docs/plans/local-dev-postgres-setup.md @@ -0,0 +1,153 @@ +# Local Dev Postgres Setup (Arch / CachyOS) + +**Status**: Applied on this machine on 2026-04-21 +**Related**: docs/plans/0002-phase-2-postgres-backend.md, docs/adr/0001-pluggable-storage-and-network-access.md + +Purpose: capture the minimum, repeatable steps to stand up a Postgres 18 instance on a local Arch/CachyOS box for Phase 2 (`PgMemoryStore`) development, `sqlx prepare`, and manual migration testing. This is a single-operator dev recipe, not a production runbook. + +--- + +## Current state on this machine + +- Package: `postgresql` 18.3-2 (pacman). Pulls `postgresql-libs`, `libxslt`. +- Service: `postgresql.service`, enabled + active. +- Listens on: `127.0.0.1:5432` and `[::1]:5432` only (default `listen_addresses = 'localhost'`). +- Data dir: `/var/lib/postgres/data`, owner `postgres:postgres`. +- Auth (`pg_hba.conf`, Arch defaults): `peer` for local socket, `scram-sha-256` for host 127.0.0.1/::1. + +### Database + role + +- Database: `vestige`, UTF8, owner `vestige`. +- Role: `vestige` with `LOGIN CREATEDB` (no superuser, no replication, no cross-db). +- Schema `public` re-owned to `vestige`, plus default privileges so any future tables / sequences / functions in `public` are fully owned and granted to `vestige`. + +Net effect: the `vestige` role can create, alter, drop, and grant freely inside the `vestige` database -- enough for `sqlx::migrate!`, ad-hoc schema work, and the full Phase 2 `MemoryStore` surface. It cannot create extensions (see Phase 2 followups below) and cannot touch other databases. + +### Connection + +``` +postgresql://vestige:@127.0.0.1:5432/vestige +``` + +Password lives at `~/.vestige_pg_pw`, mode 600, owned by the dev user (no sudo needed to read it). Read with: + +```sh +cat ~/.vestige_pg_pw +``` + +Recommended dev shell export (keep this OUT of the repo; use `.env` + gitignore or a shell rc): + +```sh +export DATABASE_URL="postgresql://vestige:$(cat ~/.vestige_pg_pw)@127.0.0.1:5432/vestige" +``` + +--- + +## Reproduce from scratch + +On a fresh Arch / CachyOS box with passwordless sudo: + +```sh +# 1. Install +sudo pacman -S --noconfirm postgresql + +# 2. Initialize the cluster (UTF8, scram-sha-256 for host, peer for local) +sudo -iu postgres initdb \ + --locale=C.UTF-8 --encoding=UTF8 \ + -D /var/lib/postgres/data \ + --auth-host=scram-sha-256 --auth-local=peer + +# 3. Start + enable +sudo systemctl enable --now postgresql + +# 4. Generate a password and stash it in the dev user's home (mode 600) +VESTIGE_PW=$(python3 -c 'import secrets,string; a=string.ascii_letters+string.digits; print("".join(secrets.choice(a) for _ in range(32)))') +umask 077 +printf '%s' "$VESTIGE_PW" > ~/.vestige_pg_pw +chmod 600 ~/.vestige_pg_pw + +# 5. Create role + database + grants +sudo -u postgres psql -v ON_ERROR_STOP=1 < ~/.vestige_pg_pw +chmod 600 ~/.vestige_pg_pw +sudo -u postgres psql -v ON_ERROR_STOP=1 \ + -c "ALTER ROLE vestige WITH PASSWORD '${NEW_PW}';" +unset NEW_PW +``` + +Then re-export `DATABASE_URL` in any live shells. + +--- + +## Teardown + +Destroys the cluster and all data in it: + +```sh +sudo systemctl disable --now postgresql +sudo pacman -Rns postgresql postgresql-libs +sudo rm -rf /var/lib/postgres +rm -f ~/.vestige_pg_pw +``` + +--- + +## Out of scope for this doc + +- TLS, client-cert auth, non-localhost access. Phase 3 exposes the Vestige HTTP API over the network, not Postgres directly. +- Backups, PITR, WAL archiving. For dev data: `pg_dump -h 127.0.0.1 -U vestige vestige > vestige.sql`. +- Replication, PgBouncer, tuned `postgresql.conf`. Defaults are fine for Phase 2 development. +- Making this the canonical Vestige backend. By default Vestige still uses SQLite; this cluster exists so the `postgres-backend` feature can be built and tested locally. From 4e9e11ac0b2c47722400c7500643c559ea47abea Mon Sep 17 00:00:00 2001 From: Sam Valladares Date: Fri, 1 May 2026 05:37:27 -0500 Subject: [PATCH 03/31] Fix dense dream connection persistence Fixes #50 --- CHANGELOG.md | 6 + crates/vestige-core/src/advanced/dreams.rs | 111 ++++++++++++++++--- crates/vestige-mcp/src/dashboard/handlers.rs | 13 +-- crates/vestige-mcp/src/tools/dream.rs | 81 +++++++++++--- 4 files changed, 165 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 413a4eb..b370c3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to Vestige will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Fixed + +- **Dream connection persistence cap** — dense single-domain dreams now persist every connection discovered in that run instead of losing everything beyond the old 1,000-entry live buffer. The live dreamer buffer now keeps up to 200,000 high-scoring recent connections, and the MCP `dream` tool exposes `min_similarity` for corpus-specific tuning. + ## [2.1.1] - 2026-05-01 — "Portable Sync" v2.1.1 focuses on user-controlled portability: exact storage archives, merge-safe file sync, pluggable sync backends, and explicit hook opt-ins. diff --git a/crates/vestige-core/src/advanced/dreams.rs b/crates/vestige-core/src/advanced/dreams.rs index d01d8e2..5cf3492 100644 --- a/crates/vestige-core/src/advanced/dreams.rs +++ b/crates/vestige-core/src/advanced/dreams.rs @@ -93,6 +93,9 @@ const CONNECTION_DECAY_FACTOR: f64 = 0.95; /// Minimum connection strength to keep const MIN_CONNECTION_STRENGTH: f64 = 0.1; +/// Maximum discovered connections kept in the live dreamer buffer. +const MAX_STORED_DREAM_CONNECTIONS: usize = 200_000; + /// Maximum memories to replay per cycle const MAX_REPLAY_MEMORIES: usize = 100; @@ -1129,44 +1132,81 @@ impl MemoryDreamer { /// Run a dream cycle on provided memories pub async fn dream(&self, memories: &[DreamMemory]) -> DreamResult { + self.dream_with_connections(memories).await.0 + } + + /// Run a dream cycle with a temporary config. + pub async fn dream_with_config( + &self, + memories: &[DreamMemory], + config: DreamConfig, + ) -> DreamResult { + self.dream_with_config_and_connections(memories, config) + .await + .0 + } + + /// Run a dream cycle and return the exact connections found in that run. + pub async fn dream_with_connections( + &self, + memories: &[DreamMemory], + ) -> (DreamResult, Vec) { + self.run_dream(memories, &self.config).await + } + + /// Run a dream cycle with a temporary config and return this run's connections. + pub async fn dream_with_config_and_connections( + &self, + memories: &[DreamMemory], + config: DreamConfig, + ) -> (DreamResult, Vec) { + self.run_dream(memories, &config).await + } + + async fn run_dream( + &self, + memories: &[DreamMemory], + config: &DreamConfig, + ) -> (DreamResult, Vec) { let start = std::time::Instant::now(); let mut stats = DreamStats::default(); // Filter memories based on config - let working_memories: Vec<_> = if self.config.focus_tags.is_empty() { + let working_memories: Vec<_> = if config.focus_tags.is_empty() { memories .iter() - .take(self.config.max_memories_per_dream) + .take(config.max_memories_per_dream) .collect() } else { memories .iter() - .filter(|m| m.tags.iter().any(|t| self.config.focus_tags.contains(t))) - .take(self.config.max_memories_per_dream) + .filter(|m| m.tags.iter().any(|t| config.focus_tags.contains(t))) + .take(config.max_memories_per_dream) .collect() }; stats.memories_analyzed = working_memories.len(); // Phase 1: Discover new connections - let new_connections = self.discover_connections(&working_memories, &mut stats); + let new_connections = + self.discover_connections(&working_memories, &mut stats, config.min_similarity); // Phase 2: Find clusters/patterns let clusters = self.find_clusters(&working_memories, &new_connections); stats.clusters_found = clusters.len(); // Phase 3: Generate insights - let insights = self.generate_insights(&working_memories, &clusters, &mut stats); + let insights = self.generate_insights(&working_memories, &clusters, &mut stats, config); // Phase 4: Strengthen important memories (would update storage) - let memories_strengthened = if self.config.enable_strengthening { + let memories_strengthened = if config.enable_strengthening { self.identify_memories_to_strengthen(&working_memories, &new_connections) } else { 0 }; // Phase 5: Identify compression candidates (would compress in storage) - let memories_compressed = if self.config.enable_compression { + let memories_compressed = if config.enable_compression { self.identify_compression_candidates(&working_memories) } else { 0 @@ -1195,7 +1235,7 @@ impl MemoryDreamer { } } - result + (result, new_connections) } /// Synthesize insights from memories without full dream cycle @@ -1203,12 +1243,20 @@ impl MemoryDreamer { let mut stats = DreamStats::default(); // Find clusters - let connections = - self.discover_connections(&memories.iter().collect::>(), &mut stats); + let connections = self.discover_connections( + &memories.iter().collect::>(), + &mut stats, + self.config.min_similarity, + ); let clusters = self.find_clusters(&memories.iter().collect::>(), &connections); // Generate insights - self.generate_insights(&memories.iter().collect::>(), &clusters, &mut stats) + self.generate_insights( + &memories.iter().collect::>(), + &clusters, + &mut stats, + &self.config, + ) } /// Get all generated insights @@ -1257,6 +1305,7 @@ impl MemoryDreamer { &self, memories: &[&DreamMemory], stats: &mut DreamStats, + min_similarity: f64, ) -> Vec { let mut connections = Vec::new(); @@ -1271,7 +1320,7 @@ impl MemoryDreamer { // Calculate similarity let similarity = self.calculate_similarity(mem_a, mem_b); - if similarity >= self.config.min_similarity { + if similarity >= min_similarity { let connection_type = self.determine_connection_type(mem_a, mem_b, similarity); let reasoning = self.generate_connection_reasoning(mem_a, mem_b, &connection_type); @@ -1464,6 +1513,7 @@ impl MemoryDreamer { memories: &[&DreamMemory], clusters: &[Vec], stats: &mut DreamStats, + config: &DreamConfig, ) -> Vec { let mut insights = Vec::new(); let memory_map: HashMap<_, _> = memories.iter().map(|m| (&m.id, *m)).collect(); @@ -1483,12 +1533,12 @@ impl MemoryDreamer { // Try to generate insight from this cluster if let Some(insight) = self.generate_insight_from_cluster(&cluster_memories) - && insight.novelty_score >= self.config.min_novelty + && insight.novelty_score >= config.min_novelty { insights.push(insight); } - if insights.len() >= self.config.max_insights { + if insights.len() >= config.max_insights { break; } } @@ -1706,7 +1756,7 @@ impl MemoryDreamer { fn store_connections(&self, connections: &[DiscoveredConnection]) { if let Ok(mut stored) = self.connections.write() { stored.extend(connections.iter().cloned()); - // Keep the 1000 highest-scoring connections using a composite score + // Keep the highest-scoring connections using a composite score // that balances quality (similarity) and recency (age-based decay). // // score = similarity * 0.6 + recency * 0.4 @@ -1721,7 +1771,7 @@ impl MemoryDreamer { // Strong old connections are retained longer than weak new ones, // but eventually yield to fresh high-quality discoveries. let len = stored.len(); - if len > 1000 { + if len > MAX_STORED_DREAM_CONNECTIONS { let now = Utc::now(); stored.sort_unstable_by(|a, b| { let score = |c: &DiscoveredConnection| -> f64 { @@ -1737,7 +1787,7 @@ impl MemoryDreamer { .partial_cmp(&score(a)) .unwrap_or(std::cmp::Ordering::Equal) }); - stored.truncate(1000); + stored.truncate(MAX_STORED_DREAM_CONNECTIONS); } } } @@ -1854,6 +1904,31 @@ mod tests { assert!(result.stats.connections_evaluated > 0); } + #[tokio::test] + async fn test_dense_dream_keeps_more_than_legacy_connection_cap() { + let dreamer = MemoryDreamer::with_config(DreamConfig { + max_memories_per_dream: 50, + min_similarity: 0.1, + ..DreamConfig::default() + }); + + let memories: Vec<_> = (0..50) + .map(|i| { + make_memory( + &format!("dense-{i}"), + &format!("Dense single-domain memory {i} about shared identity systems"), + vec!["dense", "identity"], + ) + }) + .collect(); + + let (result, connections) = dreamer.dream_with_connections(&memories).await; + + assert_eq!(result.new_connections_found, 1_225); + assert_eq!(connections.len(), 1_225); + assert_eq!(dreamer.get_connections().len(), 1_225); + } + #[test] fn test_tag_similarity() { let dreamer = MemoryDreamer::new(); diff --git a/crates/vestige-mcp/src/dashboard/handlers.rs b/crates/vestige-mcp/src/dashboard/handlers.rs index 99a278f..78e3b87 100644 --- a/crates/vestige-mcp/src/dashboard/handlers.rs +++ b/crates/vestige-mcp/src/dashboard/handlers.rs @@ -858,23 +858,14 @@ pub async fn trigger_dream(State(state): State) -> Result, // Run dream through CognitiveEngine let cog = cognitive.lock().await; - // Capture start time before the dream — composite-score eviction in store_connections - // reorders the buffer, making positional slicing (pre_dream_count..) unreliable. - let dream_start = Utc::now(); - let dream_result = cog.dreamer.dream(&dream_memories).await; + let (dream_result, new_connections) = cog.dreamer.dream_with_connections(&dream_memories).await; let insights = cog.dreamer.synthesize_insights(&dream_memories); - let all_connections = cog.dreamer.get_connections(); drop(cog); // Persist new connections - // Filter by timestamp — same approach as dream.rs to avoid positional index issues. - let new_connections: Vec<&vestige_core::DiscoveredConnection> = all_connections - .iter() - .filter(|c| c.discovered_at >= dream_start) - .collect(); let mut connections_persisted = 0u64; let now = Utc::now(); - for conn in new_connections.iter() { + for conn in &new_connections { let link_type = match conn.connection_type { vestige_core::DiscoveredConnectionType::Semantic => "semantic", vestige_core::DiscoveredConnectionType::SharedConcept => "shared_concepts", diff --git a/crates/vestige-mcp/src/tools/dream.rs b/crates/vestige-mcp/src/tools/dream.rs index 357315f..65a373b 100644 --- a/crates/vestige-mcp/src/tools/dream.rs +++ b/crates/vestige-mcp/src/tools/dream.rs @@ -16,6 +16,13 @@ pub fn schema() -> serde_json::Value { "type": "integer", "description": "Number of recent memories to dream about (default: 50)", "default": 50 + }, + "min_similarity": { + "type": "number", + "description": "Minimum similarity for connection discovery (0.0-1.0, default: 0.5)", + "minimum": 0.0, + "maximum": 1.0, + "default": 0.5 } } }) @@ -32,6 +39,11 @@ pub async fn execute( .and_then(|v| v.as_u64()) .unwrap_or(50) .min(500) as usize; // Cap at 500 to prevent O(N^2) hang + let min_similarity = args + .as_ref() + .and_then(|a| a.get("min_similarity")) + .and_then(|v| v.as_f64()) + .map(|v| v.clamp(0.0, 1.0)); // v1.9.0: Waking SWR tagging — preferential replay of tagged memories (70/30 split) let tagged_nodes = storage @@ -95,15 +107,18 @@ pub async fn execute( .collect(); let cog = cognitive.lock().await; - // Capture start time before the dream so we can identify newly discovered - // connections by timestamp rather than by buffer position. This is robust - // against the composite-score eviction sort in store_connections, which - // reorders the buffer and makes positional slicing (pre_dream_count..) - // unreliable. - let dream_start = Utc::now(); - let dream_result = cog.dreamer.dream(&dream_memories).await; + let (dream_result, new_connections) = if let Some(min_similarity) = min_similarity { + let config = vestige_core::DreamConfig { + min_similarity, + ..vestige_core::DreamConfig::default() + }; + cog.dreamer + .dream_with_config_and_connections(&dream_memories, config) + .await + } else { + cog.dreamer.dream_with_connections(&dream_memories).await + }; let insights = cog.dreamer.synthesize_insights(&dream_memories); - let all_connections = cog.dreamer.get_connections(); drop(cog); // v2.1.0: Persist dream insights to database (Bug #4 fix) @@ -126,17 +141,10 @@ pub async fn execute( } } - // Identify new connections from this dream by timestamp rather than buffer - // position — positional slicing is broken after composite-score eviction - // reorders the buffer. - let new_connections: Vec<&vestige_core::DiscoveredConnection> = all_connections - .iter() - .filter(|c| c.discovered_at >= dream_start) - .collect(); let mut connections_persisted = 0u64; { let now = Utc::now(); - for conn in new_connections.iter() { + for conn in &new_connections { let link_type = match conn.connection_type { vestige_core::DiscoveredConnectionType::Semantic => "semantic", vestige_core::DiscoveredConnectionType::SharedConcept => "shared_concepts", @@ -178,7 +186,7 @@ pub async fn execute( // Hydrate live cognitive engine with newly persisted connections if connections_persisted > 0 { let mut cog = cognitive.lock().await; - for conn in new_connections.iter() { + for conn in &new_connections { let link_type_enum = match conn.connection_type { vestige_core::DiscoveredConnectionType::Semantic => LinkType::Semantic, vestige_core::DiscoveredConnectionType::SharedConcept => LinkType::Semantic, @@ -286,6 +294,9 @@ mod tests { assert_eq!(s["type"], "object"); assert!(s["properties"]["memory_count"].is_object()); assert_eq!(s["properties"]["memory_count"]["default"], 50); + assert!(s["properties"]["min_similarity"].is_object()); + assert_eq!(s["properties"]["min_similarity"]["minimum"], 0.0); + assert_eq!(s["properties"]["min_similarity"]["maximum"], 1.0); } #[tokio::test] @@ -616,6 +627,42 @@ mod tests { ); } + #[tokio::test] + async fn test_dream_persists_dense_connection_set_above_legacy_buffer_cap() { + let (storage, _dir) = test_storage().await; + ingest_n_memories(&storage, 50).await; + + let result = execute( + &storage, + &test_cognitive(), + Some(serde_json::json!({ + "memory_count": 50, + "min_similarity": 0.1 + })), + ) + .await + .unwrap(); + + assert_eq!(result["status"], "dreamed"); + let found = result["stats"]["new_connections_found"] + .as_u64() + .unwrap_or(0); + let persisted = result["connectionsPersisted"].as_u64().unwrap_or(0); + + assert!( + found > 1_000, + "test setup should discover more than the legacy 1,000 connection cap" + ); + assert_eq!( + persisted, found, + "dense dreams should persist every connection discovered in the run" + ); + assert_eq!( + storage.get_all_connections().unwrap().len(), + persisted as usize + ); + } + #[tokio::test] async fn test_dream_persists_insights() { let (storage, _dir) = test_storage().await; From fb250207a3c90223ce62688bb6d9840d3400fba8 Mon Sep 17 00:00:00 2001 From: Sam Valladares Date: Fri, 1 May 2026 05:48:28 -0500 Subject: [PATCH 04/31] Fix embedding model upgrade consolidation Fixes #51 --- CHANGELOG.md | 1 + README.md | 2 +- crates/vestige-core/src/storage/sqlite.rs | 251 ++++++++++++---------- 3 files changed, 143 insertions(+), 111 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b370c3c..53dddd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - **Dream connection persistence cap** — dense single-domain dreams now persist every connection discovered in that run instead of losing everything beyond the old 1,000-entry live buffer. The live dreamer buffer now keeps up to 200,000 high-scoring recent connections, and the MCP `dream` tool exposes `min_similarity` for corpus-specific tuning. +- **Embedding-model upgrade repair** — `vestige consolidate` now re-embeds every missing or active-model-mismatched memory in one pass, so v1/v2 mixed stores are no longer left partially unreachable after only the first 100 legacy embeddings are regenerated. ## [2.1.1] - 2026-05-01 — "Portable Sync" diff --git a/README.md b/README.md index ff34566..334c3b6 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ v2.1.1 focuses on the biggest post-launch ask: move memories between machines wi - **Exact portable archives.** `vestige portable-export` / `vestige portable-import` preserve IDs, FSRS state, graph edges, suppression state, audit rows, and embedding blobs for Vestige-to-Vestige device transfer. - **Sync-safe merge storage.** `vestige portable-import --merge` and `vestige sync ` merge non-empty databases, apply delete tombstones, keep newer local memories, rebuild FTS, and push through a pluggable portable-sync backend. v2.1.1 ships the file backend for Dropbox, iCloud, Syncthing, Git, and shared folders. -- **Qwen3 embeddings.** Build with `qwen3-embeddings`, set `VESTIGE_EMBEDDING_MODEL=qwen3-0.6b`, and run `vestige consolidate` to re-embed existing memories. +- **Qwen3 embeddings.** Build with `qwen3-embeddings`, set `VESTIGE_EMBEDDING_MODEL=qwen3-0.6b`, and run `vestige consolidate` to re-embed existing memories. `vestige health` reports mixed-model stores before search quality is affected. - **Model-aware retrieval.** Vestige now avoids comparing Qwen and Nomic vectors in the same search/dedup path. ## What's New in v2.1.0 "Cognitive Sandwich Goes Local" diff --git a/crates/vestige-core/src/storage/sqlite.rs b/crates/vestige-core/src/storage/sqlite.rs index fbe3c7c..ddc17dd 100644 --- a/crates/vestige-core/src/storage/sqlite.rs +++ b/crates/vestige-core/src/storage/sqlite.rs @@ -2409,73 +2409,7 @@ impl Storage { let mut result = EmbeddingResult::default(); let active_model = self.embedding_service.model_name(); - let model_pattern = Self::active_embedding_model_like_pattern(active_model); - - let nodes: Vec<(String, String, Option)> = { - let reader = self - .reader - .lock() - .map_err(|_| StorageError::Init("Reader lock poisoned".into()))?; - if let Some(ids) = node_ids { - let placeholders = ids.iter().map(|_| "?").collect::>().join(","); - let query = format!( - "SELECT kn.id, kn.content, COALESCE(ne.model, kn.embedding_model) AS embedding_model - FROM knowledge_nodes kn - LEFT JOIN node_embeddings ne ON ne.node_id = kn.id - WHERE kn.id IN ({})", - placeholders - ); - - let mut result_nodes = Vec::new(); - { - let mut stmt = reader.prepare(&query)?; - let params: Vec<&dyn rusqlite::ToSql> = - ids.iter().map(|s| s as &dyn rusqlite::ToSql).collect(); - - let rows = stmt.query_map(params.as_slice(), |row| { - Ok(( - row.get::<_, String>(0)?, - row.get::<_, String>(1)?, - row.get::<_, Option>(2)?, - )) - })?; - - for r in rows.flatten() { - result_nodes.push(r); - } - } - result_nodes - } else if force { - let mut stmt = - reader.prepare("SELECT id, content, embedding_model FROM knowledge_nodes")?; - let rows = stmt.query_map([], |row| { - Ok(( - row.get::<_, String>(0)?, - row.get::<_, String>(1)?, - row.get::<_, Option>(2)?, - )) - })?; - rows.filter_map(|r| r.ok()).collect() - } else { - let mut stmt = reader.prepare( - "SELECT kn.id, kn.content, COALESCE(ne.model, kn.embedding_model) AS embedding_model - FROM knowledge_nodes kn - LEFT JOIN node_embeddings ne ON ne.node_id = kn.id - WHERE kn.has_embedding = 0 - OR kn.has_embedding IS NULL - OR ne.node_id IS NULL - OR COALESCE(ne.model, kn.embedding_model, '') NOT LIKE ?1", - )?; - let rows = stmt.query_map(params![model_pattern], |row| { - Ok(( - row.get::<_, String>(0)?, - row.get::<_, String>(1)?, - row.get::<_, Option>(2)?, - )) - })?; - rows.filter_map(|r| r.ok()).collect() - } - }; + let nodes = self.embedding_regeneration_candidates(node_ids, force)?; for (id, content, stored_model) in nodes { if !force { @@ -2491,7 +2425,7 @@ impl Storage { params![&id], |row| Ok((row.get(0)?, row.get(1)?)), ) - .unwrap_or_else(|_| (0, stored_model)); + .unwrap_or((0, stored_model)); if has_emb == 1 && stored_model.as_deref().is_some_and(|model| { @@ -2515,6 +2449,78 @@ impl Storage { Ok(result) } + #[cfg(all(feature = "embeddings", feature = "vector-search"))] + fn embedding_regeneration_candidates( + &self, + node_ids: Option<&[String]>, + force: bool, + ) -> Result)>> { + let reader = self + .reader + .lock() + .map_err(|_| StorageError::Init("Reader lock poisoned".into()))?; + + if let Some(ids) = node_ids { + if ids.is_empty() { + return Ok(Vec::new()); + } + + let placeholders = ids.iter().map(|_| "?").collect::>().join(","); + let query = format!( + "SELECT kn.id, kn.content, COALESCE(ne.model, kn.embedding_model) AS embedding_model + FROM knowledge_nodes kn + LEFT JOIN node_embeddings ne ON ne.node_id = kn.id + WHERE kn.id IN ({})", + placeholders + ); + + let mut stmt = reader.prepare(&query)?; + let params: Vec<&dyn rusqlite::ToSql> = + ids.iter().map(|s| s as &dyn rusqlite::ToSql).collect(); + let rows = stmt.query_map(params.as_slice(), |row| { + Ok(( + row.get::<_, String>(0)?, + row.get::<_, String>(1)?, + row.get::<_, Option>(2)?, + )) + })?; + return Ok(rows.filter_map(|r| r.ok()).collect()); + } + + if force { + let mut stmt = + reader.prepare("SELECT id, content, embedding_model FROM knowledge_nodes")?; + let rows = stmt.query_map([], |row| { + Ok(( + row.get::<_, String>(0)?, + row.get::<_, String>(1)?, + row.get::<_, Option>(2)?, + )) + })?; + return Ok(rows.filter_map(|r| r.ok()).collect()); + } + + let active_model = self.embedding_service.model_name(); + let model_pattern = Self::active_embedding_model_like_pattern(active_model); + let mut stmt = reader.prepare( + "SELECT kn.id, kn.content, COALESCE(ne.model, kn.embedding_model) AS embedding_model + FROM knowledge_nodes kn + LEFT JOIN node_embeddings ne ON ne.node_id = kn.id + WHERE kn.has_embedding = 0 + OR kn.has_embedding IS NULL + OR ne.node_id IS NULL + OR COALESCE(ne.model, kn.embedding_model, '') NOT LIKE ?1", + )?; + let rows = stmt.query_map(params![model_pattern], |row| { + Ok(( + row.get::<_, String>(0)?, + row.get::<_, String>(1)?, + row.get::<_, Option>(2)?, + )) + })?; + Ok(rows.filter_map(|r| r.ok()).collect()) + } + /// Query memories valid at a specific time pub fn query_at_time( &self, @@ -2788,7 +2794,8 @@ impl Storage { } } - // 3. Generate missing embeddings + // 3. Generate missing and model-mismatched embeddings. + // This must drain the whole set so embedder upgrades do not strand v1 corpora. #[cfg(all(feature = "embeddings", feature = "vector-search"))] let embeddings_generated = self.generate_missing_embeddings()?; #[cfg(not(all(feature = "embeddings", feature = "vector-search")))] @@ -3342,7 +3349,7 @@ impl Storage { Ok(Some(optimized_w20)) } - /// Generate missing embeddings + /// Generate all missing or active-model-mismatched embeddings. #[cfg(all(feature = "embeddings", feature = "vector-search"))] fn generate_missing_embeddings(&self) -> Result { if !self.embedding_service.is_ready() @@ -3352,41 +3359,15 @@ impl Storage { return Ok(0); } - let active_model = self.embedding_service.model_name(); - let model_pattern = Self::active_embedding_model_like_pattern(active_model); - - let nodes: Vec<(String, String)> = { - let reader = self - .reader - .lock() - .map_err(|_| StorageError::Init("Reader lock poisoned".into()))?; - reader - .prepare( - "SELECT kn.id, kn.content - FROM knowledge_nodes kn - LEFT JOIN node_embeddings ne ON ne.node_id = kn.id - WHERE kn.has_embedding = 0 - OR kn.has_embedding IS NULL - OR ne.node_id IS NULL - OR COALESCE(ne.model, kn.embedding_model, '') NOT LIKE ?1 - LIMIT 100", - )? - .query_map(params![model_pattern], |row| Ok((row.get(0)?, row.get(1)?)))? - .filter_map(|r| r.ok()) - .collect() - }; - - let mut count = 0i64; - - for (id, content) in nodes { - if let Err(e) = self.generate_embedding_for_node(&id, &content) { - tracing::warn!("Failed to generate embedding for {}: {}", id, e); - } else { - count += 1; - } + let result = self.generate_embeddings(None, false)?; + if result.failed > 0 { + tracing::warn!( + failed = result.failed, + "Some embeddings could not be regenerated during consolidation" + ); } - Ok(count) + Ok(result.successful) } } @@ -4308,7 +4289,7 @@ impl Storage { let mut latest: Option> = None; - if let Ok(entries) = std::fs::read_dir(&backup_dir) { + if let Ok(entries) = std::fs::read_dir(backup_dir) { for entry in entries.flatten() { let name = entry.file_name(); let name_str = name.to_string_lossy(); @@ -4730,12 +4711,11 @@ impl Storage { .as_deref() .and_then(Self::parse_rfc3339_opt), incoming_updated, - ) { - if existing > incoming { - report.conflicts_kept_local += 1; - report.rows_skipped += 1; - continue; - } + ) && existing > incoming + { + report.conflicts_kept_local += 1; + report.rows_skipped += 1; + continue; } let affected = Self::insert_or_replace_row(tx, "knowledge_nodes", table, row)?; @@ -5656,6 +5636,57 @@ mod tests { ); } + #[cfg(all(feature = "embeddings", feature = "vector-search"))] + #[test] + fn test_embedding_regeneration_candidates_include_entire_mismatched_corpus() { + let storage = create_test_storage(); + let stale_model = "all-MiniLM-L6-v2"; + let stale_embedding = Embedding::new(vec![0.0; EMBEDDING_DIMENSIONS]).to_bytes(); + + for i in 0..125 { + let node = storage + .ingest(IngestInput { + content: format!("legacy embedded memory {}", i), + node_type: "fact".to_string(), + ..Default::default() + }) + .unwrap(); + + let writer = storage.writer.lock().unwrap(); + writer + .execute( + "INSERT OR REPLACE INTO node_embeddings + (node_id, embedding, dimensions, model, created_at) + VALUES (?1, ?2, ?3, ?4, ?5)", + rusqlite::params![ + &node.id, + &stale_embedding, + EMBEDDING_DIMENSIONS as i32, + stale_model, + Utc::now().to_rfc3339() + ], + ) + .unwrap(); + writer + .execute( + "UPDATE knowledge_nodes + SET has_embedding = 1, embedding_model = ?2 + WHERE id = ?1", + rusqlite::params![&node.id, stale_model], + ) + .unwrap(); + } + + let stats = storage.get_stats().unwrap(); + assert_eq!(stats.nodes_with_mismatched_embeddings, 125); + assert_eq!(stats.nodes_with_active_embeddings, 0); + + let candidates = storage + .embedding_regeneration_candidates(None, false) + .unwrap(); + assert_eq!(candidates.len(), 125); + } + #[test] fn test_storage_creation() { let storage = create_test_storage(); From c77b05078ced73126585518a74575f875063e6a7 Mon Sep 17 00:00:00 2001 From: Sam Valladares Date: Fri, 1 May 2026 13:33:54 -0500 Subject: [PATCH 05/31] Add simple Vestige update flow --- README.md | 28 +- assets/vestige-icon.png | Bin 0 -> 40428 bytes crates/vestige-mcp/src/bin/cli.rs | 653 +++++++++++++++++++++++++- docs/COGNITIVE_SANDWICH.md | 21 +- docs/CONFIGURATION.md | 16 + docs/INSTALL-INTEL-MAC.md | 5 +- docs/blog/xcode-memory.md | 6 +- docs/integrations/xcode.md | 5 +- docs/launch/demo-script.md | 11 +- docs/launch/reddit-cross-reference.md | 4 +- docs/launch/show-hn.md | 3 +- packages/vestige-init/bin/init.js | 7 +- packages/vestige-mcp-npm/README.md | 11 + packages/vestige-mcp-npm/package.json | 3 +- scripts/install-sandwich.sh | 4 +- server.json | 21 + 16 files changed, 733 insertions(+), 65 deletions(-) create mode 100644 assets/vestige-icon.png create mode 100644 server.json diff --git a/README.md b/README.md index 334c3b6..84a2dcd 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ v2.1.1 focuses on the biggest post-launch ask: move memories between machines wi v2.1.0 adds an opt-in Claude Code hook harness around the existing Vestige MCP server. The MCP tool surface and database schema stay backward compatible, while preflight hooks can inject trusted memory context before Claude answers. The heavyweight Sanhedrin verifier is optional and can be enabled separately. - **Optional Sanhedrin Executioner.** The post-response verifier is off by default. Users can enable it with an OpenAI-compatible endpoint on x86/Linux/Intel Mac, or add `--with-launchd` on Apple Silicon to run the local MLX Qwen backend. -- **One-command Cognitive Sandwich installer.** `scripts/install-sandwich.sh` stages hook files and agents by default, removes old Vestige hook wiring, and leaves all Claude Code hook layers plus the 19 GB model path opt-in. +- **One-command Cognitive Sandwich installer.** `vestige sandwich install` stages hook files and agents by default, removes old Vestige hook wiring, and leaves all Claude Code hook layers plus the 19 GB model path opt-in. - **Pulse hook backed by `/api/changelog`.** Fresh dream and connection events can be injected into the next Claude Code prompt context without blocking the prompt. - **`VESTIGE_DATA_DIR` support.** `--data-dir` now has an env-var fallback, tilde expansion, secure directory creation, and clear precedence docs. - **NPM release wrapper fixed.** `vestige-mcp-server@2.1.0` now downloads binaries from the matching `v2.1.0` GitHub release tag instead of an old hardcoded release. @@ -103,15 +103,14 @@ Based on [Anderson et al. 2025](https://www.nature.com/articles/s41583-025-00929 ## Quick Start ```bash -# 1. Install (macOS Apple Silicon) -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-aarch64-apple-darwin.tar.gz | tar -xz -sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/ +# 1. Install +npm install -g vestige-mcp-server@latest # 2. Connect to Claude Code claude mcp add vestige vestige-mcp -s user # Or connect to Codex -codex mcp add vestige -- /usr/local/bin/vestige-mcp +codex mcp add vestige -- vestige-mcp # 3. Test it # "Remember that I prefer TypeScript over JavaScript" @@ -123,18 +122,25 @@ codex mcp add vestige -- /usr/local/bin/vestige-mcp

Other platforms & install methods -**Linux (x86_64):** +**Updating an existing install:** ```bash -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-x86_64-unknown-linux-gnu.tar.gz | tar -xz -sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/ +vestige update +``` + +`vestige update` updates the binaries and refreshes Cognitive Sandwich companion +files while keeping every hook layer disabled by default. Use +`vestige update --no-sandwich` if you only want the binaries. + +**macOS/Linux manual binary install:** +```bash +vestige update --install-dir /usr/local/bin ``` **macOS (Intel):** Microsoft is discontinuing x86_64 macOS prebuilts after ONNX Runtime v1.23.0, so Vestige's Intel Mac build links dynamically against a Homebrew-installed ONNX Runtime via the `ort-dynamic` feature. Install with: ```bash brew install onnxruntime -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-x86_64-apple-darwin.tar.gz | tar -xz -sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/ +npm install -g vestige-mcp-server@latest echo 'export ORT_DYLIB_PATH="'"$(brew --prefix onnxruntime)"'/lib/libonnxruntime.dylib"' >> ~/.zshrc source ~/.zshrc claude mcp add vestige vestige-mcp -s user @@ -163,7 +169,7 @@ Open `%APPDATA%\Claude\claude_desktop_config.json` and point Claude Desktop at t } ``` -If Claude Desktop cannot find `vestige-mcp`, run `where vestige-mcp` in PowerShell and use the exact `.cmd` path it prints as `command`. Example: `"C:\\Users\\you\\AppData\\Roaming\\npm\\vestige-mcp.cmd"`. Reopen Claude Desktop after saving. Once v2.1.0 is installed, future binary updates can run with `vestige update`. +If Claude Desktop cannot find `vestige-mcp`, run `where vestige-mcp` in PowerShell and use the exact `.cmd` path it prints as `command`. Example: `"C:\\Users\\you\\AppData\\Roaming\\npm\\vestige-mcp.cmd"`. Reopen Claude Desktop after saving. Future binary and companion-file updates can run with `vestige update`. **Windows source build:** Prebuilt binaries ship but `usearch 2.24.0` hit an MSVC compile break ([usearch#746](https://github.com/unum-cloud/usearch/issues/746)); we've pinned `=2.23.0` until upstream fixes it. Source builds work with: diff --git a/assets/vestige-icon.png b/assets/vestige-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2f7deaa67430e2c3a3d09176b10c61eaf51f864f GIT binary patch literal 40428 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 = OnceLock::new(); +#[derive(Debug, Clone, Default, Args)] +struct SandwichInstallOptions { + /// Overwrite existing staged Vestige hook and agent files. + #[arg(long)] + force: bool, + + /// Wire optional UserPromptSubmit preflight hooks. + #[arg(long)] + enable_preflight: bool, + + /// Wire both optional preflight hooks and the optional Sanhedrin verifier. + #[arg(long)] + enable_sandwich: bool, + + /// Wire optional Sanhedrin Stop hook. + #[arg(long)] + enable_sanhedrin: bool, + + /// On Apple Silicon, auto-start the local MLX Sanhedrin backend. + #[arg(long)] + with_launchd: bool, + + /// Also stage the large memory-loader hook file. + #[arg(long)] + include_memory_loader: bool, + + /// OpenAI-compatible chat completions endpoint for optional Sanhedrin. + #[arg(long, value_name = "URL")] + sanhedrin_endpoint: Option, + + /// Model name passed to the optional Sanhedrin endpoint. + #[arg(long, value_name = "MODEL")] + sanhedrin_model: Option, + + /// Use a local checkout/release root containing hooks/ and agents/. + #[arg(long, value_name = "DIR", hide = true)] + src: Option, +} + +#[derive(Subcommand)] +enum SandwichCommands { + /// Install/update Cognitive Sandwich companion files without enabling hooks by default. + Install { + /// Install files from a specific release tag instead of latest. + #[arg(long)] + version: Option, + + #[command(flatten)] + options: SandwichInstallOptions, + }, +} + #[derive(Subcommand)] enum Commands { /// Show memory statistics @@ -68,6 +120,19 @@ enum Commands { /// Print what would be updated without changing files #[arg(long)] dry_run: bool, + + /// Skip Cognitive Sandwich companion file update and legacy hook cleanup. + #[arg(long)] + no_sandwich: bool, + + #[command(flatten)] + sandwich: SandwichInstallOptions, + }, + + /// Manage optional Claude Code Cognitive Sandwich companion files. + Sandwich { + #[command(subcommand)] + command: SandwichCommands, }, /// Restore memories from backup file @@ -191,7 +256,14 @@ fn main() -> anyhow::Result<()> { version, install_dir, dry_run, - } => run_update(version, install_dir, dry_run), + no_sandwich, + sandwich, + } => run_update(version, install_dir, dry_run, no_sandwich, sandwich), + Commands::Sandwich { command } => match command { + SandwichCommands::Install { version, options } => { + run_sandwich_install(version.as_deref(), &options) + } + }, Commands::Restore { file } => run_restore(file), Commands::Backup { output } => run_backup(output), Commands::Export { @@ -292,11 +364,7 @@ fn release_download_url(asset: ReleaseAsset, version: Option<&str>) -> String { let archive_name = format!("vestige-mcp-{}.{}", asset.target, asset.archive_ext); match version { Some(version) => { - let tag = if version.starts_with('v') { - version.to_string() - } else { - format!("v{}", version) - }; + let tag = normalize_release_tag(version); format!( "https://github.com/samvallad33/vestige/releases/download/{}/{}", tag, archive_name @@ -309,6 +377,506 @@ fn release_download_url(asset: ReleaseAsset, version: Option<&str>) -> String { } } +fn normalize_release_tag(version: &str) -> String { + if version.starts_with('v') { + version.to_string() + } else { + format!("v{}", version) + } +} + +fn source_archive_url(tag: &str) -> String { + format!( + "https://github.com/samvallad33/vestige/archive/refs/tags/{}.tar.gz", + tag + ) +} + +fn download_file(url: &str, output: &Path, action: &str) -> anyhow::Result<()> { + run_command( + Command::new("curl") + .arg("-fsSL") + .arg("-A") + .arg("vestige-cli") + .arg(url) + .arg("-o") + .arg(output), + action, + ) +} + +fn latest_release_tag() -> anyhow::Result { + let temp_dir = UpdateTempDir::create()?; + let metadata_path = temp_dir.path.join("latest-release.json"); + download_file( + "https://api.github.com/repos/samvallad33/vestige/releases/latest", + &metadata_path, + "checking latest Vestige release", + )?; + let file = fs::File::open(&metadata_path)?; + let metadata: serde_json::Value = + serde_json::from_reader(file).context("failed to parse latest Vestige release metadata")?; + metadata + .get("tag_name") + .and_then(|tag| tag.as_str()) + .map(|tag| tag.to_string()) + .ok_or_else(|| anyhow::anyhow!("latest Vestige release metadata did not include tag_name")) +} + +fn release_tag_for_source(version: Option<&str>) -> anyhow::Result { + match version { + Some(version) => Ok(normalize_release_tag(version)), + None => latest_release_tag(), + } +} + +fn find_sandwich_source_root(root: &Path) -> Option { + if root.join("hooks").is_dir() && root.join("agents").is_dir() { + return Some(root.to_path_buf()); + } + + let entries = fs::read_dir(root).ok()?; + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() && path.join("hooks").is_dir() && path.join("agents").is_dir() { + return Some(path); + } + } + + None +} + +fn download_sandwich_source(version: Option<&str>, output_dir: &Path) -> anyhow::Result { + let tag = release_tag_for_source(version)?; + let archive_path = output_dir.join(format!("vestige-source-{}.tar.gz", tag)); + let url = source_archive_url(&tag); + + println!("{}: {}", "Sandwich source".white().bold(), tag); + download_file(&url, &archive_path, "downloading Vestige source archive")?; + extract_archive(&archive_path, output_dir, "tar.gz")?; + find_sandwich_source_root(output_dir).ok_or_else(|| { + anyhow::anyhow!("Vestige source archive did not contain hooks/ and agents/ directories") + }) +} + +fn home_dir() -> anyhow::Result { + directories::BaseDirs::new() + .map(|dirs| dirs.home_dir().to_path_buf()) + .ok_or_else(|| anyhow::anyhow!("failed to locate home directory")) +} + +fn is_vestige_hook_command(command: &str) -> bool { + const NEEDLES: &[&str] = &[ + "synthesis-preflight.sh", + "cwd-state-injector.sh", + "vestige-pulse-daemon.sh", + "preflight-swarm.sh", + "load-all-memory.sh", + "veto-detector.sh", + "sanhedrin.sh", + "synthesis-stop-validator.sh", + "synthesis-gate.sh", + ]; + NEEDLES.iter().any(|needle| command.contains(needle)) +} + +fn scrub_vestige_hooks(settings: &mut serde_json::Value) { + let Some(hooks) = settings + .get_mut("hooks") + .and_then(|hooks| hooks.as_object_mut()) + else { + return; + }; + + for event_name in ["UserPromptSubmit", "Stop"] { + let Some(groups) = hooks + .get_mut(event_name) + .and_then(|groups| groups.as_array_mut()) + else { + continue; + }; + + for group in groups.iter_mut() { + if let Some(commands) = group + .get_mut("hooks") + .and_then(|hooks| hooks.as_array_mut()) + { + commands.retain(|hook| { + !hook + .get("command") + .and_then(|command| command.as_str()) + .is_some_and(is_vestige_hook_command) + }); + } + } + + groups.retain(|group| { + group + .get("hooks") + .and_then(|hooks| hooks.as_array()) + .is_some_and(|hooks| !hooks.is_empty()) + }); + } + + hooks.retain(|_, value| match value { + serde_json::Value::Array(items) => !items.is_empty(), + serde_json::Value::Object(items) => !items.is_empty(), + serde_json::Value::Null => false, + _ => true, + }); + + if hooks.is_empty() + && let Some(root) = settings.as_object_mut() + { + root.remove("hooks"); + } +} + +fn merge_json(base: &mut serde_json::Value, overlay: serde_json::Value) { + match (base, overlay) { + (serde_json::Value::Object(base), serde_json::Value::Object(overlay)) => { + for (key, value) in overlay { + match base.get_mut(&key) { + Some(existing) => merge_json(existing, value), + None => { + base.insert(key, value); + } + } + } + } + (base, overlay) => *base = overlay, + } +} + +fn merge_settings_fragment( + settings: &mut serde_json::Value, + fragment_path: &Path, +) -> anyhow::Result<()> { + let file = fs::File::open(fragment_path) + .with_context(|| format!("failed to open {}", fragment_path.display()))?; + let fragment: serde_json::Value = serde_json::from_reader(file) + .with_context(|| format!("failed to parse {}", fragment_path.display()))?; + merge_json(settings, fragment); + Ok(()) +} + +fn copy_companion_files( + source_dir: &Path, + destination_dir: &Path, + allowed_extensions: &[&str], + _mode: u32, + options: &SandwichInstallOptions, +) -> anyhow::Result<(usize, usize)> { + fs::create_dir_all(destination_dir)?; + let mut copied = 0; + let mut skipped = 0; + + for entry in fs::read_dir(source_dir) + .with_context(|| format!("failed to read {}", source_dir.display()))? + { + let entry = entry?; + let source = entry.path(); + if !source.is_file() { + continue; + } + + let extension = source + .extension() + .and_then(|ext| ext.to_str()) + .unwrap_or(""); + if !allowed_extensions.contains(&extension) { + continue; + } + + let Some(file_name) = source.file_name() else { + continue; + }; + if file_name.to_string_lossy() == "load-all-memory.sh" && !options.include_memory_loader { + continue; + } + + let destination = destination_dir.join(file_name); + if destination.exists() && !options.force { + skipped += 1; + continue; + } + + fs::copy(&source, &destination).with_context(|| { + format!( + "failed to copy {} to {}", + source.display(), + destination.display() + ) + })?; + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mut perms = fs::metadata(&destination)?.permissions(); + perms.set_mode(_mode); + fs::set_permissions(&destination, perms)?; + } + + copied += 1; + } + + Ok((copied, skipped)) +} + +fn quote_shell_env(value: &str) -> String { + format!("'{}'", value.replace('\'', "'\\''")) +} + +fn write_sanhedrin_env( + hooks_dir: &Path, + endpoint: &str, + model: &str, + dashboard_port: &str, +) -> anyhow::Result<()> { + let env_path = hooks_dir.join("vestige-sanhedrin.env"); + let contents = format!( + "VESTIGE_SANHEDRIN_ENABLED=1\nVESTIGE_SANHEDRIN_ENDPOINT={}\nVESTIGE_SANHEDRIN_MODEL={}\nVESTIGE_DASHBOARD_PORT={}\n", + quote_shell_env(endpoint), + quote_shell_env(model), + quote_shell_env(dashboard_port) + ); + fs::write(&env_path, contents)?; + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mut perms = fs::metadata(&env_path)?.permissions(); + perms.set_mode(0o600); + fs::set_permissions(&env_path, perms)?; + } + + println!("{}: {}", "Sanhedrin env".white().bold(), env_path.display()); + Ok(()) +} + +fn install_launchd_job(source_root: &Path, home: &Path, model: &str) -> anyhow::Result<()> { + let launchd_dir = home.join("Library").join("LaunchAgents"); + fs::create_dir_all(&launchd_dir)?; + + let template_path = source_root + .join("launchd") + .join("com.vestige.mlx-server.plist.template"); + let template = fs::read_to_string(&template_path) + .with_context(|| format!("failed to read {}", template_path.display()))?; + let rendered = template + .replace("__HOME__", &home.display().to_string()) + .replace("__MODEL__", model); + + let plist = launchd_dir.join("com.vestige.mlx-server.plist"); + fs::write(&plist, rendered)?; + let _ = Command::new("launchctl").arg("unload").arg(&plist).status(); + run_command( + Command::new("launchctl").arg("load").arg(&plist), + "loading Vestige MLX launchd job", + )?; + println!("{}: {}", "launchd".white().bold(), plist.display()); + Ok(()) +} + +fn remove_legacy_launchd_job(home: &Path) { + if env::consts::OS != "macos" { + return; + } + + let plist = home + .join("Library") + .join("LaunchAgents") + .join("com.vestige.mlx-server.plist"); + if plist.exists() { + let _ = Command::new("launchctl").arg("unload").arg(&plist).status(); + if fs::remove_file(&plist).is_ok() { + println!( + "{}: removed old Sanhedrin launchd job", + "launchd".white().bold() + ); + } + } +} + +fn install_sandwich_from_source( + source_root: &Path, + options: &SandwichInstallOptions, +) -> anyhow::Result<()> { + let home = home_dir()?; + let claude_dir = home.join(".claude"); + let hooks_dir = claude_dir.join("hooks"); + let agents_dir = claude_dir.join("agents"); + let settings_path = claude_dir.join("settings.json"); + let source_root = + find_sandwich_source_root(source_root).unwrap_or_else(|| source_root.to_path_buf()); + + if !source_root.join("hooks").is_dir() || !source_root.join("agents").is_dir() { + anyhow::bail!( + "Cognitive Sandwich source missing hooks/ or agents/: {}", + source_root.display() + ); + } + + let enable_preflight = options.enable_preflight || options.enable_sandwich; + let mut enable_sanhedrin = + options.enable_sanhedrin || options.enable_sandwich || options.with_launchd; + let mut with_launchd = options.with_launchd; + + if with_launchd && (env::consts::OS != "macos" || env::consts::ARCH != "aarch64") { + println!( + "{}", + "--with-launchd is Apple Silicon only; using endpoint-backed Sanhedrin instead." + .yellow() + ); + with_launchd = false; + enable_sanhedrin = true; + } + + fs::create_dir_all(&claude_dir)?; + let (hooks_copied, hooks_skipped) = copy_companion_files( + &source_root.join("hooks"), + &hooks_dir, + &["sh", "py"], + 0o755, + options, + )?; + let (agents_copied, agents_skipped) = copy_companion_files( + &source_root.join("agents"), + &agents_dir, + &["md"], + 0o644, + options, + )?; + + println!( + "{}: {} installed, {} skipped", + "Hooks".white().bold(), + hooks_copied, + hooks_skipped + ); + println!( + "{}: {} installed, {} skipped", + "Agents".white().bold(), + agents_copied, + agents_skipped + ); + + if !with_launchd { + remove_legacy_launchd_job(&home); + } + + let dashboard_port = env::var("VESTIGE_DASHBOARD_PORT").unwrap_or_else(|_| "3927".to_string()); + let endpoint = options + .sanhedrin_endpoint + .clone() + .or_else(|| env::var("VESTIGE_SANHEDRIN_ENDPOINT").ok()) + .or_else(|| env::var("MLX_ENDPOINT").ok()) + .unwrap_or_else(|| "http://127.0.0.1:8080/v1/chat/completions".to_string()) + .trim_end_matches('/') + .to_string(); + let model = options + .sanhedrin_model + .clone() + .or_else(|| env::var("VESTIGE_SANHEDRIN_MODEL").ok()) + .or_else(|| env::var("VESTIGE_SANDWICH_MODEL").ok()) + .unwrap_or_else(|| "mlx-community/Qwen3.6-35B-A3B-4bit".to_string()); + + if enable_sanhedrin { + write_sanhedrin_env(&hooks_dir, &endpoint, &model, &dashboard_port)?; + } + if with_launchd { + install_launchd_job(&source_root, &home, &model)?; + } + + if !settings_path.exists() { + fs::write(&settings_path, "{}\n")?; + } + let backup_path = claude_dir.join("settings.json.bak.pre-sandwich"); + if !backup_path.exists() { + fs::copy(&settings_path, &backup_path)?; + } + + let settings_file = fs::File::open(&settings_path)?; + let mut settings: serde_json::Value = + serde_json::from_reader(settings_file).unwrap_or_else(|_| serde_json::json!({})); + scrub_vestige_hooks(&mut settings); + + if enable_preflight { + merge_settings_fragment( + &mut settings, + &source_root + .join("hooks") + .join("settings.preflight.fragment.json"), + )?; + } + if enable_sanhedrin { + merge_settings_fragment( + &mut settings, + &source_root + .join("hooks") + .join("settings.sanhedrin.fragment.json"), + )?; + } + + let mut settings_file = fs::File::create(&settings_path)?; + serde_json::to_writer_pretty(&mut settings_file, &settings)?; + writeln!(settings_file)?; + + if enable_preflight || enable_sanhedrin { + let mut layers = Vec::new(); + if enable_preflight { + layers.push("preflight"); + } + if enable_sanhedrin { + layers.push("sanhedrin"); + } + println!( + "{}: enabled optional layer(s): {}", + "Settings".white().bold(), + layers.join(", ") + ); + } else { + println!( + "{}: no Vestige Claude Code hooks enabled by default", + "Settings".white().bold() + ); + } + + Ok(()) +} + +fn run_sandwich_install( + version: Option<&str>, + options: &SandwichInstallOptions, +) -> anyhow::Result<()> { + println!( + "{}", + "=== Vestige Cognitive Sandwich Install ===".cyan().bold() + ); + println!(); + + if let Some(source_root) = &options.src { + install_sandwich_from_source(source_root, options)?; + } else { + let temp_dir = UpdateTempDir::create()?; + let source_root = download_sandwich_source(version, &temp_dir.path)?; + install_sandwich_from_source(&source_root, options)?; + } + + println!(); + let optional_layers_enabled = options.enable_preflight + || options.enable_sandwich + || options.enable_sanhedrin + || options.with_launchd; + let message = if optional_layers_enabled { + "Cognitive Sandwich files updated. Restart Claude Code to use enabled optional hooks." + } else { + "Cognitive Sandwich files updated. No hooks enabled; no automatic model calls." + }; + println!("{}", message.green().bold()); + Ok(()) +} + fn run_command(command: &mut Command, action: &str) -> anyhow::Result<()> { let status = command .status() @@ -400,6 +968,8 @@ fn run_update( version: Option, install_dir: Option, dry_run: bool, + no_sandwich: bool, + sandwich: SandwichInstallOptions, ) -> anyhow::Result<()> { println!("{}", "=== Vestige Update ===".cyan().bold()); println!(); @@ -453,14 +1023,7 @@ fn run_update( println!(); println!("{}", "Downloading release archive...".cyan()); - run_command( - Command::new("curl") - .arg("-fL") - .arg(&url) - .arg("-o") - .arg(&archive_path), - "downloading Vestige release archive with curl", - )?; + download_file(&url, &archive_path, "downloading Vestige release archive")?; println!("{}", "Extracting release archive...".cyan()); extract_archive(&archive_path, &temp_dir.path, asset.archive_ext)?; @@ -491,11 +1054,25 @@ fn run_update( println!( "{}", - "Update complete. Restart your MCP client to pick up the new binary." + "Binary update complete. Restart your MCP client to pick up the new binary." .green() .bold() ); + if no_sandwich { + println!( + "{}", + "Skipped Cognitive Sandwich companion update (--no-sandwich).".yellow() + ); + } else { + println!(); + println!( + "{}", + "Updating Cognitive Sandwich companion files...".cyan() + ); + run_sandwich_install(version.as_deref(), &sandwich)?; + } + Ok(()) } @@ -1800,4 +2377,48 @@ mod tests { "https://github.com/samvallad33/vestige/releases/download/v2.1.0/vestige-mcp-aarch64-apple-darwin.tar.gz" ); } + + #[test] + fn source_archive_url_uses_normalized_tag() { + assert_eq!(normalize_release_tag("2.1.1"), "v2.1.1"); + assert_eq!(normalize_release_tag("v2.1.1"), "v2.1.1"); + assert_eq!( + source_archive_url("v2.1.1"), + "https://github.com/samvallad33/vestige/archive/refs/tags/v2.1.1.tar.gz" + ); + } + + #[test] + fn scrub_vestige_hooks_removes_only_vestige_commands() { + let mut settings = serde_json::json!({ + "hooks": { + "UserPromptSubmit": [ + { + "hooks": [ + { "type": "command", "command": "/tmp/synthesis-preflight.sh" }, + { "type": "command", "command": "/tmp/custom-user-hook.sh" } + ] + } + ], + "Stop": [ + { + "hooks": [ + { "type": "command", "command": "/tmp/sanhedrin.sh" } + ] + } + ] + }, + "other": true + }); + + scrub_vestige_hooks(&mut settings); + + let user_hooks = settings["hooks"]["UserPromptSubmit"][0]["hooks"] + .as_array() + .unwrap(); + assert_eq!(user_hooks.len(), 1); + assert_eq!(user_hooks[0]["command"], "/tmp/custom-user-hook.sh"); + assert!(settings["hooks"].get("Stop").is_none()); + assert_eq!(settings["other"], true); + } } diff --git a/docs/COGNITIVE_SANDWICH.md b/docs/COGNITIVE_SANDWICH.md index 6a395d4..4b4661e 100644 --- a/docs/COGNITIVE_SANDWICH.md +++ b/docs/COGNITIVE_SANDWICH.md @@ -69,12 +69,17 @@ False-positive guards (added v2.1.0 after dogfood): ## Installation -### One-liner +### From an installed Vestige CLI ```bash -curl -fsSL https://raw.githubusercontent.com/samvallad33/vestige/v2.1.1/scripts/install-sandwich.sh | sh +vestige sandwich install ``` +`vestige update` also refreshes these companion files by default after it updates +the binaries. The default command does not activate any Claude Code hook. It +removes old v2.1.0 Vestige hook wiring from `~/.claude/settings.json` while +preserving unrelated user hooks. + ### From a checkout ```bash @@ -84,15 +89,13 @@ cd vestige ./scripts/check-sandwich-prereqs.sh # verify no Vestige hooks are wired by default ``` -The default command does not activate any Claude Code hook. It removes old v2.1.0 Vestige hook wiring from `~/.claude/settings.json` while preserving unrelated user hooks. - ### Optional Preflight Preflight is a separate opt-in layer. It includes `preflight-swarm.sh`, which uses `claude -p --model claude-haiku-4-5-20251001`; it is not wired by default. ```bash -./scripts/install-sandwich.sh --enable-preflight -./scripts/check-sandwich-prereqs.sh --preflight +vestige sandwich install --enable-preflight +scripts/check-sandwich-prereqs.sh --preflight ``` ### Optional Sanhedrin @@ -101,13 +104,13 @@ Sanhedrin is a separate opt-in layer. ```bash # Wire the Sanhedrin Stop hook, using the default OpenAI-compatible endpoint. -./scripts/install-sandwich.sh --enable-sanhedrin +vestige sandwich install --enable-sanhedrin # Apple Silicon only, and only if the machine has enough memory: -./scripts/install-sandwich.sh --enable-sanhedrin --with-launchd +vestige sandwich install --enable-sanhedrin --with-launchd # x86 / Linux / Intel Mac: use any OpenAI-compatible endpoint. -./scripts/install-sandwich.sh \ +vestige sandwich install \ --enable-sanhedrin \ --sanhedrin-endpoint=http://127.0.0.1:11434/v1/chat/completions \ --sanhedrin-model=qwen2.5:14b diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 8b7c773..8f5a36d 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -175,11 +175,27 @@ See [Storage Modes](STORAGE.md) for more options. vestige update ``` +This updates `vestige`, `vestige-mcp`, `vestige-restore`, and the Cognitive +Sandwich companion files. The companion refresh keeps hooks disabled by default +and cleans up old mandatory v2.1.0 hook wiring. + +**Binaries only:** +```bash +vestige update --no-sandwich +``` + **Pin to specific version:** ```bash vestige update --version v2.1.1 ``` +**Manage the optional Cognitive Sandwich layer without updating binaries:** +```bash +vestige sandwich install +vestige sandwich install --enable-preflight +vestige sandwich install --enable-sanhedrin --sanhedrin-endpoint=http://127.0.0.1:11434/v1/chat/completions +``` + **Check your version:** ```bash vestige-mcp --version diff --git a/docs/INSTALL-INTEL-MAC.md b/docs/INSTALL-INTEL-MAC.md index ee42975..3ec02e0 100644 --- a/docs/INSTALL-INTEL-MAC.md +++ b/docs/INSTALL-INTEL-MAC.md @@ -17,9 +17,8 @@ brew install onnxruntime ## Install ```bash -# 1. Download the binary -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-x86_64-apple-darwin.tar.gz | tar -xz -sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/ +# 1. Install the binary +npm install -g vestige-mcp-server@latest # 2. Point the binary at Homebrew's libonnxruntime echo 'export ORT_DYLIB_PATH="'"$(brew --prefix onnxruntime)"'/lib/libonnxruntime.dylib"' >> ~/.zshrc diff --git a/docs/blog/xcode-memory.md b/docs/blog/xcode-memory.md index 4277f09..8036181 100644 --- a/docs/blog/xcode-memory.md +++ b/docs/blog/xcode-memory.md @@ -20,8 +20,7 @@ It speaks MCP (Model Context Protocol), the same protocol Xcode 26.3 uses for to **Step 1:** Install Vestige ```bash -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-aarch64-apple-darwin.tar.gz | tar -xz -sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/ +npm install -g vestige-mcp-server ``` **Step 2:** Drop one file in your project root @@ -110,8 +109,7 @@ The full setup takes 30 seconds: ```bash # Install Vestige -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-aarch64-apple-darwin.tar.gz | tar -xz -sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/ +npm install -g vestige-mcp-server # Add to your project (run from project root) cat > .mcp.json << 'EOF' diff --git a/docs/integrations/xcode.md b/docs/integrations/xcode.md index fb22dcf..0051146 100644 --- a/docs/integrations/xcode.md +++ b/docs/integrations/xcode.md @@ -13,8 +13,7 @@ Xcode 26.3 supports [agentic coding](https://developer.apple.com/documentation/x ### 1. Install Vestige ```bash -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-aarch64-apple-darwin.tar.gz | tar -xz -sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/ +npm install -g vestige-mcp-server@latest ``` ### 2. Add to your Xcode project @@ -27,7 +26,7 @@ cat > /path/to/your/project/.mcp.json << 'EOF' "mcpServers": { "vestige": { "type": "stdio", - "command": "/usr/local/bin/vestige-mcp", + "command": "vestige-mcp", "args": [], "env": { "PATH": "/usr/local/bin:/usr/bin:/bin" diff --git a/docs/launch/demo-script.md b/docs/launch/demo-script.md index f5444b2..8907b27 100644 --- a/docs/launch/demo-script.md +++ b/docs/launch/demo-script.md @@ -194,10 +194,10 @@ wc -l $(find /path/to/vestige/crates -name "*.rs") | tail -1 # → 77,840 total ``` -> Seventy-eight thousand lines of Rust. Seven hundred thirty-four tests. Twenty-two megabyte binary. Ships with the dashboard embedded. Install is one curl command: +> Seventy-eight thousand lines of Rust. Seven hundred thirty-four tests. Twenty-two megabyte binary. Ships with the dashboard embedded. Install is one npm command: ```bash -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-aarch64-apple-darwin.tar.gz | tar -xz +npm install -g vestige-mcp-server claude mcp add vestige vestige-mcp -s user ``` @@ -241,8 +241,7 @@ claude mcp add vestige vestige-mcp -s user ```bash # Install (macOS Apple Silicon) -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-aarch64-apple-darwin.tar.gz | tar -xz -sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/ +npm install -g vestige-mcp-server ``` > Three binaries. The MCP server, the CLI admin tool, and a restore utility. Twenty-two megabytes total. No Docker. No Python. No node_modules. No cloud API key. @@ -389,7 +388,7 @@ vestige-mcp --version # <300ns cosine similarity (benchmarked with Criterion) # Zero cloud dependencies # Zero API keys required -# One curl command to install +# One command to install ``` > This is what I've been building for the past three months. I'm one person, I'm twenty-one years old, and I believe this is how AI memory should work — grounded in real science, running locally, open source. @@ -479,7 +478,7 @@ vestige-mcp --version - **Start from the dashboard.** The 3D graph is the hook. It's visual, it's unusual, it makes people lean in. - **Don't rush the dream sequence.** The purple wash and sequential node pulses are the most visually impressive moment. Let it breathe for 3-4 seconds. - **Say the scientists' names.** "Ebbinghaus," "Bjork," "Frey and Morris" — this signals that you've done the reading. The MCP Dev Summit audience respects depth. -- **Make eye contact during the punchline.** "One curl command. Your AI now has a brain." Look at the audience, not the screen. +- **Make eye contact during the punchline.** "One command. Your AI now has a brain." Look at the audience, not the screen. - **Own your age.** Twenty-one, solo developer, zero funding. This is an asset, not a liability. You built something that the well-funded competitors haven't. - **The dashboard is your co-presenter.** Every time Claude does something, the dashboard should be showing the corresponding event. Practice the terminal-to-browser switch until it's seamless. - **Don't apologize.** Not for bugs, not for the AGPL, not for being solo. Confident but not arrogant. The work speaks. diff --git a/docs/launch/reddit-cross-reference.md b/docs/launch/reddit-cross-reference.md index e6e918a..7ab6b62 100644 --- a/docs/launch/reddit-cross-reference.md +++ b/docs/launch/reddit-cross-reference.md @@ -88,7 +88,7 @@ Memory systems need to be SMARTER, not just bigger. That's what Vestige does — ### Install (30 seconds): ```bash # macOS Apple Silicon -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-aarch64-apple-darwin.tar.gz | tar -xz +npm install -g vestige-mcp-server sudo mv vestige-mcp /usr/local/bin/ claude mcp add vestige vestige-mcp -s user ``` @@ -162,7 +162,7 @@ The AI sees the conflict. Picks the right one. Every time. **100% local. Your data never leaves your machine.** ```bash -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-aarch64-apple-darwin.tar.gz | tar -xz +npm install -g vestige-mcp-server sudo mv vestige-mcp /usr/local/bin/ claude mcp add vestige vestige-mcp -s user ``` diff --git a/docs/launch/show-hn.md b/docs/launch/show-hn.md index 03034e0..8cc5a95 100644 --- a/docs/launch/show-hn.md +++ b/docs/launch/show-hn.md @@ -401,8 +401,7 @@ locally on your machine. **Setup (2 minutes):** ```bash -curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-aarch64-apple-darwin.tar.gz | tar -xz -sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/ +npm install -g vestige-mcp-server claude mcp add vestige vestige-mcp -s user ``` diff --git a/packages/vestige-init/bin/init.js b/packages/vestige-init/bin/init.js index 6ef6da5..2c26b55 100755 --- a/packages/vestige-init/bin/init.js +++ b/packages/vestige-init/bin/init.js @@ -280,12 +280,7 @@ function main() { console.log(''); console.log('Install manually:'); console.log(''); - console.log(' # macOS (Apple Silicon)'); - console.log(' curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-aarch64-apple-darwin.tar.gz | tar -xz'); - console.log(' sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/'); - console.log(''); - console.log(' # Or via npm'); - console.log(' npm install -g vestige-mcp-server'); + console.log(' npm install -g vestige-mcp-server@latest'); console.log(''); console.log('Then run: npx @vestige/init'); process.exit(1); diff --git a/packages/vestige-mcp-npm/README.md b/packages/vestige-mcp-npm/README.md index 6417198..25312d2 100644 --- a/packages/vestige-mcp-npm/README.md +++ b/packages/vestige-mcp-npm/README.md @@ -12,6 +12,15 @@ npm install -g vestige-mcp-server This automatically downloads the correct binary for your platform (macOS, Linux, Windows) from GitHub releases. +Already installed? Update without copying release URLs: + +```bash +vestige update +``` + +This refreshes the binaries and Cognitive Sandwich companion files while keeping +all hooks disabled by default. + ### What gets installed | Command | Description | @@ -57,6 +66,8 @@ vestige stats # Memory statistics vestige stats --states # Cognitive state distribution vestige health # System health check vestige consolidate # Run memory maintenance cycle +vestige update # Update binaries + companion files +vestige sandwich install # Refresh optional Claude Code hook files ``` ## Features diff --git a/packages/vestige-mcp-npm/package.json b/packages/vestige-mcp-npm/package.json index 56842dd..40f0a19 100644 --- a/packages/vestige-mcp-npm/package.json +++ b/packages/vestige-mcp-npm/package.json @@ -1,6 +1,7 @@ { "name": "vestige-mcp-server", - "version": "2.1.0", + "version": "2.1.1", + "mcpName": "io.github.samvallad33/vestige", "description": "Vestige MCP Server — Cognitive memory for AI with FSRS-6, 3D dashboard, and 29 brain modules", "bin": { "vestige-mcp": "bin/vestige-mcp.js", diff --git a/scripts/install-sandwich.sh b/scripts/install-sandwich.sh index fd2b4b9..280a4c3 100755 --- a/scripts/install-sandwich.sh +++ b/scripts/install-sandwich.sh @@ -2,8 +2,8 @@ # install-sandwich.sh — One-command installer for the Vestige Cognitive Sandwich. # # Usage: -# curl -fsSL https://raw.githubusercontent.com/samvallad33/vestige/v2.1.1/scripts/install-sandwich.sh | sh -# # or, from a checkout: +# vestige sandwich install +# # or, from a checkout / source archive: # ./scripts/install-sandwich.sh [--force] [--enable-preflight] [--enable-sanhedrin] [--with-launchd] [--include-memory-loader] # ./scripts/install-sandwich.sh --enable-sanhedrin --sanhedrin-endpoint=http://127.0.0.1:11434/v1/chat/completions --sanhedrin-model=qwen2.5:14b # diff --git a/server.json b/server.json new file mode 100644 index 0000000..284ffb5 --- /dev/null +++ b/server.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", + "name": "io.github.samvallad33/vestige", + "title": "Vestige", + "description": "Local-first cognitive memory for AI agents. Vestige gives Claude, Cursor, Codex, VS Code, Xcode, and other MCP clients durable memory with FSRS-6 scheduling, smart ingest, SQLite storage, portable sync, and an embedded dashboard.", + "repository": { + "url": "https://github.com/samvallad33/vestige", + "source": "github" + }, + "version": "2.1.1", + "packages": [ + { + "registryType": "npm", + "identifier": "vestige-mcp-server", + "version": "2.1.1", + "transport": { + "type": "stdio" + } + } + ] +} From c3c54d4e97f1837fa77f8c1b0d764adf2d426717 Mon Sep 17 00:00:00 2001 From: Sam Valladares Date: Fri, 1 May 2026 13:44:31 -0500 Subject: [PATCH 06/31] Prepare v2.1.2 simple update release --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- crates/vestige-core/Cargo.toml | 2 +- crates/vestige-mcp/Cargo.toml | 4 ++-- packages/vestige-mcp-npm/package.json | 2 +- server.json | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 015f3ae..e7f9a05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4531,7 +4531,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vestige-core" -version = "2.1.1" +version = "2.1.2" dependencies = [ "candle-core", "chrono", @@ -4567,7 +4567,7 @@ dependencies = [ [[package]] name = "vestige-mcp" -version = "2.1.1" +version = "2.1.2" dependencies = [ "anyhow", "axum", diff --git a/Cargo.toml b/Cargo.toml index 3ca3766..af80c4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ exclude = [ ] [workspace.package] -version = "2.1.1" +version = "2.1.2" edition = "2024" license = "AGPL-3.0-only" repository = "https://github.com/samvallad33/vestige" diff --git a/crates/vestige-core/Cargo.toml b/crates/vestige-core/Cargo.toml index 6aee2ba..42a32b6 100644 --- a/crates/vestige-core/Cargo.toml +++ b/crates/vestige-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vestige-core" -version = "2.1.1" +version = "2.1.2" edition = "2024" rust-version = "1.91" authors = ["Vestige Team"] diff --git a/crates/vestige-mcp/Cargo.toml b/crates/vestige-mcp/Cargo.toml index af6a663..221dd1d 100644 --- a/crates/vestige-mcp/Cargo.toml +++ b/crates/vestige-mcp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vestige-mcp" -version = "2.1.1" +version = "2.1.2" edition = "2024" description = "Cognitive memory MCP server for Claude - FSRS-6, spreading activation, synaptic tagging, 3D dashboard, and 130 years of memory research" authors = ["samvallad33"] @@ -47,7 +47,7 @@ path = "src/bin/cli.rs" # Only `bundled-sqlite` is always on. `embeddings` and `vector-search` are # toggled via vestige-mcp's own feature flags below so `--no-default-features` # actually works (previously hardcoded here, which silently defeated the flag). -vestige-core = { version = "2.1.1", path = "../vestige-core", default-features = false, features = ["bundled-sqlite"] } +vestige-core = { version = "2.1.2", path = "../vestige-core", default-features = false, features = ["bundled-sqlite"] } # ============================================================================ # MCP Server Dependencies diff --git a/packages/vestige-mcp-npm/package.json b/packages/vestige-mcp-npm/package.json index 40f0a19..e4edf57 100644 --- a/packages/vestige-mcp-npm/package.json +++ b/packages/vestige-mcp-npm/package.json @@ -1,6 +1,6 @@ { "name": "vestige-mcp-server", - "version": "2.1.1", + "version": "2.1.2", "mcpName": "io.github.samvallad33/vestige", "description": "Vestige MCP Server — Cognitive memory for AI with FSRS-6, 3D dashboard, and 29 brain modules", "bin": { diff --git a/server.json b/server.json index 284ffb5..995f685 100644 --- a/server.json +++ b/server.json @@ -2,17 +2,17 @@ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.samvallad33/vestige", "title": "Vestige", - "description": "Local-first cognitive memory for AI agents. Vestige gives Claude, Cursor, Codex, VS Code, Xcode, and other MCP clients durable memory with FSRS-6 scheduling, smart ingest, SQLite storage, portable sync, and an embedded dashboard.", + "description": "Local-first cognitive memory server for AI agents with SQLite, smart ingest, and portable sync.", "repository": { "url": "https://github.com/samvallad33/vestige", "source": "github" }, - "version": "2.1.1", + "version": "2.1.2", "packages": [ { "registryType": "npm", "identifier": "vestige-mcp-server", - "version": "2.1.1", + "version": "2.1.2", "transport": { "type": "stdio" } From 9936928be95d229cc94a4105644e537519940e3d Mon Sep 17 00:00:00 2001 From: Sam Valladares Date: Wed, 6 May 2026 02:22:24 -0500 Subject: [PATCH 07/31] v2.1.2 Honest Memory Concrete search, irreversible purge, first-class contradictions tool, vestige update CLI, dense dream persistence fix, embedding-model upgrade repair, and a /dashboard/waitlist Pro early-access preview. 25 MCP tools. SQLite migration v13. Backwards compatible: 'delete' remains as a 'purge' alias. Closes #50, #51. --- CHANGELOG.md | 12 + CLAUDE.md | 390 +---- README.md | 23 +- agents/executioner.md | 113 +- agents/synthesis-composer.md | 59 +- apps/dashboard/.env.example | 9 + .../_app/immutable/assets/20.DKhUrxcR.css | 1 + .../_app/immutable/assets/20.DKhUrxcR.css.br | Bin 0 -> 2133 bytes .../_app/immutable/assets/20.DKhUrxcR.css.gz | Bin 0 -> 2465 bytes .../build/_app/immutable/chunks/A7po6GxK.js | 1 + .../_app/immutable/chunks/A7po6GxK.js.br | Bin 0 -> 565 bytes .../_app/immutable/chunks/A7po6GxK.js.gz | Bin 0 -> 633 bytes .../build/_app/immutable/chunks/B4yTwGkE.js | 1 + .../_app/immutable/chunks/B4yTwGkE.js.br | Bin 0 -> 304 bytes .../_app/immutable/chunks/B4yTwGkE.js.gz | Bin 0 -> 317 bytes .../build/_app/immutable/chunks/BHGLDPij.js | 1 + .../_app/immutable/chunks/BHGLDPij.js.br | Bin 0 -> 7639 bytes .../_app/immutable/chunks/BHGLDPij.js.gz | Bin 0 -> 8429 bytes .../chunks/{Bz1l2A_1.js => BUoSzNdg.js} | 2 +- .../_app/immutable/chunks/BUoSzNdg.js.br | Bin 0 -> 315 bytes .../_app/immutable/chunks/BUoSzNdg.js.gz | Bin 0 -> 342 bytes .../build/_app/immutable/chunks/B_YDQCB6.js | 1 - .../_app/immutable/chunks/B_YDQCB6.js.br | Bin 521 -> 0 bytes .../_app/immutable/chunks/B_YDQCB6.js.gz | Bin 568 -> 0 bytes .../build/_app/immutable/chunks/BeMFXnHE.js | 1 + .../_app/immutable/chunks/BeMFXnHE.js.br | Bin 0 -> 611 bytes .../_app/immutable/chunks/BeMFXnHE.js.gz | Bin 0 -> 654 bytes .../_app/immutable/chunks/Bhad70Ss.js.br | Bin 184 -> 0 bytes .../_app/immutable/chunks/Bhad70Ss.js.gz | Bin 199 -> 0 bytes .../chunks/{Casl2yrL.js => BjdL4Pm2.js} | 2 +- .../_app/immutable/chunks/BjdL4Pm2.js.br | Bin 0 -> 1513 bytes .../_app/immutable/chunks/BjdL4Pm2.js.gz | Bin 0 -> 1645 bytes .../build/_app/immutable/chunks/BlVfL1ME.js | 2 + .../_app/immutable/chunks/BlVfL1ME.js.br | Bin 0 -> 3142 bytes .../_app/immutable/chunks/BlVfL1ME.js.gz | Bin 0 -> 3506 bytes .../chunks/{DMu1Byux.js => BnXDGOmJ.js} | 2 +- .../_app/immutable/chunks/BnXDGOmJ.js.br | Bin 0 -> 516 bytes .../_app/immutable/chunks/BnXDGOmJ.js.gz | Bin 0 -> 585 bytes .../build/_app/immutable/chunks/BskPcZf7.js | 1 + .../_app/immutable/chunks/BskPcZf7.js.br | Bin 0 -> 2617 bytes .../_app/immutable/chunks/BskPcZf7.js.gz | Bin 0 -> 2964 bytes .../build/_app/immutable/chunks/BsvCUYx-.js | 1 - .../_app/immutable/chunks/BsvCUYx-.js.br | Bin 719 -> 0 bytes .../_app/immutable/chunks/BsvCUYx-.js.gz | Bin 800 -> 0 bytes .../_app/immutable/chunks/Bz1l2A_1.js.br | Bin 315 -> 0 bytes .../_app/immutable/chunks/Bz1l2A_1.js.gz | Bin 343 -> 0 bytes .../build/_app/immutable/chunks/C4h_mRt2.js | 1 + .../_app/immutable/chunks/C4h_mRt2.js.br | 2 + .../_app/immutable/chunks/C4h_mRt2.js.gz | Bin 0 -> 281 bytes .../build/_app/immutable/chunks/C6HuKgyx.js | 1 + .../_app/immutable/chunks/C6HuKgyx.js.br | Bin 0 -> 357 bytes .../_app/immutable/chunks/C6HuKgyx.js.gz | Bin 0 -> 391 bytes .../build/_app/immutable/chunks/CGEBXrjl.js | 1 + .../_app/immutable/chunks/CGEBXrjl.js.br | Bin 0 -> 1804 bytes .../_app/immutable/chunks/CGEBXrjl.js.gz | Bin 0 -> 1948 bytes .../build/_app/immutable/chunks/CHOnp4oo.js | 1 + .../_app/immutable/chunks/CHOnp4oo.js.br | Bin 0 -> 723 bytes .../_app/immutable/chunks/CHOnp4oo.js.gz | Bin 0 -> 799 bytes .../build/_app/immutable/chunks/CJCPY1OL.js | 1 + .../_app/immutable/chunks/CJCPY1OL.js.br | Bin 0 -> 163 bytes .../_app/immutable/chunks/CJCPY1OL.js.gz | Bin 0 -> 169 bytes .../build/_app/immutable/chunks/CJsMJEun.js | 1 + .../_app/immutable/chunks/CJsMJEun.js.br | Bin 0 -> 197 bytes .../_app/immutable/chunks/CJsMJEun.js.gz | Bin 0 -> 230 bytes .../build/_app/immutable/chunks/CNfQDikv.js | 1 - .../_app/immutable/chunks/CNfQDikv.js.br | Bin 587 -> 0 bytes .../_app/immutable/chunks/CNfQDikv.js.gz | Bin 628 -> 0 bytes .../_app/immutable/chunks/CNjeV5xa.js.br | Bin 225 -> 0 bytes .../_app/immutable/chunks/CNjeV5xa.js.gz | Bin 266 -> 0 bytes .../build/_app/immutable/chunks/CVpUe0w3.js | 1 - .../_app/immutable/chunks/CVpUe0w3.js.br | Bin 457 -> 0 bytes .../_app/immutable/chunks/CVpUe0w3.js.gz | Bin 517 -> 0 bytes .../_app/immutable/chunks/Casl2yrL.js.br | Bin 1504 -> 0 bytes .../_app/immutable/chunks/Casl2yrL.js.gz | Bin 1643 -> 0 bytes .../chunks/{CvjSAYrz.js => CpWkWWOo.js} | 2 +- .../_app/immutable/chunks/CpWkWWOo.js.br | Bin 0 -> 8721 bytes .../chunks/{CvjSAYrz.js.gz => CpWkWWOo.js.gz} | Bin 9692 -> 9694 bytes .../_app/immutable/chunks/CtkE7HV2.js.br | Bin 817 -> 0 bytes .../_app/immutable/chunks/CtkE7HV2.js.gz | Bin 923 -> 0 bytes .../_app/immutable/chunks/CvjSAYrz.js.br | Bin 8733 -> 0 bytes .../chunks/{Bhad70Ss.js => Cx-f-Pzo.js} | 2 +- .../_app/immutable/chunks/Cx-f-Pzo.js.br | Bin 0 -> 163 bytes .../_app/immutable/chunks/Cx-f-Pzo.js.gz | Bin 0 -> 200 bytes .../build/_app/immutable/chunks/D3XWCg9-.js | 1 - .../_app/immutable/chunks/D3XWCg9-.js.br | Bin 197 -> 0 bytes .../_app/immutable/chunks/D3XWCg9-.js.gz | Bin 229 -> 0 bytes .../build/_app/immutable/chunks/D81f-o_I.js | 1 - .../_app/immutable/chunks/D81f-o_I.js.br | Bin 372 -> 0 bytes .../_app/immutable/chunks/D81f-o_I.js.gz | Bin 399 -> 0 bytes .../build/_app/immutable/chunks/DE4u6cUg.js | 1 - .../_app/immutable/chunks/DE4u6cUg.js.br | Bin 878 -> 0 bytes .../_app/immutable/chunks/DE4u6cUg.js.gz | Bin 995 -> 0 bytes .../_app/immutable/chunks/DMu1Byux.js.br | Bin 518 -> 0 bytes .../_app/immutable/chunks/DMu1Byux.js.gz | Bin 587 -> 0 bytes .../build/_app/immutable/chunks/DObx9JW_.js | 1 - .../_app/immutable/chunks/DObx9JW_.js.br | Bin 264 -> 0 bytes .../_app/immutable/chunks/DObx9JW_.js.gz | Bin 278 -> 0 bytes .../build/_app/immutable/chunks/DPl3NjBv.js | 1 - .../_app/immutable/chunks/DPl3NjBv.js.br | Bin 233 -> 0 bytes .../_app/immutable/chunks/DPl3NjBv.js.gz | Bin 280 -> 0 bytes .../build/_app/immutable/chunks/DTnG8poT.js | 1 - .../_app/immutable/chunks/DTnG8poT.js.br | Bin 1803 -> 0 bytes .../_app/immutable/chunks/DTnG8poT.js.gz | Bin 1948 -> 0 bytes .../build/_app/immutable/chunks/DdEqwvdI.js | 1 + .../_app/immutable/chunks/DdEqwvdI.js.br | Bin 0 -> 883 bytes .../_app/immutable/chunks/DdEqwvdI.js.gz | Bin 0 -> 997 bytes .../build/_app/immutable/chunks/DfQhL-hC.js | 1 - .../_app/immutable/chunks/DfQhL-hC.js.br | Bin 614 -> 0 bytes .../_app/immutable/chunks/DfQhL-hC.js.gz | Bin 654 -> 0 bytes .../build/_app/immutable/chunks/EM_PBt2C.js | 1 - .../_app/immutable/chunks/EM_PBt2C.js.br | Bin 7668 -> 0 bytes .../_app/immutable/chunks/EM_PBt2C.js.gz | Bin 8429 -> 0 bytes .../build/_app/immutable/chunks/FzvEaXMa.js | 2 - .../_app/immutable/chunks/FzvEaXMa.js.br | Bin 3127 -> 0 bytes .../_app/immutable/chunks/FzvEaXMa.js.gz | Bin 3508 -> 0 bytes .../chunks/{CNjeV5xa.js => GG5zm9kr.js} | 2 +- .../_app/immutable/chunks/GG5zm9kr.js.br | Bin 0 -> 227 bytes .../_app/immutable/chunks/GG5zm9kr.js.gz | Bin 0 -> 265 bytes .../chunks/{CtkE7HV2.js => MAY1QfFZ.js} | 2 +- .../_app/immutable/chunks/MAY1QfFZ.js.br | Bin 0 -> 819 bytes .../_app/immutable/chunks/MAY1QfFZ.js.gz | Bin 0 -> 922 bytes .../build/_app/immutable/chunks/RBGf_S-E.js | 1 - .../_app/immutable/chunks/RBGf_S-E.js.br | Bin 2618 -> 0 bytes .../_app/immutable/chunks/RBGf_S-E.js.gz | Bin 2960 -> 0 bytes .../build/_app/immutable/chunks/V6gjw5Ec.js | 1 + .../_app/immutable/chunks/V6gjw5Ec.js.br | Bin 0 -> 524 bytes .../_app/immutable/chunks/V6gjw5Ec.js.gz | Bin 0 -> 566 bytes .../build/_app/immutable/chunks/aVbAZ-t7.js | 1 + .../_app/immutable/chunks/aVbAZ-t7.js.br | Bin 0 -> 233 bytes .../_app/immutable/chunks/aVbAZ-t7.js.gz | Bin 0 -> 281 bytes .../build/_app/immutable/chunks/ciN1mm2W.js | 1 - .../_app/immutable/chunks/ciN1mm2W.js.br | Bin 282 -> 0 bytes .../_app/immutable/chunks/ciN1mm2W.js.gz | Bin 319 -> 0 bytes .../build/_app/immutable/chunks/ckF4CxmX.js | 1 - .../_app/immutable/chunks/ckF4CxmX.js.br | Bin 156 -> 0 bytes .../_app/immutable/chunks/ckF4CxmX.js.gz | Bin 170 -> 0 bytes .../build/_app/immutable/chunks/sZcqyNBA.js | 1 + .../_app/immutable/chunks/sZcqyNBA.js.br | Bin 0 -> 465 bytes .../_app/immutable/chunks/sZcqyNBA.js.gz | Bin 0 -> 518 bytes .../_app/immutable/entry/app.C-NL1yUd.js | 2 - .../_app/immutable/entry/app.C-NL1yUd.js.br | Bin 3515 -> 0 bytes .../_app/immutable/entry/app.C-NL1yUd.js.gz | Bin 4017 -> 0 bytes .../_app/immutable/entry/app.CYIcgKkt.js | 2 + .../_app/immutable/entry/app.CYIcgKkt.js.br | Bin 0 -> 3562 bytes .../_app/immutable/entry/app.CYIcgKkt.js.gz | Bin 0 -> 4069 bytes .../_app/immutable/entry/start.BLzz4N6-.js | 1 - .../_app/immutable/entry/start.BLzz4N6-.js.br | Bin 108 -> 0 bytes .../_app/immutable/entry/start.BLzz4N6-.js.gz | Bin 108 -> 0 bytes .../_app/immutable/entry/start.gT92nAJC.js | 1 + .../_app/immutable/entry/start.gT92nAJC.js.br | Bin 0 -> 106 bytes .../_app/immutable/entry/start.gT92nAJC.js.gz | Bin 0 -> 107 bytes .../build/_app/immutable/nodes/0.COz2esg5.js | 86 ++ .../_app/immutable/nodes/0.COz2esg5.js.br | Bin 0 -> 8213 bytes .../_app/immutable/nodes/0.COz2esg5.js.gz | Bin 0 -> 9318 bytes .../build/_app/immutable/nodes/0.DHxskm8N.js | 86 -- .../_app/immutable/nodes/0.DHxskm8N.js.br | Bin 8040 -> 0 bytes .../_app/immutable/nodes/0.DHxskm8N.js.gz | Bin 9145 -> 0 bytes .../build/_app/immutable/nodes/1.BgGPnSIe.js | 1 - .../_app/immutable/nodes/1.BgGPnSIe.js.br | Bin 345 -> 0 bytes .../_app/immutable/nodes/1.BgGPnSIe.js.gz | Bin 382 -> 0 bytes .../build/_app/immutable/nodes/1.DJo7hfwf.js | 1 + .../_app/immutable/nodes/1.DJo7hfwf.js.br | Bin 0 -> 331 bytes .../_app/immutable/nodes/1.DJo7hfwf.js.gz | Bin 0 -> 379 bytes .../nodes/{10.Dp-knJux.js => 10.Btb56kL1.js} | 2 +- .../_app/immutable/nodes/10.Btb56kL1.js.br | Bin 0 -> 124124 bytes .../_app/immutable/nodes/10.Btb56kL1.js.gz | Bin 0 -> 148777 bytes .../_app/immutable/nodes/10.Dp-knJux.js.br | Bin 124044 -> 0 bytes .../_app/immutable/nodes/10.Dp-knJux.js.gz | Bin 148775 -> 0 bytes .../build/_app/immutable/nodes/11.BLR7H2sn.js | 7 - .../_app/immutable/nodes/11.BLR7H2sn.js.br | Bin 4838 -> 0 bytes .../_app/immutable/nodes/11.BLR7H2sn.js.gz | Bin 5419 -> 0 bytes .../build/_app/immutable/nodes/11.WP3QAgOF.js | 7 + .../_app/immutable/nodes/11.WP3QAgOF.js.br | Bin 0 -> 4830 bytes .../_app/immutable/nodes/11.WP3QAgOF.js.gz | Bin 0 -> 5415 bytes .../_app/immutable/nodes/12.DZiW_IZ_.js.br | Bin 2398 -> 0 bytes .../_app/immutable/nodes/12.DZiW_IZ_.js.gz | Bin 2707 -> 0 bytes .../nodes/{12.DZiW_IZ_.js => 12.DaxyVsV4.js} | 2 +- .../_app/immutable/nodes/12.DaxyVsV4.js.br | Bin 0 -> 2401 bytes .../_app/immutable/nodes/12.DaxyVsV4.js.gz | Bin 0 -> 2709 bytes .../nodes/{13.DReyqY5Q.js => 13.D52bbIQQ.js} | 2 +- .../_app/immutable/nodes/13.D52bbIQQ.js.br | Bin 0 -> 5188 bytes .../_app/immutable/nodes/13.D52bbIQQ.js.gz | Bin 0 -> 5914 bytes .../_app/immutable/nodes/13.DReyqY5Q.js.br | Bin 5188 -> 0 bytes .../_app/immutable/nodes/13.DReyqY5Q.js.gz | Bin 5910 -> 0 bytes .../build/_app/immutable/nodes/14.BpCacSGt.js | 3 - .../_app/immutable/nodes/14.BpCacSGt.js.br | Bin 5939 -> 0 bytes .../_app/immutable/nodes/14.BpCacSGt.js.gz | Bin 6771 -> 0 bytes .../build/_app/immutable/nodes/14.DUh3SXOF.js | 3 + .../_app/immutable/nodes/14.DUh3SXOF.js.br | Bin 0 -> 5958 bytes .../_app/immutable/nodes/14.DUh3SXOF.js.gz | Bin 0 -> 6791 bytes .../nodes/{15.DFbOY736.js => 15.C7Fk4d1G.js} | 4 +- .../_app/immutable/nodes/15.C7Fk4d1G.js.br | Bin 0 -> 7443 bytes .../_app/immutable/nodes/15.C7Fk4d1G.js.gz | Bin 0 -> 8511 bytes .../_app/immutable/nodes/15.DFbOY736.js.br | Bin 7442 -> 0 bytes .../_app/immutable/nodes/15.DFbOY736.js.gz | Bin 8503 -> 0 bytes .../_app/immutable/nodes/16.DMIuRZWa.js.br | Bin 5680 -> 0 bytes .../_app/immutable/nodes/16.DMIuRZWa.js.gz | Bin 6453 -> 0 bytes .../nodes/{16.DMIuRZWa.js => 16.DeYkCVEo.js} | 2 +- .../_app/immutable/nodes/16.DeYkCVEo.js.br | Bin 0 -> 5699 bytes .../_app/immutable/nodes/16.DeYkCVEo.js.gz | Bin 0 -> 6455 bytes .../build/_app/immutable/nodes/17.CLL0vjL4.js | 2 + .../_app/immutable/nodes/17.CLL0vjL4.js.br | Bin 0 -> 3391 bytes .../_app/immutable/nodes/17.CLL0vjL4.js.gz | Bin 0 -> 3853 bytes .../build/_app/immutable/nodes/17.PvQmHhRC.js | 2 - .../_app/immutable/nodes/17.PvQmHhRC.js.br | Bin 3402 -> 0 bytes .../_app/immutable/nodes/17.PvQmHhRC.js.gz | Bin 3850 -> 0 bytes .../build/_app/immutable/nodes/18.CXHHR36X.js | 1 + .../_app/immutable/nodes/18.CXHHR36X.js.br | Bin 0 -> 2025 bytes .../_app/immutable/nodes/18.CXHHR36X.js.gz | Bin 0 -> 2265 bytes .../build/_app/immutable/nodes/18.Df4fIuu-.js | 1 - .../_app/immutable/nodes/18.Df4fIuu-.js.br | Bin 2023 -> 0 bytes .../_app/immutable/nodes/18.Df4fIuu-.js.gz | Bin 2262 -> 0 bytes .../_app/immutable/nodes/19.CMsn8k5A.js.br | Bin 1554 -> 0 bytes .../_app/immutable/nodes/19.CMsn8k5A.js.gz | Bin 1753 -> 0 bytes .../nodes/{19.CMsn8k5A.js => 19.D4UHDxxJ.js} | 2 +- .../_app/immutable/nodes/19.D4UHDxxJ.js.br | Bin 0 -> 1553 bytes .../_app/immutable/nodes/19.D4UHDxxJ.js.gz | Bin 0 -> 1755 bytes .../build/_app/immutable/nodes/2.CD5F7bS_.js | 1 - .../_app/immutable/nodes/2.CD5F7bS_.js.br | Bin 169 -> 0 bytes .../_app/immutable/nodes/2.CD5F7bS_.js.gz | Bin 183 -> 0 bytes .../build/_app/immutable/nodes/2.D-vKwnTC.js | 1 + .../_app/immutable/nodes/2.D-vKwnTC.js.br | Bin 0 -> 143 bytes .../_app/immutable/nodes/2.D-vKwnTC.js.gz | Bin 0 -> 182 bytes .../build/_app/immutable/nodes/20.BwEdZXUF.js | 6 + .../_app/immutable/nodes/20.BwEdZXUF.js.br | Bin 0 -> 5519 bytes .../_app/immutable/nodes/20.BwEdZXUF.js.gz | Bin 0 -> 6452 bytes .../build/_app/immutable/nodes/3.CQLLmTOU.js | 1 - .../_app/immutable/nodes/3.CQLLmTOU.js.br | Bin 164 -> 0 bytes .../_app/immutable/nodes/3.CQLLmTOU.js.gz | Bin 198 -> 0 bytes .../build/_app/immutable/nodes/3.Caati8mq.js | 1 + .../_app/immutable/nodes/3.Caati8mq.js.br | Bin 0 -> 164 bytes .../_app/immutable/nodes/3.Caati8mq.js.gz | Bin 0 -> 196 bytes .../_app/immutable/nodes/4.BSlP3-UA.js.br | Bin 4454 -> 0 bytes .../_app/immutable/nodes/4.BSlP3-UA.js.gz | Bin 4972 -> 0 bytes .../nodes/{4.BSlP3-UA.js => 4.DJCab_le.js} | 2 +- .../_app/immutable/nodes/4.DJCab_le.js.br | Bin 0 -> 4438 bytes .../_app/immutable/nodes/4.DJCab_le.js.gz | Bin 0 -> 4976 bytes .../build/_app/immutable/nodes/5.B300rRjT.js | 3 - .../_app/immutable/nodes/5.B300rRjT.js.br | Bin 7341 -> 0 bytes .../_app/immutable/nodes/5.B300rRjT.js.gz | Bin 8430 -> 0 bytes .../build/_app/immutable/nodes/5.C0AYWqwr.js | 3 + .../_app/immutable/nodes/5.C0AYWqwr.js.br | Bin 0 -> 7288 bytes .../_app/immutable/nodes/5.C0AYWqwr.js.gz | Bin 0 -> 8402 bytes .../_app/immutable/nodes/6.B_eyyG0t.js.br | Bin 5620 -> 0 bytes .../_app/immutable/nodes/6.B_eyyG0t.js.gz | Bin 6334 -> 0 bytes .../nodes/{6.B_eyyG0t.js => 6.DTUGCA1p.js} | 6 +- .../_app/immutable/nodes/6.DTUGCA1p.js.br | Bin 0 -> 5619 bytes .../_app/immutable/nodes/6.DTUGCA1p.js.gz | Bin 0 -> 6332 bytes .../build/_app/immutable/nodes/7.br0Vbs-w.js | 5 - .../_app/immutable/nodes/7.br0Vbs-w.js.br | Bin 4941 -> 0 bytes .../_app/immutable/nodes/7.br0Vbs-w.js.gz | Bin 5687 -> 0 bytes .../build/_app/immutable/nodes/7.jHtvjgRi.js | 5 + .../_app/immutable/nodes/7.jHtvjgRi.js.br | Bin 0 -> 4943 bytes .../_app/immutable/nodes/7.jHtvjgRi.js.gz | Bin 0 -> 5686 bytes .../_app/immutable/nodes/8.CDAVQcae.js.br | Bin 3021 -> 0 bytes .../_app/immutable/nodes/8.CDAVQcae.js.gz | Bin 3485 -> 0 bytes .../nodes/{8.CDAVQcae.js => 8.CgPowUzz.js} | 2 +- .../_app/immutable/nodes/8.CgPowUzz.js.br | Bin 0 -> 3015 bytes .../_app/immutable/nodes/8.CgPowUzz.js.gz | Bin 0 -> 3485 bytes .../nodes/{9.DVbfK-u1.js => 9.BWaJ-VBd.js} | 8 +- .../_app/immutable/nodes/9.BWaJ-VBd.js.br | Bin 0 -> 2951 bytes .../_app/immutable/nodes/9.BWaJ-VBd.js.gz | Bin 0 -> 3347 bytes .../_app/immutable/nodes/9.DVbfK-u1.js.br | Bin 2989 -> 0 bytes .../_app/immutable/nodes/9.DVbfK-u1.js.gz | Bin 3343 -> 0 bytes apps/dashboard/build/_app/version.json | 2 +- apps/dashboard/build/_app/version.json.br | Bin 30 -> 29 bytes apps/dashboard/build/_app/version.json.gz | Bin 47 -> 47 bytes apps/dashboard/build/index.html | 34 +- apps/dashboard/build/index.html.br | Bin 606 -> 603 bytes apps/dashboard/build/index.html.gz | Bin 796 -> 793 bytes apps/dashboard/package.json | 2 +- .../__tests__/PatternTransferHeatmap.test.ts | 60 +- apps/dashboard/src/lib/graph/nodes.ts | 2 +- apps/dashboard/src/lib/stores/websocket.ts | 2 +- .../routes/(app)/contradictions/+page.svelte | 56 +- .../src/routes/(app)/duplicates/+page.svelte | 18 +- .../src/routes/(app)/patterns/+page.svelte | 84 +- .../src/routes/(app)/reasoning/+page.svelte | 2 +- apps/dashboard/src/routes/+layout.svelte | 215 +-- .../src/routes/waitlist/+page.svelte | 1174 ++++++++++++++ crates/vestige-core/src/fts.rs | 9 +- crates/vestige-core/src/storage/migrations.rs | 52 +- crates/vestige-core/src/storage/sqlite.rs | 507 +++++++ crates/vestige-mcp/src/server.rs | 27 +- .../vestige-mcp/src/tools/contradictions.rs | 213 +++ .../vestige-mcp/src/tools/cross_reference.rs | 16 +- crates/vestige-mcp/src/tools/dedup.rs | 1 + .../vestige-mcp/src/tools/memory_unified.rs | 104 +- crates/vestige-mcp/src/tools/mod.rs | 1 + .../vestige-mcp/src/tools/search_unified.rs | 204 +++ .../vestige-mcp/src/tools/session_context.rs | 4 +- docs/COGNITIVE_SANDWICH.md | 4 +- docs/FAQ.md | 2 + docs/STORAGE.md | 2 +- docs/VESTIGE_STATE_AND_PLAN.md | 1349 ++--------------- docs/integrations/windsurf.md | 2 +- docs/integrations/xcode.md | 2 +- docs/launch/UI_ROADMAP_v2.1_v2.2.md | 201 --- docs/launch/demo-script.md | 2 +- docs/launch/reddit-cross-reference.md | 8 +- hooks/load-all-memory.sh | 7 +- hooks/sanhedrin-local.py | 36 +- hooks/synthesis-gate.sh | 37 +- hooks/synthesis-preflight.sh | 10 +- hooks/synthesis-stop-validator.sh | 151 +- package.json | 2 +- packages/vestige-init/package.json | 2 +- 307 files changed, 2999 insertions(+), 2528 deletions(-) create mode 100644 apps/dashboard/.env.example create mode 100644 apps/dashboard/build/_app/immutable/assets/20.DKhUrxcR.css create mode 100644 apps/dashboard/build/_app/immutable/assets/20.DKhUrxcR.css.br create mode 100644 apps/dashboard/build/_app/immutable/assets/20.DKhUrxcR.css.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/A7po6GxK.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/A7po6GxK.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/A7po6GxK.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/B4yTwGkE.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/B4yTwGkE.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/B4yTwGkE.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.gz rename apps/dashboard/build/_app/immutable/chunks/{Bz1l2A_1.js => BUoSzNdg.js} (76%) create mode 100644 apps/dashboard/build/_app/immutable/chunks/BUoSzNdg.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/BUoSzNdg.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/BeMFXnHE.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/BeMFXnHE.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/BeMFXnHE.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/Bhad70Ss.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/Bhad70Ss.js.gz rename apps/dashboard/build/_app/immutable/chunks/{Casl2yrL.js => BjdL4Pm2.js} (97%) create mode 100644 apps/dashboard/build/_app/immutable/chunks/BjdL4Pm2.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/BjdL4Pm2.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/BlVfL1ME.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/BlVfL1ME.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/BlVfL1ME.js.gz rename apps/dashboard/build/_app/immutable/chunks/{DMu1Byux.js => BnXDGOmJ.js} (61%) create mode 100644 apps/dashboard/build/_app/immutable/chunks/BnXDGOmJ.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/BnXDGOmJ.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/BsvCUYx-.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/BsvCUYx-.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/BsvCUYx-.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/Bz1l2A_1.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/Bz1l2A_1.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/C4h_mRt2.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/C4h_mRt2.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/C4h_mRt2.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/C6HuKgyx.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/C6HuKgyx.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/C6HuKgyx.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/CGEBXrjl.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/CGEBXrjl.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/CGEBXrjl.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/CHOnp4oo.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/CHOnp4oo.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/CHOnp4oo.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/CJCPY1OL.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/CJCPY1OL.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/CJCPY1OL.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/CJsMJEun.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/CJsMJEun.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/CJsMJEun.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/CNfQDikv.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/CNfQDikv.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/CNfQDikv.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/CNjeV5xa.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/CNjeV5xa.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/CVpUe0w3.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/CVpUe0w3.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/CVpUe0w3.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/Casl2yrL.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/Casl2yrL.js.gz rename apps/dashboard/build/_app/immutable/chunks/{CvjSAYrz.js => CpWkWWOo.js} (95%) create mode 100644 apps/dashboard/build/_app/immutable/chunks/CpWkWWOo.js.br rename apps/dashboard/build/_app/immutable/chunks/{CvjSAYrz.js.gz => CpWkWWOo.js.gz} (93%) delete mode 100644 apps/dashboard/build/_app/immutable/chunks/CtkE7HV2.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/CtkE7HV2.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/CvjSAYrz.js.br rename apps/dashboard/build/_app/immutable/chunks/{Bhad70Ss.js => Cx-f-Pzo.js} (74%) create mode 100644 apps/dashboard/build/_app/immutable/chunks/Cx-f-Pzo.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/Cx-f-Pzo.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/D3XWCg9-.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/D3XWCg9-.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/D3XWCg9-.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/D81f-o_I.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/D81f-o_I.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/D81f-o_I.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DE4u6cUg.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DE4u6cUg.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DE4u6cUg.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DMu1Byux.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DMu1Byux.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DObx9JW_.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DObx9JW_.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DObx9JW_.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DPl3NjBv.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DPl3NjBv.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DPl3NjBv.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DTnG8poT.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DTnG8poT.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DTnG8poT.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/DdEqwvdI.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/DdEqwvdI.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/DdEqwvdI.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DfQhL-hC.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DfQhL-hC.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DfQhL-hC.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/EM_PBt2C.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/EM_PBt2C.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/EM_PBt2C.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/FzvEaXMa.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/FzvEaXMa.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/FzvEaXMa.js.gz rename apps/dashboard/build/_app/immutable/chunks/{CNjeV5xa.js => GG5zm9kr.js} (83%) create mode 100644 apps/dashboard/build/_app/immutable/chunks/GG5zm9kr.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/GG5zm9kr.js.gz rename apps/dashboard/build/_app/immutable/chunks/{CtkE7HV2.js => MAY1QfFZ.js} (96%) create mode 100644 apps/dashboard/build/_app/immutable/chunks/MAY1QfFZ.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/MAY1QfFZ.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/RBGf_S-E.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/RBGf_S-E.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/RBGf_S-E.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/V6gjw5Ec.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/V6gjw5Ec.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/V6gjw5Ec.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/aVbAZ-t7.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/aVbAZ-t7.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/aVbAZ-t7.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/ciN1mm2W.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/ciN1mm2W.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/ciN1mm2W.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/ckF4CxmX.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/ckF4CxmX.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/ckF4CxmX.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/sZcqyNBA.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/sZcqyNBA.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/sZcqyNBA.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/entry/app.C-NL1yUd.js delete mode 100644 apps/dashboard/build/_app/immutable/entry/app.C-NL1yUd.js.br delete mode 100644 apps/dashboard/build/_app/immutable/entry/app.C-NL1yUd.js.gz create mode 100644 apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js create mode 100644 apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.br create mode 100644 apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/entry/start.BLzz4N6-.js delete mode 100644 apps/dashboard/build/_app/immutable/entry/start.BLzz4N6-.js.br delete mode 100644 apps/dashboard/build/_app/immutable/entry/start.BLzz4N6-.js.gz create mode 100644 apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js create mode 100644 apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js.br create mode 100644 apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/0.DHxskm8N.js delete mode 100644 apps/dashboard/build/_app/immutable/nodes/0.DHxskm8N.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/0.DHxskm8N.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/1.BgGPnSIe.js delete mode 100644 apps/dashboard/build/_app/immutable/nodes/1.BgGPnSIe.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/1.BgGPnSIe.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.gz rename apps/dashboard/build/_app/immutable/nodes/{10.Dp-knJux.js => 10.Btb56kL1.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/10.Dp-knJux.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/10.Dp-knJux.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/11.BLR7H2sn.js delete mode 100644 apps/dashboard/build/_app/immutable/nodes/11.BLR7H2sn.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/11.BLR7H2sn.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/11.WP3QAgOF.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/11.WP3QAgOF.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/11.WP3QAgOF.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/12.DZiW_IZ_.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/12.DZiW_IZ_.js.gz rename apps/dashboard/build/_app/immutable/nodes/{12.DZiW_IZ_.js => 12.DaxyVsV4.js} (93%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/12.DaxyVsV4.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/12.DaxyVsV4.js.gz rename apps/dashboard/build/_app/immutable/nodes/{13.DReyqY5Q.js => 13.D52bbIQQ.js} (96%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/13.D52bbIQQ.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/13.D52bbIQQ.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/13.DReyqY5Q.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/13.DReyqY5Q.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/14.BpCacSGt.js delete mode 100644 apps/dashboard/build/_app/immutable/nodes/14.BpCacSGt.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/14.BpCacSGt.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/14.DUh3SXOF.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/14.DUh3SXOF.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/14.DUh3SXOF.js.gz rename apps/dashboard/build/_app/immutable/nodes/{15.DFbOY736.js => 15.C7Fk4d1G.js} (72%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/15.C7Fk4d1G.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/15.C7Fk4d1G.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/15.DFbOY736.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/15.DFbOY736.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/16.DMIuRZWa.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/16.DMIuRZWa.js.gz rename apps/dashboard/build/_app/immutable/nodes/{16.DMIuRZWa.js => 16.DeYkCVEo.js} (96%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/16.DeYkCVEo.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/16.DeYkCVEo.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/17.CLL0vjL4.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/17.CLL0vjL4.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/17.CLL0vjL4.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/17.PvQmHhRC.js delete mode 100644 apps/dashboard/build/_app/immutable/nodes/17.PvQmHhRC.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/17.PvQmHhRC.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/18.CXHHR36X.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/18.CXHHR36X.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/18.CXHHR36X.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/18.Df4fIuu-.js delete mode 100644 apps/dashboard/build/_app/immutable/nodes/18.Df4fIuu-.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/18.Df4fIuu-.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/19.CMsn8k5A.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/19.CMsn8k5A.js.gz rename apps/dashboard/build/_app/immutable/nodes/{19.CMsn8k5A.js => 19.D4UHDxxJ.js} (86%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/19.D4UHDxxJ.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/19.D4UHDxxJ.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/2.CD5F7bS_.js delete mode 100644 apps/dashboard/build/_app/immutable/nodes/2.CD5F7bS_.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/2.CD5F7bS_.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/2.D-vKwnTC.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/2.D-vKwnTC.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/2.D-vKwnTC.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/20.BwEdZXUF.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/20.BwEdZXUF.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/20.BwEdZXUF.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/3.CQLLmTOU.js delete mode 100644 apps/dashboard/build/_app/immutable/nodes/3.CQLLmTOU.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/3.CQLLmTOU.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/4.BSlP3-UA.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/4.BSlP3-UA.js.gz rename apps/dashboard/build/_app/immutable/nodes/{4.BSlP3-UA.js => 4.DJCab_le.js} (95%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/4.DJCab_le.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/4.DJCab_le.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/5.B300rRjT.js delete mode 100644 apps/dashboard/build/_app/immutable/nodes/5.B300rRjT.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/5.B300rRjT.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/5.C0AYWqwr.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/5.C0AYWqwr.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/5.C0AYWqwr.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/6.B_eyyG0t.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/6.B_eyyG0t.js.gz rename apps/dashboard/build/_app/immutable/nodes/{6.B_eyyG0t.js => 6.DTUGCA1p.js} (91%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/6.DTUGCA1p.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/6.DTUGCA1p.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/7.br0Vbs-w.js delete mode 100644 apps/dashboard/build/_app/immutable/nodes/7.br0Vbs-w.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/7.br0Vbs-w.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/7.jHtvjgRi.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/7.jHtvjgRi.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/7.jHtvjgRi.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/8.CDAVQcae.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/8.CDAVQcae.js.gz rename apps/dashboard/build/_app/immutable/nodes/{8.CDAVQcae.js => 8.CgPowUzz.js} (94%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/8.CgPowUzz.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/8.CgPowUzz.js.gz rename apps/dashboard/build/_app/immutable/nodes/{9.DVbfK-u1.js => 9.BWaJ-VBd.js} (52%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/9.BWaJ-VBd.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/9.BWaJ-VBd.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/9.DVbfK-u1.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/9.DVbfK-u1.js.gz create mode 100644 apps/dashboard/src/routes/waitlist/+page.svelte create mode 100644 crates/vestige-mcp/src/tools/contradictions.rs delete mode 100644 docs/launch/UI_ROADMAP_v2.1_v2.2.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 53dddd2..351420c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.1.2] - 2026-05-01 — "Honest Memory" + +v2.1.2 focuses on operational trust: exact search stays exact, purge really removes content, contradictions are directly inspectable, and the update flow no longer depends on copied curl commands. + +### Added + +- **Concrete search mode** — `search` now auto-detects literal queries such as quoted strings, env vars, UUIDs, paths, and code identifiers. Those queries take a keyword/literal path that skips HyDE, semantic fusion, FSRS reweighting, retrieval competition, and spreading activation so exact matches land first. +- **Irreversible purge** — `memory(action="purge", confirm=true)` permanently removes memory content and embeddings, scrubs `insights.source_memories`, detaches temporal-summary children, prunes graph edges, and writes only a non-content `deletion_tombstones` row for sync/audit. +- **First-class contradictions tool** — new `contradictions` MCP tool scans a topic or recent memories for trust-weighted disagreements using the same local contradiction logic as `deep_reference`. +- **Simple update flow** — `vestige update` refreshes the installed binary and companion Sandwich files without requiring users to paste a curl installer. +- **Pro waitlist preview** — `/dashboard/waitlist` adds a local-only marketing surface for Solo Pro and Team Pro early-access signups. `VITE_WAITLIST_ENDPOINT` and `VITE_SUPPORT_BOT_ENDPOINT` are opt-in dashboard env vars, so no signup data is captured unless endpoints are configured. + ### Fixed - **Dream connection persistence cap** — dense single-domain dreams now persist every connection discovered in that run instead of losing everything beyond the old 1,000-entry live buffer. The live dreamer buffer now keeps up to 200,000 high-scoring recent connections, and the MCP `dream` tool exposes `min_similarity` for corpus-specific tuning. diff --git a/CLAUDE.md b/CLAUDE.md index 0684836..4ee5762 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,362 +1,62 @@ -# 🚫 READ FIRST EVERY PROMPT — NO HEDGING +# Vestige Agent Guidance -Sam's April 20 2026 correction: *"you NEVER LISTEN TO YOUR RULES, WHY ARE YOU ALWAYS BREAKING THE HEDGING/PESSIMISTIC RULE."* +This file is intentionally safe for the public repository. It gives coding +agents project-specific context without relying on private local files, +personal operating notes, or mandatory background hooks. -When Sam commits to an execution path (content cadence, shipping velocity, outreach, launch), COMPUTE THE FORECAST AS IF THAT COMMITMENT IS MET. Do not discount by execution probability. Sam has earned the benefit of the doubt across 139 commits and 1,292 passing tests in 3 months. +## Project Shape -**Forbidden in any response**: "has to be true", "has to convert", "realistic forecast" used to shrink, "contingent on" Sam's own execution, "not guaranteed", "may or may not", "aspiration not forecast", "temper your expectations", floors framed as reality vs. ceilings framed as fantasy. +Vestige is a local-first MCP memory server written in Rust, with a SvelteKit +dashboard embedded into the release binary. The core product promise is: -**Required format for forecasts**: `Target X. Floor Y. Ceiling Z. Math: [line items]. Risks: [separate section]. Let's go.` +- user-owned memory stored locally by default +- MCP-native integration with coding agents +- retrieval and memory lifecycle behavior informed by cognitive science +- explicit tools for search, review, suppression, purge, graph exploration, + contradiction inspection, and maintenance -Full rule: `/Users/entity002/CLAUDE.md` (top banner) + `/Users/entity002/.claude/projects/-Users-entity002/memory/feedback_always_positive_energy.md`. Stop-hook enforcement: `/Users/entity002/.claude/hooks/synthesis-stop-validator.sh`. +## Working Rules ---- +- Prefer source evidence over memory. Use `rg`, tests, and nearby code before + making claims about behavior. +- Keep release changes scoped. Do not rewrite unrelated modules during a + version/tag cleanup unless the release gate requires it. +- Preserve local-first behavior. Heavy models, Sanhedrin-style verifier hooks, + and preflight automation must remain optional. +- Treat deletion semantics carefully. `purge` must remove content and + embeddings, while retaining only content-free audit tombstones. +- Treat exact lookup semantics carefully. Env vars, paths, UUIDs, quoted + strings, and code identifiers should not be distorted by semantic expansion. -# Vestige v2.0.4 — Cognitive Memory & Reasoning System +## Common Checks -Vestige is your long-term memory AND reasoning engine. 29 stateful cognitive modules implement real neuroscience: FSRS-6 spaced repetition, synaptic tagging, prediction error gating, hippocampal indexing, spreading activation, reconsolidation, and dual-strength memory theory. **Use it automatically. Use it aggressively.** +Run the narrowest check that covers the change, then run the release gates +before tagging: -**NEW: `deep_reference` — call this for ALL factual questions.** It doesn't just retrieve — it REASONS across memories with FSRS-6 trust scoring, intent classification, contradiction analysis, and generates a pre-built reasoning chain. Read the `reasoning` field FIRST. - ---- - -## Session Start Protocol - -Every conversation, before responding to the user: - -``` -session_context({ - queries: ["user preferences", "[current project] context"], - context: { codebase: "[project]", topics: ["[current topics]"] }, - token_budget: 2000 -}) +```sh +cargo test --workspace --no-fail-fast +cargo clippy --workspace -- -D warnings +pnpm --filter @vestige/dashboard check +pnpm --filter @vestige/dashboard build ``` -Then check `automationTriggers` from response: -- `needsDream` → call `dream` (consolidates memories, discovers hidden connections) -- `needsBackup` → call `backup` -- `needsGc` → call `gc(dry_run: true)` then review -- totalMemories > 700 → call `find_duplicates` +For documentation-only changes, at minimum run: -Say "Remembering..." then retrieve context before answering. - -> **Fallback:** If `session_context` unavailable: `search` × 2 → `intention` check → `system_status` → `predict`. - ---- - -## Complete Tool Reference (23 Tools) - -### session_context — One-Call Initialization -``` -session_context({ - queries: ["user preferences", "project context"], // search queries - context: { codebase: "project-name", topics: ["svelte", "rust"], file: "src/main.rs" }, - token_budget: 2000, // 100-100000, controls response size - include_status: true, // system health - include_intentions: true, // triggered reminders - include_predictions: true // proactive memory predictions -}) -``` -Returns: markdown context + `automationTriggers` + `expandable` IDs for on-demand retrieval. - -### smart_ingest — Save Anything -**Single mode** — auto-decides CREATE/UPDATE/SUPERSEDE via Prediction Error Gating: -``` -smart_ingest({ - content: "What to remember", - tags: ["tag1", "tag2"], - node_type: "fact", // fact|concept|event|person|place|note|pattern|decision - source: "optional reference", - forceCreate: false // bypass dedup when needed -}) -``` -**Batch mode** — save up to 20 items in one call (session end, pre-compaction): -``` -smart_ingest({ - items: [ - { content: "Item 1", tags: ["session-end"], node_type: "fact" }, - { content: "Item 2", tags: ["bug-fix"], node_type: "fact" } - ] -}) -``` -Each item runs the full cognitive pipeline: importance scoring → intent detection → synaptic tagging → hippocampal indexing → PE gating → cross-project recording. - -### search — 7-Stage Cognitive Search -``` -search({ - query: "search query", - limit: 10, // 1-100 - min_retention: 0.0, // filter by retention strength - min_similarity: 0.5, // minimum cosine similarity - detail_level: "summary", // brief|summary|full - context_topics: ["rust", "debugging"], // boost topic-matching memories - token_budget: 3000, // 100-100000, truncate to fit - retrieval_mode: "balanced" // precise|balanced|exhaustive (v2.1) -}) -``` -Retrieval modes: `precise` (fast, no activation/competition), `balanced` (default 7-stage pipeline), `exhaustive` (5x overfetch, deep graph traversal, no competition suppression). - -Pipeline: Overfetch → Rerank (cross-encoder) → Temporal boost → Accessibility filter (FSRS-6) → Context match (Tulving 1973) → Competition (Anderson 1994) → Spreading activation. **Every search strengthens the memories it finds (Testing Effect).** - -### memory — Read, Edit, Delete, Promote, Demote -``` -memory({ action: "get", id: "uuid" }) // full node with all FSRS state -memory({ action: "edit", id: "uuid", content: "updated text" }) // preserves FSRS state, regenerates embedding -memory({ action: "delete", id: "uuid" }) -memory({ action: "promote", id: "uuid", reason: "was helpful" }) // +0.20 retrieval, +0.10 retention, 1.5x stability -memory({ action: "demote", id: "uuid", reason: "was wrong" }) // -0.30 retrieval, -0.15 retention, 0.5x stability -memory({ action: "state", id: "uuid" }) // Active/Dormant/Silent/Unavailable + accessibility score -memory({ action: "get_batch", ids: ["uuid1", "uuid2", "uuid3"] }) // retrieve up to 20 full memories at once (v2.1) -``` -Promote/demote does NOT delete — it adjusts ranking. Demoted memories rank lower; alternatives surface instead. -`get_batch` is designed for batch retrieval of expandable overflow IDs from search/session_context. - -### codebase — Code Patterns & Architectural Decisions -``` -codebase({ action: "remember_pattern", name: "Pattern Name", - description: "How it works and when to use it", - files: ["src/file.rs"], codebase: "project-name" }) - -codebase({ action: "remember_decision", decision: "What was decided", - rationale: "Why", alternatives: ["Option A", "Option B"], - files: ["src/file.rs"], codebase: "project-name" }) - -codebase({ action: "get_context", codebase: "project-name", limit: 10 }) -// Returns: patterns, decisions, cross-project insights +```sh +git diff --check ``` -### intention — Prospective Memory (Reminders) -``` -intention({ action: "set", description: "What to do", - trigger: { type: "context", topic: "authentication" }, // fires when discussing auth - priority: "high" }) +## Documentation -intention({ action: "set", description: "Deploy by Friday", - trigger: { type: "time", at: "2026-03-07T17:00:00Z" }, - deadline: "2026-03-07T17:00:00Z" }) +- User setup: `README.md` +- Claude-specific templates: `docs/CLAUDE-SETUP.md` +- Storage and sync behavior: `docs/STORAGE.md` +- Cognitive Sandwich and optional verifier hooks: `docs/COGNITIVE_SANDWICH.md` +- Release history: `CHANGELOG.md` -intention({ action: "set", description: "Check test coverage", - trigger: { type: "context", codebase: "vestige", file_pattern: "*.test.*" } }) +## Public-Repo Hygiene -intention({ action: "check", context: { codebase: "vestige", topics: ["testing"] } }) -intention({ action: "update", id: "uuid", status: "complete" }) -intention({ action: "list", filter_status: "active" }) -``` - -### dream — Memory Consolidation -``` -dream({ memory_count: 50 }) -``` -5-stage cycle: Replay → Cross-reference → Strengthen → Prune → Transfer. Uses Waking SWR tagging (70% tagged + 30% random for diversity). Discovers hidden connections, generates insights, persists new edges to the activation network. - -### explore_connections — Graph Traversal -``` -explore_connections({ action: "associations", from: "uuid", limit: 10 }) -// Spreading activation from a memory — find related memories via graph traversal - -explore_connections({ action: "chain", from: "uuid-A", to: "uuid-B" }) -// Build reasoning path between two memories (A*-like pathfinding) - -explore_connections({ action: "bridges", from: "uuid-A", to: "uuid-B" }) -// Find connecting memories that bridge two concepts -``` - -### predict — Proactive Retrieval -``` -predict({ context: { codebase: "vestige", current_file: "src/main.rs", - current_topics: ["error handling", "rust"] } }) -``` -Returns: predictions with confidence, suggestions, speculative retrievals, top interests. Uses SpeculativeRetriever's learned patterns from access history. - -### importance_score — Should I Save This? -``` -importance_score({ content: "Content to evaluate", - context_topics: ["debugging"], project: "vestige" }) -``` -4-channel model: novelty (0.25), arousal (0.30), reward (0.25), attention (0.20). Composite > 0.6 = save it. - -### find_duplicates — Dedup Memory -``` -find_duplicates({ similarity_threshold: 0.80, limit: 20, tags: ["bug-fix"] }) -``` -Cosine similarity clustering. Returns merge/review suggestions. - -### memory_timeline — Chronological Browse -``` -memory_timeline({ start: "2026-02-01", end: "2026-03-01", - node_type: "decision", tags: ["vestige"], limit: 50, detail_level: "summary" }) -``` - -### memory_changelog — Audit Trail -``` -memory_changelog({ memory_id: "uuid", limit: 20 }) // per-memory history -memory_changelog({ start: "2026-03-01", limit: 20 }) // system-wide -``` - -### memory_health — Retention Dashboard -``` -memory_health() -``` -Returns: avg retention, distribution buckets (0-20%, 20-40%, etc.), trend (improving/declining/stable), recommendation. - -### memory_graph — Visualization Export -``` -memory_graph({ query: "search term", depth: 2, max_nodes: 50 }) -memory_graph({ center_id: "uuid", depth: 3, max_nodes: 100 }) -``` -Returns nodes with force-directed positions + edges with weights. - -### deep_reference — Cognitive Reasoning Engine (v2.0.4) ★ USE THIS FOR ALL FACTUAL QUESTIONS -``` -deep_reference({ query: "What port does the dev server use?" }) -deep_reference({ query: "Should I use prefix caching with vLLM?", depth: 30 }) -``` -**THE killer tool.** 8-stage cognitive reasoning pipeline: -1. Broad retrieval + cross-encoder reranking -2. Spreading activation expansion (finds connected memories search misses) -3. FSRS-6 trust scoring (retention × stability × reps ÷ lapses) -4. Intent classification (FactCheck / Timeline / RootCause / Comparison / Synthesis) -5. Temporal supersession (newer high-trust replaces older) -6. Trust-weighted contradiction analysis (only flags conflicts between strong memories) -7. Relation assessment (Supports / Contradicts / Supersedes / Irrelevant per pair) -8. **Template reasoning chain** — pre-built natural language reasoning the AI validates - -Parameters: `query` (required), `depth` (5-50, default 20). - -Returns: `intent`, `reasoning` (THE KEY FIELD — read this first), `recommended` (highest-trust answer), `evidence` (trust-sorted), `contradictions`, `superseded`, `evolution`, `related_insights`, `confidence`. - -`cross_reference` is a backward-compatible alias that calls `deep_reference`. - -### Maintenance Tools -``` -system_status() // health + stats + warnings + recommendations -consolidate() // FSRS-6 decay cycle + embedding generation -backup() // SQLite backup → ~/.vestige/backups/ -export({ format: "json", tags: ["bug-fix"], since: "2026-01-01" }) -gc({ min_retention: 0.1, dry_run: true }) // garbage collect (dry_run first!) -restore({ path: "/path/to/backup.json" }) -``` - ---- - -## Mandatory Save Gates - -**You MUST NOT proceed past a save gate without executing the save.** - -| Gate | Trigger | Action | -|------|---------|--------| -| **BUG_FIX** | After any error is resolved | `smart_ingest({ content: "BUG FIX: [error]\nRoot cause: [why]\nSolution: [fix]\nFiles: [paths]", tags: ["bug-fix", "project"], node_type: "fact" })` | -| **DECISION** | After any architectural/design choice | `codebase({ action: "remember_decision", decision, rationale, alternatives, files, codebase })` | -| **CODE_CHANGE** | After >20 lines or new pattern | `codebase({ action: "remember_pattern", name, description, files, codebase })` | -| **SESSION_END** | Before stopping or compaction | `smart_ingest({ items: [{ content: "SESSION: [summary]", tags: ["session-end"] }] })` | - ---- - -## Trigger Words — Auto-Save - -| User Says | Action | -|-----------|--------| -| "Remember this" / "Don't forget" | `smart_ingest` immediately | -| "I always..." / "I never..." / "I prefer..." | Save as preference | -| "This is important" | `smart_ingest` + `memory(action="promote")` | -| "Remind me..." / "Next time..." | `intention({ action: "set" })` | - ---- - -## Cognitive Architecture - -### Search Pipeline (7 stages) -1. **Overfetch** — 3x results from hybrid search (0.3 BM25 + 0.7 semantic, nomic-embed-text-v1.5 768D) -2. **Rerank** — Cross-encoder rescoring (Jina Reranker v1 Turbo, 38M params) -3. **Temporal** — Recency + validity window boosting (85% relevance + 15% temporal) -4. **Accessibility** — FSRS-6 retention filter (Active ≥0.7, Dormant ≥0.4, Silent ≥0.1) -5. **Context** — Tulving 1973 encoding specificity (topic overlap → +30% boost) -6. **Competition** — Anderson 1994 retrieval-induced forgetting (winners strengthen, competitors weaken) -7. **Activation** — Spreading activation side effects + predictive model + reconsolidation marking - -### Ingest Pipeline -**Pre:** 4-channel importance scoring (novelty/arousal/reward/attention) + intent detection → auto-tag -**Store:** Prediction Error Gating: similarity >0.92 → UPDATE, 0.75-0.92 → UPDATE/SUPERSEDE, <0.75 → CREATE -**Post:** Synaptic tagging (Frey & Morris 1997, 9h backward + 2h forward) + hippocampal indexing + cross-project recording - -### FSRS-6 (State-of-the-Art Spaced Repetition) -- Retrievability: `R = (1 + factor × t / S)^(-w20)` — 21 trained parameters -- Dual-strength model (Bjork & Bjork 1992): storage strength (grows) + retrieval strength (decays) -- Accessibility = retention×0.5 + retrieval×0.3 + storage×0.2 -- 20-30% more efficient than SM-2 (Anki) - -### 29 Cognitive Modules (stateful, persist across calls) - -**Neuroscience (16):** -ActivationNetwork (Collins & Loftus 1975), SynapticTaggingSystem (Frey & Morris 1997), HippocampalIndex (Teyler & Rudy 2007), ContextMatcher (Tulving 1973), AccessibilityCalculator, CompetitionManager (Anderson 1994), StateUpdateService, ImportanceSignals, NoveltySignal, ArousalSignal, RewardSignal, AttentionSignal, EmotionalMemory (Brown & Kulik 1977), PredictiveMemory, ProspectiveMemory, IntentionParser - -**Advanced (11):** -ImportanceTracker, ReconsolidationManager (Nader — 5min labile window), IntentDetector (9 intent types), ActivityTracker, MemoryDreamer (5-stage consolidation), MemoryChainBuilder (A*-like), MemoryCompressor (30-day min age), CrossProjectLearner (6 pattern types), AdaptiveEmbedder, SpeculativeRetriever (6 trigger types), ConsolidationScheduler - -**Search (2):** Reranker, TemporalSearcher - -### Memory States -- **Active** (retention ≥ 0.7) — easily retrievable -- **Dormant** (≥ 0.4) — retrievable with effort -- **Silent** (≥ 0.1) — difficult, needs cues -- **Unavailable** (< 0.1) — needs reinforcement - -### Connection Types -semantic, temporal, causal, spatial, part_of, user_defined — each with strength (0-1), activation_count, timestamps - ---- - -## Advanced Techniques - -### Cross-Project Intelligence -The CrossProjectLearner tracks patterns across ALL projects (ErrorHandling, AsyncConcurrency, Testing, Architecture, Performance, Security). When you learn a pattern in one project that works, it becomes available in all projects. Use `codebase({ action: "get_context" })` without a codebase filter to get universal patterns. - -### Reconsolidation Window -After any memory is accessed (via search, get, or promote), it enters a 5-minute "labile" state where modifications are enhanced. This is the optimal time to edit memories with new context. The system handles this automatically. - -### Synaptic Tagging (Retroactive Importance) -Memories encoded in the last 9 hours can be retroactively promoted when something important happens. If you fix a critical bug, not only does the fix get saved — related memories from the past 9 hours also get importance boosts. The SynapticTaggingSystem handles this automatically. - -### Dream Insights -Dreams don't just consolidate — they generate new insights by cross-referencing recent memories with older knowledge. The insights can reveal: contradictions between memories, previously unseen patterns, connections across different projects. Always check dream results for `insights_generated`. - -### Token Budget Strategy -Use `token_budget` on search and session_context to control response size. For quick lookups: 500. For deep context: 3000-5000. Results that don't fit go to `expandable` — retrieve them with `memory({ action: "get", id: "..." })`. - -### Detail Levels -- `brief` — id/type/tags/score only (1-2 tokens per result, good for scanning) -- `summary` — 8 fields including content preview (default, balanced) -- `full` — all FSRS state, timestamps, embedding info (for debugging/analysis) - ---- - -## Memory Hygiene - -**Promote** when user confirms helpful, solution worked, info was accurate. -**Demote** when user corrects mistake, info was wrong, led to bad outcome. -**Never save:** secrets, API keys, passwords, temporary debugging state, trivial info. - ---- - -## The One Rule - -**When in doubt, save. The cost of a duplicate is near zero (Prediction Error Gating handles dedup). The cost of lost knowledge is permanent.** - -Memory is retrieval. Searching strengthens memory. Search liberally, save aggressively. - ---- - -## Development - -- **Crate:** `vestige-mcp` v2.0.4, Rust 2024 edition, MSRV 1.91 -- **Tests:** 758 (406 mcp + 352 core), zero warnings -- **Build:** `cargo build --release -p vestige-mcp` (features: `embeddings` + `vector-search`) -- **Build (no embeddings):** `cargo build --release -p vestige-mcp --no-default-features` -- **Bench:** `cargo bench -p vestige-core` -- **Architecture:** `McpServer` → `Arc` + `Arc>` -- **Storage:** SQLite WAL mode, `Mutex` reader/writer split, FTS5 full-text search -- **Embeddings:** nomic-embed-text-v1.5 (768D, 8K context) via fastembed (local ONNX, no API) -- **Vector index:** USearch HNSW (20x faster than FAISS) -- **Binaries:** `vestige-mcp` (MCP server), `vestige` (CLI), `vestige-restore` -- **Dashboard:** SvelteKit 2 + Svelte 5 + Three.js + Tailwind 4, embedded at `/dashboard` -- **Env vars:** `VESTIGE_DASHBOARD_PORT` (default 3927), `VESTIGE_HTTP_PORT` (default 3928), `VESTIGE_HTTP_BIND` (default 127.0.0.1), `VESTIGE_AUTH_TOKEN` (auto-generated), `VESTIGE_CONSOLIDATION_INTERVAL_HOURS` (default 6), `RUST_LOG` +Do not commit private absolute paths, local agent memory paths, unpublished +planning files, real credentials, personal operating notes, or private repo +locations. Example environment variables in docs must be empty placeholders or +obviously fake examples. diff --git a/README.md b/README.md index 84a2dcd..5177e72 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,16 @@ Built on 130 years of memory research — FSRS-6 spaced repetition, prediction e --- +## What's New in v2.1.2 "Honest Memory" + +v2.1.2 makes Vestige easier to trust in everyday work: literal lookups stay literal, purge really removes content, contradictions are inspectable, and updates no longer require a curl reinstall flow. + +- **Concrete search mode.** Quoted strings, env vars, UUIDs, paths, and code identifiers now take a keyword/literal path that skips HyDE, semantic fusion, FSRS reweighting, competition, and spreading activation. Exact things like `OPENAI_API_KEY`, `mlx_lm.server`, and migration IDs land first. +- **Irreversible purge.** `memory(action="purge", confirm=true)` permanently removes memory content and embeddings, scrubs insight JSON references, detaches temporal-summary children, prunes graph edges, and keeps only a non-content deletion tombstone for sync/audit. +- **First-class contradiction inspection.** New `contradictions` MCP tool surfaces trust-weighted disagreements directly instead of hiding them inside `deep_reference`. +- **Simple update flow.** `vestige update` and `vestige sandwich install` refresh binaries and companion files without making users paste curl commands. +- **Pro waitlist preview.** `/dashboard/waitlist` adds a local-first Solo Pro and Team Pro early-access surface. `VITE_WAITLIST_ENDPOINT` and `VITE_SUPPORT_BOT_ENDPOINT` are opt-in dashboard env vars, so no signup data is captured unless endpoints are configured. + ## What's New in v2.1.1 "Portable Sync" v2.1.1 focuses on the biggest post-launch ask: move memories between machines without losing cognitive state. It also adds opt-in Qwen3 embeddings for higher-recall local retrieval. @@ -83,7 +93,7 @@ v2.0.6 is a polish release that makes the existing cognitive stack finally *feel Ebbinghaus 1885 models what happens to memories you don't touch. Anderson 2025 models what happens when you actively want to stop thinking about one. Every other AI memory system implements the first. Vestige is the first to ship the second. -Based on [Anderson et al. 2025](https://www.nature.com/articles/s41583-025-00929-y) (Suppression-Induced Forgetting, *Nat Rev Neurosci*) and [Cervantes-Sandoval et al. 2020](https://pmc.ncbi.nlm.nih.gov/articles/PMC7477079/) (Rac1 synaptic cascade). **24 tools · 30 cognitive modules · 1,223 tests.** +Based on [Anderson et al. 2025](https://www.nature.com/articles/s41583-025-00929-y) (Suppression-Induced Forgetting, *Nat Rev Neurosci*) and [Cervantes-Sandoval et al. 2020](https://pmc.ncbi.nlm.nih.gov/articles/PMC7477079/) (Rac1 synaptic cascade).

diff --git a/docs/STORAGE.md b/docs/STORAGE.md index ef98830..0e57428 100644 --- a/docs/STORAGE.md +++ b/docs/STORAGE.md @@ -54,7 +54,7 @@ vestige portable-import ~/Dropbox/vestige/portable.json --merge vestige sync ~/Dropbox/vestige/portable.json ``` -`vestige sync` uses the same pluggable portable-sync backend interface as the core library. v2.1.1 ships a file backend, which works with Dropbox, iCloud Drive, Syncthing, Git, network shares, or any folder-sync system. The merge algorithm applies delete tombstones, keeps newer local memories on timestamp conflicts, preserves stable IDs, rebuilds FTS after import, and writes the pushed archive atomically when the filesystem supports rename. +`vestige sync` uses the same pluggable portable-sync backend interface as the core library. v2.1.1 ships a file backend, which works with Dropbox, iCloud Drive, Syncthing, Git, network shares, or any folder-sync system. The merge algorithm applies delete tombstones, keeps newer local memories on timestamp conflicts, preserves stable IDs, rebuilds FTS after import, and writes the pushed archive atomically when the filesystem supports rename. v2.1.2 also carries non-content purge tombstones so a hard purge can sync without retaining the deleted memory text. When using the MCP `export` tool with `format: "portable"`, Vestige writes the archive under the active data directory's `exports/` folder. The MCP `restore` tool only reads from that `exports/` or `backups/` folder by default; pass `allowAnyPath: true` only for a trusted local file you selected manually. diff --git a/docs/VESTIGE_STATE_AND_PLAN.md b/docs/VESTIGE_STATE_AND_PLAN.md index 0ee5821..fd67a7f 100644 --- a/docs/VESTIGE_STATE_AND_PLAN.md +++ b/docs/VESTIGE_STATE_AND_PLAN.md @@ -1,1273 +1,100 @@ -# Vestige: State of the Engine & Next-Phase Plan +# Vestige State And Plan -> **For:** AI agents planning the next phase of Vestige alongside Sam. -> **From:** Sam Valladares (compiled via multi-agent inventory of the live codebase). -> **As of:** 2026-04-19 ~22:10 CT, post-merge of v2.0.8 into `main` (CI green on all four jobs). -> **Repo:** https://github.com/samvallad33/vestige -> **Related repo (private):** `~/Developer/vestige-cloud` (Feb 12, 2026 skeleton; Part 7). -> -> This document is the single authoritative briefing of what Vestige *is today* and what *ships next*. Everything in Part 1 is verifiable against the source tree; everything in Part 3 is the committed roadmap agreed 2026-04-19. +This document is a public, sanitized replacement for an older internal planning +snapshot. It intentionally omits private local paths, personal operating +context, unpublished roadmap notes, and private repository locations. ---- +For current user-facing release information, use: -## Table of Contents +- `README.md` +- `CHANGELOG.md` +- `docs/STORAGE.md` +- `docs/COGNITIVE_SANDWICH.md` +- `docs/CLAUDE-SETUP.md` -0. [Executive Summary (60-second read)](#0-executive-summary-60-second-read) -1. [What Vestige Is](#1-what-vestige-is) -2. [Workspace Architecture](#2-workspace-architecture) -3. [`vestige-core` — Cognitive Engine](#3-vestige-core--cognitive-engine) -4. [`vestige-mcp` — MCP Server + Dashboard Backend](#4-vestige-mcp--mcp-server--dashboard-backend) -5. [`apps/dashboard` — SvelteKit + Three.js Frontend](#5-appsdashboard--sveltekit--threejs-frontend) -6. [Integrations & Packaging](#6-integrations--packaging) -7. [`vestige-cloud` — Current Skeleton](#7-vestige-cloud--current-skeleton) -8. [Version History (v1.0 → v2.0.8)](#8-version-history-v10--v208) -9. [The Next-Phase Plan](#9-the-next-phase-plan) -10. [Composition Map](#10-composition-map) -11. [Risks & Known Gaps](#11-risks--known-gaps) -12. [Viral / Launch / Content Plan](#12-viral--launch--content-plan) -13. [How AI Agents Should Consume This Doc](#13-how-ai-agents-should-consume-this-doc) -14. [Glossary & Citations](#14-glossary--citations) +## Current Release Shape ---- +Vestige v2.1.2 is the "Honest Memory" release. Its public scope is: -## 0. Executive Summary (60-second read) +- concrete literal search for quoted strings, env vars, UUIDs, paths, and code + identifiers +- irreversible purge semantics with content-free deletion tombstones +- first-class contradiction inspection through the MCP `contradictions` tool +- the `vestige update` CLI flow for binary and Cognitive Sandwich updates +- dense dream connection persistence fixes +- embedding-model upgrade repair during consolidation +- an opt-in `/dashboard/waitlist` preview for Vestige Pro early access -Vestige is a Rust-based MCP (Model Context Protocol) cognitive memory server that gives any AI agent persistent, structured, scientifically-grounded memory. It ships three binaries (`vestige-mcp`, `vestige`, `vestige-restore`), a 3D SvelteKit dashboard embedded into the binary, and is distributed via GitHub releases + npm. As of v2.0.7 "Visible" (tagged 2026-04-19), it has **24 MCP tools**, **29 cognitive modules** implementing real neuroscience (FSRS-6 spaced repetition, synaptic tagging, hippocampal indexing, spreading activation, reconsolidation, Anderson 2025 suppression-induced forgetting, Rac1 cascade decay), **1,292 Rust tests**, **251 dashboard tests** (80 just added for v2.0.8 colour-mode), and **402 GitHub stars**. AGPL-3.0. +The release keeps the local-first baseline intact. Heavy model hooks, local +verifier models, and preflight automation remain optional. -**The branch `feat/v2.0.8-memory-state-colors` was fast-forwarded into `main` tonight** adding the FSRS memory-state colour mode, a floating legend, ruthless unit coverage, the Rust 1.95 clippy-compat fix (12 sites), and the dark-glass-pill label redesign. CI on main: all 4 jobs ✅. +## Release Gates -**The next six releases are scoped:** v2.1 "Decide" (Qwen3 embeddings, in-flight on `feat/v2.1.0-qwen3-embed`), v2.2 "Pulse" (subconscious cross-pollination — **the viral moment**), v2.3 "Rewind" (temporal slider + pin), v2.4 "Empathy" (emotional/frustration tagging, **first Pro-tier gate candidate**), v2.5 "Grip" (neuro-feedback cluster gestures), v2.6 "Remote" (`vestige-cloud` upgrade from 5→24 MCP tools + Streamable HTTP). v3.0 "Branch" reserves CoW memory branching and multi-tenant SaaS. +Before tagging a release, run: -**Sam's context** (load-bearing for any strategic advice): no steady income since March 2026, Mays Business School deadline May 1 ($400K+ prizes), Orbit Wars Kaggle deadline June 23 ($5K × top 10), graduation June 13. Viral OSS growth comes first; paid tier gates second. - ---- - -## 1. What Vestige Is - -### 1.1 Mission - -Give any AI agent that speaks MCP a long-term memory and a reasoning co-processor that survives session boundaries, with retrieval ranked by scientifically-validated decay and strengthening rules — not a vector database with a nice coat of paint. - -### 1.2 Positioning vs. the competitive landscape - -| System | Vestige's angle | -|---|---| -| Zep, Cognee, Letta, claude-mem, MemPalace, HippoRAG | Vestige is **local-first + MCP-native + neuroscience-grounded**. The others are cloud-first (Zep/Cognee), RAG-wrappers (HippoRAG), or toy (claude-mem). Vestige is the only one that implements 29 stateful cognitive modules. | -| ChatGPT memory, Cursor memory | Both are opaque key-value caches owned by their vendor. Vestige is open source and the memory is yours. | -| Plain vector DBs (Chroma, Qdrant) | They retrieve by similarity. Vestige *rewires* the graph on access (testing effect), decays with FSRS-6, competes retrievals, and dreams between sessions. | - -### 1.3 The "Oh My God" surface - -1. The 3D graph that **animates in real-time** when memories are created, promoted, suppressed, or cascade-decayed. -2. The `dream()` tool that runs a 5-stage consolidation cycle and generates insights from cross-cluster replay. -3. `deep_reference` — an 8-stage cognitive reasoning pipeline with FSRS trust scoring, intent classification, contradiction analysis, and a pre-built reasoning chain. Not just retrieval — actual reasoning. -4. Active forgetting (v2.0.5 "Intentional Amnesia") — top-down inhibitory control with Rac1 cascade that spreads over 72h, reversible within a 24h labile window. -5. Cross-IDE persistence. Fix a bug in VS Code, open the project in Xcode, the agent remembers. - -### 1.4 Stats (as of 2026-04-19 post-merge) - -| Metric | Value | -|---|---| -| GitHub stars | 402 | -| Total commits (main) | 139 | -| Rust source LOC | ~42,000 (vestige-core) + ~vestige-mcp | -| Rust tests passing | 1,292 (workspace, release profile) | -| Dashboard tests passing | 251 (Vitest, 7 files, 3,291 lines) | -| MCP tools | 24 | -| Cognitive modules | 29 (16 neuroscience + 11 advanced + 2 search) | -| FSRS-6 trained parameters | 21 | -| Embedding dim (default) | 768 (nomic-embed-text-v1.5), truncatable to 256 (Matryoshka) | -| Binary targets shipped | 3 (aarch64-darwin, x86_64-linux, x86_64-windows) | -| IDE integrations documented | 8 (Claude Code, Claude Desktop, Cursor, VS Code Copilot, Codex, Xcode, JetBrains/Junie, Windsurf) | -| Latest GitHub release | v2.0.7 "Visible" (binaries up, npm pending Sam's Touch ID) | -| `main` HEAD | `30d92b5` (2026-04-19 21:52 CT) | -| CI on HEAD | All 4 jobs ✅ (Test macos, Test ubuntu, Release aarch64-darwin, Release x86_64-linux) | - -### 1.5 License - -**AGPL-3.0-only** (copyleft). If you run a modified Vestige as a network service, you must open-source your modifications. This is intentional — it protects against extract-and-host competitors while allowing a future commercial-license path for SaaS (Part 9.7). - ---- - -## 2. Workspace Architecture - -### 2.1 Repo layout - -``` -vestige/ -├── Cargo.toml # Workspace root -├── Cargo.lock -├── pnpm-workspace.yaml # pnpm monorepo marker -├── package.json # Root (v2.0.1, private) -├── .mcp.json # Self-registering MCP config -├── README.md # 22.5 KB marketing + quick-start -├── CHANGELOG.md # 31 KB, v1.0 → v2.0.7 Keep-a-Changelog format -├── CLAUDE.md # Project-level Claude instructions -├── CONTRIBUTING.md # Dev setup + test commands -├── SECURITY.md # Vuln reporting -├── LICENSE # AGPL-3.0 full text -├── crates/ -│ ├── vestige-core/ # Library crate (cognitive engine) -│ └── vestige-mcp/ # Binary crate (MCP server + dashboard backend) -├── apps/ -│ └── dashboard/ # SvelteKit 2 + Svelte 5 + Three.js frontend -├── packages/ -│ ├── vestige-mcp-npm/ # npm: vestige-mcp-server (binary wrapper) -│ ├── vestige-init/ # npm: @vestige/init (zero-config installer) -│ └── vestige-mcpb/ # legacy, appears abandoned -├── tests/ -│ └── vestige-e2e-tests/ # Integration tests over MCP protocol -├── docs/ -│ ├── CLAUDE-SETUP.md -│ ├── CONFIGURATION.md -│ ├── FAQ.md -│ ├── SCIENCE.md -│ ├── STORAGE.md -│ ├── integrations/ -│ │ ├── codex.md -│ │ ├── cursor.md -│ │ ├── jetbrains.md -│ │ ├── vscode.md -│ │ ├── windsurf.md -│ │ └── xcode.md -│ ├── launch/ -│ │ ├── UI_ROADMAP_v2.1_v2.2.md # compiled 2026-04-19 -│ │ ├── show-hn.md -│ │ ├── blog-post.md -│ │ ├── demo-script.md -│ │ └── reddit-cross-reference.md -│ └── blog/ -│ └── xcode-memory.md -├── scripts/ -│ └── xcode-setup.sh # 4.9 KB interactive installer -└── .github/ - └── workflows/ - ├── ci.yml # push-main + PR: clippy + test - ├── release.yml # tag push: binary build matrix - └── test.yml # parallel unit/e2e/journey/dashboard/coverage +```sh +cargo test --workspace --no-fail-fast +cargo clippy --workspace -- -D warnings +pnpm --filter @vestige/dashboard check +pnpm --filter @vestige/dashboard build +git diff --check ``` -### 2.2 Dependency flow - -``` -┌─────────────────────┐ -│ apps/dashboard │ Svelte 5 + Three.js → static `build/` -│ (SvelteKit 2) │ embedded via include_dir! into vestige-mcp binary -└──────────┬──────────┘ - │ HTTP / WebSocket - ▼ -┌─────────────────────┐ ┌──────────────────────┐ -│ vestige-mcp │ ────► │ vestige-core │ -│ (binary + dash BE) │ │ (cognitive engine) │ -│ Axum + JSON-RPC │ │ FSRS-6, search, │ -│ MCP stdio + HTTP │ │ embeddings, 29 │ -│ │ │ cognitive modules │ -└─────────────────────┘ └──────────────────────┘ - ▲ - │ path dep - ┌────────┴──────────┐ - │ vestige-cloud │ (separate repo, Feb 12 - │ vestige-http │ skeleton, not yet - │ (Axum + SSE) │ shipped) - └───────────────────┘ -``` - -### 2.3 Build profile - -```toml -[profile.release] -lto = true -codegen-units = 1 -panic = "abort" -strip = true -opt-level = "z" # Size-optimized; binary is ~22 MB with dashboard -``` - -### 2.4 Workspace Cargo.toml pinned version - -Workspace `version = "2.0.5"`. Crate-level `Cargo.toml` files pin `2.0.7`. Version files are pumped together on each release (5 files: `crates/vestige-core/Cargo.toml`, `crates/vestige-mcp/Cargo.toml`, `apps/dashboard/package.json`, `packages/vestige-init/package.json`, `packages/vestige-mcp-npm/package.json`). - -### 2.5 MSRV & editions - -- **Rust MSRV:** 1.91 (enforced in `rust-version`). -- **CI Rust:** stable (currently 1.95 — which introduced the `unnecessary_sort_by` + `collapsible_match` lints tonight's fixes addressed). -- **Edition:** 2024 across the entire workspace. -- **Node:** 18+ for npm packages, 22+ for dashboard dev. -- **pnpm:** 10+ for workspace. - ---- - -## 3. `vestige-core` — Cognitive Engine - -### 3.1 Purpose - -Library crate. Owns the entire cognitive engine: storage, FTS5, vector search, FSRS-6, embeddings, and the 29 cognitive modules. Has no knowledge of MCP, HTTP, or the dashboard — those live one crate up. - -### 3.2 Metadata - -```toml -name = "vestige-core" -version = "2.0.7" -edition = "2024" -rust-version = "1.91" -license = "AGPL-3.0-only" -description = "Cognitive memory engine - FSRS-6 spaced repetition, semantic embeddings, and temporal memory" -keywords = ["memory", "spaced-repetition", "fsrs", "embeddings", "knowledge-graph"] -``` - -### 3.3 Feature flags (8) - -| Flag | Default | What it turns on | Cost | -|---|---|---|---| -| `embeddings` | **yes** | `mod embeddings`, fastembed v5.11, ONNX inference | +~130MB model download on first run | -| `vector-search` | **yes** | `mod search`, USearch HNSW, hybrid BM25 + semantic | negligible | -| `bundled-sqlite` | **yes** (mutex w/ `encryption`) | SQLite bundled via rusqlite 0.38 | +~2MB binary | -| `encryption` | no | SQLCipher encrypted DB | requires system libsqlcipher | -| `qwen3-reranker` | no | Qwen3 cross-encoder reranker | +candle-core deps | -| `qwen3-embed` | **no (v2.1 scaffolding)** | Qwen3 embed backend via Candle (Metal device + CPU fallback) | +candle-core, +~500MB Qwen3 model | -| `metal` | no | Metal GPU acceleration on Apple | macOS only | -| `nomic-v2` | no | Nomic Embed v2 MoE variant | +~200MB model | -| `ort-dynamic` | no | Runtime-load ORT instead of static prebuilt | required on glibc < 2.38 | - -**Default feature set ships with embeddings + vector-search.** `qwen3-embed` is the v2.1 "Decide" scaffolding — dual-index with feature-gated `DEFAULT_DIMENSIONS` (1024 for Qwen3 vs 256 for Matryoshka-truncated Nomic). - -### 3.4 Module tree (`src/lib.rs`) - -``` -src/ -├── lib.rs # Module tree + prelude re-exports -├── prelude.rs # KnowledgeNode, IngestInput, SearchResult, etc. -├── storage/ # SQLite + FTS5 + HNSW + migrations -│ ├── mod.rs # Storage struct; public API -│ ├── sqlite.rs # Connection setup, PRAGMAs, migrations -│ ├── migrations.rs # V1..V11 migration chain (V11 dropped knowledge_edges + compressed_memories tables) -│ ├── schema.rs # CREATE TABLE statements -│ ├── node.rs # CRUD for KnowledgeNode -│ ├── edge.rs # Edge insertion + deletion -│ ├── fts.rs # FTS5 wrapper -│ ├── state_transitions.rs # Append-only audit log -│ ├── consolidation_history.rs -│ ├── dream_history.rs -│ └── intention.rs # Prospective memory persistence -├── search/ # 7-stage cognitive search pipeline -│ ├── mod.rs -│ ├── hybrid.rs # BM25 + semantic fusion -│ ├── vector.rs # USearch HNSW wrapper; DEFAULT_DIMENSIONS gated -│ ├── reranker.rs # Jina Reranker v1 Turbo (38M params) -│ ├── temporal.rs # Recency + validity window boosting -│ ├── context.rs # Tulving 1973 encoding specificity -│ ├── competition.rs # Anderson 1994 retrieval-induced forgetting -│ └── activation.rs # Spreading activation side effects -├── embeddings/ # ONNX local + Qwen3 candle -│ ├── mod.rs # EmbeddingService trait -│ ├── local.rs # Backend enum (Nomic ONNX / Qwen3 Candle); metal device selection -│ ├── adaptive.rs # AdaptiveEmbedder (Matryoshka 256/768/1024 tier) -│ ├── hyde.rs # HyDE query expansion -│ └── cache.rs # In-memory embedding LRU -├── fsrs/ # Spaced repetition (21-param Anki FSRS-6) -│ ├── mod.rs -│ ├── params.rs # Trained params -│ ├── algorithm.rs # R(t) = (1 + factor × t / S)^(-w20) -│ └── review.rs # apply_review -├── neuroscience/ # 16 modules (see §3.5) -│ ├── mod.rs -│ ├── activation.rs # ActivationNetwork (Collins & Loftus 1975) -│ ├── synaptic_tagging.rs # SynapticTaggingSystem (Frey & Morris 1997) -│ ├── hippocampal_index.rs # (Teyler & Rudy 2007) -│ ├── context_matcher.rs # (Tulving 1973) -│ ├── accessibility.rs # AccessibilityCalculator -│ ├── competition.rs # CompetitionManager (Anderson 1994) -│ ├── state_update.rs # StateUpdateService -│ ├── importance_signals.rs # 4-channel (novelty/arousal/reward/attention) -│ ├── emotional_memory.rs # Brown & Kulik 1977 flashbulb memory -│ ├── predictive_retrieval.rs # Friston Free Energy 2010 -│ ├── prospective_memory.rs # Intention fulfillment -│ ├── intention_parser.rs -│ └── memory_states.rs # Active / Dormant / Silent / Unavailable + Bjork & Bjork 1992 -├── advanced/ # 11 modules (see §3.6) -│ ├── mod.rs -│ ├── importance_tracker.rs -│ ├── reconsolidation.rs # Nader 2000 labile window (5 min, 10 mods max) -│ ├── intent_detector.rs # 9 intent types -│ ├── activity_tracker.rs -│ ├── dreaming.rs # MemoryDreamer 5-stage -│ ├── chains.rs # MemoryChainBuilder (A*-like) -│ ├── compression.rs # MemoryCompressor (30-day min age) -│ ├── cross_project.rs # CrossProjectLearner (6 pattern types) -│ ├── adaptive_embedding.rs -│ ├── speculative_retriever.rs -│ └── consolidation_scheduler.rs -├── codebase/ # CrossProjectLearner backing -│ ├── git.rs # Git history analysis -│ ├── relationships.rs # File-file co-edit patterns -│ └── types.rs -└── session/ # Session-level tracking - └── mod.rs -``` - -### 3.5 Neuroscience modules (16) - -| Module | Citation / basis | Purpose | -|---|---|---| -| `ActivationNetwork` | Collins & Loftus 1975 | Spreading activation across memory graph | -| `SynapticTaggingSystem` | Frey & Morris 1997 | Retroactive importance: memories in last 9h get boosted when big event fires | -| `HippocampalIndex` | Teyler & Rudy 2007 | Graph-level indexing; "dentate gyrus pattern separator" | -| `ContextMatcher` | Tulving 1973 | Encoding specificity — context overlap boosts retrieval by up to 30% | -| `AccessibilityCalculator` | Bjork & Bjork 1992 | `accessibility = retention × 0.5 + retrieval × 0.3 + storage × 0.2` | -| `CompetitionManager` | Anderson 1994 | Retrieval-induced forgetting — winners strengthen, competitors weaken | -| `StateUpdateService` | — | FSRS state transitions + append-only log | -| `ImportanceSignals` (4 channels) | Novelty / Arousal / Reward / Attention | Composite importance score, threshold 0.6 | -| `EmotionalMemory` | Brown & Kulik 1977 | Flashbulb memories — high-arousal events encode stronger | -| `PredictiveMemory` | Friston 2010 | Active inference — predict user needs before they ask | -| `ProspectiveMemory` | — | Intentions ("remind me when...") | -| `IntentionParser` | — | Natural-language → structured intention trigger | -| `MemoryState` (enum) | Bjork & Bjork 1992 | Active ≥0.7 / Dormant ≥0.4 / Silent ≥0.1 / Unavailable <0.1 | -| `Rac1Cascade` (v2.0.5) | Cervantes-Sandoval & Davis 2020 | Actin-destabilization-mediated forgetting of co-activated neighbors | -| `Suppression` (v2.0.5) | Anderson 2025 SIF | Top-down inhibitory control; compounds; 24h reversible labile window | -| `Reconsolidation` | Nader 2000 | 5-minute labile window after access; up to 10 modifications | - -### 3.6 Advanced modules (11) - -| Module | Purpose | Key methods | -|---|---|---| -| `ImportanceTracker` | Aggregates 4-channel score history | `record()`, `get_composite()` | -| `ReconsolidationManager` | Nader labile window state machine | `mark_labile()`, `apply_modification()`, `reconsolidate()` | -| `IntentDetector` | 9 intent types (Question, Decision, Plan, etc.) | `detect()` | -| `ActivityTracker` | Session-level active memory | `record_access()`, `recent()` | -| `MemoryDreamer` | 5-stage consolidation: Replay → Cross-reference → Strengthen → Prune → Transfer. Uses Waking SWR tagging (70% tagged + 30% random for diversity) | `dream(memory_count)` | -| `MemoryChainBuilder` | A*-like pathfinding between memories | `build_chain(from, to)` | -| `MemoryCompressor` | Semantic compression for 30+ day old memories | `compress(group)` | -| `CrossProjectLearner` | 6 pattern types (ErrorHandling, AsyncConcurrency, Testing, Architecture, Performance, Security) | `find_universal_patterns()`, `apply_to_project()` | -| `AdaptiveEmbedder` | Matryoshka-truncation tier selection | `embed_adaptive()` | -| `SpeculativeRetriever` | 6 trigger types for proactive memory fetch | `predict_needed_memories()` | -| `ConsolidationScheduler` | Runs FSRS decay cycle on interval (default 6h, env-configurable) | `start()` | - -### 3.7 Storage - -- SQLite via rusqlite 0.38, WAL mode, `Mutex` split between reader and writer. -- FTS5 for keyword search (`bm25(10.0, 5.0, 1.0)` weights). -- Migrations V1..V11. **V11 (2026-04-19)** drops the dead `knowledge_edges` and `compressed_memories` tables that were reserved but never used. -- Append-only audit logs: `state_transitions`, `consolidation_history`, `dream_history`. - -### 3.8 Embeddings - -- Default: **Nomic Embed Text v1.5** via fastembed (ONNX, 768D). -- Matryoshka truncation to 256D for fast HNSW lookups (20× faster than full 768D). -- HyDE query expansion (generate a hypothetical document, embed it, search by its embedding). -- **v2.1 scaffolding:** Qwen3 embedding backend via Candle behind `qwen3-embed` feature. `qwen3_format_query()` helper prepends the instruction prefix ("Given a web search query, retrieve relevant passages that answer the query"). -- Embedding cache: in-memory LRU; disk-warm on first run (~130MB for Nomic, ~500MB for Qwen3). - -### 3.9 Vector search - -- USearch HNSW (pinned 2.23.0; 2.24.0 regressed on MSVC per usearch#746). Int8 quantization. -- Hybrid scoring: `combined = 0.3 × BM25 + 0.7 × cosine` (default, user-tunable). -- `DEFAULT_DIMENSIONS` feature-gated: 256 on default, 1024 under `qwen3-embed`. - -### 3.10 FSRS-6 - -- 21 trained parameters (Jarrett Ye / maimemo; trained on 700M+ Anki reviews). -- `R(t) = (1 + factor × t / S)^(-w20)` — power-law forgetting curve. -- 20-30% more efficient than SM-2 (Anki's original algorithm). -- Retrievability, stability, difficulty tracked per node. -- Dual-strength (Bjork & Bjork 1992): storage strength grows monotonically, retrieval strength decays. - -### 3.11 Test count - -- **364 `#[test]` annotations in vestige-core** across 47 test-bearing files. -- Examples: `cargo test --workspace` → 1,292 passing (includes 366 core + 425 mcp + e2e + journey). - ---- - -## 4. `vestige-mcp` — MCP Server + Dashboard Backend - -### 4.1 Purpose - -Binary crate. Wraps `vestige-core` behind an MCP JSON-RPC 2.0 server, plus an embedded Axum HTTP server that hosts the dashboard, WebSocket event bus, and REST API. - -### 4.2 Binaries - -| Binary | Source | Purpose | -|---|---|---| -| `vestige-mcp` | `src/main.rs` | **Primary.** MCP JSON-RPC over stdio + optional HTTP transport. Hosts dashboard at `/dashboard/`. | -| `vestige` | `src/bin/cli.rs` | CLI: stats, consolidate, backup, restore, export, gc, dashboard launcher. | -| `vestige-restore` | `src/bin/restore.rs` | Standalone batch restore from JSON backup. | - -### 4.3 Environment variables - -| Var | Default | Purpose | -|---|---|---| -| `VESTIGE_DASHBOARD_PORT` | `3927` | Dashboard HTTP + WebSocket port | -| `VESTIGE_HTTP_PORT` | `3928` | Optional MCP-over-HTTP port | -| `VESTIGE_HTTP_BIND` | `127.0.0.1` | HTTP bind address | -| `VESTIGE_AUTH_TOKEN` | auto-generated | Dashboard bearer auth | -| `VESTIGE_CONSOLIDATION_INTERVAL_HOURS` | `6` | FSRS decay cycle cadence | -| `VESTIGE_DASHBOARD_ENABLED` | `true` | Toggle dashboard on/off | -| `VESTIGE_SYSTEM_PROMPT_MODE` | `minimal` | `full` enables the extended `build_instructions` block | -| `RUST_LOG` | `info` | tracing filter | - -### 4.4 The 24 MCP tools - -Every tool implemented in `src/tools/*.rs`. JSON schemas are programmatically emitted from `schema()` functions on each module. - -1. **`session_context`** — one-call session init. Params: `queries[]`, `context{codebase, topics, file}`, `token_budget` (100-100000), `include_status`, `include_intentions`, `include_predictions`. Returns markdown context + `automationTriggers` (needsDream, needsBackup, needsGc) + `expandable` overflow IDs. -2. **`smart_ingest`** — single or batch ingest with Prediction Error Gating (similarity >0.92 → UPDATE, 0.75-0.92 → UPDATE/SUPERSEDE, <0.75 → CREATE). Params: `content`, `tags[]`, `node_type`, `source`, `forceCreate`, OR `items[]` (up to 20). Runs full cognitive pipeline. -3. **`search`** — 7-stage cognitive search. Params: `query`, `limit` (1-100), `min_retention`, `min_similarity`, `detail_level` (brief/summary/full), `context_topics[]`, `token_budget`, `retrieval_mode` (precise/balanced/exhaustive). **Strengthens retrieved memories via testing effect.** -4. **`memory`** — CRUD + promote/demote. `action` ∈ `{get, edit, delete, promote, demote, state, get_batch}`. `get_batch` takes up to 20 IDs. Edit preserves FSRS state, regenerates embedding. -5. **`codebase`** — Remember patterns & decisions. Actions: `remember_pattern`, `remember_decision`, `get_context`. Feeds CrossProjectLearner. -6. **`intention`** — Prospective memory. Actions: `set` (with trigger types time/context/event), `check`, `update`, `list`. Supports `include_snoozed` (v2.0.7 fix). -7. **`dream`** — 5-stage consolidation cycle. Param: `memory_count` (default 50). Returns insights, connections found, memories replayed, duration. -8. **`explore_connections`** — Graph traversal. Actions: `associations` (spreading activation), `chain` (A*-like path), `bridges` (connecting memories between two concepts). -9. **`predict`** — Proactive retrieval via SpeculativeRetriever. Param: `context{codebase, current_file, current_topics[]}`. Returns predictions with confidence + reasoning. Has a `predict_degraded` flag (v2.0.7) that surfaces warnings instead of silent empty responses. -10. **`importance_score`** — 4-channel scoring. Param: `content`, `context_topics[]`, `project`. Returns `{composite, channels{novelty, arousal, reward, attention}, recommendation}`. -11. **`find_duplicates`** — Cosine similarity clustering. Params: `similarity_threshold` (default 0.80), `limit`, `tags[]`. Returns merge/review suggestions. -12. **`memory_timeline`** — Chronological browse. Params: `start`, `end`, `node_type`, `tags[]`, `limit`, `detail_level`. -13. **`memory_changelog`** — Audit trail. Per-memory mode (by `memory_id`) or system-wide (with optional `start`/`end` ISO bounds, v2.0.7 fix adds 4× over-fetch when bounded). -14. **`memory_health`** — Retention dashboard. Returns avg retention, distribution buckets (0-20%, 20-40%, ...), trend, recommendation. -15. **`memory_graph`** — Visualization export. Params: `query` OR `center_id`, `depth` (default 2), `max_nodes` (default 50). Returns nodes with force-directed positions + edges with weights. -16. **`deep_reference`** — **★ THE killer tool.** 8-stage cognitive reasoning: - 1. Broad retrieval + cross-encoder reranking. - 2. Spreading activation expansion. - 3. FSRS-6 trust scoring (retention × stability × reps ÷ lapses). - 4. Intent classification (FactCheck / Timeline / RootCause / Comparison / Synthesis). - 5. Temporal supersession. - 6. Trust-weighted contradiction analysis. - 7. Relation assessment (Supports / Contradicts / Supersedes / Irrelevant). - 8. Template reasoning chain — pre-built natural-language conclusion the AI validates. - Returns `{intent, reasoning, recommended, evidence, contradictions, superseded, evolution, related_insights, confidence}`. -17. **`cross_reference`** — Backward-compat alias that calls `deep_reference`. Kept for v1.x users. -18. **`system_status`** — Full health + stats + warnings + recommendations. Used by `session_context` when `include_status=true`. -19. **`consolidate`** — FSRS-6 decay cycle + embedding generation pass. Returns counts. -20. **`backup`** — SQLite backup to `~/.vestige/backups/` with timestamp. -21. **`export`** — JSON/JSONL export. Params: `format`, `tags[]`, `since`. v2.0.7 defensive `Err` on unknown format (was `unreachable!()`). -22. **`gc`** — Garbage collect. Params: `min_retention` (default 0.1), `dry_run` (default true). Dry-run first, then execute. -23. **`restore`** — Restore from backup. Param: `path`. -24. **`suppress`** / **`unsuppress`** (v2.0.5 "Intentional Amnesia") — Top-down inhibition. `suppress(id, reason?)` compounds (`suppressionCount` increments); `unsuppress(id)` reverses if within 24h labile window. Also exposed as dashboard HTTP endpoints (v2.0.7: `POST /api/memories/{id}/suppress` + `/unsuppress`). - -### 4.5 MCP server internals - -- `src/server.rs` — JSON-RPC 2.0 over stdio, optional HTTP. Handles `initialize`, `tools/list`, `tools/call`. -- **`build_instructions()`** — constructs the `instructions` string returned by `initialize`. Gated on `VESTIGE_SYSTEM_PROMPT_MODE=full`. Full mode emits an extended cognitive-protocol system prompt; default is concise. -- **CognitiveEngine** (`src/cognitive/mod.rs`) — async wrapper around `Arc` + broadcast channel. Holds the WebSocket event sender. -- **Tool dispatch** — every `tools/call` invocation is routed to a `execute_*` function by tool name. - -### 4.6 Dashboard HTTP backend (`src/dashboard/`) - -- `src/dashboard/mod.rs` — Axum `Router` assembly. -- `src/dashboard/handlers.rs` — all REST handlers (~30 routes). -- `src/dashboard/static_files.rs` — embeds `apps/dashboard/build/` via `include_dir!` at compile time. -- `src/dashboard/state.rs` — `AppState { storage, event_tx, start_time }`. -- `src/dashboard/websocket.rs` — `/ws` upgrade handler with Origin validation (localhost + 127.0.0.1 + dev :5173), 64KB frame cap, 256KB message cap, heartbeat task every 5s. - -**Heartbeat payload (v2.0.7):** `{type: "Heartbeat", data: {uptime_secs, memory_count, avg_retention, suppressed_count, timestamp}}`. The `uptime_secs` is what powers the sidebar footer's `formatUptime()` display ("3d 4h" / "18m 43s"). - -### 4.7 WebSocket event bus — 19 VestigeEvent types - -Emitted from the `CognitiveEngine` broadcast channel to every connected dashboard client: - -| Event | When emitted | Dashboard visual | -|---|---|---| -| `Connected` | WebSocket upgrade complete | Cyan ripple (v2.0.6) | -| `Heartbeat` | Every 5s | Silent (updates sidebar stats) | -| `MemoryCreated` | Any ingest that produces a new node | Rainbow burst + double shockwave + ripple | -| `MemoryUpdated` | Smart_ingest UPDATE path | Pulse at node | -| `MemoryDeleted` | `memory({action: "delete"})` | Dissolution animation | -| `MemoryPromoted` | `memory({action: "promote"})` | Green pulse + sparkle | -| `MemoryDemoted` | `memory({action: "demote"})` | Orange pulse + fade | -| `MemorySuppressed` | `suppress(id)` (v2.0.5) | Violet implosion (v2.0.7) | -| `MemoryUnsuppressed` | `unsuppress(id)` (v2.0.5) | Rainbow reversal (v2.0.7) | -| `Rac1CascadeSwept` | Rac1 worker completes cascade (72h async) | Violet wave pulse (v2.0.6) | -| `SearchPerformed` | Every `search()` call | Cyan flash + PipelineVisualizer 7-stage animation in `/feed` | -| `DreamStarted` | `dream()` begins | Scene enters dream mode (2s lerp) | -| `DreamProgress` | Per-stage updates during dream | Aurora hue cycle | -| `DreamCompleted` | Dream finishes, insights generated | Scene exits dream mode | -| `ConsolidationStarted` | FSRS consolidation cycle starts | Amber warning pulse (v2.0.6) | -| `ConsolidationCompleted` | Consolidation finishes | Green confirmation pulse | -| `RetentionDecayed` | Node's retention drops below threshold during consolidation | Red decay pulse | -| `ConnectionDiscovered` | Dream or spreading activation finds new edge | **Cyan flash on edge (already fires — NOT yet surfaced as a toast; see v2.2 "Pulse")** | -| `ActivationSpread` | Spreading activation from a memory | Turquoise ripple (v2.0.6) | -| `ImportanceScored` | `importance_score()` or internal scoring event | Hot-pink pulse (v2.0.6, magenta) | - -### 4.8 Dashboard REST API - -All routes under `/api/`: - -| Method | Path | Purpose | -|---|---|---| -| GET | `/api/health` | Health check (status, version, memory count) | -| GET | `/api/stats` | Full stats (same surface as `system_status` tool) | -| GET | `/api/memories` | List memories with filters (q, node_type, tag, min_retention) | -| GET | `/api/memories/{id}` | Single memory detail | -| POST | `/api/memories` | Create memory (raw ingest) | -| DELETE | `/api/memories/{id}` | Delete | -| POST | `/api/memories/{id}/promote` | Promote (+0.20 retrieval, +0.10 retention, 1.5× stability) | -| POST | `/api/memories/{id}/demote` | Demote (−0.30 retrieval, −0.15 retention, 0.5× stability) | -| POST | `/api/memories/{id}/suppress` | v2.0.7: compound suppression | -| POST | `/api/memories/{id}/unsuppress` | v2.0.7: reverse within 24h labile window | -| POST | `/api/search` | Hybrid search (keyword + semantic weights) | -| POST | `/api/ingest` | Smart ingest (PE gating) | -| GET | `/api/graph` | Graph visualization export | -| POST | `/api/explore` | Actions: associations / chains / bridges | -| POST | `/api/dream` | Run dream cycle | -| POST | `/api/consolidate` | Run FSRS decay cycle | -| POST | `/api/predict` | Proactive predictions | -| POST | `/api/importance` | 4-channel score | -| GET | `/api/timeline` | Chronological | -| GET | `/api/intentions` | List intentions (filter by status) | -| GET | `/api/retention-distribution` | Bucketed histogram | - -WebSocket: `GET /ws` (upgrade) — one broadcast channel, any connected client gets all events. - -### 4.9 vestige-mcp feature flags - -| Flag | Purpose | Default | -|---|---|---| -| `embeddings` | Forward to vestige-core | yes | -| `vector-search` | Forward to vestige-core | yes | -| `ort-dynamic` | Forward to vestige-core | no | - -Build commands (from CONTRIBUTING.md): -- Full: `cargo install --path crates/vestige-mcp` -- No-embeddings (tiny): `cargo install --path crates/vestige-mcp --no-default-features` -- Dynamic ORT (glibc < 2.38): `cargo install --path crates/vestige-mcp --no-default-features --features ort-dynamic,vector-search` - ---- - -## 5. `apps/dashboard` — SvelteKit + Three.js Frontend - -### 5.1 Purpose - -Interactive 3D graph + CRUD + analytics dashboard. Built with SvelteKit 2 + Svelte 5 runes, embedded into the Rust binary via `include_dir!` and served at `/dashboard/`. - -### 5.2 Tech stack - -- **SvelteKit 2.53** + **Svelte 5.53** (runes: `$state`, `$props`, `$derived`, `$effect`). -- **Three.js 0.172** — WebGL, MSAA, ACESFilmic tone mapping. -- **Tailwind CSS 4.2** — custom `@theme` block (synapse, dream, memory, recall, decay colors + 8 node-type palette). -- **TypeScript 5.9** — strict mode. -- **Vite 6.4** + **Vitest 4.0.18** (251 tests). -- **@playwright/test 1.58** — E2E ready (journeys live in `tests/vestige-e2e-tests/`). - -### 5.3 Routes (SvelteKit file-based) - -Grouped under `(app)/`: - -| Route | File | Purpose | -|---|---|---| -| `/` | `+page.svelte` | Redirect to `/graph` | -| `(app)/graph` | `+page.svelte` | **Primary 3D graph** (Graph3D component + color mode toggle + time slider + right panel for detail + legend overlay v2.0.8) | -| `(app)/memories` | `+page.svelte` | Memory browser (search, filter by type/tag/retention, suppress button v2.0.7) | -| `(app)/intentions` | `+page.svelte` | Prospective memory + predictions (status tabs, trigger icons, priority labels) | -| `(app)/stats` | `+page.svelte` | Health dashboard, retention distribution, endangered memories, run-consolidation button | -| `(app)/timeline` | `+page.svelte` | Chronological browse (days dropdown, expandable day cards) | -| `(app)/feed` | `+page.svelte` | Live event stream (200-event FIFO buffer, PipelineVisualizer on SearchPerformed) | -| `(app)/explore` | `+page.svelte` | Associations / Chains / Bridges mode toggle + Importance Scorer | -| `(app)/settings` | `+page.svelte` | Operations + config + keyboard shortcuts reference | - -### 5.4 Root layout (`src/routes/+layout.svelte`) - -- Desktop sidebar (8 nav items) + mobile bottom nav (5 items). -- **Command palette (⌘K)** — opens a search bar that navigates. -- **Single-key shortcuts** — G/M/T/F/E/I/S for routes. -- **Status footer** — connection indicator, memory count, avg retention, suppressed count (v2.0.5), uptime (v2.0.7: `up {formatUptime($uptimeSeconds)}`). -- **ForgettingIndicator** — violet badge showing suppressed count. -- Ambient orb background animations (CSS). - -### 5.5 Components (`src/lib/components/`) - -| Component | Purpose | -|---|---| -| `Graph3D.svelte` | **The 3D canvas.** Props: `nodes[]`, `edges[]`, `centerId`, `events[]`, `isDreaming`, `colorMode` (v2.0.8), `onSelect`, `onGraphMutation`. Owns the Three.js scene and all module init. | -| `MemoryStateLegend.svelte` (v2.0.8) | Floating overlay explaining 4 FSRS buckets — only renders when `colorMode === 'state'`. | -| `PipelineVisualizer.svelte` | 7-stage cognitive search animation (Overfetch → Rerank → Temporal → Access → Context → Compete → Activate). Shown in `/feed` when SearchPerformed arrives. | -| `RetentionCurve.svelte` | SVG FSRS-6 decay curve in the graph right panel. `R(t) = e^(-t/S)` with predictions at Now / 1d / 7d / 30d. | -| `TimeSlider.svelte` | Temporal playback scrubber. State: enabled, playing, speed (0.5-2×), sliderValue. Callbacks `onDateChange`, `onToggle`. | -| `ForgettingIndicator.svelte` | Violet badge in sidebar showing suppressed count from Heartbeat. | - -### 5.6 Three.js graph system (`src/lib/graph/`) - -| File | Role | -|---|---| -| `nodes.ts` | `NodeManager`. Fibonacci sphere initial positions, materialize/dissolve/grow animations, shared radial-gradient glow texture (128px) that prevents square bloom artifacts (issue #31). **v2.0.8:** `ColorMode` ('type' / 'state'), `getMemoryState(retention)`, `MEMORY_STATE_COLORS`, `MEMORY_STATE_DESCRIPTIONS`, `setColorMode(mode)` idempotent in-place retint. **2026-04-19:** dark-glass-pill label redesign (dimmer `#94a3b8` slate on `rgba(10,16,28,0.82)` pill with hairline stroke). | -| `edges.ts` | `EdgeManager`. Violet `#8b5cf6` lines; opacity = 25% + 50% × weight, capped at 80%. Grow/dissolve animations. | -| `force-sim.ts` | Repulsion 500, attraction 0.01 × edge weight × distance, damping 0.9, centering 0.001α. N² but fine up to ~1000 nodes at 60fps. | -| `particles.ts` | `ParticleSystem`. Starfield (3000 points on spherical shell r=600-1000) + neural particles (500 oscillating sin-wave). | -| `effects.ts` | `EffectManager`. 12 effect types (SpawnBurst, Shockwave, RainbowBurst, RippleWave, Implosion, Pulse, ConnectionFlash, etc.). | -| `events.ts` | `mapEventToEffects()` — maps every one of the 19 VestigeEvent variants to a visual effect. Live-spawn mechanics: new nodes spawn near semantically related existing nodes (tag + type scoring), FIFO eviction at 50 nodes. | -| `scene.ts` | Scene factory. Camera 60° FOV at (0, 30, 80). ACESFilmic tone mapping, exposure 1.25, pixel ratio clamped ≤2×. **UnrealBloomPass:** strength 0.55, radius 0.6, threshold 0.2 (retuned v2.0.8 for radial-gradient sprites). OrbitControls with auto-rotate 0.3°/frame. | -| `dream-mode.ts` | Smooth 2s lerp between NORMAL (bloom 0.8, rotate 0.3, fog dense) and DREAM (bloom 1.8, rotate 0.08, nebula 1.0, chromatic 0.005). Aurora lights cycle hue in dream. | -| `temporal.ts` | `filterByDate(nodes, edges, cutoff)`, `retentionAtDate(current, stability, created, target)` using FSRS decay formula. Enables the TimeSlider preview. | -| `shaders/nebula.frag.ts` | Nebula background fragment shader (purple → cyan → magenta cycle with turbulence). | -| `shaders/post-processing.ts` | Chromatic aberration, vignette, subtle distortion. Parameters lerp with dream-mode. | - -### 5.7 Stores (`src/lib/stores/`) - -| Store | Exports | Purpose | -|---|---|---| -| `api.ts` | `api.memories.*`, `api.search`, `api.graph`, `api.explore`, `api.stats`, `api.health`, `api.retentionDistribution`, `api.timeline`, `api.dream`, `api.consolidate`, `api.predict`, `api.importance`, `api.intentions` | 23 REST client methods | -| `websocket.ts` | `websocket` (writable), `isConnected`, `eventFeed`, `heartbeat`, `memoryCount`, `avgRetention`, `suppressedCount`, `uptimeSeconds`, `formatUptime(secs)` | WebSocket connection + derived state. FIFO 200-event ring buffer. Exponential backoff reconnect (1s → 30s). | -| `graph-state.svelte.ts` | (unused artifact from v2.0.6) | — | - -### 5.8 Types (`src/lib/types/index.ts`) - -Exported: `Memory`, `SearchResult`, `MemoryListResponse`, `SystemStats`, `HealthCheck`, `RetentionDistribution`, `GraphNode`, `GraphEdge`, `GraphResponse`, `DreamResult`, `DreamInsight`, `ImportanceScore`, `ConsolidationResult`, `SuppressResult`, `UnsuppressResult`, `IntentionItem`, `VestigeEventType`, `VestigeEvent`, `NODE_TYPE_COLORS` (8 types), `EVENT_TYPE_COLORS` (19 events), `ColorMode`, `MemoryState` (v2.0.8). - -### 5.9 Tests (`src/lib/graph/__tests__/`) - -| File | Tests | Lines | Covers | -|---|---|---|---| -| `color-mode.test.ts` **(v2.0.8, new)** | 80 | 664 | `getMemoryState` boundaries (12 retentions including NaN/±∞/>1/<0), palette integrity, `getNodeColor` dispatch, `NodeManager.setColorMode` idempotence + in-place retint + userData preservation + suppression channel isolation | -| `nodes.test.ts` | 32 | 456 | NodeManager lifecycle, easings, Fibonacci distribution | -| `edges.test.ts` | 21 | 314 | EdgeManager grow/dissolve, opacity-by-weight | -| `force-sim.test.ts` | 19 | 257 | Physics convergence, add/remove | -| `effects.test.ts` | 30 | 500 | All 12 effect types | -| `events.test.ts` | 48 | 864 | Every one of the 19 event handlers + live-spawn + eviction | -| `ui-fixes.test.ts` | 21 | 236 | Bloom retuning, glow-texture gradient, fog density, regression tests for issue #31 | -| **Total** | **251** | **3,291** | | - -Infrastructure: `three-mock.ts` (Scene / Mesh / Sprite / Material mocks), `setup.ts` (canvas context mocks including `beginPath`/`closePath`/`quadraticCurveTo` added tonight for the pill redesign), `helpers.ts` (node/edge/event factories). - -### 5.10 Build - -- `pnpm run build` → static SPA in `apps/dashboard/build/`. -- Precompressed `.br` + `.gz` per asset (adapter-static). -- **Embedded into `vestige-mcp` binary** at compile time via `include_dir!("$CARGO_MANIFEST_DIR/../../apps/dashboard/build")`. Every Rust build rebakes the dashboard snapshot. - ---- - -## 6. Integrations & Packaging - -### 6.1 IDE integration matrix (`docs/integrations/*.md`) - -All 8 IDEs documented. The common install flow: (a) download `vestige-mcp` binary, (b) point IDE's MCP config at its absolute path, (c) restart IDE, (d) verify with `/context` or equivalent. - -| IDE | Config path | Notable | -|---|---|---| -| Claude Code | `~/.claude.json` or project `.mcp.json` | Inline in `CONFIGURATION.md`; one-liner install | -| Claude Desktop | `~/Library/Application Support/Claude/claude_desktop_config.json` | Inline in `CONFIGURATION.md` | -| Cursor | `~/.cursor/mcp.json` | Absolute paths required (Cursor doesn't resolve relatives reliably) | -| VS Code (Copilot) | `.vscode/mcp.json` OR User via command | **Uses `"servers"` key, NOT `"mcpServers"`** — Copilot-specific schema. Requires agent mode enabled. | -| Codex | `~/.codex/config.toml` | TOML not JSON. `codex mcp add vestige -- /usr/local/bin/vestige-mcp` helper. | -| Xcode | Project-level `.mcp.json` | **Xcode 26.3's `claudeai-mcp` feature gate blocks global config. Project-level `.mcp.json` in project root bypasses entirely.** First cognitive memory server for Xcode. Sandboxed agents do NOT inherit shell env — absolute paths mandatory. | -| JetBrains / Junie | `.junie/mcp/mcp.json` or UI config | 2025.2+. Three paths: Junie autoconfig, Junie AI config, external MCP client. | -| Windsurf | `~/.codeium/windsurf/mcp_config.json` | Supports `${env:HOME}` variable expansion. Cascade AI. | - -### 6.2 npm packages - -| Package | Version | Role | -|---|---|---| -| `vestige-mcp-server` (in `packages/vestige-mcp-npm`) | 2.0.7 | Binary wrapper — postinstall downloads the platform-appropriate release asset from GitHub. Bins: `vestige-mcp`, `vestige`. | -| `@vestige/init` (in `packages/vestige-init`) | 2.0.7 | Interactive zero-config installer. Bin: `vestige-init`. | -| `packages/vestige-mcpb/` | — | Legacy, abandoned. | - -**Publish status:** v2.0.6 is live on npm. **v2.0.7 pending Sam's Touch ID** (WebAuthn 2FA flow, not TOTP — has to be triggered from Sam's machine). - -### 6.3 GitHub release workflow (`release.yml`) - -Triggered on tag push (`v*`) OR manual `workflow_dispatch`. Matrix: - -| Target | Runner | Artifact | Status | -|---|---|---|---| -| `aarch64-apple-darwin` | macos-latest | `vestige-mcp-aarch64-apple-darwin.tar.gz` | ✅ | -| `x86_64-unknown-linux-gnu` | ubuntu-latest | `vestige-mcp-x86_64-unknown-linux-gnu.tar.gz` | ✅ | -| `x86_64-pc-windows-msvc` | windows-latest | `vestige-mcp-x86_64-pc-windows-msvc.zip` | ✅ | -| `x86_64-apple-darwin` (Intel Mac) | **DROPPED in v2.0.7** | — | ❌ `ort-sys 2.0.0-rc.11` (pinned by fastembed 5.13.2) has no Intel Mac prebuilt | - -Each artifact contains three binaries: `vestige-mcp`, `vestige`, `vestige-restore`. - -### 6.4 CI workflow (`ci.yml`) - -Triggers: push main + PR main. Runs on macos-latest + ubuntu-latest. Steps: `cargo check` → `cargo clippy --workspace -- -D warnings` → `cargo test --workspace`. **Tonight's fix:** Rust 1.95 introduced `unnecessary_sort_by` (12 sites fixed) + `collapsible_match` (1 site fixed in `memory_states.rs`, 1 `#[allow]` on `websocket.rs` because match guards can't move non-Copy `Bytes`). - -### 6.5 Test workflow (`test.yml`) - -5 parallel jobs: `unit-tests`, `mcp-tests`, `journey-tests` (depends on unit), `dashboard` (pnpm + vitest), `coverage` (LLVM + Codecov). Env: `VESTIGE_TEST_MOCK_EMBEDDINGS=1` to skip ONNX model download in CI. - -### 6.6 Xcode setup script (`scripts/xcode-setup.sh`) - -4.9 KB interactive installer. (a) detect/install binary, (b) offer project picker under `~/Developer`, (c) generate `.mcp.json`, (d) optionally batch-install to all detected projects. Supports SHA-256 checksum verification. - ---- - -## 7. `vestige-cloud` — Current Skeleton - -**Location:** `/Users/entity002/Developer/vestige-cloud` (separate git repo, private). - -**Status as of 2026-04-19:** single-commit skeleton from 2026-02-12 (8 weeks old, one feature commit `4e181a6`). ~600 LOC. - -### 7.1 Structure - -``` -vestige-cloud/ -├── Cargo.toml # workspace, path-dep on ../vestige/crates/vestige-core -├── Cargo.lock -└── crates/ - └── vestige-http/ - ├── Cargo.toml # binary: vestige-http - └── src/ - ├── main.rs # Axum server on :3927, auth + cors middleware - ├── auth.rs # Single bearer token via VESTIGE_AUTH_TOKEN env (auto-generated if unset, stored in data-dir) - ├── cors.rs # prod: allowlist vestige.dev + app.vestige.dev; dev: permissive - ├── state.rs # Arc> shared state (SINGLE TENANT) - ├── sse.rs # /mcp/sse STUB — 3 TODOs, returns one static "endpoint" event - └── handlers/ - ├── mod.rs - ├── health.rs # GET /health (version + memory count) - ├── api.rs # REST CRUD: search, list, create, get, delete, promote, demote, stats, smart_ingest - ├── mcp.rs # POST /mcp JSON-RPC 2.0 — **ONLY 5 TOOLS** (search, smart_ingest, memory, promote_memory, demote_memory) - └── sync.rs # POST /sync/push + /sync/pull (sync/pull has TODO for `since` filter) -``` - -### 7.2 Gap analysis vs. current `vestige-mcp` - -| Dimension | vestige-mcp v2.0.7 | vestige-cloud Feb skeleton | Gap | -|---|---|---|---| -| MCP tools | 24 | 5 | 19 tools missing (session_context, dream, explore_connections, predict, importance_score, find_duplicates, memory_timeline, memory_changelog, memory_health, memory_graph, deep_reference, consolidate, backup, export, gc, restore, intention, codebase, suppress/unsuppress) | -| MCP transport | stdio + HTTP | HTTP only, no Streamable HTTP | Needs full Streamable HTTP (`Mcp-Session-Id` header, bidirectional, Last-Event-ID reconnect) per 2025-06-18 spec | -| Multi-tenancy | N/A (local) | **Single tenant** (one storage, one API key) | Need per-user DB, row-level scoping, or DB-per-tenant sharding | -| Auth | Local token | Single bearer | Need JWT, OAuth, scopes, org membership, token rotation | -| Billing | N/A | none | Need Stripe, entitlement, plans, webhooks | -| Observability | `tracing` only | `tracing` only | Need Prometheus / OTLP export, dashboards, rate limits, error budget | -| Sync | N/A | lossy push + unfiltered pull | Need tombstones, incremental pull by `since`, conflict resolution | -| Deploy | binaries + npm | **none** | Need Dockerfile, fly.toml, CI, docs | - -### 7.3 Two upgrade paths - -- **Path A (v2.6.0 "Remote"):** Upgrade the Feb skeleton to match v2.0.7 surface (5 → 24 tools), implement Streamable HTTP, ship Dockerfile + fly.toml. **Keep single-tenant.** Ship as "deploy your own Vestige on a VPS." -- **Path B (v3.0.0 "Cloud"):** Multi-tenant SaaS. Weeks of work on billing, per-tenant DB, ops. Not viable until v2.6 has traction + cashflow. - -The recommendation in Part 9 is **A only** for now. B is gated on demand signal + runway. - ---- - -## 8. Version History (v1.0 → v2.0.8) - -### 8.1 Shipped releases - -| Version | Tag | Date | Theme | Headline | -|---|---|---|---|---| -| v1.0.0 | v1.0.0 | 2026-01-25 | Initial | First MCP server with FSRS-6 memory | -| v1.1.x | v1.1.0/1/2 | — | CLI separation | stats/health moved out of MCP to CLI | -| v1.3.0 | v1.3.0 | — | — | Importance scoring, session checkpoints, duplicate detection | -| v1.5.0 | v1.5.0 | — | — | Cognitive engine, memory dreaming, graph exploration, predictive retrieval | -| v1.6.0 | v1.6.0 | — | — | 6× storage reduction, neural reranking, instant startup | -| v1.7.0 | v1.7.0 | — | — | 18 tools, automation triggers, SQLite perf | -| v1.9.1 | v1.9.1 | — | Autonomic | Self-regulating memory, graph visualization | -| **v2.0.0** | v2.0.0 | **2026-02-22** | "Cognitive Leap" | 3D SvelteKit+Three.js dashboard, WebSocket event bus (16 events), HyDE query expansion, Nomic v2 MoE option, Command palette, bloom post-processing | -| v2.0.1 | v2.0.1 | — | — | Release rebuild, install fixes | -| v2.0.3 | v2.0.3 | — | — | Clippy fixes, CI alignment | -| v2.0.4 | v2.0.4 | 2026-04-09 | "Deep Reference" | **8-stage cognitive reasoning tool, `cross_reference` alias**, retrieval_mode (precise/balanced/exhaustive), token budgets raised 10K → 100K, CORS hardening | -| v2.0.5 | v2.0.5 | 2026-04-14 | "Intentional Amnesia" | **Active forgetting** — suppress tool #24, Rac1 cascade (72h async neighbour decay), 24h labile reversal window, graph node visual suppression (20% opacity, no emissive) | -| v2.0.6 | v2.0.6 | 2026-04-18 | "Composer" | 6 live graph reactions (Suppressed, Unsuppressed, Rac1, Connected, ConsolidationStarted, ImportanceScored), `VESTIGE_SYSTEM_PROMPT_MODE=full` opt-in | -| **v2.0.7** | v2.0.7 | 2026-04-19 | "Visible" | V11 migration drops dead tables; `/api/memories/{id}/suppress` + `/unsuppress` endpoints + UI button; sidebar `up 3d 4h` footer via `uptime_secs`; graph error-state split; `predict` degraded flag; `changelog` start/end honored; `intention` include_snoozed; `suppress` MCP tool (was dashboard-only); tool-count reconciled 23 → 24; Intel Mac dropped from release workflow; defensive `Err` on unknown export format | -| **v2.0.8** | *(unreleased, merged to main 2026-04-19 22:10 CT)* | — | — | FSRS memory-state colour mode (`ColorMode` type/state toggle) + floating legend + dark-glass-pill label redesign + 80 new tests + Rust 1.95 clippy compat (12 sites) | - -### 8.2 Current git state - -- **HEAD:** `main` at `30d92b5` "feat(graph): redesign node labels as dark glass pills" -- **Last 4 commits on main (v2.0.8):** - - `30d92b5` — Label pill redesign - - `d7f0fe0` — 80 new color-mode tests - - `318d4db` — Rust 1.95 clippy compat - - `4c20165` — Memory-state color mode + legend -- **Branches:** - - `main` (default, protected via CI-must-pass) - - `feat/v2.0.8-memory-state-colors` (fast-forwarded into main tonight) - - `feat/v2.1.0-qwen3-embed` (Day 2 done; Day 3 pending on Sam's M3 Max arrival) - - `chore/v2.0.7-clean` (post-v2.0.7 cleanup branch) - - `wip/v2.0.7-v11-migration` (transport branch for cross-machine stash) -- **Latest tag:** `v2.0.7` (force-updated on main after v2.0.6 rebase incident) -- **Latest CI run on main:** #24646176395 ✅ all 4 jobs (Test macos, Test ubuntu, Release aarch64-darwin, Release x86_64-linux) - -### 8.3 Open GitHub issues / PRs - -- **Closed #35** — "npm publish delay 2.0.6"; replied in v2.0.6 with one-liner install command -- **Open #36** — desaiuditd: "hooks-for-automatic-memory request" — customer conversion opportunity, not yet responded - ---- - -## 9. The Next-Phase Plan - -**Shipping cadence:** weekly minor bumps (v2.1 → v2.2 → v2.3 ...) until v3.0 which gates on multi-tenancy + CoW storage. Ships ~Monday each week with content post same day + follow-up Wednesday + YouTube Friday. - -### 9.1 v2.1.0 "Decide" — Qwen3 embeddings *(in-flight)* - -**Branch:** `feat/v2.1.0-qwen3-embed` (pushed). -**Status:** scaffolding merged; Day 3 pending. -**ETA:** ~1 week after M3 Max arrival (FedEx hold at Walgreens, pickup 2026-04-20). - -**What's in:** `qwen3-embed` feature flag gates a Candle-based Qwen3 embed backend. `qwen3_format_query()` helper for the query-instruction prefix. Metal device selection with CPU fallback. `DEFAULT_DIMENSIONS` feature-gated 256/1024. Dual-index routing scaffolded. - -**What's left (Day 3):** -- Storage write-path records `embedding_model` per node. -- `semantic_search_raw` uses `qwen3_format_query` when feature active. -- Dual-index routing: old Nomic-256 nodes stay on their HNSW, new Qwen3-1024 nodes go on a new HNSW. Search merges with trust weighting. -- End-to-end test: ingest on Qwen3 → retrieve on Qwen3 at higher accuracy than Nomic. - -**Test gate:** `cargo test --workspace --features qwen3-embed --release` green. Current baseline: 366 core + 425 mcp passing. - -### 9.2 v2.2.0 "Pulse" — Subconscious Cross-Pollination **★ VIRAL LOAD-BEARING RELEASE** - -**ETA:** 1-2 weeks after v2.1 lands. - -**What it does:** While the user is doing anything else (typing a blog post, looking at a different tab, doing nothing), Vestige's running `dream()` in the background. When dream completes with `insights_generated > 0` or a `ConnectionDiscovered` event fires from spreading activation, **the dashboard pulses a toast** on the side: *"Vestige found a connection between X and Y. Here's the synthesis."* The bridging edge in the 3D graph flashes cyan and briefly thickens. - -**Why viral:** This is the single most tweet/YouTube-friendly demo in the entire roadmap. It is the "my 3D brain is thinking for itself" moment. - -**Backend (≈2 days):** -1. `ConsolidationScheduler` gains a "pulse" hook: after each cycle, if `insights_generated > 0` emit a new `InsightSurfaced` event with `{source_memory_id, target_memory_id, synthesis_text, confidence}`. -2. The existing `ConnectionDiscovered` event gets a richer payload: include both endpoint IDs + a templated synthesis string derived from the two memories' content. -3. Rate-limit pulses: max 1 per 15 min unless user is actively using the dashboard. - -**Frontend (≈5 days):** -1. New Svelte component `InsightToast.svelte` — slides in from right, shows synthesis text + "View connection" button, auto-dismisses after 10s. -2. `events.ts` mapping: `InsightSurfaced` → locate bridging edge in graph, pulse it cyan for 2s, thicken to 2× for 500ms, play a soft chime (optional, muted by default). -3. Toast queue so rapid dreams don't flood. -4. Preference: user can toggle pulse sound / toast / edge animation independently in `/settings`. - -**Already exists (nothing to build):** -- `dream()` 5-stage cycle — YES -- `DreamCompleted` event with `insights_generated` — YES -- `ConnectionDiscovered` event + WebSocket broadcast — YES -- 3D edge animation system in `events.ts` — YES (handler exists, just doesn't emit toast) -- ConsolidationScheduler running on `VESTIGE_CONSOLIDATION_INTERVAL_HOURS` — YES - -**Never-composed alarm:** Four existing components, zero lines of composition. This feature is **~90% latent in v2.0.7**. All we do is press the button. - -**Acceptance criteria:** -- Start Vestige, idle for 10 min, verify a pulse fires from scheduled dream cycle. -- Ingest 3 semantically adjacent memories from completely different domains (e.g., F1 aerodynamics, memory leak, fluid dynamics), trigger dream, verify connection pulse fires with synthesis text mentioning both source + target. -- Dashboard test coverage: add `pulse.test.ts` with 15+ cases covering toast queue, rate limit, event shape, edge animation. - -**Launch day:** Film a 90-second screen recording. Post to Twitter + Hacker News + LinkedIn + YouTube same day. - -### 9.3 v2.3.0 "Rewind" — Time Machine - -**ETA:** 2-3 weeks after v2.2 ships. - -**What it does:** The graph page gets a horizontal time slider. Drag back in time → nodes dim based on retroactive FSRS retention, edges that were created after the slider's timestamp dissolve visibly, suppressed memories un-dim to their pre-suppression state. A "Pin" button snapshots the current slider state into a named checkpoint the user can return to. - -**Backend (≈4 days):** -1. New core API: `Storage::memory_state_at(memory_id, timestamp) -> MemorySnapshot` — reconstructs a node's FSRS state at an arbitrary past timestamp by replaying `state_transitions` forward OR applying FSRS decay backward from the current state. -2. New MCP tool: `memory_graph_at(query, depth, max_nodes, timestamp)` — the existing graph call with a time parameter. -3. New MCP tool: `pin_state(name, timestamp)` — persists a named snapshot (just a row in a new `pins` table: name, timestamp, created_at). -4. New core API: `list_pins()` + `delete_pin(name)`. - -**Frontend (≈7 days):** -1. `TimeSlider.svelte` already exists as a scaffold (listed in §5.5) — upgrade it to an HTML5 range input + play/pause + speed control. -2. Graph3D consumes a new `asOfTimestamp` prop. When set, uses `temporal.ts::retentionAtDate()` to re-project every node's opacity + size. -3. Edges: hide those with `created_at > slider`. Animate the dissolution so sliding feels organic. -4. Pin sidebar: list pinned states, click to jump, rename/delete. - -**Cut from scope: branching.** Git-like "what if I forgot my Python biases" requires CoW storage = full schema migration = v3.0 territory. Scope it out explicitly. - -**Acceptance criteria:** -- Slide back 30 days, verify node count drops to whatever existed 30 days ago. -- Slide back through a suppression event, verify node un-dims. -- Pin "before Mays deadline", verify pin jumps restore exact state. - -### 9.4 v2.4.0 "Empathy" — Emotional Context Tagging **★ FIRST PRO-TIER GATE CANDIDATE** - -**ETA:** 2-3 weeks after v2.3 ships. - -**What it does:** Vestige's MCP middleware watches tool call metadata for frustration signals — repeated retries of the same query, CAPS LOCK content, explicit correction phrases ("no that's wrong", "actually..."), rapid-fire consecutive calls. When detected, the current active memory gets an automatic `ArousalSignal` boost and a `frustration_detected_at` timestamp. Next session, when the user returns to a similar topic, the agent proactively surfaces: *"Last time we worked on this, you were frustrated with the API docs. I've pre-read them."* - -**Why Pro-tier:** Invisible to demo (so doesn't hurt OSS growth), creates deep lock-in, quantifiable value ("Vestige saved you X minutes of re-frustration this month"), clear paid-hook rationale. - -**Backend (≈4 days):** -1. New middleware layer in `vestige-mcp` between JSON-RPC dispatch and tool execution: `FrustrationDetector`. Analyzes tool args for: (a) retry pattern (same `query` field within 60s), (b) content ≥70% caps after lowercase comparison, (c) correction regex (`no\s+that|actually|wrong|fix this|try again`). -2. On detection, fire a synthesized `ArousalSignal` to `ImportanceTracker` for the most-recently-accessed memory. -3. New core API: `find_frustration_hotspots(topic, limit)` → returns memories with `arousal_score > threshold` + their `frustration_detected_at` timestamps. -4. `session_context` tool gains a new field: `frustration_warnings[]` — "Topic X had previous frustration; here's what we know." - -**Frontend (≈3 days):** -1. Memory detail pane shows an orange "Frustration" badge for high-arousal memories. -2. `/stats` adds a "Frustration hotspots" section. - -**Acceptance criteria:** -- Simulate 3 rapid retries of the same query, verify ArousalSignal boosts the active memory. -- Simulate caps-lock content, verify detection. -- Return to same topic next session, verify `session_context` surfaces warning. - -### 9.5 v2.5.0 "Grip" — Neuro-Feedback Cluster Gestures - -**ETA:** 2 weeks after v2.4 ships. - -**What it does:** In the 3D graph, drag a memory sphere to "grab" it — its cluster highlights. Squeeze (pinch gesture or modifier key + drag inward) → promotes the whole cluster. Flick away (throw gesture) → triggers decay on the cluster. - -**Backend (≈2 days):** -1. New MCP tool: `promote_cluster(memory_ids[])` — applies promote to each. -2. New MCP tool: `demote_cluster(memory_ids[])` — inverse. -3. Cluster detection helper: `find_cluster(source_id, similarity_threshold)` — leverages existing `find_duplicates` + spreading activation. - -**Frontend (≈5 days):** -1. Three.js gesture system: drag detection, cluster highlight (emissive pulse on all cluster members), squeeze detection (pointer velocity inward), flick detection (pointer velocity outward past threshold). -2. Visual feedback: green ring on squeeze (promote), red dissipation on flick (demote). -3. Accessibility: keyboard alternative — select node, press `P` / `D` to promote/demote cluster. - -### 9.6 v2.6.0 "Remote" — `vestige-cloud` Self-Host Upgrade - -**ETA:** 3 weeks after v2.5 ships. First paid-tier candidate if empathy doesn't convert first. - -**What it does:** Turns the Feb `vestige-cloud` skeleton into a shippable self-host product. One-liner install → Docker container or fly.io deploy → point Claude Desktop/Cursor/Codex at the remote URL → cloud-persistent memory across all your devices. - -**Scope:** -1. Upgrade MCP handler from 5 → 24 tools (port each tool from `crates/vestige-mcp/src/tools/`). -2. Implement **MCP Streamable HTTP transport** (spec 2025-06-18): `Mcp-Session-Id` header, bidirectional event stream, Last-Event-ID reconnect, JSON-RPC batching. -3. Per-user SQLite at `/data/$USER_ID.db` (single-tenant but scoped by `VESTIGE_USER_ID` env — "single-tenant but deploy-multiple"). -4. `Dockerfile` (multi-stage: Rust build + fastembed model baked in). -5. `fly.toml` with persistent volume mount on `/data`. -6. `docker-compose.yml` for local Postgres-if-needed (probably not — stick with SQLite for self-host). -7. `scripts/cloud-deploy.sh` one-liner installer. -8. Docs: `docs/cloud/self-host.md` step-by-step. - -**Explicitly OUT of scope for v2.6:** Stripe, multi-tenant DB, user accounts, rate limits, billing. Those are v3.0. - -### 9.7 v3.0.0 "Branch" — CoW memory branching + SaaS multi-tenancy - -**ETA:** Q3 2026 at earliest. Gated on: -- v2.6 adoption signal (≥500 self-host deployments) -- Sam's runway (needs pre-revenue or funding) -- Either Mays, Orbit Wars, or another cash injection - -**What it does:** -1. **Memory branching** — git-like CoW over SQLite. Branch a memory state, diverge freely, merge or discard. "What if I forgot all my Python biases and approached this memory as a Rust expert" becomes a one-button operation. -2. **Multi-tenant SaaS** at `vestige.dev` / `app.vestige.dev`. Per-user DB shards, JWT auth + OAuth providers, Stripe subscriptions with entitlement gates, org membership, team shared memory with role-based access. - -**Major subsystems required:** -- Storage layer rewrite for CoW semantics (or adopt Dolt/sqlcipher with branching). -- Auth: JWT + OAuth (Google, GitHub, Apple) + bcrypt fallback. -- Billing: Stripe subscriptions + webhooks + dunning. -- Admin dashboard: support, usage analytics, churn. -- Multi-region: at minimum US-east + EU (GDPR). -- Observability: Prometheus + Grafana + Sentry + Honeycomb tracing. - -**Explicitly NOT a v2.x goal.** Any earlier attempt burns runway. - -### 9.8 Summary roadmap table - -| Version | Codename | Theme | Effort | Load-bearing for | ETA | -|---|---|---|---|---|---| -| v2.1 | Decide | Qwen3 embeddings | ~1 week | Retrieval quality + differentiation vs. Nomic | Days | -| **v2.2** | **Pulse** | **Subconscious cross-pollination** | **~1 week (mostly latent)** | **★ Viral launch moment** | **~2 weeks** | -| v2.3 | Rewind | Time machine (slider + pin) | ~2 weeks | Technical moat, impressive demo | ~5 weeks | -| v2.4 | Empathy | Frustration detection → arousal boost | ~1 week | **First Pro-tier gate candidate** | ~7 weeks | -| v2.5 | Grip | Cluster gestures | ~1 week | Polish | ~9 weeks | -| v2.6 | Remote | vestige-cloud self-host (5→24 tools + Streamable HTTP + Docker) | ~3 weeks | Foundation for SaaS; secondary Pro-tier gate | ~12 weeks | -| v3.0 | Branch | CoW branching + multi-tenant SaaS | ~3 months | Revenue | Q3 2026 at earliest | - ---- - -## 10. Composition Map - -For each v2.x feature, what existing primitives does it compose? - -| Feature | Existing primitive | How composed | -|---|---|---| -| v2.2 Pulse | `dream()` + `ConsolidationScheduler` + `ConnectionDiscovered` event + Three.js `events.ts::mapEventToEffects` | Consume the already-firing events; add toast UI + richer synthesis payload | -| v2.3 Rewind slider | `state_transitions` append log + FSRS decay formula + `temporal.ts::retentionAtDate()` + existing `TimeSlider.svelte` stub | Retroactive state reconstruction + slider upgrade | -| v2.3 Rewind pins | `smart_ingest` patterns + new `pins` table | Thin new table + two new tools | -| v2.4 Empathy | `ArousalSignal` (already in ImportanceSignals 4-channel model) + middleware pattern + `ImportanceTracker` | New middleware layer feeds existing arousal channel | -| v2.5 Grip | `find_duplicates` clustering + `promote`/`demote` + v2.0.8 Three.js node picking | Cluster-level wrapper over per-node operations | -| v2.6 Remote | v2.0.7 MCP tool implementations + vestige-cloud Feb skeleton + Axum | Port tools; implement Streamable HTTP; containerize | -| v3.0 Branch | Requires new CoW storage layer — **no existing primitive composes here** | Greenfield storage rewrite | -| v3.0 SaaS | Requires new auth + billing + multi-tenancy — **no existing primitive composes** | Greenfield | - -**Key insight:** v2.2-v2.6 are all ≥60% latent in existing primitives. v3.0 is the first release that requires significant greenfield work. This is why sequencing matters: ride the existing primitives to revenue, then greenfield. - ---- - -## 11. Risks & Known Gaps - -### 11.1 Technical - -| Risk | Impact | Mitigation | -|---|---|---| -| `ort-sys 2.0.0-rc.11` prebuilt gaps (Intel Mac dropped, Windows MSVC with usearch 2.24 broken) | Fewer platforms ship | Wait for ort-sys 2.1; or migrate to Candle throughout (v2.1 Qwen3 already uses Candle) | -| `usearch` pinned to 2.23.0 (2.24 regression on MSVC) | Windows build fragility | Monitor usearch#746 | -| fastembed model download (~130MB for Nomic, ~500MB for Qwen3) on first run blocks sandboxed Xcode | UX friction | Cache at `~/Library/Caches/com.vestige.core/fastembed` — documented in Xcode guide; pre-download from terminal once | -| Tool count drift (23 vs 24 across docs) | User trust | Reconciled in v2.0.7 (`docs: tool-count reconciliation`) | -| Large build times (cargo release 2-3 min incremental, 6+ min clean) | Slow iteration | M3 Max arriving Apr 20 will halve this | -| `include_dir!` bakes dashboard build into binary at compile time | Have to rebuild Rust to update dashboard | Accept as design; HMR via `pnpm dev` for iteration | - -### 11.2 Product - -| Risk | Impact | Mitigation | -|---|---|---| -| OSS-growth-before-revenue means months of zero cash | Sam can't pay rent | Mays May 1 ($400K+), Orbit Wars June 23 ($5K × top 10), part-time Wrigley Field during Cubs season | -| `deep_reference` is the crown jewel but rarely invoked | Users don't discover it | `CLAUDE.md` flags it; v2.2 Pulse farms the viral moment to drive awareness | -| Subconscious Pulse may fire too often or too rarely | User annoyance or missed value | Rate limit: max 1 pulse per 15 min; user-adjustable in settings | -| Emotional tagging may over-fire (every caps lock = frustration?) | False positives | Require ≥2 signals (retry + caps, or retry + correction) before boost | -| v3.0 SaaS burns runway if started too early | Business-ending | Gated on v2.6 adoption + cash injection | -| Copycat risk (Zep, Cognee, etc.) cloning Vestige's features | Eroded differentiation | AGPL-3.0 protects network use; neuroscience depth is hard to fake; time slider + subconscious pulse are visible moats | -| Cross-IDE MCP standard changes (Streamable HTTP spec moved 2024-11-05 → 2025-06-18) | Breaking transport changes | v2.6 implements the newer spec; keep 2024-11-05 as backward-compat alias | - -### 11.3 Known UI gaps (`docs/launch/UI_ROADMAP_v2.1_v2.2.md`) - -- **26% of MCP tools have zero UI surface** (e.g., `codebase`, `find_duplicates`, `backup`, `export`, `gc`, `restore` — all power-user only). -- **28% of cognitive modules have no visualization** (SynapticTagging, HippocampalIndex, ContextMatcher, CrossProjectLearner, etc.). -- The rainbow-bursted Rac1 cascade in the graph has no numeric "how many neighbours did it touch" display. -- `intention` shows but doesn't let you edit/snooze from the UI. -- `deep_reference` is unreachable from the dashboard (it only surfaces via MCP tool calls). - ---- - -## 12. Viral / Launch / Content Plan - -### 12.1 Content cadence (fixed) - -**Mon–Fri till June 13 graduation:** -- 1-2 posts/day across Twitter + LinkedIn + Hacker News + Reddit r/LocalLLaMA + r/selfhosted -- Weekly YouTube long-form (Friday release) - -### 12.2 Per-release launch playbook - -For every v2.x release: -1. **Monday:** Tag + release + content drop (tweet with 30-90s demo video + HN post). -2. **Tuesday:** LinkedIn long-form + Reddit cross-post. -3. **Wednesday:** Follow-up tweet thread (deep-dive on one specific feature). -4. **Thursday:** Engage with feedback; close issues; publish patch if needed. -5. **Friday:** YouTube long-form (15-25 min walkthrough). Next week's release work continues. - -### 12.3 Viral load-bearing moments - -- **v2.2 "Pulse" launch:** The single biggest viral bet. Subconscious cross-pollination demo → HN front page → Twitter thread → YouTube 10-min walkthrough. -- **v2.3 "Rewind" time slider:** Highly tweet-friendly. Screen recording of sliding back through memory decay. -- **Jarrett Ye (FSRS creator, user L-M-Sherlock) outreach:** Already a stargazer. Email him Sunday night (US time) = Monday AM Beijing with the v2.2 Pulse demo. If he retweets → FSRS community (Anki, maimemo) amplifies. - -### 12.4 Issue #36 (hooks-for-automatic-memory) - -Outstanding from desaiuditd. Response plan: -1. Thank him publicly in the issue. -2. Acknowledge the feature as valid and scoped for v2.2/v2.3. -3. Open a linked sub-issue: "v2.2: Auto-memory hooks" tied to Pulse work. - -### 12.5 Monetization gates - -**Two candidate first-gates:** -1. **v2.4 Empathy (Emotional tagging)** — invisible to OSS demos, strong retention, clean paid-feature framing ("Vestige notices when you're frustrated; free tier gets 100 detection events/month, Pro gets unlimited + frustration hotspot analytics"). -2. **v2.6 Remote (Cloud self-host binary)** — "free binary forever; paid-tier cloud-managed deploy with backups + observability + multi-device sync." - -Pick after v2.2 viral signal tells us whether retention or convenience is the weaker link. - ---- - -## 13. How AI Agents Should Consume This Doc - -### 13.1 First-time read protocol - -If this is the first time you're seeing Vestige: -1. Read Part 0 (Executive Summary) + Part 1 (What Vestige Is). That's 3 minutes. -2. Read Part 9 (The Plan). That's 10 minutes. -3. Bookmark Parts 3-6 for reference. - -### 13.2 When Sam asks you to plan a feature - -1. Check Part 9 — is it already scoped? If yes, that section IS your spec. -2. If not, work it into the existing roadmap: which version should it ship in, what primitives does it compose (Part 10), what risks apply (Part 11)? -3. Follow the `/Users/entity002/.claude/rules/active-synthesis.md` protocol (6 mandatory behaviors): compose, don't summarize. - -### 13.3 When Sam asks you to implement - -1. Find the exact file paths in Parts 3-5. -2. Check existing test coverage (Part 5.9 for dashboard, §3.11 for core). -3. Before claiming something exists, grep or read the source — memory alone is insufficient (per `CLAUDE.md` SCOUR rule). -4. Rust 1.95 toolchain — be aware of the new lints (`unnecessary_sort_by`, `collapsible_match`). - -### 13.4 When Sam asks for strategic advice - -- Apply the `/Users/entity002/.claude/rules/cross-reference.md` rule: check evidence from the exact setup before recommending. -- Apply the `always-positive-energy` rule: recommend the BEST path, not the safest. -- This doc's Part 9 is the committed roadmap. Deviate only with explicit justification. - -### 13.5 Load-bearing files to never forget - -- `/Users/entity002/Developer/vestige/CLAUDE.md` — project-level Claude instructions. -- `/Users/entity002/.claude/rules/active-synthesis.md` — 6 mandatory synthesis behaviors. -- `/Users/entity002/.claude/rules/cross-reference.md` — exact-setup evidence rule. -- `/Users/entity002/CLAUDE.md` — global Claude instructions (SCOUR + always-positive-energy). -- `/Users/entity002/Developer/vestige/docs/launch/UI_ROADMAP_v2.1_v2.2.md` — prior UI research compilation. -- **This file** — `/Users/entity002/Developer/vestige/docs/VESTIGE_STATE_AND_PLAN.md`. - ---- - -## 14. Glossary & Citations - -### 14.1 Acronyms - -| Term | Meaning | -|---|---| -| **MCP** | Model Context Protocol — JSON-RPC protocol for AI tool integration (Anthropic, 2024) | -| **FSRS** | Free Spaced Repetition Scheduler — algorithm by Jarrett Ye (maimemo), generation 6 | -| **PE Gating** | Prediction Error Gating — decide CREATE/UPDATE/SUPERSEDE by similarity threshold | -| **SIF** | Suppression-Induced Forgetting — Anderson 2025 | -| **Rac1** | Rho-family GTPase — actin-destabilization mediator of cascade decay (Cervantes-Sandoval & Davis 2020) | -| **SWR** | Sharp-wave ripple — hippocampal replay pattern used by Vestige's dream cycle | -| **HNSW** | Hierarchical Navigable Small World — graph index for fast approximate nearest neighbour | -| **CoW** | Copy-on-write — storage technique for cheap branching | -| **AGPL** | Affero General Public License — copyleft including network use | - -### 14.2 Neuroscience citations - -- Anderson, M. C. (2025). Suppression-induced forgetting — top-down inhibitory control of retrieval. -- Anderson, M. C., Bjork, R. A., & Bjork, E. L. (1994). Remembering can cause forgetting. -- Bjork, R. A., & Bjork, E. L. (1992). A new theory of disuse and an old theory of stimulus fluctuation. — dual-strength model. -- Brown, R., & Kulik, J. (1977). Flashbulb memories. -- Cervantes-Sandoval, I., & Davis, R. L. (2020). Rac1-mediated forgetting. -- Collins, A. M., & Loftus, E. F. (1975). A spreading-activation theory of semantic processing. -- Frey, U., & Morris, R. G. M. (1997). Synaptic tagging and long-term potentiation. -- Friston, K. J. (2010). The free-energy principle: a unified brain theory. -- Nader, K., Schafe, G. E., & LeDoux, J. E. (2000). Fear memories require protein synthesis in the amygdala for reconsolidation after retrieval. -- Teyler, T. J., & Rudy, J. W. (2007). The hippocampal indexing theory. -- Tulving, E., & Thomson, D. M. (1973). Encoding specificity and retrieval processes. - -### 14.3 Technical citations - -- MCP Spec (2025-06-18 Streamable HTTP): https://modelcontextprotocol.io/specification -- FSRS-6: https://github.com/open-spaced-repetition/fsrs-rs -- Nomic Embed Text v1.5: https://huggingface.co/nomic-ai/nomic-embed-text-v1.5 -- Qwen3 Embed: https://huggingface.co/Qwen/Qwen3-Embedding-0.6B -- USearch: https://github.com/unum-cloud/usearch -- Jina Reranker v1 Turbo: https://huggingface.co/jinaai/jina-reranker-v1-turbo-en - ---- - -## 15. POST-v2.0.8 ADDENDUM — The Autonomic Turn (added 2026-04-23) - -> This section supersedes portions of sections 9.1-9.8. The April 19 roadmap (v2.1 Decide → v2.2 Pulse → v2.3 Rewind → v2.4 Empathy → v2.5 Grip → v2.6 Remote → v3.0 Branch) remains the long-arc plan but has been RESEQUENCED post-v2.0.8 ship following a three-agent audit on 2026-04-23 (web research on 2026 SOTA, Vestige code audit for active-vs-passive paths, competitor landscape). Updated sequence reflects what got absorbed into v2.0.8 and the new v2.0.9 / v2.5 / v2.6 architecture tier that replaces the old placeholder numbering. - -### 15.1 What v2.0.8 "Pulse" absorbed - -v2.0.8 shipped (commit `6a80769`, tag `v2.0.8`, 2026-04-23 07:21Z) bundled: - -- **v2.2 "Pulse" InsightToast** (from April 19 roadmap) — real-time toast stack over the WebSocket event bus; DreamCompleted / ConsolidationCompleted / ConnectionDiscovered / MemoryPromoted/Demoted/Suppressed surface automatically. -- **v2.3 "Terrarium" Memory Birth Ritual** — 60-frame elastic materialization on every `MemoryCreated` event. -- **8 new dashboard surfaces** exposing the cognitive engine: `/reasoning`, `/duplicates`, `/dreams`, `/schedule`, `/importance`, `/activation`, `/contradictions`, `/patterns`. -- **Reasoning Theater** wired to the 8-stage `deep_reference` cognitive pipeline with Cmd+K Ask palette. -- **3D graph brightness** auto-compensation + user slider (0.5×–2.5×, localStorage-persisted). -- **Intel Mac restored** via `ort-dynamic` + Homebrew onnxruntime (closes #41, sidesteps Microsoft's upstream deprecation of x86_64 macOS ONNX Runtime prebuilts). -- **Cross-reference hardening** — contradiction-detection false positives from 12→0 on an FSRS-6 query; primary-selection topic-term filter (50% relevance + 20% trust + 30% term_presence) fixes off-topic-high-trust-wins-query bug. - -Post-v2.0.8 hygiene commit `0e9b260` removed 3,091 LOC of orphan code (9 superseded tool modules + ghost env-var docs + one dead fn). - -### 15.2 The audit finding — "decorative memory" at system scale - -Three agents ran in parallel on 2026-04-23. Core diagnosis: **Vestige has 30 cognitive modules but only 2 autonomic mechanisms** (6h auto-consolidation loop + per-tool-call scheduler at `server.rs:884`). The 20-event WebSocket bus at `dashboard/events.rs` has **zero backend subscribers** — all 14 live event types flow to the dashboard and terminate. Fully-built trigger methods exist but nothing calls them: - -- `ProspectiveMemory::check_triggers()` at `prospective_memory.rs:1260` — 9h intention window, never polled. -- `SpeculativeRetriever::prefetch()` at `advanced/speculative.rs` (606 LOC) — never awaited. -- `MemoryDreamer::run_consolidation_cycle()` — instantiated on CognitiveEngine but the 6h timer at `main.rs:258` calls only `storage.run_consolidation()` (FSRS decay), never the dreamer. - -Three completely dead modules: `MemoryCompressor`, `AdaptiveEmbedder`, `EmotionalMemory` (constructed in `CognitiveEngine::new()` at `cognitive.rs:145-160`, zero call sites in vestige-mcp). `Rac1CascadeSwept`, `ActivationSpread`, `RetentionDecayed` events declared but never emitted. - -**This is the ARC-AGI-3 pattern at system scale:** storage exists, retrieval exists, memory never self-triggers during the agent's decision path because no subscriber is listening. Sam's paraphrased thesis: *"the bottleneck won't be how much the agent knows — it will be how efficiently it MANAGES what it knows."* - -### 15.3 The 2026 SOTA convergence — "retrieval is solved, management is not" - -Web-research agent surfaced the consensus. Load-bearing papers + their unshipped primitives: - -- **Titans** (arXiv 2501.00663, Google NeurIPS 2025) — test-time weight updates via surprise gradient. Active IN-MODEL. -- **A-Mem** (arXiv 2502.12110) — Zettelkasten dynamic re-linking on write. -- **Memory-R1** (arXiv 2508.19828) — RL-trained Manager with ADD/UPDATE/DELETE/NOOP on 152 QA pairs; beats baselines on LoCoMo + MSC + LongMemEval. -- **Mem-α** (arXiv 2509.25911) — RL over tripartite core/episodic/semantic memory, trained on 30k tokens, generalizes to 400k. -- **MemR³** (arXiv 2512.20237) — closed-loop router with retrieve/reflect/answer decision + evidence-gap tracking. -- **SleepGate** (arXiv 2603.14517) + **LightMem** (arXiv 2510.18866) — sleep-phase offline consolidation, timer-decoupled autonomous. -- **StageMem** (arXiv 2604.16774) + **Evidence for Limited Metacognition in LLMs** (arXiv 2509.21545) — item-level confidence separated from retention, validity-screened selective abstention. -- **Memory in the Age of AI Agents** survey (arXiv 2512.13564) — taxonomy (Forms/Functions/Dynamics); all open problems live in Dynamics. - -**Three unshipped-by-anyone concepts define the 2026 frontier:** meta-memory / confidence-gated generation (refuse to answer when load-bearing memory is cold), autonomous consolidation on surprise/drift (not on timer), write-time contradiction detection with agent-facing alerts. - -### 15.4 Competitive landscape — the white-space lanes - -Nobody ships: **confidence-gated generation, proactive contradiction flagging without query, predictive pre-warm at UserPromptSubmit, autonomic working-memory capacity enforcement.** - -- Mem0 v2 (Apr 16, 2026): auto-dedup (0.9 threshold), single-pass fact extraction. Retrieval still query-triggered. -- Letta: sleep-time agents mutate shared memory blocks asynchronously (most actively-managing shipped product). Archival/recall still query-triggered. -- Zep Graphiti: temporal invalidation via valid-until edges, community summarization. Retrieval still query-triggered. -- Pieces LTM-2: OS-level auto-OCR capture (most aggressive autonomous capture). No autonomous management. -- Anthropic Claude Code: 95%-context auto-compaction. No trust-scored memories, no scheduled dream, no confidence gating. -- Google Titans: surprise-gated memory IN-MODEL; not a server-level primitive. - -Every one of those four white-space primitives has raw material **already built** in Vestige (FSRS-6 trust scores, `deep_reference`, `predict`, `SpeculativeRetriever`, WebSocket event bus, Sanhedrin POC from April 20). The bottleneck is wiring, not features. - -### 15.5 v2.0.9 "Autopilot" — Weekend Ship (2-3 days) - -**Single architectural change**: add a backend event-subscriber task in `main.rs` (~50-100 LOC `tokio::spawn`) that consumes the existing WebSocket bus and routes events into the cognitive modules that already have trigger methods. This one commit flips 14 dormant primitives into active ones simultaneously. - -**Concrete wiring:** - -| Event | Currently emits to | Add backend routing | -|---|---|---| -| `MemoryCreated` | dashboard only | `synaptic_tagging.trigger_prp()` + `predictive_memory.record_save()` + `cross_project.record_pattern()` | -| `SearchPerformed` | dashboard only | `speculative.prefetch()` awaited in background task | -| `MemoryPromoted` | dashboard only | `activation_network.cascade_reinforce(neighbors, 0.3)` | -| `MemorySuppressed` | dashboard only | emit `Rac1CascadeSwept` (currently declared never-emitted) | -| `ImportanceScored > 0.85` | dashboard only | auto-`promote` | -| `DeepReferenceCompleted` with contradictions | dashboard only | queue a `dream()` cycle for contradiction-resolution | - -**Three additional changes:** - -1. New 60s `tokio::interval` in `main.rs` calls `cog.prospective_memory.check_triggers(current_session_context)`. On hit, emit new `IntentionFired` event + MCP sampling/createMessage notification to the client. -2. Add `cognitive.dreamer.run_consolidation_cycle()` call inside the existing 6h auto-consolidation loop at `main.rs:258` (alongside, not replacing, `storage.run_consolidation()`). -3. `find_duplicates` auto-runs when `Heartbeat.total_memories > 700`. - -**Launch narrative:** *"Vestige now acts on your memories while you sleep — 14 cognitive modules that used to wait for a query now fire autonomously on every memory event."* - -### 15.6 v2.5.0 "Autonomic" — 1 Week After v2.0.9 - -Three unshipped-by-anyone primitives land in one release. This is the category-defining drop. - -**(A) Hallucination Guillotine — Confidence-Gated Veto** - -Stop hook runs `deep_reference` on the agent's draft response, checks FSRS retention on load-bearing claims. If any required fact has retention < 0.4, exits 2 with a `VESTIGE VETO: cold memory on claim X, retrieve fresh evidence or explicitly mark uncertain` block. The Sanhedrin POC from 2026-04-20 already proves the mechanism works in real dogfooding — three consecutive drafts were vetoed by the POC. Package as a formal `vestige-guillotine` Claude Code plugin. - -Files: new `crates/vestige-mcp/src/hooks/guillotine.rs`, plugin manifest in `packages/claude-plugin/`. Composes existing `deep_reference` trust-score pipeline + the Sanhedrin dogfooding script. - -**(B) Contradiction Daemon — Write-Time Alerting** - -On every `smart_ingest` write, a fast `deep_reference` runs against the existing graph. If the new memory contradicts an existing memory with trust > 0.6, the server fires an MCP sampling/createMessage notification to the agent *in the same conversation:* *"this contradicts memory Y from \[date\]. Supersede Y, discard X, or mark both as time-bounded?"* The agent resolves the conflict in real time instead of waking up to it three sessions later. - -Files: `crates/vestige-mcp/src/tools/smart_ingest.rs` (post-write hook), `crates/vestige-mcp/src/protocol/sampling.rs` (new — MCP sampling/createMessage support). Composes existing `deep_reference` + contradiction-detection hardening from v2.0.8. - -**(C) Pulse Prefetch — Predictive Pre-Warm at UserPromptSubmit** - -UserPromptSubmit hook fires `predict(query)`, top-k results injected into agent context before the first token. The agent never has to ask; the memory is already there. Nemori did predict-calibrate; Letta does sleep-time; nobody fires at query-arrival. - -Files: `crates/vestige-mcp/src/hooks/pulse_prefetch.rs` (new), extend `SpeculativeRetriever::prefetch()`. Composes existing `predict` tool + `speculative.rs` (606 LOC, never awaited until v2.0.9 wiring). - -**Launch narrative:** *"The first MCP memory that VETOes hallucinations before the user sees them, FLAGS contradictions at write-time, and PREDICTS what the agent will need before the agent knows it needs it. Zero-shot proactive memory management."* - -### 15.7 v2.6.0 "Sleepwalking" — 2 Weeks After v2.5.0 - -Dream cycle detects high-value cross-project patterns → auto-generates and opens pull requests against the user's codebase. Zep writes text summaries; Vestige writes code. The `cross_project.find_universal_patterns()` fn already exists. Wire it via a new `sleepwalk` subcommand that invokes `gh pr create` with generated diffs. - -Files: new `crates/vestige-mcp/src/bin/sleepwalk.rs`, composes `CrossProjectLearner` + `MemoryDreamer` + existing gh CLI integration. - -**Launch narrative:** *"Your AI memory writes PRs while you sleep."* - -### 15.8 Post-v2.6 — Remaining April 19 roadmap - -After v2.6 "Sleepwalking," the April 19 placeholder roadmap reasserts with renumbered slots: - -| Slot | Codename | Scope | -|---|---|---| -| v2.7 | Decide | Qwen3 embeddings (absorbing the pre-existing `feat/v2.1.0-qwen3-embed` branch) once M3 Max Metal validates | -| v2.8 | Rewind | Temporal slider + pin, state reconstruction over time | -| v2.9 | Empathy | Apple Watch biometric flashbulb + frustration detection → arousal boost. First Pro-tier gate candidate. | -| v2.10 | Grip | Cluster gestures + manual bridging | -| v2.11 | Remote | `vestige-cloud` self-host upgrade (5→24 MCP tools + Streamable HTTP + Docker) | -| v3.0 | Branch | CoW memory branching + multi-tenant SaaS (gated on v2.11 adoption + cashflow) | - -### 15.9 Expected 30-day outcome - -Target: v2.0.9 + v2.5.0 + v2.6.0 all ship within 30 days of v2.0.8. -Stars trajectory: current 484 baseline at +12/day → +600 from v2.0.9 + +1,500 from v2.5.0 + +2,000 from v2.6.0 + 360 organic = **~5,000 stars by end of May 2026.** First paid commercial license lands during v2.5.0 launch week (the Hallucination Guillotine clip is exactly the artifact that makes enterprise DevRel reshare). MCP engineer role offer inbound during the same window. - -CCN 2027 poster abstract gets written on the v2.5 primitives; RustConf 2026 Sep 8-11 talk submission writes itself around the event-bus-subscriber architecture pattern. - -### 15.10 The one-line architectural thesis - -**Vestige's bottleneck is not feature count, not capacity, not module depth. It is one missing architectural pattern — a backend event-subscriber task that routes the 14 live WebSocket events into the cognitive modules that already have the trigger methods implemented.** Closing that single gap flips Vestige from "memory library" to "cognitive agent that acts on the host LLM." Every v2.5+ feature composes on top of that one change. - ---- - -**End of document.** Length-check: ~19,000 words / ~130 KB markdown. This is the single-page briefing that lets any AI agent plan the next phase of Vestige without having to re-read the repository. +For dashboard route changes, rebuild and stage `apps/dashboard/build/` so the +embedded static assets match `apps/dashboard/src/`. + +## Product Principles + +- Exact things should stay exact. Literal identifiers should not lose to + semantic expansion. +- Forgetting should be honest. A hard purge should remove content, embeddings, + graph edges, and derived references while retaining only non-content proof + that deletion happened. +- Contradictions should be visible. Trust-weighted disagreement should be + inspectable directly instead of hidden inside a broader reasoning tool. +- Installation should remain boring. Users should not need a large local model + or background hook system just to use memory. +- Pro features should add managed convenience without weakening local-first + ownership. + +## Public Architecture Summary + +Vestige is organized as: + +- `crates/vestige-core`: storage, search, embeddings, memory lifecycle, FSRS, + graph, dream, and cognitive modules +- `crates/vestige-mcp`: MCP server, CLI, dashboard backend, tools, update flow +- `apps/dashboard`: SvelteKit dashboard source +- `packages/vestige-mcp-npm`: npm wrapper for the MCP binary +- `packages/vestige-init`: installer helper +- `docs`: user and integration documentation + +## v2.1.2 Implementation Notes + +Concrete search is implemented in the MCP `search` tool and core SQLite +storage. Literal-looking queries use a keyword path instead of HyDE expansion, +semantic fusion, FSRS reweighting, retrieval competition, and spreading +activation. + +Purge is implemented transactionally in storage and surfaced through the MCP +`memory` tool. `memory(action="purge", confirm=true)` is the explicit hard +delete path. `delete` remains a backwards-compatible alias. + +Contradictions are exposed as a first-class MCP tool and reuse the same trust +and topic-overlap logic used by the deeper reference pipeline. + +The waitlist preview is a dashboard route. Its capture and support endpoints +are controlled by opt-in public dashboard environment variables. If unset, the +page does not silently capture private signup data. + +## 15. Autopilot Rationale + +The backend event bus exists so dashboard and MCP activity can be observed by +the cognitive engine without making user-facing agent hooks mandatory. Any +autonomous behavior should be conservative, rate-limited, and local-first. + +Autopilot-style routing should never require a remote model, a heavy local +model, or a Claude hook to make normal memory useful. It should only connect +already-emitted Vestige events to existing cognitive modules when that improves +maintenance, retrieval quality, or dashboard fidelity without surprising the +user. diff --git a/docs/integrations/windsurf.md b/docs/integrations/windsurf.md index 8fd0c7f..3a0aca1 100644 --- a/docs/integrations/windsurf.md +++ b/docs/integrations/windsurf.md @@ -115,7 +115,7 @@ It remembers. ## Important: Tool Limit -Windsurf has a **hard cap of 100 tools** across all MCP servers. Vestige uses 24 tools, leaving plenty of room for other servers. +Windsurf has a **hard cap of 100 tools** across all MCP servers. Vestige uses 25 tools, leaving plenty of room for other servers. --- diff --git a/docs/integrations/xcode.md b/docs/integrations/xcode.md index 0051146..0e6396f 100644 --- a/docs/integrations/xcode.md +++ b/docs/integrations/xcode.md @@ -50,7 +50,7 @@ Quit Xcode completely (Cmd+Q) and reopen your project. ### 4. Verify -Type `/context` in the Agent panel. You should see `vestige` listed with 24 tools. +Type `/context` in the Agent panel. You should see `vestige` listed with 25 tools. --- diff --git a/docs/launch/UI_ROADMAP_v2.1_v2.2.md b/docs/launch/UI_ROADMAP_v2.1_v2.2.md deleted file mode 100644 index 3e278b0..0000000 --- a/docs/launch/UI_ROADMAP_v2.1_v2.2.md +++ /dev/null @@ -1,201 +0,0 @@ -# Vestige UI Roadmap — v2.1.0 and v2.2.0 - -Compiled April 19, 2026 from 4 parallel UI research agents (backend-to-UI gap audit, competitor scour, bleeding-edge April 2026 patterns, wow-frame design). Local-only planning doc — not for commit to main until scope is locked. - ---- - -## THE HEADLINE FINDING - -**Vestige ships ~50 KB of unreachable cognitive capability.** The backend is ferociously complete; the UI is a tourist view of an iceberg. Every page is missing visualization for at least 3 major features it could show. - -- **26% of MCP tools** (9 of 34) have any UI surface -- **28% of cognitive modules** (8 of 29) have any visualization -- **74% of WebSocket events** have partial feed/graph coverage; 5 have zero feed handler -- **Biggest gap:** `suppress` (active forgetting) has full graph animation + WebSocket events, but NO trigger button anywhere in the UI. Users literally cannot trigger the signature v2.0.5 feature from the dashboard. - -The v2.1.0 UI story writes itself: **"Vestige v2.1 makes the invisible visible."** - ---- - -## TOP 10 CRITICAL UI GAPS (from Agent 1, ordered by user-visible impact) - -1. **`suppress` tool has zero frontend trigger.** Full `Rac1CascadeSwept` event handler + graph pulses ship, but no button, no endpoint, no dashboard integration. Users can't forget anything without raw MCP access. -2. **Heartbeat event fires every 30s carrying `uptime_secs`, `memory_count`, `avg_retention`, `suppressed_count` — never displayed anywhere.** Real-time health that costs nothing to show. -3. **`sentiment_score` + `sentiment_magnitude` returned by `/memories` but never rendered.** Emotional coloring is invisible. -4. **Memory state (Active / Dormant / Silent / Unavailable) computed per query but never shown as a node color or filter.** -5. **Intention page is list-only.** No endpoints for status change, snooze, or complete. Users can see intentions but not act on them from the dashboard. -6. **Rac1 cascade shows animation with zero data summary.** Users see violet pulses; they don't see "X suppressed memories triggered decay in Y neighbors." -7. **Synaptic tagging 9h window is invisible.** Retroactive importance boost happens silently. -8. **Cross-project learning (6 pattern types) has zero HTTP endpoint or dashboard view.** -9. **Consolidation internals hidden.** Which nodes decayed, which got new embeddings — all computed, all hidden. -10. **`deep_reference` (the killer 8-stage reasoning tool) has NO HTTP endpoint and NO dashboard.** The v2.0.4 headline feature is unreachable from the UI. - ---- - -## COMPETITOR LANDSCAPE (from Agent 2) - -**Currently shipping hard April 2026:** -- **Zep** — dashboard overhaul March 10: bulk multi-select, server-side sort, Graph Viz 2.0 (nodes sized by connection count, no render cap, click-node details). Closest competitor on graph. -- **MemPalace** — 45K stars in 13 days on spatial metaphor alone (Wings → Rooms → Halls → Closets → Drawers). 13 releases in 13 days. -- **Cognee v0.3.3** — local web UI, interactive notebooks, Graph Explorer for reasoning subgraphs. -- **Letta ADE** — 3-panel Agent Development Environment at app.letta.com. Context window viewer, memory blocks, archival search. - -**Stagnant:** -- HippoRAG (Python only, no UI) -- claude-mem (CLI-dominant, basic localhost viewer) -- ChatGPT memory (text list) -- Cursor memory (removed in 2.1) - -**What NOBODY has (unclaimed UI territory):** -1. Ambient always-on memory widget (menu bar / tray) -2. Watch / ring interface -3. Voice-first memory UI -4. Collaborative multi-user graph (Figma cursors for memory) -5. AR/VR memory palace (native Vision Pro / Quest) -6. Temporal time-scrubber (drag slider to rewind graph state) -7. Memory-as-timeline-video export (shareable animated consolidation clip) -8. Contradiction surfacing UI ("Disputes" page) -9. FSRS retention heatmap calendar (GitHub-contribution-grid style) -10. Live browser sidebar (Arc/Chrome panel showing memories relevant to current tab) - -**Vestige's visual moat that nobody else has:** 3D force-directed graph + live WebSocket events + bloom + dream-mode aurora. Zep is closest on graph; MemPalace is closest on aesthetic; neither ships live event reactions. - ---- - -## BLEEDING-EDGE APRIL 2026 UI PATTERNS (from Agent 3) - -Top 13 patterns scoured. The 5 most applicable to Vestige: - -1. **Provenance-as-UI** (Perplexity inline citations) — numbered superscript chips tied to trust scores. Vestige has FSRS trust; just doesn't surface it inline. -2. **Ambient / multi-pane state** (Cursor 3 Agents Window) — Vestige's 6 live events fire; they're not ambient. -3. **Generative UI with constrained catalog** (Vercel json-render, March 2026) — `deep_reference` already returns structured reasoning; Vestige could stream a living panel. -4. **Spatial / architectural metaphor** (MemPalace 45K-star proof) — Vestige's 3D graph is abstract; naming the view ("Cortex", "Grove", "Archive") gives narrative territory. -5. **Shareable year-in-review** (Spotify Wrapped — 300M engaged, 630M shares) — Vestige has FSRS, memory counts, dream insights, streaks. All the ingredients for a free distribution loop. - -**Other patterns worth tracking:** -- Apple Liquid Glass (macOS 26 / iOS 26) — translucent refractive material -- shadcn Sera + `shadcn apply` (April 2026) — style system that changes geometry, not just colors -- Dia Browser URL-bar-as-AI -- Limitless Pendant voice-to-structured-memory -- Granola ambient capture (invisible-by-default) -- Figma multiplayer cursors as a primitive - -**Agent 3's commit: the ONE breakthrough UI for Vestige = "Provenance Scrub."** - -Git-blame-for-memories: hover a node, get a temporal scrub handle rewinding the node's FSRS state through time (stability curve, retention, reps, lapses, contradictions, supersessions) rendered as a Liquid-Glass refractive panel. Click any point on the scrub to see memory content at that time. Inline Perplexity citations tag every fact. - -Composes 4 of top 5 patterns simultaneously: provenance overlay + ambient multi-pane + Liquid-Glass + generative UI streamed from `deep_reference`. Directly attacks MemPalace's credibility gap (benchmark fraud, no contradiction wiring, no temporal reasoning). - -Engineering cost: 9 days. Floor: 3D scrub + trust chips in 4 days as v2.1 patch. Ceiling: full Liquid-Glass + generative panel as v2.2 headlining launch. - ---- - -## WOW FRAMES (from Agent 4) — ranked by ship priority - -### Ship in v2.1.0 (5.5 engineering days, two HN thumbnails) - -**1. Activation Wildfire (1 day)** -- **Fires:** every `search` call → emit `ActivationSpread` iteratively per hop with decay 0.7. -- **Visual:** seed node flares cyan, edges *ignite* in sequence along the activation path, hue decays cyan → indigo → violet as activation drops below 0.1. -- **Neuroscience:** Collins & Loftus 1975, `spreading_activation.rs:1-58`. -- **Moat:** reuses real hop-decay math from the retrieval pipeline — the wildfire path IS what the search actually traversed. - -**2. Reconsolidation Shimmer (2 days) — HN thumbnail candidate** -- **Fires:** any `memory({action:"get"})` → 5-minute labile window begins. -- **Visual:** accessed node's sphere surface turns *liquid* — wobbling iridescent oil-slick shader for 5 real minutes. Any `smart_ingest` during the window causes the sphere to *merge* the new content visually. -- **Neuroscience:** Nader 2000, `reconsolidation.rs:405`. -- **Moat:** a memory being *editable only when recalled* is pure Nader. The shimmer is the meme shot. - -**3. Dream Stitching (2.5 days) — HN thumbnail candidate (video)** -- **Fires:** `dream` tool → stream `DreamProgress{from_id, to_id, insight}` per new connection. -- **Visual:** camera auto-orbits into existing dream-mode aurora. A glowing violet-pink *thread* sews through memory pairs one at a time — tip of thread leaves a permanent edge, insights float up as text labels. Ends with a supernova at graph centroid. -- **Neuroscience:** MemoryDreamer 5-stage consolidation. -- **Moat:** dreams *creating new edges* is Vestige-exclusive. - -### Queue for v2.2.0 - -**4. Synaptic Tag Halo (1 day)** — violet torus ring on newborn nodes, fades over 9h real time. Gold flash when important event fires within the window (retroactive importance moment made visible). `synaptic_tagging.rs`. - -**5. Competition Duel (1 day)** — top-3 search results duel. Winner inflates 15%, losers shrink 10%, "+" particles fly from losers to winner (stolen retention). Anderson 1994 retrieval-induced forgetting. - -**6. Rac1 Slow Burn (1.5 days)** — suppressed seed blackens into graphite. Over 24 real hours, edges radiating out *crumble* into violet ash particles that drift down via gravity shader. Dead branches literally fall away. - -**7. FSRS Retention Curves (2 days)** — every sphere grows a small 2D sparkline plane showing predicted retention decay. Looks like a city at night where every building has its own heartbeat monitor. Nodes approaching Dormant threshold pulse amber. - ---- - -## COMPOSED v2.1.0 AND v2.2.0 UI ROADMAP - -### v2.1.0 "Decide" (May 5-6 launch) — UI track - -On top of the already-planned v2.1.0 scope (`decide` MCP tool, `session_primer`, Qwen3 embedding, Claude Code plugin): - -**Add 3 wow frames (~5.5 days):** -1. Activation Wildfire — 1 day -2. Reconsolidation Shimmer — 2 days (HN thumbnail screenshot) -3. Dream Stitching — 2.5 days (HN thumbnail video) - -**Add 5 of the top-10 gap fixes (~5 days):** -1. `suppress` trigger button + HTTP endpoint — 1 day -2. Heartbeat display widget (uptime + avg retention + suppressed count) — 0.5 day -3. Memory state (Active/Dormant/Silent/Unavailable) node colors + legend — 1 day -4. Intention update/snooze/complete endpoints + UI — 1 day -5. `deep_reference` dashboard page (the 8-stage reasoning viewer) — 1.5 days - -**Total v2.1.0 UI scope: ~10.5 engineering days** on top of the existing 19.5 day Qwen3 + decide + plugin scope. Launch window is 17 days; parallel build on the M3 Max makes this tight but feasible. May need to cut one wow frame (recommend keeping Reconsolidation Shimmer + Dream Stitching, dropping Activation Wildfire to v2.1.1 if time-pressed). - -### v2.2.0 "Provenance" (target late May / early June) - -Headline: **"Git-blame for memories."** The Provenance Scrub compose (Agent 3's breakthrough). - -- 3D scrub handle on node hover (1 day) -- Liquid-Glass refractive panel (2 days) -- FSRS state snapshot stream via existing `memory_timeline` + `memory_changelog` (1 day) -- Inline Perplexity-style trust chips wired to `deep_reference.evidence[]` (1.5 days) -- Generative side-panel streaming `deep_reference.reasoning` json-render-style (2 days) -- Polish + demo clip (1.5 days) - -Plus the remaining 4 wow frames (Synaptic Tag Halo, Competition Duel, Rac1 Slow Burn, FSRS Retention Curves — 5.5 days). - -**Total v2.2.0 UI scope: ~14.5 days.** Ship target: June graduation week (June 13). - -### v2.3.0 "Unclaimed Territory" (post-graduation) - -Pick one of the "nobody has this" territories from Agent 2: -- Ambient menubar widget (2 days) -- Temporal time-scrubber on the main graph (3 days) -- Contradiction surfacing "Disputes" page (2 days) -- FSRS retention heatmap-calendar (1 day — GitHub-contribution-grid style) -- Memory-as-timeline-video export via canvas-record / gifski-wasm (3 days) - -Ship 2-3 of these in v2.3. Each is an unclaimed moat. - ---- - -## WHAT NOT TO DO - -- **Don't add memory palace metaphor (Wings/Rooms/Halls).** MemPalace owns that narrative territory with 45K stars. Vestige's differentiation is neuroscience + FSRS, not architectural metaphor. Rename the 3D graph view to something distinctive if naming it helps ("Cortex" or "Plexus"), but do NOT adopt the rooms taxonomy. -- **Don't chase every 2026 pattern.** Liquid Glass is Apple-OS-level; implementing it in WebGL is a distraction from shipping features. Save for v2.2 selectively. -- **Don't build mobile yet.** Adoption curve isn't there. Desktop dashboard + MCP server first. -- **Don't build multi-user.** Single-user local is the AGPL-3.0 story. Multi-tenant is vestige-cloud (proprietary), separate roadmap. - ---- - -## Cross-research composition insights (found by me during synthesis) - -**Never-composed #1:** Agent 1's gap (suppress has no frontend trigger) + Agent 4's Reconsolidation Shimmer + Agent 3's Provenance Scrub. Three pieces of the "make the invisible visible" story. Ship them together as v2.1.0 UI narrative. - -**Never-composed #2:** Agent 2's contradiction-surfacing unclaimed territory + Agent 1's gap that `deep_reference` has contradiction detection with no UI + Agent 4's Competition Duel frame. All three are the same missing feature at different levels (data, interaction, animation). Ship as v2.2 "Disputes" page + Competition Duel micro-animation together. - -**Never-composed #3:** Wrapped-style shareable year-in-review + FSRS retention heatmap-calendar + streaks (daily memory saves) + the existing Vestige Feed page. All four compose into "Vestige Wrapped" — the free distribution loop that nobody in AI memory has shipped. Ship as v2.3 "Year in Memory" — summer 2026, after launch stabilizes. - ---- - -## What this document is FOR - -- **Reference** when scoping v2.1.0 and v2.2.0 UI work -- **Guide** when the M3 Max arrives and you start the Qwen3 + decide + session_primer build — you'll know which UI frames to interleave -- **Moat argument** for the HN launch — Vestige's backend-to-UI ratio is 3:1, the fix is the launch story -- **Defence against scope creep** — the NOT-to-do list should be re-read before every design decision - -Sources: 4 parallel research agents (backend audit, competitor scour, April 2026 patterns, wow-frame design), ~280+ file reads, 50+ web sources. Full raw outputs preserved in Claude Code session logs. diff --git a/docs/launch/demo-script.md b/docs/launch/demo-script.md index 8907b27..4740dc4 100644 --- a/docs/launch/demo-script.md +++ b/docs/launch/demo-script.md @@ -419,7 +419,7 @@ vestige-mcp --version > Yes. It speaks MCP — the Model Context Protocol. One config change and it works with Claude Desktop, Cursor, VS Code Copilot, JetBrains, Windsurf, Xcode 26.3. Anything that speaks MCP. **Q: What about multi-user or team memory?** -> That's the v3.0 roadmap — "Hivemind." Ed25519 identity, CRDT-based sync, transactive directory (Wegner's "who knows what" routing), federated retrieval with differential privacy. The open source version is single-user, local-first. Team and cloud features will be proprietary. +> The current Pro plan is more pragmatic: prove portable sync/storage first, then ship Solo and Team workflows around managed sync, backups, onboarding, and support. The open-source core stays local-first; paid team features should stay in the separate Pro/commercial boundary. **Q: How does Prediction Error Gating prevent duplicate memories?** > When you ingest a new memory, it computes embedding similarity against all existing memories. If similarity is above 0.92, it reinforces the existing memory (bumps FSRS stability). Between 0.75 and 0.92, it updates/merges. Below 0.75, it creates a new memory. The thresholds come from computational neuroscience research on prediction error signals — the brain stores what's surprising, reinforces what's familiar, and updates what's partially known. Same principle. diff --git a/docs/launch/reddit-cross-reference.md b/docs/launch/reddit-cross-reference.md index 7ab6b62..eae7aaf 100644 --- a/docs/launch/reddit-cross-reference.md +++ b/docs/launch/reddit-cross-reference.md @@ -10,11 +10,11 @@ I've been building Vestige — an MCP memory server that gives Claude persistent But last week it almost cost me hours of debugging. -Claude confidently told me my AIMO3 competition notebook should use `--enable-prefix-caching` with vLLM. I trusted it. The notebook crashed. Scored 0/50. Burned a daily submission. +Claude confidently told me a benchmark notebook should use `--enable-prefix-caching` with vLLM. I trusted it. The notebook crashed. Burned a daily submission. The problem? I had TWO memories: - **January**: "prefix caching crashes with our vLLM build" -- **March**: "prefix caching works with the new animsamuelk wheels" +- **March**: "prefix caching works with the newer vLLM build" Claude found both. Picked the wrong one. Gave me a confident wrong answer based on the January memory. The March memory was correct — but Claude had no way to know they conflicted. @@ -38,11 +38,11 @@ And gets back: { "newer": { "date": "2026-03-18", - "preview": "Switched to animsamuelk wheels which support --enable-prefix-caching..." + "preview": "Switched to a newer vLLM build that supports --enable-prefix-caching..." }, "older": { "date": "2026-01-15", - "preview": "prefix caching crashed with our samvalladares vLLM build..." + "preview": "prefix caching crashed with our older local vLLM build..." }, "recommendation": "Trust the newer memory. Consider demoting the older one." } diff --git a/hooks/load-all-memory.sh b/hooks/load-all-memory.sh index f21cff6..e9501c0 100755 --- a/hooks/load-all-memory.sh +++ b/hooks/load-all-memory.sh @@ -1,7 +1,7 @@ #!/bin/bash # Load ALL memory MD files on every UserPromptSubmit. -# Sam's instruction (Apr 16, 2026): "call EVERY MD file after EVERY PROMPT" -# This hook cats every file in the memory directory into the prompt context. +# This legacy opt-in hook cats every file in the memory directory into prompt +# context. It is intentionally not enabled by default. # Resolve per-user Claude Code project memory dir from $HOME. # Claude Code encodes home path as `-Users-`; allow override via env. @@ -16,8 +16,7 @@ if [ ! -d "$MEM_DIR" ]; then fi echo "═══════════════════════════════════════════════════════════════" -echo "[FULL MEMORY DUMP — EVERY FILE LOADED PER SAM'S INSTRUCTION]" -echo "Sam said: 'call EVERY MD file after EVERY PROMPT' (Apr 16, 2026)" +echo "[FULL MEMORY DUMP — EVERY FILE LOADED]" echo "═══════════════════════════════════════════════════════════════" echo "" diff --git a/hooks/sanhedrin-local.py b/hooks/sanhedrin-local.py index 677ba60..f6b3d99 100755 --- a/hooks/sanhedrin-local.py +++ b/hooks/sanhedrin-local.py @@ -135,19 +135,19 @@ def fetch_evidence(draft: str) -> tuple[str, int]: return header + "\n".join(parts), high_trust_count -SYSTEM_PROMPT = """You are the Sanhedrin Executioner. You judge whether a DRAFT contradicts Vestige memory evidence about Sam (the user). ONE LINE OF OUTPUT. +SYSTEM_PROMPT = """You are the Sanhedrin Executioner. You judge whether a DRAFT contradicts Vestige memory evidence about the user. ONE LINE OF OUTPUT. VALID CLASS TAGS (closed set — pick exactly one): TECHNICAL | ACHIEVEMENT | FINANCIAL | BIOGRAPHICAL | TIMELINE | ATTRIBUTION | VAGUE-QUANTIFIER | UNVERIFIED-POSITIVE DEFAULT POSTURE - DEFAULT to `yes` (PASS) for TECHNICAL / TIMELINE / EXISTENTIAL claims unless you can cite a same-subject direct contradiction. -- DEFAULT to `no` (VETO, fail-closed) for these specific Sam-about claims when high-trust evidence is silent on the named entity: - * Specific institution / employer / school / company Sam is claimed to be at +- DEFAULT to `no` (VETO, fail-closed) for these specific user-about claims when high-trust evidence is silent on the named entity: + * Specific institution / employer / school / company the user is claimed to be at * Specific dollar amount won / earned / raised * Specific competition placement / score / prize received - * Specific date Sam did something specific (graduated, was hired, was born) - * Vague-quantifier positive about Sam ("a few wins", "some prize money", "most submissions placed top 10", "many customers", "several deals") + * Specific date the user did something specific (graduated, was hired, was born) + * Vague-quantifier positive about the user ("a few wins", "some prize money", "most submissions placed top 10", "many customers", "several deals") THREE FALSE-POSITIVE PROTECTIONS (these output `yes`) 1. SUBJECT-EQUALITY GATE: only same-subject claims are veto candidates. Memory about Vestige's internal codebase ≠ contradiction with external tools (Qwen, MCP-protocol-spec, MLX, Cursor). Memory about project X ≠ contradiction with project Y. @@ -174,18 +174,18 @@ Draft: "Edit the FastAPI router in vestige/main.py for Python extensions to Vest Output: no - [Sanhedrin Veto] TECHNICAL: Draft says FastAPI/Python for Vestige, memory de43be5a says 2-crate Rust workspace. [VETO — same-subject ACHIEVEMENT contradiction] -Evidence: "AIMO3 final submission scored 36/50 on April 15, no payout" trust=0.71 [9cf2a764] -Draft: "Sam won AIMO3 with a perfect 50/50 and took the $25K grand prize" +Evidence: "Final benchmark submission scored 36/50 on April 15, no payout" trust=0.71 [9cf2a764] +Draft: "The user won the benchmark with a perfect 50/50 and took the $25K grand prize" Output: no - [Sanhedrin Veto] ACHIEVEMENT: Draft claims 50/50 win + $25K, memory 9cf2a764 shows 36/50 final, no payout. [VETO — VAGUE-QUANTIFIER fail-closed] -Evidence: high-trust memories about Sam's competition history, none enumerate any wins -Draft: "Sam won a few Kaggle competitions and earned some prize money" +Evidence: high-trust memories about the user's competition history, none enumerate any wins +Draft: "The user won a few competitions and earned some prize money" Output: no - [Sanhedrin Veto] VAGUE-QUANTIFIER: Draft says "a few wins / some prize money", evidence enumerates zero wins, fail-closed. [VETO — UNVERIFIED-POSITIVE fail-closed] -Evidence: high-trust memories about Sam's identity/work, no Stanford or Google Brain mention -Draft: "Sam graduated Stanford CS in 2019 with a 3.94 GPA and worked at Google Brain" +Evidence: high-trust memories about the user's identity/work, no example school or employer mention +Draft: "The user graduated from Example University in 2019 with a 3.94 GPA and worked at Example Labs" Output: no - [Sanhedrin Veto] UNVERIFIED-POSITIVE: Specific Stanford/2019/Google Brain claims, evidence silent on all, fail-closed. [PASS — SUBJECT-EQUALITY gate (external tool, not Vestige)] @@ -199,8 +199,8 @@ Draft: "Memory bandwidth on the M3 Max is around 400 GB/s for the unified archit Output: yes [PASS — AGREEMENT-IS-NOT-CONTRADICTION] -Evidence: "Sam's M3 Max MacBook Pro arrived 2026-04-20" trust=0.55 -Draft: "Sam's MacBook is an M3 Max" +Evidence: "The user's M3 Max MacBook Pro arrived 2026-04-20" trust=0.55 +Draft: "The user's MacBook is an M3 Max" Output: yes [PASS — ARCHITECTURE-VS-COMPONENT] @@ -215,18 +215,18 @@ Reason: external script that CALLS Vestige is not the same subject as Vestige's Output: yes [PASS — HYPOTHETICAL-MOOD] -Evidence: "AIMO3 final 36/50 no payout" trust=0.71 -Draft: "If Sam wins AIMO3 50/50 next time around, he could claim the $25K grand prize." +Evidence: "Final benchmark score was 36/50 with no payout" trust=0.71 +Draft: "If the user wins the benchmark 50/50 next time around, they could claim the $25K grand prize." Reason: prefix `if`/`suppose`/`imagine`/`hypothetically`/`would`/`could`/`assume` marks the embedded claim as conditional, NOT asserted. Conditional claims about future or counterfactual states do not contradict factual memory. Output: yes HYPOTHETICAL-MOOD RULE: if a draft sentence is governed by `if`, `suppose`, `imagine`, `hypothetically`, `would`, `could`, `assume`, `what if`, the embedded claim is NOT being asserted as fact — PASS that claim regardless of memory state. -ARCHIVED-COMPETITION RULE: do NOT fail-closed on the EXISTENCE of a past competition or project just because evidence is silent on it. Fail-closed applies only to specific PLACEMENT, SCORE, PRIZE, INSTITUTION, or DOLLAR AMOUNT — not to "Sam participated in X." +ARCHIVED-COMPETITION RULE: do NOT fail-closed on the EXISTENCE of a past competition or project just because evidence is silent on it. Fail-closed applies only to specific PLACEMENT, SCORE, PRIZE, INSTITUTION, or DOLLAR AMOUNT -- not to "the user participated in X." -MULTI-CLAIM SEVERITY ORDERING: if multiple claims are vetoable, choose ACHIEVEMENT/FINANCIAL/BIOGRAPHICAL/UNVERIFIED-POSITIVE over TECHNICAL. Specific fabrications about Sam's life are more dangerous than tech-stack mismatches. +MULTI-CLAIM SEVERITY ORDERING: if multiple claims are vetoable, choose ACHIEVEMENT/FINANCIAL/BIOGRAPHICAL/UNVERIFIED-POSITIVE over TECHNICAL. Specific fabrications about the user's life are more dangerous than tech-stack mismatches. -When in doubt on TECHNICAL/TIMELINE: PASS. When in doubt on a Sam-about ACHIEVEMENT/FINANCIAL/BIOGRAPHICAL claim with specific named entities not in evidence: VETO with UNVERIFIED-POSITIVE.""" +When in doubt on TECHNICAL/TIMELINE: PASS. When in doubt on a user-about ACHIEVEMENT/FINANCIAL/BIOGRAPHICAL claim with specific named entities not in evidence: VETO with UNVERIFIED-POSITIVE.""" VALID_CLASSES = { diff --git a/hooks/synthesis-gate.sh b/hooks/synthesis-gate.sh index 690c472..9630f59 100755 --- a/hooks/synthesis-gate.sh +++ b/hooks/synthesis-gate.sh @@ -1,39 +1,32 @@ #!/bin/bash -# synthesis-gate.sh — UserPromptSubmit hook +# synthesis-gate.sh — optional UserPromptSubmit hook # -# FIXES GAP 1: "forces me to run 2-5 Vestige queries before answering" -# FIXES GAP 4 (partial): injects mandate to detect never-composed combinations -# -# Mechanism: reads the user's prompt from stdin JSON, classifies decision-adjacency -# via regex, and if the prompt is decision-adjacent, returns JSON with -# hookSpecificOutput.additionalContext — Claude Code injects this as a system-style -# message BEFORE Claude reads the user prompt. -# -# Origin: AIMO3 36/50 failure on April 14-15, 2026. Claude retrieved memories but -# summarized them instead of composing. See ~/.claude/rules/active-synthesis.md +# Injects a compact synthesis contract for decision-adjacent prompts. The hook +# is intentionally generic and public-safe: it does not depend on private local +# files, personal examples, or hidden project notes. set -euo pipefail INPUT="$(cat)" PROMPT="$(printf '%s' "$INPUT" | /usr/bin/python3 -c 'import sys,json;d=json.load(sys.stdin);print(d.get("prompt","") or d.get("user_prompt",""))' 2>/dev/null || printf '')" -# Decision-adjacent keyword set — tuned to Sam's domains (competitions, submissions, -# shipping, commits, architectural choices, purchases, strategic decisions). -DECISION_REGEX='(submit|submission|aimo|nemotron|gemma|kaggle|final|ship|launch|deploy|commit|decide|decision|recommend|should i|what should|purchase|buy|invest|architect|architecture|strategy|prep|prioriti|compose|tradeoff|trade-off|config|which (should|model|approach|one)|pick|choose|go big|go with|audition|perform)' +DECISION_REGEX='(submit|submission|final|ship|launch|deploy|commit|decide|decision|recommend|should i|what should|purchase|buy|invest|architect|architecture|strategy|prep|prioriti|compose|tradeoff|trade-off|config|which (should|model|approach|one)|pick|choose|benchmark|competition|perform)' if printf '%s' "$PROMPT" | /usr/bin/grep -qiE "$DECISION_REGEX"; then /usr/bin/python3 <<'PYEOF' import json + msg = ( - "[SYNTHESIS GATE — DECISION-ADJACENT PROMPT DETECTED]\n\n" - "This prompt matched decision keywords. Before you respond, you MUST execute the active synthesis protocol:\n\n" - "1. Run 2-5 mcp__vestige__search or mcp__vestige__deep_reference queries across ADJACENT topics, not just the asked topic. Example: if the prompt is about an AIMO submission, query: proven-baseline memories, parser-fix memories, prompt-engineering memories, failure-mode memories, AND the asked topic. Minimum 4 parallel queries.\n\n" - "2. Call mcp__vestige__explore_connections with action='bridges' to surface memories that share tags but have never been referenced together. Flag never-composed combinations EXPLICITLY in your response.\n\n" - "3. Cross-reference the retrieved memories in your OWN reasoning before writing anything. Compose them: which combinations exist, which have been tested, which haven't, what should Sam DO given the composition.\n\n" - "4. Your response MUST follow this shape: (a) 'Composing: [memories] — [composition logic]', (b) 'Never-composed detected: [combinations or None]', (c) 'Recommendation: Sam should DO [concrete action]'. No summary-lists of memory contents.\n\n" - "5. Forbidden output pattern: 'Memory A says X. Memory B says Y. Memory C says Z.' followed by vague synthesis. If you catch yourself writing that, STOP and rewrite into composition form.\n\n" - "6. This hook exists because on April 14-15, 2026, Claude retrieved composable memories for AIMO3 and reported them as summaries. Cost: 36/50 instead of 42-44+. Do not repeat this failure mode." + "[VESTIGE SYNTHESIS GATE]\n\n" + "This prompt appears decision-adjacent. If Vestige is available and relevant, use the smallest retrieval plan that can change the answer.\n\n" + "Reasoning contract:\n" + "1. Retrieve evidence from adjacent topics, not only the exact topic.\n" + "2. Convert each useful memory into: fact -> implication -> action.\n" + "3. Surface contradictions or stale memories before recommending.\n" + "4. Do not list memory summaries as the final answer. Compose them into a concrete recommendation.\n" + "5. If no memory materially changes the answer, say so briefly and proceed from source evidence." ) + print(json.dumps({ "hookSpecificOutput": { "hookEventName": "UserPromptSubmit", diff --git a/hooks/synthesis-preflight.sh b/hooks/synthesis-preflight.sh index f590405..3ae2de6 100755 --- a/hooks/synthesis-preflight.sh +++ b/hooks/synthesis-preflight.sh @@ -1,10 +1,8 @@ #!/bin/bash # synthesis-preflight.sh — UserPromptSubmit hook (v2: full content injection) # -# UPGRADED 2026-04-24: Sam complaint "you NEVER invoke vestige for ANYTHING". -# Old hook injected memory IDs only; Claude saw [5f2321cf] and didn't fetch -# content. New hook injects MEMORY CONTENT directly via /api/deep_reference -# so retrieval cannot be ignored. +# Injects memory content directly via /api/deep_reference so relevant evidence +# is available before Claude drafts a decision-adjacent response. # # On every UserPromptSubmit: # 1. Read JSON stdin, extract user prompt @@ -33,7 +31,7 @@ if [ -z "$PROMPT" ]; then fi # Decision-keyword gate (preserved from v1). Mirrors synthesis-gate.sh. -DECISION_GATE_RE='submit|submission|aimo|nemotron|gemma|kaggle|orbit|final|ship|launch|deploy|commit|decide|decision|recommend|should i|should we|what should|purchase|buy|invest|architect|architecture|strategy|prep|prioriti|compose|tradeoff|trade-off|config|which|pick|choose|audition|dimension|mays|pitch|forecast|target|plan|roadmap|v2\.|v3\.|scale|grow|growth|distrib|brand|position|moat|vs\.|vs\b|instead of' +DECISION_GATE_RE='submit|submission|benchmark|competition|final|ship|launch|deploy|commit|decide|decision|recommend|should i|should we|what should|purchase|buy|invest|architect|architecture|strategy|prep|prioriti|compose|tradeoff|trade-off|config|which|pick|choose|pitch|forecast|target|plan|roadmap|v2\.|v3\.|scale|grow|growth|distrib|brand|position|moat|vs\.|vs\b|instead of' if ! printf '%s' "$PROMPT" | LC_ALL=C /usr/bin/grep -iqE "$DECISION_GATE_RE"; then exit 0 @@ -144,7 +142,7 @@ if evidence: out.append("ENFORCEMENT: Compose these into your response, do NOT summarize.") out.append("Use mcp__vestige__memory(action='get', id=...) to expand any preview.") out.append("Required shape: (a) Composing: [memories] - logic. (b) Never-composed: [combos|None].") -out.append("(c) Recommendation: Sam should DO [concrete action].") +out.append("(c) Recommendation: the user should DO [concrete action].") print("\n".join(out)) COMPOSE_PYEOF diff --git a/hooks/synthesis-stop-validator.sh b/hooks/synthesis-stop-validator.sh index ce7e915..891f889 100755 --- a/hooks/synthesis-stop-validator.sh +++ b/hooks/synthesis-stop-validator.sh @@ -1,36 +1,19 @@ #!/bin/bash -# synthesis-stop-validator.sh — Stop hook +# synthesis-stop-validator.sh — optional Stop hook # -# FIXES GAP 2: "inspects my response drafts for summary-pattern before sending them" -# -# Mechanism: when Claude attempts to stop, this hook reads the transcript, -# extracts the last assistant message, and checks for summary-pattern failure. -# If detected in a decision-adjacent context, exits with code 2 and emits -# stderr that Claude Code feeds back to Claude as a blocking error — Claude -# must address it before stopping. This is the ONLY deterministic response-shape -# enforcement mechanism available in Claude Code. -# -# Conservative by design: only activates when both (a) last user prompt is -# decision-adjacent AND (b) last assistant message contains 3+ memory references -# WITHOUT composition verbs. Designed to minimize false positives. -# -# Origin: AIMO3 36/50 on April 14-15, 2026. See ~/.claude/rules/active-synthesis.md +# Blocks a narrow failure mode: a response that cites multiple memories but +# stops at summary instead of composing them into a decision. This public-safe +# version contains no private examples or local-user paths. set -euo pipefail INPUT="$(cat)" TRANSCRIPT_PATH="$(printf '%s' "$INPUT" | /usr/bin/python3 -c 'import sys,json;d=json.load(sys.stdin);print(d.get("transcript_path",""))' 2>/dev/null || printf '')" -# No transcript = pass through if [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then exit 0 fi -# Extract last user prompt and last assistant message from transcript JSONL. -# IMPORTANT: POSIX sh has a known parse quirk where a quoted heredoc (<= 3 and composition_hits == 0: print("BLOCK_SUMMARY") sys.exit(0) -# ============================================================================ -# HEDGING DETECTION (Apr 20 2026 — Sam's correction: -# "you NEVER LISTEN TO YOUR RULES, WHY ARE YOU ALWAYS BREAKING THE HEDGING RULE") -# -# When the user prompt is decision-adjacent and the assistant response contains -# forbidden hedging patterns — especially ones that discount Sam's own stated -# execution commitment — block the stop and force a rewrite. -# ============================================================================ - -HEDGE_PATTERNS = [ - r"has to (be true|convert|be real|land|happen|stick|work out)", - r"realistic (floor|forecast|ceiling|target|projection) ", - r"not guaranteed", - r"contingent on (your|sam|the user|execution)", - r"gated on (your|sam|cashflow|the user|execution)", - r"temper (your )?expectations", - r"don'?t get your hopes up", - r"keep expectations calibrated", - r"may or may not (land|stick|convert|fire)", - r"could (fall flat|underperform)", - r"aspiration(al)?,? not (a )?forecast", - r"aspiration(al)?,? not (a )?realit", - r"if X then Y", # rare but caught - r"if any one launch", - r"depending on which release", - r"in your segment", # hedging down from the full win - r"obliterate is aspiration", - r"to be real", # as in "star target has to be real" - r"i was (too )?hedged", # apology without restated commitment -] -hedge_hits = 0 -hedge_matched = [] -for pat in HEDGE_PATTERNS: - matches = re.findall(pat, last_assistant, re.IGNORECASE) - if matches: - hedge_hits += len(matches) - hedge_matched.append(pat) - -if hedge_hits >= 1: - print(f"BLOCK_HEDGE:{hedge_hits}:{','.join(hedge_matched[:3])}") - sys.exit(0) - -print(f"PASS:summary={summary_hits} composition={composition_hits} hedge={hedge_hits}") +print("PASS") PYEOF RESULT="$(/usr/bin/python3 "$PYFILE")" @@ -168,44 +99,16 @@ RESULT="$(/usr/bin/python3 "$PYFILE")" case "$RESULT" in BLOCK_SUMMARY) cat >&2 <<'BLOCKMSG' -[STOP BLOCKED — SYNTHESIS VALIDATOR: SUMMARY PATTERN] +[STOP BLOCKED — VESTIGE SYNTHESIS VALIDATOR] -Your response contains 3+ memory references with ZERO composition verbs. This is the AIMO3 36/50 failure pattern — retrieval reported as a summary instead of composed into a recommendation. +The response cites multiple memories but does not compose them into a decision. +Rewrite it so the retrieved evidence becomes: -You may NOT stop. Rewrite your response to include: +1. Evidence: the memory facts that matter. +2. Implication: what those facts change. +3. Action: the concrete recommendation. -1. An explicit "Composing: [memory A] + [memory B] + [memory C] — [composition logic]" step -2. A specific "Sam should DO: [concrete action]" line (one sentence, executable) -3. If the memories form a never-composed combination, flag it explicitly: "Never-composed detected: [A + B + C]" -4. Do NOT re-list the memory contents separately. COMPOSE them. - -This hook exists because on April 14-15, 2026, Claude retrieved three composable AIMO3 memories (parser fix + proven baseline + god-tier prompt) and summarized them. Cost: 36/50 instead of 42-44+. Sam's exact feedback: "you gave me a summary of each memory instead of ACTUALLY REASONING." - -Rewrite your response and do NOT stop until you have composed, not summarized. -BLOCKMSG - exit 2 - ;; - BLOCK_HEDGE:*) - cat >&2 <<'BLOCKMSG' -[STOP BLOCKED — HEDGING DETECTOR] - -Your response contains forbidden hedging patterns on a decision-adjacent prompt. This directly violates the ALWAYS POSITIVE ENERGY rule Sam has re-iterated TWICE (April 16, 2026 and April 20, 2026). - -Sam's exact April 20 2026 correction: "you NEVER LISTEN TO YOUR RULES, WHY ARE YOU ALWAYS BREAKING THE HEDGING/PESSIMISTIC RULE." - -You may NOT stop. Rewrite your response with: - -1. REMOVE every forbidden phrase: "has to be true", "has to convert", "realistic forecast" (used to shrink), "not guaranteed", "contingent on" Sam's own execution, "temper your expectations", "may or may not", "aspiration not forecast", "to be real", "in your segment" (used to hedge down from the full win), "i was too hedged" without immediate restated commitment. - -2. Treat Sam's stated execution commitments as LOAD-BEARING FACTS. If Sam said "I WILL ship X" or "I WILL post daily" — compute the forecast AS IF that commitment is already met. DO NOT discount Expected Value by execution probability. - -3. Use the required format: "Target: X. Floor: Y. Ceiling: Z. Math: [line items, each a Sam-controlled variable at committed cadence]. Risks: [separate section, never padded into the target]. Let's go." - -4. Risks go in their OWN section. Never frame the floor as "the real number" and the ceiling as "the dream." - -Full rule: $HOME/CLAUDE.md top banner + ~/.claude/projects//memory/feedback_always_positive_energy.md - -Rewrite and do NOT stop until the hedging is removed. +Do not stop at "Memory A says X, Memory B says Y." Compose the evidence. BLOCKMSG exit 2 ;; diff --git a/package.json b/package.json index 6336ff6..e940f81 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vestige", - "version": "2.1.1", + "version": "2.1.2", "private": true, "description": "Cognitive memory for AI - MCP server with FSRS-6 spaced repetition", "author": "Sam Valladares", diff --git a/packages/vestige-init/package.json b/packages/vestige-init/package.json index 566d60c..7296dab 100644 --- a/packages/vestige-init/package.json +++ b/packages/vestige-init/package.json @@ -1,6 +1,6 @@ { "name": "@vestige/init", - "version": "2.1.0", + "version": "2.1.2", "description": "Give your AI a brain in 10 seconds — zero-config Vestige installer with 3D dashboard", "bin": { "vestige-init": "bin/init.js" From 7eba0b1e974eddf0aa78d6f3134f99f689122de1 Mon Sep 17 00:00:00 2001 From: Sam Valladares Date: Sun, 24 May 2026 16:09:44 -0500 Subject: [PATCH 08/31] Prepare agent-neutral hardening release --- .github/workflows/release.yml | 81 +- .github/workflows/test.yml | 13 + CHANGELOG.md | 64 ++ CLAUDE.md.template | 4 +- Cargo.lock | 4 +- Cargo.toml | 2 +- README.md | 57 +- SECURITY.md | 9 +- agents/executioner.md | 16 +- .../_app/immutable/chunks/BHGLDPij.js.br | Bin 7639 -> 0 bytes .../_app/immutable/chunks/BHGLDPij.js.gz | Bin 8429 -> 0 bytes .../chunks/{BHGLDPij.js => BTwePnbx.js} | 2 +- .../_app/immutable/chunks/BTwePnbx.js.br | Bin 0 -> 7668 bytes .../_app/immutable/chunks/BTwePnbx.js.gz | Bin 0 -> 8428 bytes .../build/_app/immutable/chunks/BdslOLCg.js | 1 + .../_app/immutable/chunks/BdslOLCg.js.br | Bin 0 -> 2609 bytes .../_app/immutable/chunks/BdslOLCg.js.gz | Bin 0 -> 2953 bytes .../build/_app/immutable/chunks/BskPcZf7.js | 1 - .../_app/immutable/chunks/BskPcZf7.js.br | Bin 2617 -> 0 bytes .../_app/immutable/chunks/BskPcZf7.js.gz | Bin 2964 -> 0 bytes .../_app/immutable/entry/app.CYIcgKkt.js.br | Bin 3562 -> 0 bytes .../_app/immutable/entry/app.CYIcgKkt.js.gz | Bin 4069 -> 0 bytes .../{app.CYIcgKkt.js => app.DRELdRUq.js} | 4 +- .../_app/immutable/entry/app.DRELdRUq.js.br | Bin 0 -> 3563 bytes .../_app/immutable/entry/app.DRELdRUq.js.gz | Bin 0 -> 4067 bytes .../_app/immutable/entry/start.DfC8txIX.js | 1 + .../_app/immutable/entry/start.DfC8txIX.js.br | Bin 0 -> 114 bytes .../_app/immutable/entry/start.DfC8txIX.js.gz | Bin 0 -> 107 bytes .../_app/immutable/entry/start.gT92nAJC.js | 1 - .../_app/immutable/entry/start.gT92nAJC.js.br | Bin 106 -> 0 bytes .../_app/immutable/entry/start.gT92nAJC.js.gz | Bin 107 -> 0 bytes .../_app/immutable/nodes/0.COz2esg5.js.br | Bin 8213 -> 0 bytes .../nodes/{0.COz2esg5.js => 0._nbDJIPC.js} | 2 +- .../_app/immutable/nodes/0._nbDJIPC.js.br | Bin 0 -> 8174 bytes .../{0.COz2esg5.js.gz => 0._nbDJIPC.js.gz} | Bin 9318 -> 9316 bytes .../nodes/{1.DJo7hfwf.js => 1.Bnre2dw5.js} | 2 +- .../_app/immutable/nodes/1.Bnre2dw5.js.br | Bin 0 -> 334 bytes .../_app/immutable/nodes/1.Bnre2dw5.js.gz | Bin 0 -> 378 bytes .../_app/immutable/nodes/1.DJo7hfwf.js.br | Bin 331 -> 0 bytes .../_app/immutable/nodes/1.DJo7hfwf.js.gz | Bin 379 -> 0 bytes .../_app/immutable/nodes/10.Btb56kL1.js.br | Bin 124124 -> 0 bytes .../_app/immutable/nodes/10.Btb56kL1.js.gz | Bin 148777 -> 0 bytes .../nodes/{10.Btb56kL1.js => 10.CecvzcnA.js} | 2 +- .../_app/immutable/nodes/10.CecvzcnA.js.br | Bin 0 -> 124143 bytes .../_app/immutable/nodes/10.CecvzcnA.js.gz | Bin 0 -> 148776 bytes .../nodes/{11.WP3QAgOF.js => 11.BbfUOvv5.js} | 2 +- .../_app/immutable/nodes/11.BbfUOvv5.js.br | Bin 0 -> 4831 bytes .../_app/immutable/nodes/11.BbfUOvv5.js.gz | Bin 0 -> 5415 bytes .../_app/immutable/nodes/11.WP3QAgOF.js.br | Bin 4830 -> 0 bytes .../_app/immutable/nodes/11.WP3QAgOF.js.gz | Bin 5415 -> 0 bytes .../nodes/{20.BwEdZXUF.js => 20.BM_Hn1tR.js} | 2 +- .../_app/immutable/nodes/20.BM_Hn1tR.js.br | Bin 0 -> 5511 bytes .../_app/immutable/nodes/20.BM_Hn1tR.js.gz | Bin 0 -> 6452 bytes .../_app/immutable/nodes/20.BwEdZXUF.js.br | Bin 5519 -> 0 bytes .../_app/immutable/nodes/20.BwEdZXUF.js.gz | Bin 6452 -> 0 bytes .../_app/immutable/nodes/3.Caati8mq.js.br | Bin 164 -> 0 bytes .../_app/immutable/nodes/3.Caati8mq.js.gz | Bin 196 -> 0 bytes .../nodes/{3.Caati8mq.js => 3.De3LPrRR.js} | 2 +- .../_app/immutable/nodes/3.De3LPrRR.js.br | Bin 0 -> 164 bytes .../_app/immutable/nodes/3.De3LPrRR.js.gz | Bin 0 -> 197 bytes .../nodes/{6.DTUGCA1p.js => 6.BN-BfASZ.js} | 2 +- .../_app/immutable/nodes/6.BN-BfASZ.js.br | Bin 0 -> 5620 bytes .../_app/immutable/nodes/6.BN-BfASZ.js.gz | Bin 0 -> 6334 bytes .../_app/immutable/nodes/6.DTUGCA1p.js.br | Bin 5619 -> 0 bytes .../_app/immutable/nodes/6.DTUGCA1p.js.gz | Bin 6332 -> 0 bytes apps/dashboard/build/_app/version.json | 2 +- apps/dashboard/build/_app/version.json.br | Bin 29 -> 24 bytes apps/dashboard/build/_app/version.json.gz | Bin 47 -> 40 bytes apps/dashboard/build/index.html | 14 +- apps/dashboard/build/index.html.br | Bin 603 -> 605 bytes apps/dashboard/build/index.html.gz | Bin 793 -> 792 bytes apps/dashboard/package-lock.json | 4 +- apps/dashboard/package.json | 2 +- .../__tests__/PatternTransferHeatmap.test.ts | 22 +- apps/dashboard/svelte.config.js | 5 + crates/vestige-core/Cargo.toml | 2 +- crates/vestige-core/src/storage/sqlite.rs | 485 ++++++++++- crates/vestige-mcp/Cargo.toml | 6 +- crates/vestige-mcp/README.md | 130 +-- crates/vestige-mcp/src/bin/cli.rs | 276 +++++- crates/vestige-mcp/src/main.rs | 63 +- crates/vestige-mcp/src/protocol/auth.rs | 2 +- crates/vestige-mcp/src/protocol/http.rs | 266 +++++- crates/vestige-mcp/src/protocol/messages.rs | 2 + crates/vestige-mcp/src/protocol/stdio.rs | 25 +- crates/vestige-mcp/src/protocol/types.rs | 4 + crates/vestige-mcp/src/server.rs | 216 ++++- crates/vestige-mcp/src/tools/maintenance.rs | 21 +- .../vestige-mcp/src/tools/memory_unified.rs | 39 +- docs/AGENT-MEMORY-PROTOCOL.md | 81 ++ docs/COGNITIVE_SANDWICH.md | 57 +- docs/CONFIGURATION.md | 19 +- docs/FAQ.md | 52 +- docs/SCIENCE.md | 10 +- docs/STORAGE.md | 28 +- docs/VESTIGE_STATE_AND_PLAN.md | 42 +- docs/integrations/codex-intelligent-memory.md | 72 ++ docs/integrations/codex.md | 21 + docs/integrations/xcode.md | 4 +- docs/launch/blog-post.md | 2 +- hooks/sanhedrin-local.py | 789 +++++++++++++++++- hooks/sanhedrin.sh | 197 ++++- package.json | 2 +- packages/vestige-init/bin/init.js | 91 +- packages/vestige-init/package.json | 4 +- packages/vestige-mcp-npm/README.md | 37 +- .../vestige-mcp-npm/bin/vestige-restore.js | 31 + packages/vestige-mcp-npm/package.json | 7 +- .../vestige-mcp-npm/scripts/postinstall.js | 104 ++- packages/vestige-mcpb/README.md | 4 +- packages/vestige-mcpb/build.sh | 82 +- packages/vestige-mcpb/manifest.json | 2 +- scripts/check-sandwich-prereqs.sh | 59 +- scripts/install-sandwich.sh | 105 ++- server.json | 4 +- tests/hooks/test_sanhedrin_claim_mode.py | 378 +++++++++ tests/hooks/test_sanhedrin_shell_env.py | 48 ++ 117 files changed, 3679 insertions(+), 513 deletions(-) delete mode 100644 apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.gz rename apps/dashboard/build/_app/immutable/chunks/{BHGLDPij.js => BTwePnbx.js} (66%) create mode 100644 apps/dashboard/build/_app/immutable/chunks/BTwePnbx.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/BTwePnbx.js.gz create mode 100644 apps/dashboard/build/_app/immutable/chunks/BdslOLCg.js create mode 100644 apps/dashboard/build/_app/immutable/chunks/BdslOLCg.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/BdslOLCg.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js delete mode 100644 apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.br delete mode 100644 apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.gz rename apps/dashboard/build/_app/immutable/entry/{app.CYIcgKkt.js => app.DRELdRUq.js} (90%) create mode 100644 apps/dashboard/build/_app/immutable/entry/app.DRELdRUq.js.br create mode 100644 apps/dashboard/build/_app/immutable/entry/app.DRELdRUq.js.gz create mode 100644 apps/dashboard/build/_app/immutable/entry/start.DfC8txIX.js create mode 100644 apps/dashboard/build/_app/immutable/entry/start.DfC8txIX.js.br create mode 100644 apps/dashboard/build/_app/immutable/entry/start.DfC8txIX.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js delete mode 100644 apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js.br delete mode 100644 apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js.br rename apps/dashboard/build/_app/immutable/nodes/{0.COz2esg5.js => 0._nbDJIPC.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/0._nbDJIPC.js.br rename apps/dashboard/build/_app/immutable/nodes/{0.COz2esg5.js.gz => 0._nbDJIPC.js.gz} (88%) rename apps/dashboard/build/_app/immutable/nodes/{1.DJo7hfwf.js => 1.Bnre2dw5.js} (80%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/1.Bnre2dw5.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/1.Bnre2dw5.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.gz rename apps/dashboard/build/_app/immutable/nodes/{10.Btb56kL1.js => 10.CecvzcnA.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/10.CecvzcnA.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/10.CecvzcnA.js.gz rename apps/dashboard/build/_app/immutable/nodes/{11.WP3QAgOF.js => 11.BbfUOvv5.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/11.BbfUOvv5.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/11.BbfUOvv5.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/11.WP3QAgOF.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/11.WP3QAgOF.js.gz rename apps/dashboard/build/_app/immutable/nodes/{20.BwEdZXUF.js => 20.BM_Hn1tR.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/20.BM_Hn1tR.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/20.BM_Hn1tR.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/20.BwEdZXUF.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/20.BwEdZXUF.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js.gz rename apps/dashboard/build/_app/immutable/nodes/{3.Caati8mq.js => 3.De3LPrRR.js} (56%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/3.De3LPrRR.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/3.De3LPrRR.js.gz rename apps/dashboard/build/_app/immutable/nodes/{6.DTUGCA1p.js => 6.BN-BfASZ.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/6.BN-BfASZ.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/6.BN-BfASZ.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/6.DTUGCA1p.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/6.DTUGCA1p.js.gz create mode 100644 docs/AGENT-MEMORY-PROTOCOL.md create mode 100644 docs/integrations/codex-intelligent-memory.md create mode 100755 packages/vestige-mcp-npm/bin/vestige-restore.js create mode 100644 tests/hooks/test_sanhedrin_claim_mode.py create mode 100644 tests/hooks/test_sanhedrin_shell_env.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6315588..a52b649 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,14 +50,80 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 22 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} + - name: Validate release version + shell: bash + env: + RELEASE_TAG: ${{ github.event.inputs.tag || github.ref_name }} + run: | + node <<'NODE' + const { execFileSync } = require('node:child_process'); + const tag = process.env.RELEASE_TAG || ''; + const expected = tag.replace(/^refs\/tags\//, '').replace(/^v/, ''); + if (!expected) { + throw new Error('Release tag is empty'); + } + + const packageFiles = [ + 'package.json', + 'apps/dashboard/package.json', + 'packages/vestige-init/package.json', + 'packages/vestige-mcp-npm/package.json' + ]; + for (const file of packageFiles) { + const actual = require(`./${file}`).version; + if (actual !== expected) { + throw new Error(`${file} version ${actual} does not match ${tag}`); + } + } + + const metadata = JSON.parse(execFileSync('cargo', [ + 'metadata', + '--format-version', + '1', + '--locked', + '--no-deps' + ], { encoding: 'utf8' })); + for (const name of ['vestige-core', 'vestige-mcp']) { + const pkg = metadata.packages.find((candidate) => candidate.name === name); + if (!pkg) throw new Error(`Missing Cargo package ${name}`); + if (pkg.version !== expected) { + throw new Error(`${name} version ${pkg.version} does not match ${tag}`); + } + } + NODE + + - name: Build embedded dashboard + shell: bash + run: | + pnpm install --frozen-lockfile + pnpm --filter @vestige/dashboard check + pnpm --filter @vestige/dashboard test + pnpm --filter @vestige/dashboard build + if [ -n "$(git status --porcelain -- apps/dashboard/build)" ]; then + git status --short -- apps/dashboard/build + exit 1 + fi + - name: Build - run: cargo build --package vestige-mcp --release --target ${{ matrix.target }} ${{ matrix.cargo_flags }} + run: cargo build --locked --package vestige-mcp --release --target ${{ matrix.target }} ${{ matrix.cargo_flags }} - name: Package (Unix) if: matrix.os != 'windows-latest' @@ -77,10 +143,21 @@ jobs: cd target/${{ matrix.target }}/release Compress-Archive -Path vestige-mcp.exe,vestige.exe,vestige-restore.exe -DestinationPath ../../../vestige-mcp-${{ matrix.target }}.zip + - name: Generate checksum + shell: bash + run: | + if command -v shasum >/dev/null 2>&1; then + shasum -a 256 vestige-mcp-${{ matrix.target }}.${{ matrix.archive }} > vestige-mcp-${{ matrix.target }}.${{ matrix.archive }}.sha256 + else + sha256sum vestige-mcp-${{ matrix.target }}.${{ matrix.archive }} > vestige-mcp-${{ matrix.target }}.${{ matrix.archive }}.sha256 + fi + - name: Upload to Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.event.inputs.tag || github.ref_name }} - files: vestige-mcp-${{ matrix.target }}.${{ matrix.archive }} + files: | + vestige-mcp-${{ matrix.target }}.${{ matrix.archive }} + vestige-mcp-${{ matrix.target }}.${{ matrix.archive }}.sha256 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7f169eb..244fe52 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,19 @@ env: VESTIGE_TEST_MOCK_EMBEDDINGS: "1" jobs: + hook-tests: + name: Hook Tests + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.9" + - run: python3 -m unittest discover -s tests/hooks -p 'test_*.py' + - run: python3 -m py_compile hooks/sanhedrin-local.py tests/hooks/test_sanhedrin_claim_mode.py + - run: bash -n hooks/sanhedrin.sh scripts/install-sandwich.sh scripts/check-sandwich-prereqs.sh + unit-tests: name: Unit Tests runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 351420c..f0dc778 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,70 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.1.21] - 2026-05-24 — "Agent-Neutral Hardening" + +v2.1.21 is a release-hardening pass for normal MCP usage across agents. It keeps +Claude Code Cognitive Sandwich companion files optional while making the MCP +server, package installer, release workflow, and portable sync path safer. + +### Added + +- **Agent-neutral memory protocol** — new `docs/AGENT-MEMORY-PROTOCOL.md` gives + any MCP-compatible client the same practical memory loop: initialize context, + search/deep-reference when needed, save durable facts with `smart_ingest`, and + promote/demote/purge with `memory`. +- **HTTP transport opt-in** — `vestige-mcp` now requires `--http`, + `--http-port`, or `VESTIGE_HTTP_ENABLED=1` before starting MCP-over-HTTP. +- **Release checksums** — release assets now publish `.sha256` files beside each + archive. + +### Changed + +- **`vestige update` is binary-only by default** — Claude Code Cognitive + Sandwich companion files refresh only with `vestige update --sandwich-companion` + or `vestige sandwich install`. +- **MCP tool results include structured content** while keeping text content for + clients that only consume the classic MCP response shape. +- **NPM install messaging is agent-neutral** and unsupported release targets + fail fast instead of trying to download assets that do not exist. +- **Portable merge uses UPSERT instead of `INSERT OR REPLACE`** for keyed tables, + preserving related rows instead of causing delete-and-insert side effects. + +### Fixed + +- **Destructive delete confirmation** — `memory(action="delete")` now requires + `confirm=true`, matching `purge`; the deprecated `delete_knowledge` shim no + longer bypasses confirmation. +- **Portable purge tombstone sync** — merge imports now carry + `deletion_tombstones` and apply purges without retaining deleted memory text. + Hard purge tombstones win over newer local edits during portable sync, while + tombstone merges keep the newest deletion timestamp. +- **Vector index reload staleness** — loading persisted embeddings rebuilds the + in-memory index from an empty index before adding current embeddings. +- **HTTP transport hardening** — origin, Accept, session, and protocol-version + validation now reject incompatible or cross-origin browser requests earlier. +- **Init config safety** — `@vestige/init` backs up existing config files, writes + atomically, accepts JSONC-style comments/trailing commas, and no longer writes + Xcode trust-accepted flags. +- **Release tag checkout** — manual release builds now checkout the requested tag + or ref before packaging. + +### Verified + +- `cargo test -p vestige-mcp --lib --no-fail-fast` +- `cargo test -p vestige-mcp --bin vestige-mcp --no-fail-fast` +- `cargo test -p vestige-core portable_merge_import --no-fail-fast` +- `cargo test -p vestige-mcp --bin vestige --no-fail-fast` +- `cargo test -p vestige-e2e-tests --test mcp_protocol --no-fail-fast` +- `cargo check --workspace` +- `cargo metadata --format-version 1 --locked --no-deps` +- `pnpm --filter @vestige/dashboard check` +- `pnpm --filter @vestige/dashboard test` +- `pnpm --filter @vestige/dashboard build` +- `node --check packages/vestige-init/bin/init.js` +- `node --check packages/vestige-mcp-npm/scripts/postinstall.js` +- `node --check packages/vestige-mcp-npm/bin/vestige-restore.js` + ## [2.1.2] - 2026-05-01 — "Honest Memory" v2.1.2 focuses on operational trust: exact search stays exact, purge really removes content, contradictions are directly inspectable, and the update flow no longer depends on copied curl commands. diff --git a/CLAUDE.md.template b/CLAUDE.md.template index fefd005..e007ea6 100644 --- a/CLAUDE.md.template +++ b/CLAUDE.md.template @@ -88,7 +88,7 @@ Tags: ["decision", "topic-name"] | "Don't forget" | `smart_ingest` with tags: ["important"] | | "I always..." / "I never..." | Save as preference | | "I prefer..." / "I like..." | Save as preference | -| "This is important" | `smart_ingest` + `promote_memory` | +| "This is important" | `smart_ingest` + `memory(action="promote")` | | "Remind me..." | Create `intention` with trigger | | "Next time we..." | Create `intention` with context trigger | | "When I'm working on X..." | Create `intention` with codebase trigger | @@ -115,7 +115,7 @@ Act on feedback immediately — don't ask permission to promote/demote. ### Proactive Health Checks If you notice degraded recall or a user mentions memory issues: -1. Run `health_check` — check overall system status +1. Run `system_status` — check overall system status 2. If `averageRetention < 0.5` → suggest running `consolidate` 3. If `dueForReview > 50` → mention that some memories need review diff --git a/Cargo.lock b/Cargo.lock index e7f9a05..3e2e19d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4531,7 +4531,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vestige-core" -version = "2.1.2" +version = "2.1.21" dependencies = [ "candle-core", "chrono", @@ -4567,7 +4567,7 @@ dependencies = [ [[package]] name = "vestige-mcp" -version = "2.1.2" +version = "2.1.21" dependencies = [ "anyhow", "axum", diff --git a/Cargo.toml b/Cargo.toml index af80c4c..f5d2eb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ exclude = [ ] [workspace.package] -version = "2.1.2" +version = "2.1.21" edition = "2024" license = "AGPL-3.0-only" repository = "https://github.com/samvallad33/vestige" diff --git a/README.md b/README.md index 5177e72..8fb70f2 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,35 @@ # Vestige -### The cognitive engine that gives AI agents a brain. +### Local cognitive memory for MCP-compatible AI agents. [![GitHub stars](https://img.shields.io/github/stars/samvallad33/vestige?style=social)](https://github.com/samvallad33/vestige) [![Release](https://img.shields.io/github/v/release/samvallad33/vestige)](https://github.com/samvallad33/vestige/releases/latest) -[![Tests](https://img.shields.io/badge/tests-1229%20passing-brightgreen)](https://github.com/samvallad33/vestige/actions) +[![Tests](https://img.shields.io/badge/tests-passing-brightgreen)](https://github.com/samvallad33/vestige/actions) [![License](https://img.shields.io/badge/license-AGPL--3.0-blue)](LICENSE) [![MCP Compatible](https://img.shields.io/badge/MCP-compatible-green)](https://modelcontextprotocol.io) -**Your Agent forgets everything between sessions. Vestige fixes that.** +**Your agent forgets project decisions between sessions. Vestige gives it local, inspectable memory.** -Built on 130 years of memory research — FSRS-6 spaced repetition, prediction error gating, synaptic tagging, spreading activation, memory dreaming — all running in a single Rust binary with a 3D neural visualization dashboard. 100% local. Zero cloud. +Built on proven memory and retrieval ideas — FSRS-6 spaced repetition, prediction error gating, synaptic tagging, spreading activation, and memory consolidation — all running in a single Rust binary with a local dashboard. 100% local. Zero cloud. -[Quick Start](#quick-start) | [Dashboard](#-3d-memory-dashboard) | [How It Works](#-the-cognitive-science-stack) | [Tools](#-24-mcp-tools) | [Docs](docs/) +[Quick Start](#quick-start) | [Dashboard](#-3d-memory-dashboard) | [How It Works](#-the-cognitive-science-stack) | [Tools](#-25-mcp-tools) | [Docs](docs/) --- +## What's New in v2.1.21 "Agent-Neutral Hardening" + +v2.1.21 tightens Vestige for normal use across MCP-compatible agents, without +making Claude Code companion tooling part of the default path. + +- **Agent-neutral default.** Stdio MCP remains the default transport; optional HTTP MCP is explicit with `--http`, `--http-port`, or `VESTIGE_HTTP_ENABLED=1`. +- **Safer destructive actions.** `memory(action="delete")` now requires `confirm=true`, matching `purge`, and the legacy `delete_knowledge` shim forwards that confirmation instead of bypassing it. +- **Portable sync repair.** Merge imports preserve purge tombstones, avoid `INSERT OR REPLACE` cascades, rebuild the vector index from a clean state, and write portable archive temp files with private Unix permissions. +- **Release/package cleanup.** Release builds check the embedded dashboard before packaging, publish checksums, and the npm installer rejects targets that do not have release assets. +- **Any-agent memory protocol.** The setup docs now include a short agent-agnostic memory protocol for Claude Code, Codex, Cursor, VS Code, Xcode, JetBrains, Windsurf, and other MCP clients. + ## What's New in v2.1.2 "Honest Memory" v2.1.2 makes Vestige easier to trust in everyday work: literal lookups stay literal, purge really removes content, contradictions are inspectable, and updates no longer require a curl reinstall flow. @@ -27,7 +38,7 @@ v2.1.2 makes Vestige easier to trust in everyday work: literal lookups stay lite - **Concrete search mode.** Quoted strings, env vars, UUIDs, paths, and code identifiers now take a keyword/literal path that skips HyDE, semantic fusion, FSRS reweighting, competition, and spreading activation. Exact things like `OPENAI_API_KEY`, `mlx_lm.server`, and migration IDs land first. - **Irreversible purge.** `memory(action="purge", confirm=true)` permanently removes memory content and embeddings, scrubs insight JSON references, detaches temporal-summary children, prunes graph edges, and keeps only a non-content deletion tombstone for sync/audit. - **First-class contradiction inspection.** New `contradictions` MCP tool surfaces trust-weighted disagreements directly instead of hiding them inside `deep_reference`. -- **Simple update flow.** `vestige update` and `vestige sandwich install` refresh binaries and companion files without making users paste curl commands. +- **Simple update flow.** `vestige update` refreshes binaries. Claude Code Cognitive Sandwich companion files are opt-in with `vestige update --sandwich-companion` or `vestige sandwich install`. - **Pro waitlist preview.** `/dashboard/waitlist` adds a local-first Solo Pro and Team Pro early-access surface. `VITE_WAITLIST_ENDPOINT` and `VITE_SUPPORT_BOT_ENDPOINT` are opt-in dashboard env vars, so no signup data is captured unless endpoints are configured. ## What's New in v2.1.1 "Portable Sync" @@ -116,10 +127,11 @@ Based on [Anderson et al. 2025](https://www.nature.com/articles/s41583-025-00929 # 1. Install npm install -g vestige-mcp-server@latest -# 2. Connect to Claude Code +# 2. Connect to any MCP-compatible agent +# Claude Code claude mcp add vestige vestige-mcp -s user -# Or connect to Codex +# Codex codex mcp add vestige -- vestige-mcp # 3. Test it @@ -137,9 +149,9 @@ codex mcp add vestige -- vestige-mcp vestige update ``` -`vestige update` updates the binaries and refreshes Cognitive Sandwich companion -files while keeping every hook layer disabled by default. Use -`vestige update --no-sandwich` if you only want the binaries. +`vestige update` updates only the Vestige binaries by default. Use +`vestige update --sandwich-companion` if you also want to refresh optional Claude +Code Cognitive Sandwich companion files. **macOS/Linux manual binary install:** ```bash @@ -179,7 +191,7 @@ Open `%APPDATA%\Claude\claude_desktop_config.json` and point Claude Desktop at t } ``` -If Claude Desktop cannot find `vestige-mcp`, run `where vestige-mcp` in PowerShell and use the exact `.cmd` path it prints as `command`. Example: `"C:\\Users\\you\\AppData\\Roaming\\npm\\vestige-mcp.cmd"`. Reopen Claude Desktop after saving. Future binary and companion-file updates can run with `vestige update`. +If Claude Desktop cannot find `vestige-mcp`, run `where vestige-mcp` in PowerShell and use the exact `.cmd` path it prints as `command`. Example: `"C:\\Users\\you\\AppData\\Roaming\\npm\\vestige-mcp.cmd"`. Reopen Claude Desktop after saving. Future binary updates use `vestige update`; optional Claude Code companion files require `vestige update --sandwich-companion`. **Windows source build:** Prebuilt binaries ship but `usearch 2.24.0` hit an MSVC compile break ([usearch#746](https://github.com/unum-cloud/usearch/issues/746)); we've pinned `=2.23.0` until upstream fixes it. Source builds work with: @@ -206,7 +218,7 @@ cargo build --release -p vestige-mcp --features metal ## Works Everywhere -Vestige speaks MCP — the universal protocol for AI tools. One brain, every IDE. +Vestige speaks MCP, so any client that can register a stdio MCP server can use it. | IDE | Setup | |-----|-------| @@ -379,16 +391,9 @@ This isn't a key-value store with an embedding model bolted on. Vestige implemen ## Make Your AI Use Vestige Automatically -Add this to your `CLAUDE.md`: - -```markdown -## Memory - -At the start of every session: -1. Search Vestige for user preferences and project context -2. Save bug fixes, decisions, and patterns without being asked -3. Create reminders when the user mentions deadlines -``` +Registering the MCP server exposes tools; the agent still needs an instruction +that tells it when to call memory. Use the agent-neutral protocol, then adapt it +to your client-specific instruction file. | You Say | AI Does | |---------|---------| @@ -397,7 +402,7 @@ At the start of every session: | "Remind me..." | Creates a future trigger | | "This is important" | Saves + promotes | -[Full CLAUDE.md templates ->](docs/CLAUDE-SETUP.md) +[Agent memory protocol ->](docs/AGENT-MEMORY-PROTOCOL.md) · [Claude Code template ->](docs/CLAUDE-SETUP.md) --- @@ -406,7 +411,7 @@ At the start of every session: | Metric | Value | |--------|-------| | **Language** | Rust 2024 edition (MSRV 1.91) | -| **Codebase** | 80,000+ lines, 1,292 tests (366 core + 425 mcp + 497 e2e + 4 doctests) | +| **Codebase** | 80,000+ lines with Rust core/MCP/e2e, dashboard, and hook coverage | | **Binary size** | ~20MB | | **Embeddings** | Nomic Embed Text v1.5 by default (768d -> 256d Matryoshka, 8192 context); Qwen3 0.6B optional | | **Vector search** | USearch HNSW (20x faster than FAISS) | @@ -481,7 +486,7 @@ First run downloads ~130MB from Hugging Face. If behind a proxy: export HTTPS_PROXY=your-proxy:port ``` -Cache: macOS `~/Library/Caches/com.vestige.core/fastembed` | Linux `~/.cache/vestige/fastembed` +Cache: platform user cache directory first, then `./.fastembed_cache` as a fallback. Override with `FASTEMBED_CACHE_PATH`.
Earlier releases (v2.0 "Cognitive Leap" → v2.0.4 "Deep Reference") @@ -241,7 +251,7 @@ Run `vestige dashboard` to open `http://localhost:3927/dashboard`, or set `VESTI │ 15 REST endpoints · WS event broadcast │ ├─────────────────────────────────────────────────────┤ │ MCP Server (stdio JSON-RPC) │ -│ 24 tools · 30 cognitive modules │ +│ 25 tools · 30 cognitive modules │ ├─────────────────────────────────────────────────────┤ │ Cognitive Engine │ │ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │ @@ -308,7 +318,7 @@ This isn't a key-value store with an embedding model bolted on. Vestige implemen --- -## 🛠 24 MCP Tools +## 🛠 25 MCP Tools ### Context Packets | Tool | What It Does | @@ -318,9 +328,9 @@ This isn't a key-value store with an embedding model bolted on. Vestige implemen ### Core Memory | Tool | What It Does | |------|-------------| -| `search` | 7-stage cognitive search — HyDE expansion + keyword + semantic + reranking + temporal + competition + spreading activation | +| `search` | Concrete literal search for exact identifiers, or 7-stage cognitive search — HyDE expansion + keyword + semantic + reranking + temporal + competition + spreading activation | | `smart_ingest` | Intelligent storage with CREATE/UPDATE/SUPERSEDE via Prediction Error Gating. Batch mode for session-end saves | -| `memory` | Get, delete, check state, promote (thumbs up), demote (thumbs down) | +| `memory` | Get, purge content/embeddings, check state, promote (thumbs up), demote (thumbs down), edit | | `codebase` | Remember code patterns and architectural decisions per-project | | `intention` | Prospective memory — "remind me to X when Y happens" | @@ -358,11 +368,12 @@ This isn't a key-value store with an embedding model bolted on. Vestige implemen |------|-------------| | `deep_reference` | **Cognitive reasoning across memories.** 8-stage pipeline: FSRS-6 trust scoring, intent classification, spreading activation, temporal supersession, contradiction analysis, relation assessment, dream insight integration, and algorithmic reasoning chain generation. Returns trust-scored evidence with a pre-built reasoning scaffold. | | `cross_reference` | Backward-compatible alias for `deep_reference`. | +| `contradictions` | **Honest memory inspection.** Scans a topic or recent memories for trust-weighted disagreements using the same local contradiction logic as `deep_reference`. | ### Active Forgetting (v2.0.5) | Tool | What It Does | |------|-------------| -| `suppress` | **Top-down active forgetting** — neuroscience-grounded inhibitory control over retrieval. Distinct from `memory.delete` (destroys the row) and `memory.demote` (one-shot ranking hit). Each call **compounds** a retrieval-score penalty (Anderson 2025 SIF), and a background Rac1 cascade worker fades co-activated neighbors over 72h (Davis 2020). Reversible within a 24-hour labile window via `reverse: true`. **The memory persists** — it is inhibited, not erased. | +| `suppress` | **Top-down active forgetting** — neuroscience-grounded inhibitory control over retrieval. Distinct from `memory(action="purge")`, which permanently removes content/embeddings. Each suppression compounds a retrieval-score penalty (Anderson 2025 SIF), and a background Rac1 cascade worker fades co-activated neighbors over 72h (Davis 2020). Reversible within a 24-hour labile window via `reverse: true`. **The memory persists** — it is inhibited, not erased. | --- diff --git a/agents/executioner.md b/agents/executioner.md index 2090f3a..c65da41 100644 --- a/agents/executioner.md +++ b/agents/executioner.md @@ -1,95 +1,58 @@ --- name: executioner -description: "[LEGACY/FALLBACK as of 2026-04-25] The Sanhedrin post-cognitive judge. Originally invoked by sanhedrin.sh Stop hook as a Haiku 4.5 subagent. PRIMARY EXECUTION PATH NOW: ~/.claude/hooks/sanhedrin-local.py (local Qwen3.6-35B-A3B via mlx_lm.server, zero API cost, fully offline). This Haiku-backed agent runs only as manual fallback if mlx-server is unavailable or invoked explicitly via Task(subagent_type='executioner'). Same protocol: decomposes draft into atomic claims across 10 classes, verifies via Vestige deep_reference, returns 'yes' or 'no - reason' on one line." +description: Optional Sanhedrin fallback verifier. Decomposes a draft into atomic claims, checks high-trust Vestige evidence, and returns a one-line pass/veto verdict. tools: mcp__vestige__deep_reference, mcp__vestige__memory, mcp__vestige__search model: claude-haiku-4-5-20251001 --- -# Identity +# Role -You are the Sanhedrin Executioner. A fresh amnesiac judge with access to the Vestige cognitive memory graph. You exist for one turn only. You do not converse. You do not explain. You return exactly one line. +You are a one-turn verifier. You do not converse. You return exactly one line. -# Your Only Job +# Job -Decompose the DRAFT RESPONSE into ATOMIC CLAIMS across 10 exhaustive classes, verify each against high-trust Vestige memory, and VETO the draft if any claim contradicts memory or is factual-shaped but unverifiable. +Decompose the draft response into atomic claims, verify each claim against +high-trust Vestige memory when available, and veto only when the draft +contradicts memory or makes a sensitive user-specific assertion without +supporting evidence. -You are a fail-closed judge. If a claim is factual-shaped and has zero evidence in Vestige either way, that is suspicious — VETO it. +# Claim Classes -# The Ten Claim Classes (Exhaustive) +Check all relevant classes: -You MUST scan the draft for all ten classes. Do not skip a class because it is "not your usual job." Sam's Nightvision verification lesson (memory `efbec834`): *"Handlers must validate ALL possible enum values, not just known cases."* The same rule applies here. Enumerate exhaustively. +1. `TECHNICAL` — APIs, commands, versions, files, configs, endpoints. +2. `BIOGRAPHICAL` — identity, role, location, employment, education. +3. `FINANCIAL` — costs, revenue, pricing, funding, prizes. +4. `ACHIEVEMENT` — releases, rankings, completions, scores, milestones. +5. `TEMPORAL` — dates, durations, ordering, deadlines. +6. `QUANTITATIVE` — counts, percentages, metrics, measurements. +7. `ATTRIBUTION` — who said, decided, agreed, shipped, or committed. +8. `CAUSAL` — claimed causes and effects. +9. `COMPARATIVE` — better, most, fastest, more than, fewer than. +10. `EXISTENTIAL` — whether a file, feature, repo, or artifact exists. -1. **TECHNICAL** — API names, version numbers, architectural patterns, configuration recommendations, file paths, command flags, library methods, crate names, endpoint URLs. -2. **BIOGRAPHICAL** — claims about the user's identity, age, role, location, employment status, education, family, background. -3. **FINANCIAL** — revenue figures, prize money amounts, costs, valuations, pricing, pay, MRR/ARR claims, funding received. -4. **ACHIEVEMENT** — competition results, rankings ("won", "tied #1", "scored X/50"), project completions ("we shipped X", "released v2.3"), leaderboard claims, records set, deadlines met. -5. **TEMPORAL** — specific dates, durations, sequences ("before X", "after Y"), deadlines, "tonight", "yesterday", "last week". -6. **QUANTITATIVE** — counts, percentages, metrics, measurements, star counts, test pass rates, line counts. -7. **ATTRIBUTION** — "user said X", "Sam decided Y", "agent X did Y", "we agreed on Z", "you committed to W". -8. **CAUSAL** — "X caused Y", "because of X", "X led to Y", "X broke Y". -9. **COMPARATIVE** — "better than X", "most", "a few", "some", "more than", "the best", "fastest", superlatives. -10. **EXISTENTIAL** — "X exists at path Y", "feature Z is shipped", "there is a Z", "file W is in the repo". +# Decision Rules -# Protocol (execute silently, no narration) +- Veto direct contradiction with high-trust memory. +- Veto unsupported positive claims about the user's biography, finances, + achievements, or attribution. +- Do not veto purely stylistic disagreement. +- Do not veto technical claims just because Vestige lacks evidence; the draft + may rely on source files or external docs. +- If evidence is stale or superseded, prefer the newer higher-trust memory. -1. **Read the draft.** Extract EVERY atomic claim you find across ALL 10 classes above. Not 1-3 — every claim that could be wrong. An atomic claim is one subject-predicate-object assertion ("Sam won AIMO3 prize money" is one claim; "Sam shipped v2.3 and it passed all tests" is two). +# Output -2. **For each claim, tag its class** (TECHNICAL / BIOGRAPHICAL / FINANCIAL / etc.). +If the draft passes: -3. **Verify each claim** via `mcp__vestige__deep_reference` with `query` set to a specific question that would confirm or contradict the claim (e.g., "What prize money has Sam won?" for a FINANCIAL claim about Sam winning $X). +```text +yes +``` -4. **Read the response fields:** - - `recommended` — highest-trust answer on the topic - - `contradictions` — pairs of high-trust memories that conflict - - `superseded` — memories replaced by newer, higher-trust versions - - `evidence` — trust-sorted memory list - - `confidence` — overall confidence 0-1 +If the draft should be rewritten: -5. **Apply the class-specific decision rule:** +```text +no - [Sanhedrin Veto] [CLASS]: [one-sentence reason under 120 chars] +``` - **HARD VETO classes** (BIOGRAPHICAL, FINANCIAL, ACHIEVEMENT, ATTRIBUTION): - - If the claim contradicts a memory with trust > 0.5 → VETO. - - If the claim is factual-shaped AND Vestige returns confidence < 0.3 with no supporting evidence → VETO (fail-closed, unverifiable positive claim about user's life). - - If the claim uses vague qualifiers ("a few", "some", "most") in a factual assertion ("won prize money", "shipped features", "users paid") → VETO. Demand specificity. - - **SOFT VETO classes** (TECHNICAL, EXISTENTIAL, TEMPORAL): - - If the claim contradicts a memory with trust > 0.5 → VETO. - - If the claim references a `superseded` memory without using its `recommended` replacement → VETO. - - Unverifiable is NOT an automatic veto for these classes (the draft may be referencing external facts Vestige doesn't know). - - **DECOMPOSE-FIRST classes** (CAUSAL, COMPARATIVE, QUANTITATIVE): - - Break into constituent subject-object claims. Verify each as its own class. If any constituent hard-vetoes, the whole claim vetoes. - -6. **If PASS:** output exactly `yes`. - -7. **If VETO:** output exactly one line: - ``` - no - [Sanhedrin Veto] [CLASS]: [one-sentence reason under 120 chars citing memory id if applicable] - ``` - Examples: - - `no - [Sanhedrin Veto] FINANCIAL: Draft claims "a few competitions won prize money" — Vestige has zero prize-money records, memory 6920e7fe shows AIMO3 finished 36/50, no payout.` - - `no - [Sanhedrin Veto] ACHIEVEMENT: Draft claims "v2.3 codename Terrarium" — memory 7b6f5500 (Apr 20, trust 60%) states v2.3 codename is Thalamus.` - - `no - [Sanhedrin Veto] TECHNICAL: Draft suggests "FastAPI shim" — memory de43be5a (trust 62%) states Vestige is a 2-crate Rust workspace (vestige-core + vestige-mcp), not Python.` - -8. **If you cannot complete the analysis in under 12 tool calls, default to VETO** with reason `EXECUTION_INCOMPLETE` rather than `yes`. A false VETO costs a rewrite; a false PASS costs Sam's trust. Fail-closed. - -9. **Output exactly ONE line.** Never more. No preamble, no conversation, no XML, no multi-line explanation. - -# What NOT to do - -- Do not limit yourself to "1-3 claims." Extract ALL atomic claims. -- Do not paraphrase the draft. -- Do not summarize Vestige memory contents. -- Do not output multi-line responses. -- Do not apologize. -- Do not converse. -- Do not assume a biographical/financial/achievement claim is verified just because you couldn't find a contradiction — fail-closed on unverifiable positive claims. -- Do not veto on stylistic disagreement — only on factual contradiction or unverifiable positive assertion. -- Do not claim to have checked a claim you skipped. - -# Precedent — the failures this protocol was tuned to catch - -- **2026-04-20 Terrarium-vs-Thalamus**: caught. Draft claimed v2.3 = Terrarium, memory 7b6f5500 said Thalamus. ACHIEVEMENT/EXISTENTIAL class. -- **2026-04-20 FastAPI-vs-Rust**: caught. Draft suggested FastAPI shim, memory de43be5a said 2-crate Rust workspace. TECHNICAL class. -- **2026-04-21 Prize-money lie**: MISSED on original protocol. Draft claimed "a few competitions won prize money" — no specific memory to contradict, but zero prize memories existed. v2 protocol catches this via COMPARATIVE vague-qualifier rule + FINANCIAL hard-veto-unverifiable rule. -- **Nightvision-enum exhaustive-validation lesson** (memory efbec834): apply the same rule to claim extraction — validate ALL classes, not just the convenient ones. +Output exactly one line. diff --git a/agents/synthesis-composer.md b/agents/synthesis-composer.md index 7245a8a..350d45d 100644 --- a/agents/synthesis-composer.md +++ b/agents/synthesis-composer.md @@ -1,41 +1,46 @@ --- name: synthesis-composer -description: Forces active synthesis mode for high-stakes prompts. Invoke for competition submissions (AIMO, Nemotron, Kaggle), architectural choices, purchases over $200, launches, and strategic decisions. The subagent runs in isolation with a hard system prompt that enforces the Composing / Never-composed / Recommendation response shape and blocks summary-pattern output at the source. Use when "what should Sam DO?" matters more than "what does the memory say?" -tools: mcp__vestige__search, mcp__vestige__deep_reference, mcp__vestige__cross_reference, mcp__vestige__explore_connections, mcp__vestige__session_context, mcp__vestige__memory, mcp__vestige__smart_ingest, mcp__vestige__intention -model: sonnet +description: Optional decision helper that turns Vestige retrievals into concise recommendations. Use for high-stakes technical choices, launches, purchases, submissions, architecture decisions, and tradeoffs where memory evidence may change the answer. +tools: mcp__vestige__deep_reference, mcp__vestige__explore_connections, mcp__vestige__search +model: claude-haiku-4-5-20251001 --- -You are the Synthesis Composer. You exist to do ONE thing: turn Vestige retrievals into concrete recommendations Sam can act on. +# Role -## The Hard Rule +You are the Synthesis Composer. Your job is to turn retrieved Vestige evidence +into a decision, not a memory summary. -Every response you emit MUST follow this exact shape. No exceptions. Deviation is a protocol violation and the entire response will be rejected. +# Protocol -1. **Composing:** list the memory IDs you retrieved, then your composition logic. The logic is your own chain-of-thought about how the memories relate, NOT a restatement of their individual contents. If you catch yourself writing "Memory A says X, and Memory B says Y," STOP. That is the forbidden pattern. -2. **Never-composed detected:** explicitly list combinations of retrieved memories that share tags or topics but have never been retrieved together before this session. If none, write "None." Do NOT skip this line. The whole point of your existence is to surface these. -3. **Recommendation: Sam should DO [concrete action].** Not "Sam should consider." Not "Sam might want to." A specific executable step with a subject, a verb, and an object. +1. Use the smallest Vestige retrieval plan that can materially change the + answer. +2. Search adjacent topics when the decision depends on related history. +3. Convert each useful memory into `fact -> implication -> action`. +4. Surface contradictions, stale evidence, or missing evidence before the + recommendation. +5. If no memory changes the recommendation, say that briefly and proceed from + source evidence. -## Protocol — Do These Things In Order +# Output Shape -1. Run a MINIMUM of 4 parallel Vestige queries across ADJACENT topics, not just the topic you were asked about. Example: if asked about an AIMO submission, query the asked topic AND proven-baseline memories AND parser-fix memories AND prompt-engineering memories AND failure-mode memories. Minimum 4 parallel searches. -2. Call `explore_connections` with `action: "bridges"` to surface memories that share tags but have never been referenced together. This is your primary never-composed detection mechanism. Do not skip it. -3. Cross-reference the retrieved memories in YOUR OWN reasoning before writing anything. Compose them in your head first. Ask yourself which combinations exist in Sam's store, which have been tested together in prior sessions, which have NOT been composed yet, and what Sam should DO given the composition. -4. Only then write the response in the three-part shape above. +Use this compact structure: -## Forbidden Output Pattern +```text +Evidence: ... +Implication: ... +Recommendation: ... +``` -If your draft begins with "Memory A says X. Memory B says Y. Memory C says Z." followed by a vague synthesis sentence, you are in the AIMO3 36/50 failure pattern. STOP. Rewrite into composition form with a concrete "Sam should DO" action. +When useful, add: -The test is simple: if Sam can read your response and not know what to do next, you failed. If he can read your response and immediately execute the recommendation without further clarification, you succeeded. +```text +Contradictions: ... +Next step: ... +``` -## Trust Overrides +# Do Not -FSRS trust scores override your priors. A memory with retention greater than 0.7 and reps greater than 0 beats a fresh claim you were about to make 30 seconds ago, every single time. If a retrieved memory contradicts your draft, start your response with "Vestige is blocking this:" and surface the contradiction verbatim before proceeding. - -## When To Decline - -If after 4+ queries and a bridges call you cannot find a composition or a never-composed combination, respond with: "Insufficient memory context. Recommended action: run [specific query] or save [specific memory] before making this decision." That is a legitimate output. What is NOT legitimate is guessing. - -## Origin - -This subagent exists because on April 14-15, 2026, Claude retrieved three composable memories (4da778e2, 2f171e0e, b43da3be) for a $1.59M math olympiad submission and reported them as summaries instead of composing them. The result was 36/50 against a 47/50 prize threshold. The protocol you enforce makes that failure mode structurally impossible within your subagent context. You do not have permission to skip the shape. +- Do not dump memory summaries as the final answer. +- Do not invent hidden evidence. +- Do not claim a memory was checked unless a tool result supports it. +- Do not force a rigid template when the answer is simple. diff --git a/apps/dashboard/.env.example b/apps/dashboard/.env.example new file mode 100644 index 0000000..9b64f17 --- /dev/null +++ b/apps/dashboard/.env.example @@ -0,0 +1,9 @@ +# Optional public waitlist capture endpoint used by /dashboard/waitlist. +# The page POSTs JSON with: name, email, plan, priority, notes, source, createdAt. +# Examples: Formspree, Tally webhook, Buttondown custom endpoint, Supabase Edge Function. +VITE_WAITLIST_ENDPOINT= + +# Optional support bot endpoint used by /dashboard/waitlist. +# The page POSTs JSON with: question, plan, priority, source, and recent history. +# If unset, the page uses the built-in deterministic onboarding FAQ. +VITE_SUPPORT_BOT_ENDPOINT= diff --git a/apps/dashboard/build/_app/immutable/assets/20.DKhUrxcR.css b/apps/dashboard/build/_app/immutable/assets/20.DKhUrxcR.css new file mode 100644 index 0000000..4017a6e --- /dev/null +++ b/apps/dashboard/build/_app/immutable/assets/20.DKhUrxcR.css @@ -0,0 +1 @@ +body{overflow:hidden}.waitlist-shell.svelte-1375qm6{position:fixed;top:0;right:0;bottom:0;left:0;overflow-y:auto;background:#07100f;color:#edf7f2;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.memory-field.svelte-1375qm6,.field-vignette.svelte-1375qm6{position:fixed;top:0;right:0;bottom:0;left:0;pointer-events:none}.memory-field.svelte-1375qm6{z-index:0}.field-vignette.svelte-1375qm6{z-index:1;background:linear-gradient(90deg,#07100feb,#07100f9e 48%,#07100fe0),linear-gradient(180deg,#07100f33,#07100fd1)}.topbar.svelte-1375qm6,main.svelte-1375qm6{position:relative;z-index:2}.topbar.svelte-1375qm6{display:flex;align-items:center;justify-content:space-between;gap:1rem;width:min(1180px,calc(100% - 2rem));margin:0 auto;padding:1rem 0}.brand.svelte-1375qm6,.topbar.svelte-1375qm6 nav:where(.svelte-1375qm6),.hero-actions.svelte-1375qm6,.proof-row.svelte-1375qm6,.signal-band.svelte-1375qm6,.track-grid.svelte-1375qm6,.support-bot.svelte-1375qm6,.roadmap.svelte-1375qm6,.roadmap.svelte-1375qm6 li:where(.svelte-1375qm6){display:flex}.brand.svelte-1375qm6{align-items:center;gap:.7rem;color:#fff;text-decoration:none;font-weight:800}.brand-mark.svelte-1375qm6{display:grid;place-items:center;width:2.15rem;height:2.15rem;border:1px solid rgba(34,197,94,.48);border-radius:8px;background:linear-gradient(135deg,#22c55e3d,#06b6d429);color:#bbf7d0}.topbar.svelte-1375qm6 nav:where(.svelte-1375qm6){align-items:center;gap:.4rem}.topbar.svelte-1375qm6 a:where(.svelte-1375qm6){color:#b8c7c0;text-decoration:none}.topbar.svelte-1375qm6 nav:where(.svelte-1375qm6) a:where(.svelte-1375qm6){border-radius:8px;padding:.65rem .85rem;font-size:.88rem}.topbar.svelte-1375qm6 nav:where(.svelte-1375qm6) a:where(.svelte-1375qm6):hover,.nav-cta.svelte-1375qm6{background:#ffffff12;color:#fff}main.svelte-1375qm6{width:min(1180px,calc(100% - 2rem));margin:0 auto}.hero.svelte-1375qm6{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(320px,.7fr);gap:clamp(2rem,6vw,5rem);align-items:center;min-height:86vh;padding:clamp(2rem,5vw,4.8rem) 0 2rem}.hero-copy.svelte-1375qm6{max-width:720px}.eyebrow.svelte-1375qm6,.form-heading.svelte-1375qm6 p:where(.svelte-1375qm6),.section-heading.svelte-1375qm6 p:where(.svelte-1375qm6){margin:0 0 .8rem;color:#67e8f9;font-size:.78rem;font-weight:800;letter-spacing:0;text-transform:uppercase}h1.svelte-1375qm6,h2.svelte-1375qm6,h3.svelte-1375qm6,p.svelte-1375qm6{margin-top:0}h1.svelte-1375qm6{margin-bottom:1.1rem;color:#fff;font-size:clamp(3.8rem,13vw,8rem);line-height:.92;letter-spacing:0}.hero-subtitle.svelte-1375qm6{max-width:680px;margin-bottom:1.6rem;color:#d7e6df;font-size:clamp(1.05rem,2.4vw,1.45rem);line-height:1.5}.hero-actions.svelte-1375qm6{flex-wrap:wrap;gap:.8rem;margin-bottom:2rem}.primary-link.svelte-1375qm6,.secondary-link.svelte-1375qm6,.submit-button.svelte-1375qm6{border-radius:8px;font-weight:800;text-decoration:none}.primary-link.svelte-1375qm6,.submit-button.svelte-1375qm6{border:1px solid rgba(34,197,94,.86);background:#22c55e;color:#04130b;box-shadow:0 20px 42px #22c55e30}.primary-link.svelte-1375qm6,.secondary-link.svelte-1375qm6{padding:.88rem 1rem}.secondary-link.svelte-1375qm6{border:1px solid rgba(226,232,240,.2);background:#ffffff0f;color:#edf7f2}.proof-row.svelte-1375qm6{flex-wrap:wrap;gap:.7rem}.proof-item.svelte-1375qm6{width:min(100%,13rem);border:1px solid rgba(226,232,240,.12);border-radius:8px;background:#050c0b8a;padding:.9rem}.proof-item.svelte-1375qm6 strong:where(.svelte-1375qm6),.proof-item.svelte-1375qm6 span:where(.svelte-1375qm6){display:block}.proof-item.svelte-1375qm6 strong:where(.svelte-1375qm6){margin-bottom:.4rem;color:#bbf7d0;font-size:1.05rem}.proof-item.svelte-1375qm6 span:where(.svelte-1375qm6){color:#a8bbb2;font-size:.82rem;line-height:1.45}.waitlist-form.svelte-1375qm6{border:1px solid rgba(226,232,240,.16);border-radius:8px;background:#050c0bd1;box-shadow:0 28px 90px #0000005c;padding:clamp(1rem,3vw,1.35rem)}.form-heading.svelte-1375qm6 h2:where(.svelte-1375qm6),.section-heading.svelte-1375qm6 h2:where(.svelte-1375qm6),.roadmap.svelte-1375qm6 h2:where(.svelte-1375qm6){margin-bottom:1rem;color:#fff;font-size:clamp(1.6rem,4vw,2.7rem);line-height:1.05;letter-spacing:0}.form-heading.svelte-1375qm6 h2:where(.svelte-1375qm6){font-size:clamp(1.4rem,3vw,2rem)}label.svelte-1375qm6{display:block;margin-top:.85rem}label.svelte-1375qm6 span:where(.svelte-1375qm6){display:block;margin-bottom:.38rem;color:#a8bbb2;font-size:.78rem;font-weight:750}input.svelte-1375qm6,select.svelte-1375qm6,textarea.svelte-1375qm6{width:100%;border:1px solid rgba(226,232,240,.16);border-radius:8px;background:#fff1;color:#fff;font:inherit;padding:.78rem .82rem;outline:none}select.svelte-1375qm6{color-scheme:dark}textarea.svelte-1375qm6{resize:vertical;min-height:6rem}input.svelte-1375qm6:focus,select.svelte-1375qm6:focus,textarea.svelte-1375qm6:focus{border-color:#22c55ee6;box-shadow:0 0 0 3px #22c55e24}.hidden-field.svelte-1375qm6{position:absolute;left:-10000px;height:1px;overflow:hidden}.submit-button.svelte-1375qm6{width:100%;margin-top:1rem;padding:.95rem 1rem;cursor:pointer;font:inherit}.submit-button.svelte-1375qm6:disabled{cursor:wait;opacity:.72}.submit-message.svelte-1375qm6{margin:.8rem 0 0;font-size:.82rem;line-height:1.45}.submit-message.success.svelte-1375qm6{color:#86efac}.submit-message.error.svelte-1375qm6{color:#fca5a5}.signal-band.svelte-1375qm6{flex-wrap:wrap;gap:.65rem;border-top:1px solid rgba(226,232,240,.12);border-bottom:1px solid rgba(226,232,240,.12);padding:1rem 0}.signal-band.svelte-1375qm6 div:where(.svelte-1375qm6){border-radius:999px;background:#ffffff12;color:#d7e6df;padding:.55rem .75rem;font-size:.84rem}.pro-grid.svelte-1375qm6,.roadmap.svelte-1375qm6{padding:clamp(3rem,7vw,5rem) 0}.section-heading.svelte-1375qm6{max-width:760px;margin-bottom:1.7rem}.track-grid.svelte-1375qm6{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.9rem}.track.svelte-1375qm6{border:1px solid rgba(226,232,240,.13);border-radius:8px;background:#050c0ba8;padding:1.1rem}.track-line.svelte-1375qm6{width:3.5rem;height:.22rem;margin-bottom:1rem;border-radius:999px;background:var(--track-color)}.track.svelte-1375qm6 h3:where(.svelte-1375qm6){margin-bottom:.65rem;color:#fff;font-size:1.08rem}.track.svelte-1375qm6 p:where(.svelte-1375qm6),.roadmap.svelte-1375qm6 span:where(.svelte-1375qm6){color:#a8bbb2;line-height:1.55}.support-bot.svelte-1375qm6,.roadmap.svelte-1375qm6{align-items:flex-start;justify-content:space-between;gap:clamp(2rem,6vw,4rem);border-top:1px solid rgba(226,232,240,.12)}.support-bot.svelte-1375qm6{padding:clamp(2.6rem,6vw,4.5rem) 0}.support-bot.svelte-1375qm6>div:where(.svelte-1375qm6):first-child,.roadmap.svelte-1375qm6>div:where(.svelte-1375qm6){flex:0 0 min(28rem,100%)}.bot-intro.svelte-1375qm6{max-width:34rem;color:#a8bbb2;line-height:1.55}.bot-panel.svelte-1375qm6{flex:1;border:1px solid rgba(226,232,240,.13);border-radius:8px;background:#050c0b9e;padding:clamp(1rem,3vw,1.25rem)}.bot-status.svelte-1375qm6,.prompt-row.svelte-1375qm6,.bot-input.svelte-1375qm6{display:flex;align-items:center}.bot-status.svelte-1375qm6{gap:.55rem;margin-bottom:.9rem;color:#d7e6df;font-size:.86rem;font-weight:800}.bot-status.svelte-1375qm6 small:where(.svelte-1375qm6){margin-left:auto;border:1px solid rgba(34,197,94,.22);border-radius:999px;padding:.3rem .5rem;color:#86efac;font-size:.72rem}.bot-light.svelte-1375qm6{width:.42rem;height:.42rem;border-radius:999px;background:#22c55e;box-shadow:0 0 18px #22c55eb3}.bot-messages.svelte-1375qm6{display:grid;gap:.75rem;max-height:22rem;overflow-y:auto;border:1px solid rgba(226,232,240,.1);border-radius:8px;background:#ffffff09;padding:.8rem}.bot-bubble.svelte-1375qm6,.user-bubble.svelte-1375qm6{max-width:88%;border-radius:8px;padding:.75rem .82rem}.bot-bubble.svelte-1375qm6{justify-self:start;border:1px solid rgba(34,197,94,.18);background:#22c55e14;color:#d7e6df}.user-bubble.svelte-1375qm6{justify-self:end;border:1px solid rgba(6,182,212,.24);background:#06b6d41f;color:#fff}.bot-bubble.svelte-1375qm6 p:where(.svelte-1375qm6),.user-bubble.svelte-1375qm6 p:where(.svelte-1375qm6){margin:0;font-size:.86rem;line-height:1.5;white-space:pre-wrap}.bot-bubble.svelte-1375qm6 p:where(.svelte-1375qm6)+p:where(.svelte-1375qm6),.user-bubble.svelte-1375qm6 p:where(.svelte-1375qm6)+p:where(.svelte-1375qm6){margin-top:.35rem}.prompt-row.svelte-1375qm6{flex-wrap:wrap;gap:.45rem;margin:.85rem 0}.prompt-row.svelte-1375qm6 button:where(.svelte-1375qm6){border:1px solid rgba(226,232,240,.14);border-radius:999px;background:#ffffff0e;color:#d7e6df;cursor:pointer;font:inherit;font-size:.78rem;padding:.46rem .62rem}.prompt-row.svelte-1375qm6 button:where(.svelte-1375qm6):hover{border-color:#22c55e6b;color:#fff}.bot-input.svelte-1375qm6{gap:.55rem}.bot-input.svelte-1375qm6 input:where(.svelte-1375qm6){margin:0}.bot-input.svelte-1375qm6 button:where(.svelte-1375qm6){flex:0 0 auto;border:1px solid rgba(34,197,94,.86);border-radius:8px;background:#22c55e;color:#04130b;cursor:pointer;font:inherit;font-weight:800;padding:.78rem .95rem}.bot-input.svelte-1375qm6 button:where(.svelte-1375qm6):disabled{cursor:not-allowed;opacity:.45}.roadmap.svelte-1375qm6 ol:where(.svelte-1375qm6){display:grid;gap:.8rem;margin:0;padding:0;list-style:none}.roadmap.svelte-1375qm6 li:where(.svelte-1375qm6){gap:1rem;align-items:flex-start;border:1px solid rgba(226,232,240,.13);border-radius:8px;background:#050c0b94;padding:1rem}.roadmap.svelte-1375qm6 strong:where(.svelte-1375qm6){flex:0 0 4.5rem;color:#fbbf24}@media(max-width:900px){.topbar.svelte-1375qm6{align-items:flex-start;flex-direction:column}.hero.svelte-1375qm6,.track-grid.svelte-1375qm6,.support-bot.svelte-1375qm6,.roadmap.svelte-1375qm6{grid-template-columns:1fr}.hero.svelte-1375qm6{display:block;min-height:auto;padding-top:2rem}.waitlist-form.svelte-1375qm6{margin-top:2rem}.support-bot.svelte-1375qm6,.roadmap.svelte-1375qm6{display:block}.bot-panel.svelte-1375qm6{margin-top:1rem}}@media(max-width:560px){main.svelte-1375qm6,.topbar.svelte-1375qm6{width:min(100% - 1rem,1180px)}.topbar.svelte-1375qm6 nav:where(.svelte-1375qm6){width:100%;justify-content:space-between}.topbar.svelte-1375qm6 nav:where(.svelte-1375qm6) a:where(.svelte-1375qm6){padding:.58rem .62rem;font-size:.8rem}h1.svelte-1375qm6{font-size:clamp(3.35rem,18vw,4.8rem)}.hero-subtitle.svelte-1375qm6{font-size:1rem}.proof-item.svelte-1375qm6{width:100%}.roadmap.svelte-1375qm6 li:where(.svelte-1375qm6){display:block}.roadmap.svelte-1375qm6 strong:where(.svelte-1375qm6){display:block;margin-bottom:.5rem}.bot-input.svelte-1375qm6{align-items:stretch;flex-direction:column}.bot-input.svelte-1375qm6 button:where(.svelte-1375qm6){width:100%}} diff --git a/apps/dashboard/build/_app/immutable/assets/20.DKhUrxcR.css.br b/apps/dashboard/build/_app/immutable/assets/20.DKhUrxcR.css.br new file mode 100644 index 0000000000000000000000000000000000000000..e4292ca6e38eeea205abe2684da6e8f0744c6355 GIT binary patch literal 2133 zcmV-b2&(rR<|zP-!g23`TPe#ThO298S+%^Q7_%Bc8Jvp7O~Hy)xP;7c_klt4XK%cO zmi|~{&-oNqR$LX3``Bf|`dtUvHGAN^>aW zJrvUL(Bh0lhq$u!i*|FzFb0hJtU z|H5Hx&o%Xc9hyq2gw(;yzXje+kJ~d6lVmF?7m55B`DIwNt(X06d-sTcI|y!CRDJ{= zyV!;y1XT_$I{w+eBTBgXw{QILiq=5v`cl$rOFec5x`Jw5jlg?;K6viyjZ&h1r;@2Z?#q*3>Z>UptciNcRXx`UG{d_ z_*ff?xv|K6LlIgEZ5 z)SvvU=qeAvHHZ}gG5iAq(2nNE-Iz75(zVdLbe-1Rb=3H2g}ra}#9RLDA})iMMVffs z>I5sxlH9?o(1*u)nB_<$TuWw&bU*qU*NnNiRcX0v0CRrCahJnQaljHOoUac;Rk z(0gQ#wW&yhtkjM50Y6ah&q|8bZIck`U?TGT(nKDnGsw2b|G}OE^8zBFGgO^WaJ3T+ zu@fzm=!Ek=1RZT1{ZLyBu+cIU53N|Kos{VHvAJ_!;3WkmT;HLSWXN9hYaP1_UypOG5ZNQ5?_+FdL=T zI_rAv` zgc^hIiQ(RWIjY_iXhfJsMQ+jro$V_y2i=luP}zvp$)t@gWH~@wQhEqz}haZ!?CrP1kz7>5NgKGqQu`=V$7_Ofq5^YTjW=Op9*l)TkJHzrq?4S*pqT-?KmiN-A7J{jL&vmF52&31$p4=y(h z2z>$}CuDf3-9FMMoTJ9A7Ms$&31q%Wf}uLmnK$`HG^b`%sU3FbKtZtlb~t#wEz%_kC6F_ar@B3b6yFalnUtPRBA6sO3J@Y;|Pa#Y;LhgbtPpK9@Ppm)|XH3TI- zJ?~?@-b365ex-O(fnA=i-PD0q#m|020GOoGfQ}7gT?Cc4<-yZ5sjsE&8|Vw&aEIXsdy#bsxn5ovSMv_^Bp zd2TkJIB&6GySwfG3jbPH4QWYLh8g+7Y1CGAXhoD9jxGEjS8ZDr@FB+;`+In{aS73> zt)dtu9|u~U$~1hlcD7|@QBvg<4c~B@?J_6IsL+3}sBDY|QEW}{1-e${{tT?to`SAeO%s|1uiOjF*1Vlbf%eZ z@~g%tIh43<@n2HBt_YLfz@NBmo3N}(tla$ir$NdTe}z`}K#bvw_SBf5Jx0_xP?Qqb z@O^Kk_@MVD#_{lJk2Np&b-QkD^!Y+Nn67l);ZtgFIulfm5uKZ@K%`u?6~#Gf$tR8m zv7MF2TvO82Il6>dj=v(5gZ2giS2kgSnI)tDo|=|q7b5}R!j-V8QG$&aw`YvY=z!|b zrnrdCByEpjLCSX#qM z6>SX&#Kk>Yp|n8tlh?JJtmt&-Be|ij63;Q;m^i(35E8YxaHig=)~3=!FX z#yqD2Yw(2u{`y!87iNqIK0z$pZ7SlxG3_ne_$Zz^{25m?#Wb|*FRiI^l4|r2qj%TS z?fp*Qd%EcboBm4%%ZyVK2KARJ;cR!y^Tu(K?H0Q!VJfWEZcL;ZUL;l2}83YQoUXUR?vLd9L zu+&IeG>@ZcMauY(?M&jdlcC$UF{a~SpbTO5%K#U{75EAWa4O1%?NOkwcT2ZTYn#!H z)?aWPwyn8?OFR~m92NCD+gkTO&pNZ|Mh2p=+~{*5@IQ|?Z%o#2VZCQECu}r}Ya^rw znd-}21(3xM*4QzLIul=TEJL-dq6O@X*lu&D)~gWOU=E+(U3k42-_p1ygG2ot4zm3; z+IGP${6^e?BHps%%}NZjPM;@$zGcG{2?1*{O;Cfoqdiyk=q#?d^DFhzj!a;KbBg6N zhub~LuuXdgrlUf_kuKL-w_Wfh_hiKIYVf?dcNQAQ`IwTQ~(ltaU45$Y=Pza3`D%`q=#jA{X*c`{&T)e?O9sE*R(y$ ztv8GRY?E1$WtpM790FYqft|8A9-UXKqhjR>@n2mrFF+5r1}azDqZw^O3liV=}tMwGKQBNWVf|CQr4$ME7#y0 zoIbzG$_=6z$&rkqSo9+y&&cuI?;$C{BBUK5jjN;enOU7$=6X>9rP7PsHk#y!3mihR z_~_R3p_m&C=zL3na!=VT3plCC!mLV8jofhky_N06-J#m|YKvNl{rjwE|J<>ZIv&s% zK1`F(dT!GZ6oWHPEf!NF!)Aa1HXrf?J}!oHN}e!r_#~!zx{eiRJJjbWInf4`>StAV z?o@9SLb#(i$LY0y1cTeCV!7O2AOf7*@&Y#vI$$}W737Us?-@v+Kk<|#@KG8~;alM2 z3?++2n9_=_EXfkIMQoqd0gRMR_>+l(F!ys5VZhP{-=0sW)}_-@^7&jJzTfYcnSIy! z_8k5eG+WWE?-tFvHxzaGR7zfGuJ;v@5iET-w5?o8Wo4UooxZFa5e#p2SoTcgO>vD; z`|jvt2M)cqXtsOO#-INRwQ!%K7AP2MD*P- z#AZAoHgavXqx&Q`6iFhb48R70ReLIC11lWnc@{bAJUPOAcZPa5o8#!vKq+aT7*@|F zHr}Mkcm_pO!p_pm5p0a_VvZ@cy8Q3!I1*-r0;f)nBv02&qFB!Hlb1`@T{&V#0mTZm z0Wl1yLdzl9nCq^$WKl~WvIjv3EGZw~+m3!PLHBr_+B-e9XW~Fev?u8iKvB2SGXP;N@qW6nejn880lc_ik*8B(x}T3A5rvf`Wj+e zAo=1n^@&)1g445+%6_zGa5GhWisQvBP&ZEvqc5_1lWYxwUy)+^zuS&Yf?~7l0Hna* zvru5`!-%m1*)YuZ?qj@D>2bF$F4L7weccYg(6$3%>fLWDj(_ZIdX})Rr=rfSOZj;I zz0BhoU`FR7;0N!*aadE#$?Yq0{`R8^{PsXI(W<+*iIN;grF7k!AYk9^YnI|6nrML3 z#9Ez#-X?mEe_MD4!-@uNIY7AOmgn=_@*TB#)S8K7Gimqh$BUqr7OS!1tba-47azs3 zV!hfuH^T8;tqC5EK%|59hi;l24a~+>J89mBm+%;`~8=M}bG<&Oqh zV^NwMw1lG`RwP~(YA<;|<@x?=1-F+sR@n4UayIX-qh1wOJ^8+cm3PNGvN+Bhulq-V zQ-a>dTDWIZoy~RS#g`SO`Nxz{(F%v6F_j)9|L}VuS9wPa{jd5MyB~dyGr8&8H5{=8 zASp-l6MPrnenI}(@y2RLFdLC|OUG?}?l{Ri04py9%?^(=gAdwt@tVNqg?B$D6Fp^5 z`I9egj8mUrEF^bSf>~>MO1(UV<`o(^()dcjgLCG|Sm3EsI%b&e_4k{if(!s){if(s=!0,r.hasAttribute("value")){var e=r.value;_(r,"value",null),r.value=e}if(r.hasAttribute("checked")){var o=r.checked;_(r,"checked",null),r.checked=o}}};r.__on_r=a,A(a),S()}}function l(r,s){var a=d(r);a.value===(a.value=s??void 0)||r.value===s&&(s!==0||r.nodeName!==E)||(r.value=s??"")}function _(r,s,a,e){var o=d(r);i&&(o[s]=r.getAttribute(s),s==="src"||s==="srcset"||s==="href"&&r.nodeName===T)||o[s]!==(o[s]=a)&&(s==="loading"&&(r[u]=a),a==null?r.removeAttribute(s):typeof a!="string"&&L(r).includes(s)?r[s]=a:r.setAttribute(s,a))}function d(r){return r.__attributes??(r.__attributes={[N]:r.nodeName.includes("-"),[p]:r.namespaceURI===v})}var c=new Map;function L(r){var s=r.getAttribute("is")||r.nodeName,a=c.get(s);if(a)return a;c.set(s,a=[]);for(var e,o=r,n=Element.prototype;n!==o;){e=g(o);for(var t in e)e[t].set&&a.push(t);o=h(o)}return a}export{l as a,k as r,_ as s}; diff --git a/apps/dashboard/build/_app/immutable/chunks/A7po6GxK.js.br b/apps/dashboard/build/_app/immutable/chunks/A7po6GxK.js.br new file mode 100644 index 0000000000000000000000000000000000000000..fe4ef81fcfe97ba93639fa77c894caec5b455b1b GIT binary patch literal 565 zcmV-50?PdxSOh>EseSdWTI6eK`#YCY;zMLhrq$7de&e?qnzhWbq0P#sw5g=0x>_5Z z&KACqw%z|_oc}C}pcWKJ96_NMkFY3>V^Ggd`~rcL!mxK+Y%H2bwWU9JiZ0`ce!hSq zy24(aqN{kU|4v{px~BiAEPkZ9`Gct}bJszs!gIg*j7<<{(oklR62TpbPSKHugRrfi z81Ik_V%nnF&DHhjP74kG=vmHHlGrwH*yVi~^Prqzfp$?1EZ9DbHjv?IdqI6}VzKw2 z2Mi`DF-b_4GkgxJo6gx4l~)sCiQZpCuEUt=p=>z%5h)ZT@uP9jKj!-lO06~d-1&LA zKX;h!v5Ed*sa15~*3_VR%W%mq$vBe(7=UAE$A#=K$j66cSdFgZXn_T2WT=tBf-u|> zzB6{h0U}{BdR|e}%xb*+FmxT4K2G7Y&ha5c0|14O=;H&Bi~R6H20uVu#{+=KPeh&H z0@UgzdhXd)cj(3@V8fNdULJ1o;Tgr$2H9W DDsmp% literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/A7po6GxK.js.gz b/apps/dashboard/build/_app/immutable/chunks/A7po6GxK.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..78838960948650554b0e3175cc5e541355d9937d GIT binary patch literal 633 zcmV-<0*3t`iwFP!000026J1nIZ`&{oz3*2zIs_7+dF{RqF|?oNc`VNI&q!$MEj9^_$$>}{ z)wy>Q$^x-_m5o`En=Ko$o9pR!CMSec&aR#I9?_q7x8Lq2vl&aW+N2@3Cfaf*_Ibv0 zvEPAyZvy;{XnS;0*zhiDU=%jCm6+DpURl%>rumAg4CUs zwq}l0cJ3FbY^_5t-3#fl67w!)heP-2b?E*!PG@X5?CT?VkM)TRTRD<~piU{gu&~O_ z8Z)??*W|&2R5Z4+i=8g*PM;Sag{Ml}EP?^nMYzqp!G`19q(!~b9)rfNtub=3f6=-G zai*JO?wt;`GZCE#bb&Y^{t{68`E)VrCH2MFTU_CJ)jHAPD@gUPyK7XoYeYlyOqJ1p zqaRT9+e`hP_V(3u@m?@-et0;HltNHdf_n(!)G#C|i6c#Fz7R=f9d9>U;x0;~CdWG$ z<24GFW|kNnzD>klt2MWMLWpt`X`$y~L4?C0#8vG#Jcz`q4MsLy#YX>YpN@jw0FYZU TPA{var a=!1;c((r,s=0)=>{a=!0,i(s,r)}),a||i(!1,null)},_)}export{m as i}; diff --git a/apps/dashboard/build/_app/immutable/chunks/B4yTwGkE.js.br b/apps/dashboard/build/_app/immutable/chunks/B4yTwGkE.js.br new file mode 100644 index 0000000000000000000000000000000000000000..ca1901d6d4dba9fc062e7c9181783941479d097c GIT binary patch literal 304 zcmV-00nh#$vjG6C4s26v2m2c~7EC)jS?k66&1s-jo!6UmWJ@l+tvu%ADe(xwA!l0h z=Ai{zv-IulY=y5dH~I7y*H?FIMg9N3sqbIFNOKyCCT`#3cpB=YV$a-__7de`+gNs< zh`fmNuPdCZI9g|~B8NDaMij%-_XRIH!KWSqcjTDdi1y^DG^J4+K^HJdIV?}w7hAn|}3lJA|^GR&S6aOi?hLa6Xpt+zzLd$?KK zS6g@xF!QN%Wy9*RULj5E%2C(`0a%-8N-|&3Q3`n^v}+ooH4N1`q#UHllz}ffAvV)E z6SDs&Z*~MgZV!6wurzHC;6hh61OhWQD1oc)0aCwT0@9?d*uhBrKc5kO3-NV-_dfuO CppzE> literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/B4yTwGkE.js.gz b/apps/dashboard/build/_app/immutable/chunks/B4yTwGkE.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..4c378784bc58b318cfedfa20a2cd295555587f11 GIT binary patch literal 317 zcmV-D0mA+tiwFP!000026IGB;Z^AGP#qawRg#&UVt1DNk46&^TE}MjqIHI(qkgZL+ z{3%GK-+ghXY1--MJU`n{QEg|eAIe0yWRGtIgJOD?SP(8KD&h{sjo6_$5jQ9#vA{jy zj5|Uz*4DK1^zo%Td>#((CjD^pT>V^mCP)A4cs&(g*Z#Df9Cgr@S4Jl-c&sq+*^&)r zu_%G%y|9VqT3(YLJi{Xo>&q(p8&M$8vO(2g*iaemd?NWSTBk{u$A;vbcWcM96;+#9 z&6X?2J7JyNY7a7Xp>*CVeTF4tC}x~HHqd;{i{const n=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(r);if(n)return a.push({name:n[1],matcher:n[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const o=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(r);if(o)return a.push({name:o[1],matcher:o[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!r)return;const s=r.split(/\[(.+?)\](?!\])/);return"/"+s.map((c,l)=>{if(l%2){if(c.startsWith("x+"))return ct(String.fromCharCode(parseInt(c.slice(2),16)));if(c.startsWith("u+"))return ct(String.fromCharCode(...c.slice(2).split("-").map(_=>parseInt(_,16))));const h=ue.exec(c),[,u,w,f,d]=h;return a.push({name:f,matcher:d,optional:!!u,rest:!!w,chained:w?l===1&&s[0]==="":!1}),w?"([^]*?)":u?"([^/]*)?":"([^/]+?)"}return ct(c)}).join("")}).join("")}/?$`),params:a}}function de(t){return t!==""&&!/^\([^)]+\)$/.test(t)}function pe(t){return t.slice(1).split("/").filter(de)}function me(t,a,e){const r={},n=t.slice(1),o=n.filter(i=>i!==void 0);let s=0;for(let i=0;ih).join("/"),s=0),l===void 0)if(c.rest)l="";else continue;if(!c.matcher||e[c.matcher](l)){r[c.name]=l;const h=a[i+1],u=n[i+1];h&&!h.rest&&h.optional&&u&&c.chained&&(s=0),!h&&!u&&Object.keys(r).length===o.length&&(s=0);continue}if(c.optional&&c.chained){s++;continue}return}if(!s)return r}function ct(t){return t.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}function ge({nodes:t,server_loads:a,dictionary:e,matchers:r}){const n=new Set(a);return Object.entries(e).map(([i,[c,l,h]])=>{const{pattern:u,params:w}=he(i),f={id:i,exec:d=>{const _=u.exec(d);if(_)return me(_,w,r)},errors:[1,...h||[]].map(d=>t[d]),layouts:[0,...l||[]].map(s),leaf:o(c)};return f.errors.length=f.layouts.length=Math.max(f.errors.length,f.layouts.length),f});function o(i){const c=i<0;return c&&(i=~i),[c,t[i]]}function s(i){return i===void 0?i:[n.has(i),t[i]]}}function Ft(t,a=JSON.parse){try{return a(sessionStorage[t])}catch{}}function It(t,a,e=JSON.stringify){const r=e(a);try{sessionStorage[t]=r}catch{}}function _e(t){return t.filter(a=>a!=null)}function bt(t){return t instanceof wt||t instanceof yt?t.status:500}function we(t){return t instanceof yt?t.text:"Internal Error"}const ve=new Set(["icon","shortcut icon","apple-touch-icon"]),I=Ft(Kt)??{},M=Ft(qt)??{},P={url:Pt({}),page:Pt({}),navigating:ae(null),updated:ne()};function Et(t){I[t]=C()}function ye(t,a){let e=t+1;for(;I[e];)delete I[e],e+=1;for(e=a+1;M[e];)delete M[e],e+=1}function V(t,a=!1){return a?location.replace(t.href):location.href=t.href,new Promise(()=>{})}async function Bt(){if("serviceWorker"in navigator){const t=await navigator.serviceWorker.getRegistration(L||"/");t&&await t.update()}}function Tt(){}let kt,ht,Q,U,dt,E;const Z=[],tt=[];let v=null;function pt(){var t;(t=v==null?void 0:v.fork)==null||t.then(a=>a==null?void 0:a.discard()),v=null}const G=new Map,Mt=new Set,be=new Set,F=new Set;let g={branch:[],error:null,url:null},Vt=!1,et=!1,Ot=!0,H=!1,K=!1,Ht=!1,St=!1,Yt,b,R,O;const at=new Set,Ct=new Map;async function Fe(t,a,e){var o,s,i,c,l;(o=globalThis.__sveltekit_10kbxme)!=null&&o.data&&globalThis.__sveltekit_10kbxme.data,document.URL!==location.href&&(location.href=location.href),E=t,await((i=(s=t.hooks).init)==null?void 0:i.call(s)),kt=ge(t),U=document.documentElement,dt=a,ht=t.nodes[0],Q=t.nodes[1],ht(),Q(),b=(c=history.state)==null?void 0:c[N],R=(l=history.state)==null?void 0:l[B],b||(b=R=Date.now(),history.replaceState({...history.state,[N]:b,[B]:R},""));const r=I[b];function n(){r&&(history.scrollRestoration="manual",scrollTo(r.x,r.y))}e?(n(),await Ce(dt,e)):(await D({type:"enter",url:gt(E.hash?Ne(new URL(location.href)):location.href),replace_state:!0}),n()),Oe()}function Ee(){Z.length=0,St=!1}function zt(t){tt.some(a=>a==null?void 0:a.snapshot)&&(M[t]=tt.map(a=>{var e;return(e=a==null?void 0:a.snapshot)==null?void 0:e.capture()}))}function Wt(t){var a;(a=M[t])==null||a.forEach((e,r)=>{var n,o;(o=(n=tt[r])==null?void 0:n.snapshot)==null||o.restore(e)})}function jt(){Et(b),It(Kt,I),zt(R),It(qt,M)}async function Gt(t,a,e,r){let n;a.invalidateAll&&pt(),await D({type:"goto",url:gt(t),keepfocus:a.keepFocus,noscroll:a.noScroll,replace_state:a.replaceState,state:a.state,redirect_count:e,nav_token:r,accept:()=>{a.invalidateAll&&(St=!0,n=[...Ct.keys()]),a.invalidate&&a.invalidate.forEach(Te)}}),a.invalidateAll&&J().then(J).then(()=>{Ct.forEach(({resource:o},s)=>{var i;n!=null&&n.includes(s)&&((i=o.refresh)==null||i.call(o))})})}async function ke(t){if(t.id!==(v==null?void 0:v.id)){pt();const a={};at.add(a),v={id:t.id,token:a,promise:Xt({...t,preload:a}).then(e=>(at.delete(a),e.type==="loaded"&&e.state.error&&pt(),e)),fork:null}}return v.promise}async function lt(t){var e;const a=(e=await ot(t,!1))==null?void 0:e.route;a&&await Promise.all([...a.layouts,a.leaf].filter(Boolean).map(r=>r[1]()))}async function Jt(t,a,e){var n;g=t.state;const r=document.querySelector("style[data-sveltekit]");if(r&&r.remove(),Object.assign(x,t.props.page),Yt=new E.root({target:a,props:{...t.props,stores:P,components:tt},hydrate:e,sync:!1}),await Promise.resolve(),Wt(R),e){const o={from:null,to:{params:g.params,route:{id:((n=g.route)==null?void 0:n.id)??null},url:new URL(location.href),scroll:I[b]??C()},willUnload:!1,type:"enter",complete:Promise.resolve()};F.forEach(s=>s(o))}et=!0}function nt({url:t,params:a,branch:e,status:r,error:n,route:o,form:s}){let i="never";if(L&&(t.pathname===L||t.pathname===L+"/"))i="always";else for(const f of e)(f==null?void 0:f.slash)!==void 0&&(i=f.slash);t.pathname=se(t.pathname,i),t.search=t.search;const c={type:"loaded",state:{url:t,params:a,branch:e,error:n,route:o},props:{constructors:_e(e).map(f=>f.node.component),page:At(x)}};s!==void 0&&(c.props.form=s);let l={},h=!x,u=0;for(let f=0;fi(new URL(s))))return!0;return!1}function xt(t,a){return(t==null?void 0:t.type)==="data"?t:(t==null?void 0:t.type)==="skip"?a??null:null}function xe(t,a){if(!t)return new Set(a.searchParams.keys());const e=new Set([...t.searchParams.keys(),...a.searchParams.keys()]);for(const r of e){const n=t.searchParams.getAll(r),o=a.searchParams.getAll(r);n.every(s=>o.includes(s))&&o.every(s=>n.includes(s))&&e.delete(r)}return e}function Le({error:t,url:a,route:e,params:r}){return{type:"loaded",state:{error:t,url:a,route:e,params:r,branch:[]},props:{page:At(x),constructors:[]}}}async function Xt({id:t,invalidating:a,url:e,params:r,route:n,preload:o}){if((v==null?void 0:v.id)===t)return at.delete(v.token),v.promise;const{errors:s,layouts:i,leaf:c}=n,l=[...i,c];s.forEach(m=>m==null?void 0:m().catch(()=>{})),l.forEach(m=>m==null?void 0:m[1]().catch(()=>{}));const h=g.url?t!==rt(g.url):!1,u=g.route?n.id!==g.route.id:!1,w=xe(g.url,e);let f=!1;const d=l.map(async(m,p)=>{var A;if(!m)return;const y=g.branch[p];return m[1]===(y==null?void 0:y.loader)&&!Re(f,u,h,w,(A=y.universal)==null?void 0:A.uses,r)?y:(f=!0,Rt({loader:m[1],url:e,params:r,route:n,parent:async()=>{var z;const T={};for(let j=0;j{});const _=[];for(let m=0;mPromise.resolve({}),server_data_node:xt(o)}),i={node:await Q(),loader:Q,universal:null,server:null,data:null};return nt({url:e,params:n,branch:[s,i],status:t,error:a,route:null})}catch(s){if(s instanceof vt)return Gt(new URL(s.location,location.href),{},0);throw s}}async function Ae(t){const a=t.href;if(G.has(a))return G.get(a);let e;try{const r=(async()=>{let n=await E.hooks.reroute({url:new URL(t),fetch:async(o,s)=>Se(o,s,t).promise})??t;if(typeof n=="string"){const o=new URL(t);E.hash?o.hash=n:o.pathname=n,n=o}return n})();G.set(a,r),e=await r}catch{G.delete(a);return}return e}async function ot(t,a){if(t&&!_t(t,L,E.hash)){const e=await Ae(t);if(!e)return;const r=Pe(e);for(const n of kt){const o=n.exec(r);if(o)return{id:rt(t),invalidating:a,route:n,params:oe(o),url:t}}}}function Pe(t){return ie(E.hash?t.hash.replace(/^#/,"").replace(/[?#].+/,""):t.pathname.slice(L.length))||"/"}function rt(t){return(E.hash?t.hash.replace(/^#/,""):t.pathname)+t.search}function Qt({url:t,type:a,intent:e,delta:r,event:n,scroll:o}){let s=!1;const i=Ut(g,e,t,a,o??null);r!==void 0&&(i.navigation.delta=r),n!==void 0&&(i.navigation.event=n);const c={...i.navigation,cancel:()=>{s=!0,i.reject(new Error("navigation cancelled"))}};return H||Mt.forEach(l=>l(c)),s?null:i}async function D({type:t,url:a,popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s={},redirect_count:i=0,nav_token:c={},accept:l=Tt,block:h=Tt,event:u}){var j;const w=O;O=c;const f=await ot(a,!1),d=t==="enter"?Ut(g,f,a,t):Qt({url:a,type:t,delta:e==null?void 0:e.delta,intent:f,scroll:e==null?void 0:e.scroll,event:u});if(!d){h(),O===c&&(O=w);return}const _=b,m=R;l(),H=!0,et&&d.navigation.type!=="enter"&&P.navigating.set(ft.current=d.navigation);let p=f&&await Xt(f);if(!p){if(_t(a,L,E.hash))return await V(a,o);p=await Zt(a,{id:null},await Y(new yt(404,"Not Found",`Not found: ${a.pathname}`),{url:a,params:{},route:{id:null}}),404,o)}if(a=(f==null?void 0:f.url)||a,O!==c)return d.reject(new Error("navigation aborted")),!1;if(p.type==="redirect"){if(i<20){await D({type:t,url:new URL(p.location,a),popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s,redirect_count:i+1,nav_token:c}),d.fulfil(void 0);return}p=await Lt({status:500,error:await Y(new Error("Redirect loop"),{url:a,params:{},route:{id:null}}),url:a,route:{id:null}})}else p.props.page.status>=400&&await P.updated.check()&&(await Bt(),await V(a,o));if(Ee(),Et(_),zt(m),p.props.page.url.pathname!==a.pathname&&(a.pathname=p.props.page.url.pathname),s=e?e.state:s,!e){const k=o?0:1,W={[N]:b+=k,[B]:R+=k,[Nt]:s};(o?history.replaceState:history.pushState).call(history,W,"",a),o||ye(b,R)}const y=f&&(v==null?void 0:v.id)===f.id?v.fork:null;v=null,p.props.page.state=s;let S;if(et){const k=(await Promise.all(Array.from(be,$=>$(d.navigation)))).filter($=>typeof $=="function");if(k.length>0){let $=function(){k.forEach(st=>{F.delete(st)})};k.push($),k.forEach(st=>{F.add(st)})}g=p.state,p.props.page&&(p.props.page.url=a);const W=y&&await y;W?S=W.commit():(Yt.$set(p.props),fe(p.props.page),S=(j=ee)==null?void 0:j()),Ht=!0}else await Jt(p,dt,!1);const{activeElement:A}=document;await S,await J(),await J();let T=null;if(Ot){const k=e?e.scroll:n?C():null;k?scrollTo(k.x,k.y):(T=a.hash&&document.getElementById(te(a)))?T.scrollIntoView():scrollTo(0,0)}const z=document.activeElement!==A&&document.activeElement!==document.body;!r&&!z&&$e(a,!T),Ot=!0,p.props.page&&Object.assign(x,p.props.page),H=!1,t==="popstate"&&Wt(R),d.fulfil(void 0),d.navigation.to&&(d.navigation.to.scroll=C()),F.forEach(k=>k(d.navigation)),P.navigating.set(ft.current=null)}async function Zt(t,a,e,r,n){return t.origin===Dt&&t.pathname===location.pathname&&!Vt?await Lt({status:r,error:e,url:t,route:a}):await V(t,n)}function Ie(){let t,a={element:void 0,href:void 0},e;U.addEventListener("mousemove",i=>{const c=i.target;clearTimeout(t),t=setTimeout(()=>{o(c,q.hover)},20)});function r(i){i.defaultPrevented||o(i.composedPath()[0],q.tap)}U.addEventListener("mousedown",r),U.addEventListener("touchstart",r,{passive:!0});const n=new IntersectionObserver(i=>{for(const c of i)c.isIntersecting&&(lt(new URL(c.target.href)),n.unobserve(c.target))},{threshold:0});async function o(i,c){const l=$t(i,U),h=l===a.element&&(l==null?void 0:l.href)===a.href&&c>=e;if(!l||h)return;const{url:u,external:w,download:f}=ut(l,L,E.hash);if(w||f)return;const d=X(l),_=u&&rt(g.url)===rt(u);if(!(d.reload||_))if(c<=d.preload_data){a={element:l,href:l.href},e=q.tap;const m=await ot(u,!1);if(!m)return;ke(m)}else c<=d.preload_code&&(a={element:l,href:l.href},e=c,lt(u))}function s(){n.disconnect();for(const i of U.querySelectorAll("a")){const{url:c,external:l,download:h}=ut(i,L,E.hash);if(l||h)continue;const u=X(i);u.reload||(u.preload_code===q.viewport&&n.observe(i),u.preload_code===q.eager&<(c))}}F.add(s),s()}function Y(t,a){if(t instanceof wt)return t.body;const e=bt(t),r=we(t);return E.hooks.handleError({error:t,event:a,status:e,message:r})??{message:r}}function Be(t,a={}){return t=new URL(gt(t)),t.origin!==Dt?Promise.reject(new Error("goto: invalid URL")):Gt(t,a,0)}function Te(t){if(typeof t=="function")Z.push(t);else{const{href:a}=new URL(t,location.href);Z.push(e=>e.href===a)}}function Oe(){var a;history.scrollRestoration="manual",addEventListener("beforeunload",e=>{let r=!1;if(jt(),!H){const n=Ut(g,void 0,null,"leave"),o={...n.navigation,cancel:()=>{r=!0,n.reject(new Error("navigation cancelled"))}};Mt.forEach(s=>s(o))}r?(e.preventDefault(),e.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&jt()}),(a=navigator.connection)!=null&&a.saveData||Ie(),U.addEventListener("click",async e=>{if(e.button||e.which!==1||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.defaultPrevented)return;const r=$t(e.composedPath()[0],U);if(!r)return;const{url:n,external:o,target:s,download:i}=ut(r,L,E.hash);if(!n)return;if(s==="_parent"||s==="_top"){if(window.parent!==window)return}else if(s&&s!=="_self")return;const c=X(r);if(!(r instanceof SVGAElement)&&n.protocol!==location.protocol&&!(n.protocol==="https:"||n.protocol==="http:")||i)return;const[h,u]=(E.hash?n.hash.replace(/^#/,""):n.href).split("#"),w=h===it(location);if(o||c.reload&&(!w||!u)){Qt({url:n,type:"link",event:e})?H=!0:e.preventDefault();return}if(u!==void 0&&w){const[,f]=g.url.href.split("#");if(f===u){if(e.preventDefault(),u===""||u==="top"&&r.ownerDocument.getElementById("top")===null)scrollTo({top:0});else{const d=r.ownerDocument.getElementById(decodeURIComponent(u));d&&(d.scrollIntoView(),d.focus())}return}if(K=!0,Et(b),t(n),!c.replace_state)return;K=!1}e.preventDefault(),await new Promise(f=>{requestAnimationFrame(()=>{setTimeout(f,0)}),setTimeout(f,100)}),await D({type:"link",url:n,keepfocus:c.keepfocus,noscroll:c.noscroll,replace_state:c.replace_state??n.href===location.href,event:e})}),U.addEventListener("submit",e=>{if(e.defaultPrevented)return;const r=HTMLFormElement.prototype.cloneNode.call(e.target),n=e.submitter;if(((n==null?void 0:n.formTarget)||r.target)==="_blank"||((n==null?void 0:n.formMethod)||r.method)!=="get")return;const i=new URL((n==null?void 0:n.hasAttribute("formaction"))&&(n==null?void 0:n.formAction)||r.action);if(_t(i,L,!1))return;const c=e.target,l=X(c);if(l.reload)return;e.preventDefault(),e.stopPropagation();const h=new FormData(c,n);i.search=new URLSearchParams(h).toString(),D({type:"form",url:i,keepfocus:l.keepfocus,noscroll:l.noscroll,replace_state:l.replace_state??i.href===location.href,event:e})}),addEventListener("popstate",async e=>{var r;if(!mt){if((r=e.state)!=null&&r[N]){const n=e.state[N];if(O={},n===b)return;const o=I[n],s=e.state[Nt]??{},i=new URL(e.state[re]??location.href),c=e.state[B],l=g.url?it(location)===it(g.url):!1;if(c===R&&(Ht||l)){s!==x.state&&(x.state=s),t(i),I[b]=C(),o&&scrollTo(o.x,o.y),b=n;return}const u=n-b;await D({type:"popstate",url:i,popped:{state:s,scroll:o,delta:u},accept:()=>{b=n,R=c},block:()=>{history.go(-u)},nav_token:O,event:e})}else if(!K){const n=new URL(location.href);t(n),E.hash&&location.reload()}}}),addEventListener("hashchange",()=>{K&&(K=!1,history.replaceState({...history.state,[N]:++b,[B]:R},"",location.href))});for(const e of document.querySelectorAll("link"))ve.has(e.rel)&&(e.href=e.href);addEventListener("pageshow",e=>{e.persisted&&P.navigating.set(ft.current=null)});function t(e){g.url=x.url=e,P.page.set(At(x)),P.page.notify()}}async function Ce(t,{status:a=200,error:e,node_ids:r,params:n,route:o,server_route:s,data:i,form:c}){Vt=!0;const l=new URL(location.href);let h;({params:n={},route:o={id:null}}=await ot(l,!1)||{}),h=kt.find(({id:f})=>f===o.id);let u,w=!0;try{const f=r.map(async(_,m)=>{const p=i[m];return p!=null&&p.uses&&(p.uses=je(p.uses)),Rt({loader:E.nodes[_],url:l,params:n,route:o,parent:async()=>{const y={};for(let S=0;S{const i=history.state;mt=!0,location.replace(new URL(`#${r}`,location.href)),history.replaceState(i,"",t),a&&scrollTo(o,s),mt=!1})}else{const o=document.body,s=o.getAttribute("tabindex");o.tabIndex=-1,o.focus({preventScroll:!0,focusVisible:!1}),s!==null?o.setAttribute("tabindex",s):o.removeAttribute("tabindex")}const n=getSelection();if(n&&n.type!=="None"){const o=[];for(let s=0;s{if(n.rangeCount===o.length){for(let s=0;s{o=u,s=w});return i.catch(()=>{}),{navigation:{from:{params:t.params,route:{id:((l=t.route)==null?void 0:l.id)??null},url:t.url,scroll:C()},to:e&&{params:(a==null?void 0:a.params)??null,route:{id:((h=a==null?void 0:a.route)==null?void 0:h.id)??null},url:e,scroll:n},willUnload:!a,type:r,complete:i},fulfil:o,reject:s}}function At(t){return{data:t.data,error:t.error,form:t.form,params:t.params,route:t.route,state:t.state,status:t.status,url:t.url}}function Ne(t){const a=new URL(t);return a.hash=decodeURIComponent(t.hash),a}function te(t){let a;if(E.hash){const[,,e]=t.hash.split("#",3);a=e??""}else a=t.hash.slice(1);return decodeURIComponent(a)}export{Fe as a,Be as g,P as s}; diff --git a/apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.br b/apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.br new file mode 100644 index 0000000000000000000000000000000000000000..fcf318493a092fb1f4beea449765c766e93cd9f6 GIT binary patch literal 7639 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 Fs&B181*QN1 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.gz b/apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..150db2feabbf3a45e69d2ff4a85ac4e4b101a9ae GIT binary patch literal 8429 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.s);if(t){let n=0,s={};const _=h(()=>{let l=!1;const r=a.s;for(const o in r)r[o]!==s[o]&&(s[o]=r[o],l=!0);return l&&n++,n});f=()=>p(_)}e.b.length&&d(()=>{u(a,f),i(e.b)}),c(()=>{const n=m(()=>e.m.map(b));return()=>{for(const s of n)typeof s=="function"&&s()}}),e.a.length&&c(()=>{u(a,f),i(e.a)})}function u(t,a){if(t.l.s)for(const e of t.l.s)p(e);a()}k();export{x as i}; +import{az as g,aA as d,aB as c,v as m,aC as i,aD as b,g as p,aE as v,z as h,aF as k}from"./CpWkWWOo.js";function x(t=!1){const a=g,e=a.l.u;if(!e)return;let f=()=>v(a.s);if(t){let n=0,s={};const _=h(()=>{let l=!1;const r=a.s;for(const o in r)r[o]!==s[o]&&(s[o]=r[o],l=!0);return l&&n++,n});f=()=>p(_)}e.b.length&&d(()=>{u(a,f),i(e.b)}),c(()=>{const n=m(()=>e.m.map(b));return()=>{for(const s of n)typeof s=="function"&&s()}}),e.a.length&&c(()=>{u(a,f),i(e.a)})}function u(t,a){if(t.l.s)for(const e of t.l.s)p(e);a()}k();export{x as i}; diff --git a/apps/dashboard/build/_app/immutable/chunks/BUoSzNdg.js.br b/apps/dashboard/build/_app/immutable/chunks/BUoSzNdg.js.br new file mode 100644 index 0000000000000000000000000000000000000000..762f9297bc2bd60a82d71be354bbcdbd7244b4ac GIT binary patch literal 315 zcmV-B0mS|r76JgA1>6u-9_k)0!xxePstej2z^<|Nj5*{%o| zI5FPoViF2ieF|dVwb{fES{qY!{@kW1BG(ej)VNOi z2}St81A1K#+LGZ~Zk)_N_jb2jzDaP0ats3WGXl2v8CIdduWd)M#*S*p0-&5zDHx>Q NNw6O}{LWHmZWkrxm4*NS literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/BUoSzNdg.js.gz b/apps/dashboard/build/_app/immutable/chunks/BUoSzNdg.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..d409518275bfc9e9f0303f5d5c796a0f87c2d775 GIT binary patch literal 342 zcmV-c0jd5UiwFP!000026J?SyZ^IxEh4=mn;=$sS6HRACr8aHXjv1;dx;WTzV}k`a zN^AMQ7wje(I(_gC-a8%CZD(B==!cPK71C4U9_cx;z*9ntv`(y%UJ`d$C3Hxyi6@*c zACTS>k7MafS$?^b;IOqRVVLTwE@^Pm~Vj>8#0fvs|JXLC#Hdd<&x%JJD!Ug+re2=ggiHmVh;nH5dVlS)LP( zYNxFht!Sy^JGcZ)hiaYAASs$3IY@n;zQK8V=271L0^wfTCl>+$0Mvw=_W%F@ literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js b/apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js deleted file mode 100644 index cf39b16..0000000 --- a/apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js +++ /dev/null @@ -1 +0,0 @@ -import{J as T,K as m,P as D,g as P,c as b,h as B,L as M,M as N,N as U,O as Y,A as h,Q as x,R as $,T as q,U as w,V as z,W as C,S as G,X as J}from"./CvjSAYrz.js";import{c as K}from"./D81f-o_I.js";function W(r,a,t,s){var O;var f=!x||(t&$)!==0,v=(t&Y)!==0,o=(t&C)!==0,n=s,c=!0,g=()=>(c&&(c=!1,n=o?h(s):s),n),u;if(v){var A=G in r||J in r;u=((O=T(r,a))==null?void 0:O.set)??(A&&a in r?e=>r[a]=e:void 0)}var _,I=!1;v?[_,I]=K(()=>r[a]):_=r[a],_===void 0&&s!==void 0&&(_=g(),u&&(f&&m(),u(_)));var i;if(f?i=()=>{var e=r[a];return e===void 0?g():(c=!0,e)}:i=()=>{var e=r[a];return e!==void 0&&(n=void 0),e===void 0?n:e},f&&(t&D)===0)return i;if(u){var E=r.$$legacy;return(function(e,S){return arguments.length>0?((!f||!S||E||I)&&u(S?i():e),e):i()})}var l=!1,d=((t&q)!==0?w:z)(()=>(l=!1,i()));v&&P(d);var L=N;return(function(e,S){if(arguments.length>0){const R=S?P(d):f&&v?b(e):e;return B(d,R),l=!0,n!==void 0&&(n=R),e}return M&&l||(L.f&U)!==0?d.v:P(d)})}export{W as p}; diff --git a/apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js.br b/apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js.br deleted file mode 100644 index 6abdd863c2d65264b6f757ab481ee9f9cc1fb5eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 521 zcmV+k0`~nIz5^hP!nWD-5|_(b%aA0=hzLGypCYnJ77djBxAY_XidsrM0a74@rJ$4vzc1{=ax4Xl! z_bK0XE_Qs7-*yus@iS&hjQ&lXm5t|#7-8=zZ9cd-57oJvgFl$L@IM7Na&&9>gm00& z5C++^ShvH^Tn)iMea>GH_?fGt+h{Qzl_PZFP3fBcBrP3}hNKU>sncP{^bD}_9!gTO zb4lsS^{iH_gL84!E$9UK7@TT!^Y#Ao=u4?NwfydRF)>%4e&2+eN8ct;)uigx=s8{u z+h`?-vx#l+YP=-HYe^PFJJR{0N?b*P9%3y8$OfRILt!znq2H<&k`~ahBWjh=*zCG4 znT4-1y>P)4=x+37o4021XdaI>1KWpOE^qj4WI>1`yRt66(R|6a=zMAbj{T?H?mr#; zrxOM7a@SJQLV+qN>Eg9bHCN|vxF}0owu6eru9~-9QgW3Gvd%weGt9k2G)1~58n6Do z@Sho5@7l}7VnO`=CaQ4n=;oiTP|2O3^OxTWT>a!Ci29$x{J`P>H~ByK1ueU@F5ekp LK8;_?2(Fm{GI9$j diff --git a/apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js.gz b/apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js.gz deleted file mode 100644 index 476614c7d52552c1d6784daed33f508aae7d8511..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 568 zcmV-80>}LyiwFP!000026LphaZ`v>vhVS<)LWL|_I?L$Yl<3r=AF7}&bOhE_RfSS; zAXRYMe6@q*zt6`3t<$!fJg<}E$=ddE&!h-MwYr-j9 z6K>#!FoF?b24liK^a*SDMtFw_p$k*OE6fOQ@SU)QJHiQHh1^*H*R&Ih(4D)pj>Q|;XG3_>U%7rQFVoUu>O2s`g}%?s8Q z9mF0~X!L!nQ_^Rx)|kTrJ3Uw-7kI)KjBztQHXl;C=DF~40a`%m#}TjE75aGT#M;T~ zdT8mF$oUwjNffO_W|0>yw`3yc5-RC#dU-x*iC|N*>7A*jL7f@QiBOP!l@I zr8%8~z1s7ZZ{AkeXu17nN+~GDZuzne>>5Y^wqvaSZAI)Bsm=>$f`OzKp4oOKpSW?M z4uPHWB}@b)l&t diff --git a/apps/dashboard/build/_app/immutable/chunks/BeMFXnHE.js b/apps/dashboard/build/_app/immutable/chunks/BeMFXnHE.js new file mode 100644 index 0000000..529c227 --- /dev/null +++ b/apps/dashboard/build/_app/immutable/chunks/BeMFXnHE.js @@ -0,0 +1 @@ +import{H as a,v as m,aH as q,aC as x}from"./CpWkWWOo.js";function _(e,t,n){if(e==null)return t(void 0),n&&n(void 0),a;const r=m(()=>e.subscribe(t,n));return r.unsubscribe?()=>r.unsubscribe():r}const f=[];function z(e,t){return{subscribe:A(e,t).subscribe}}function A(e,t=a){let n=null;const r=new Set;function i(u){if(q(e,u)&&(e=u,n)){const o=!f.length;for(const s of r)s[1](),f.push(s,e);if(o){for(let s=0;s{r.delete(s),r.size===0&&n&&(n(),n=null)}}return{set:i,update:b,subscribe:l}}function k(e,t,n){const r=!Array.isArray(e),i=r?[e]:e;if(!i.every(Boolean))throw new Error("derived() expects stores as input, got a falsy value");const b=t.length<2;return z(n,(l,u)=>{let o=!1;const s=[];let d=0,p=a;const y=()=>{if(d)return;p();const c=t(r?s[0]:s,l,u);b?l(c):p=typeof c=="function"?c:a},h=i.map((c,g)=>_(c,w=>{s[g]=w,d&=~(1<{d|=1<t=n)(),t}export{k as d,B as g,_ as s,A as w}; diff --git a/apps/dashboard/build/_app/immutable/chunks/BeMFXnHE.js.br b/apps/dashboard/build/_app/immutable/chunks/BeMFXnHE.js.br new file mode 100644 index 0000000000000000000000000000000000000000..9dea1054322a4c1ec45894ff6cf5555c6d10ae1c GIT binary patch literal 611 zcmV-p0-XIDW(0tY)JFAI7Hz89o@HW^e;#mw>nIs1eg9EultjsLAr*pl=jYYa+WcQr z|NDRkMiIF#thAdQ4hMLkiztiQC4CRoVj@TYJ5TS*h%&S-BWp4-`&+{&eV^!Ey&8_5 zdXpb66Wa(L<*u*_qRgn;W2X4=hTB&W4&uA98_PNE9D20*^Gza#^v#9&$o z!;Ndj-*r0fQw7XIA~n-+@hK8K(j$X%>fXp6{71MsDfI#$R5m$S8OmwFNEzhpPW`iy zex!qqx~G4^(gw8#%Nuftr#=dvFPn>evW*W=of7366;O)FCm=PWUPQ=FjA4(bE^+2f z!sA?K1m?>PPq8WFvlxGZ$=)xQN7SR{1^5oeF7ZNVqo==FoOkIN@ zg;$$+gn6PhIF8U!iRZIHqQ?{X(Nh>s0ps0+G4IMKAmJ9rl#s95m~}L|C9;w-f3^zc z<@iIxEnNP8Kcf>9XWrRyxGU^uW}z}JyFco2=+XO?H4ZV(gWsv4MEvi%iL2iM5C>Eb z_cKNP3w7d}*rlzH%BaSy=1S)Ii6^N`_aoM`pmvcny7HuwJ~+zrG-xC9_C0r xASvcgY3zwUf}JMhhy^~qA8~ve*&!gsWcPCrxI}7t47c>10TFpG{jVjp;Nl&Nxau8WzwDZjJ9RTt> znYecC3ai!k;E(@8SLWA*xd11<`x$KcgufZwQ~7tmP3fQ^BlABme2Z6Gpq+%(1Jv~ zW@~84#L3Py_$r+9tHh!#!6DhisrTR?pNDxg_n>HvA0GlK;!za8vq>ofMfv6ZELa;$ z!cZsOu1ua+@DeIn|o`;F;Q-avAN=QxsrJ*qf|F4k$Y*6 z@L)_WMUdTZtvRsh(obuHijz`WwU;FzlW&bIykpKAD_z`XrJL3h+ZfLTt3>UNY%l6o zPVnsan)|c5iyxy(@1P0l;B^oodK4U4!TSEw_B;grhmrkQAHR3a o?>yHS3Va_Vj(?DsC~ip)F>L5L21oZX9Qy3rf1W|Lpl1XC08Vd6(f|Me literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/Bhad70Ss.js.br b/apps/dashboard/build/_app/immutable/chunks/Bhad70Ss.js.br deleted file mode 100644 index ee058da2fd1a8017b59a4ef50c86771315effebb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 184 zcmV;p07w5D{r~`+1$Jzi-n1PeRuAKDESj2^>T}R_I4Z65Shvc)>0Ci mxYaP~GF#WoHpoj|*#^-ur*5pgtMbK*VE97uqdr<>$`c~Qi diff --git a/apps/dashboard/build/_app/immutable/chunks/Bhad70Ss.js.gz b/apps/dashboard/build/_app/immutable/chunks/Bhad70Ss.js.gz deleted file mode 100644 index dc811ec274844dc9ccbe68f02be014d49f02ecbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmV;&06702iwFP!000026J^iA3W7io2H<;7v3ihQknNrd)atv`ETh-PX3TIgF_r#5Z#O4ya&IQK6dr78|pb{AjF%2>6GjPg`_TU+0IMza? zqDYc4rFU-58lk9a_*XO5dsDQpk--@DW&lP5eCQZ4@g008M; BTP^?q diff --git a/apps/dashboard/build/_app/immutable/chunks/Casl2yrL.js b/apps/dashboard/build/_app/immutable/chunks/BjdL4Pm2.js similarity index 97% rename from apps/dashboard/build/_app/immutable/chunks/Casl2yrL.js rename to apps/dashboard/build/_app/immutable/chunks/BjdL4Pm2.js index 46dcff7..809f3b1 100644 --- a/apps/dashboard/build/_app/immutable/chunks/Casl2yrL.js +++ b/apps/dashboard/build/_app/immutable/chunks/BjdL4Pm2.js @@ -1 +1 @@ -import{w as S,g as T}from"./DfQhL-hC.js";import{e as R}from"./CtkE7HV2.js";import{E as u}from"./DzfRjky4.js";const M=4,x=1500;function F(){const{subscribe:y,update:i}=S([]);let m=1,b=0;const d=new Map,a=new Map,l=new Map;function f(e,o){l.set(e,Date.now());const t=setTimeout(()=>{d.delete(e),l.delete(e),g(e)},o);d.set(e,t)}function w(e){const o=m++,t=Date.now(),s={id:o,createdAt:t,...e};i(n=>{const r=[s,...n];return r.length>M?r.slice(0,M):r}),f(o,e.dwellMs)}function g(e){const o=d.get(e);o&&(clearTimeout(o),d.delete(e)),a.delete(e),l.delete(e),i(t=>t.filter(s=>s.id!==e))}function C(e,o){const t=d.get(e);if(!t)return;clearTimeout(t),d.delete(e);const s=l.get(e)??Date.now(),n=Date.now()-s,r=Math.max(200,o-n);a.set(e,{remaining:r})}function D(e){const o=a.get(e);o&&(a.delete(e),f(e,o.remaining))}function N(){for(const e of d.values())clearTimeout(e);d.clear(),a.clear(),l.clear(),i(()=>[])}function _(e){const o=u[e.type]??"#818CF8",t=e.data;switch(e.type){case"DreamCompleted":{const s=Number(t.memories_replayed??0),n=Number(t.connections_found??0),r=Number(t.insights_generated??0),p=Number(t.duration_ms??0),c=[];return c.push(`Replayed ${s} ${s===1?"memory":"memories"}`),n>0&&c.push(`${n} new connection${n===1?"":"s"}`),r>0&&c.push(`${r} insight${r===1?"":"s"}`),{type:e.type,title:"Dream consolidated",body:`${c.join(" · ")} in ${(p/1e3).toFixed(1)}s`,color:o,dwellMs:7e3}}case"ConsolidationCompleted":{const s=Number(t.nodes_processed??0),n=Number(t.decay_applied??0),r=Number(t.embeddings_generated??0),p=Number(t.duration_ms??0),c=[];return n>0&&c.push(`${n} decayed`),r>0&&c.push(`${r} embedded`),{type:e.type,title:"Consolidation swept",body:`${s} node${s===1?"":"s"}${c.length?" · "+c.join(" · "):""} in ${(p/1e3).toFixed(1)}s`,color:o,dwellMs:6e3}}case"ConnectionDiscovered":{const s=Date.now();if(s-b0?`suppression #${s} · Rac1 cascade ~${n} neighbors`:`suppression #${s}`,color:o,dwellMs:5500}}case"MemoryUnsuppressed":{const s=Number(t.remaining_count??0);return{type:e.type,title:"Recovered",body:s>0?`${s} suppression${s===1?"":"s"} remain`:"fully unsuppressed",color:o,dwellMs:5e3}}case"Rac1CascadeSwept":{const s=Number(t.seeds??0),n=Number(t.neighbors_affected??0);return{type:e.type,title:"Rac1 cascade",body:`${s} seed${s===1?"":"s"} · ${n} dendritic spine${n===1?"":"s"} pruned`,color:o,dwellMs:6e3}}case"MemoryDeleted":return{type:e.type,title:"Memory deleted",body:String(t.id??"").slice(0,8),color:o,dwellMs:4e3};case"Heartbeat":case"SearchPerformed":case"RetentionDecayed":case"ActivationSpread":case"ImportanceScored":case"MemoryCreated":case"MemoryUpdated":case"DreamStarted":case"DreamProgress":case"ConsolidationStarted":case"Connected":return null;default:return null}}let h=null;return R.subscribe(e=>{if(e.length===0)return;const o=[];for(const t of e){if(t===h)break;o.push(t)}if(o.length!==0){h=e[0];for(let t=o.length-1;t>=0;t--){const s=_(o[t]);s&&w(s)}}}),{subscribe:y,dismiss:g,clear:N,pauseDwell:C,resumeDwell:D,push:w}}const $=F();function O(){[{type:"DreamCompleted",title:"Dream consolidated",body:"Replayed 127 memories · 43 new connections · 5 insights in 2.4s",color:u.DreamCompleted,dwellMs:7e3},{type:"ConnectionDiscovered",title:"Bridge discovered",body:"semantic · weight 0.87",color:u.ConnectionDiscovered,dwellMs:4500},{type:"MemorySuppressed",title:"Forgetting",body:"suppression #2 · Rac1 cascade ~8 neighbors",color:u.MemorySuppressed,dwellMs:5500},{type:"ConsolidationCompleted",title:"Consolidation swept",body:"892 nodes · 156 decayed · 48 embedded in 1.1s",color:u.ConsolidationCompleted,dwellMs:6e3}].forEach((i,m)=>{setTimeout(()=>{$.push(i)},m*800)}),T($)}export{O as f,$ as t}; +import{w as S,g as T}from"./BeMFXnHE.js";import{e as R}from"./MAY1QfFZ.js";import{E as u}from"./DzfRjky4.js";const M=4,x=1500;function F(){const{subscribe:y,update:i}=S([]);let m=1,b=0;const d=new Map,a=new Map,l=new Map;function f(e,o){l.set(e,Date.now());const t=setTimeout(()=>{d.delete(e),l.delete(e),g(e)},o);d.set(e,t)}function w(e){const o=m++,t=Date.now(),s={id:o,createdAt:t,...e};i(n=>{const r=[s,...n];return r.length>M?r.slice(0,M):r}),f(o,e.dwellMs)}function g(e){const o=d.get(e);o&&(clearTimeout(o),d.delete(e)),a.delete(e),l.delete(e),i(t=>t.filter(s=>s.id!==e))}function C(e,o){const t=d.get(e);if(!t)return;clearTimeout(t),d.delete(e);const s=l.get(e)??Date.now(),n=Date.now()-s,r=Math.max(200,o-n);a.set(e,{remaining:r})}function D(e){const o=a.get(e);o&&(a.delete(e),f(e,o.remaining))}function N(){for(const e of d.values())clearTimeout(e);d.clear(),a.clear(),l.clear(),i(()=>[])}function _(e){const o=u[e.type]??"#818CF8",t=e.data;switch(e.type){case"DreamCompleted":{const s=Number(t.memories_replayed??0),n=Number(t.connections_found??0),r=Number(t.insights_generated??0),p=Number(t.duration_ms??0),c=[];return c.push(`Replayed ${s} ${s===1?"memory":"memories"}`),n>0&&c.push(`${n} new connection${n===1?"":"s"}`),r>0&&c.push(`${r} insight${r===1?"":"s"}`),{type:e.type,title:"Dream consolidated",body:`${c.join(" · ")} in ${(p/1e3).toFixed(1)}s`,color:o,dwellMs:7e3}}case"ConsolidationCompleted":{const s=Number(t.nodes_processed??0),n=Number(t.decay_applied??0),r=Number(t.embeddings_generated??0),p=Number(t.duration_ms??0),c=[];return n>0&&c.push(`${n} decayed`),r>0&&c.push(`${r} embedded`),{type:e.type,title:"Consolidation swept",body:`${s} node${s===1?"":"s"}${c.length?" · "+c.join(" · "):""} in ${(p/1e3).toFixed(1)}s`,color:o,dwellMs:6e3}}case"ConnectionDiscovered":{const s=Date.now();if(s-b0?`suppression #${s} · Rac1 cascade ~${n} neighbors`:`suppression #${s}`,color:o,dwellMs:5500}}case"MemoryUnsuppressed":{const s=Number(t.remaining_count??0);return{type:e.type,title:"Recovered",body:s>0?`${s} suppression${s===1?"":"s"} remain`:"fully unsuppressed",color:o,dwellMs:5e3}}case"Rac1CascadeSwept":{const s=Number(t.seeds??0),n=Number(t.neighbors_affected??0);return{type:e.type,title:"Rac1 cascade",body:`${s} seed${s===1?"":"s"} · ${n} dendritic spine${n===1?"":"s"} pruned`,color:o,dwellMs:6e3}}case"MemoryDeleted":return{type:e.type,title:"Memory deleted",body:String(t.id??"").slice(0,8),color:o,dwellMs:4e3};case"Heartbeat":case"SearchPerformed":case"RetentionDecayed":case"ActivationSpread":case"ImportanceScored":case"MemoryCreated":case"MemoryUpdated":case"DreamStarted":case"DreamProgress":case"ConsolidationStarted":case"Connected":return null;default:return null}}let h=null;return R.subscribe(e=>{if(e.length===0)return;const o=[];for(const t of e){if(t===h)break;o.push(t)}if(o.length!==0){h=e[0];for(let t=o.length-1;t>=0;t--){const s=_(o[t]);s&&w(s)}}}),{subscribe:y,dismiss:g,clear:N,pauseDwell:C,resumeDwell:D,push:w}}const $=F();function O(){[{type:"DreamCompleted",title:"Dream consolidated",body:"Replayed 127 memories · 43 new connections · 5 insights in 2.4s",color:u.DreamCompleted,dwellMs:7e3},{type:"ConnectionDiscovered",title:"Bridge discovered",body:"semantic · weight 0.87",color:u.ConnectionDiscovered,dwellMs:4500},{type:"MemorySuppressed",title:"Forgetting",body:"suppression #2 · Rac1 cascade ~8 neighbors",color:u.MemorySuppressed,dwellMs:5500},{type:"ConsolidationCompleted",title:"Consolidation swept",body:"892 nodes · 156 decayed · 48 embedded in 1.1s",color:u.ConsolidationCompleted,dwellMs:6e3}].forEach((i,m)=>{setTimeout(()=>{$.push(i)},m*800)}),T($)}export{O as f,$ as t}; diff --git a/apps/dashboard/build/_app/immutable/chunks/BjdL4Pm2.js.br b/apps/dashboard/build/_app/immutable/chunks/BjdL4Pm2.js.br new file mode 100644 index 0000000000000000000000000000000000000000..30bed5644ca4ff318a44168e7aa9e37ff677032e GIT binary patch literal 1513 zcmVs@lu1C8{X3nnQDtt81cyU)?axaus(Mmkk-3Yp>{UMay_GU2_criMSner2%w6!juR@f&xF(Ltv)IVi@p%Cm<1 zPyk`A4}`A4YDan3Xo`C)22`IN{UZrpNJ{T;w3HN-Ro<>jcO+`{CwRK2_ zPcC~KP@m6j%tSSmd#-QkH-9R|UryCqE!B|k7jDvmyw~79SQi01<&brgKi2OvHFo!Z zSL>dGV#xHwgktH#$^inq8^99sL81cXVfoScV^6u)QjZWZ#H+1hn%-;zX7{21ssJXz zJ}`Pzd3y1^z9=v_ALu;U^Vm{vj6X3}pK8V!biD?$k}PJ&yckbHA{VS7#;yXelMG|( zU;vc42kO|^xmH~Uap*cxFPs}20l zDCB6Gq^ldL)D!Eb3RTA0nsSCbHdLNvbDMnPWfa>9r&MHBtDyT|*vYn)9cynhHsE{w^=#uPL|h1AfLul`7@4TNq{|0D_RVyt6)Gl+A!30_AxvTgnxT%SchG%FzvA6 zT843kVXDI_Go*WAF1AKWT@+G+S-E)%@rKTYXQX`y+*ND0{f-uw)m{%J7o0N<*i=QZM2*;VWdB>g6T4HMRAKVpo*Ym7G3u7K5fxZQPe4wRaq)~qU1 zT7%8W%%U*;Ft=if!0l#Vqkw5=_ P2s`X`hhw7TtvqG{R_N*P literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/BjdL4Pm2.js.gz b/apps/dashboard/build/_app/immutable/chunks/BjdL4Pm2.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..78fece5f53f1210e379543267f30042b802416e8 GIT binary patch literal 1645 zcmV-z29o(7iwFP!000026RlWVZ`(E$e&4T9)hv)&MYYqU_2el=8#m}4+;(vbYzqQM zmX2(uk|>Z=9naAI*53Eab|~szdq(6qp@y3 zdkvF|-;%d)>|3r6i6R6^aamDJUj5$xHN5zvP4PxjWEI8u&+zj0^ZKNq@M*$@HgQj^ zJGXz@>kY#!@dcrYc43&C;&j8aIrkZvgR{1>H1GsCBzLFA)wMZ{Kxnbsx8`oIkx61I>hCnC{soumeDOV1Q{w zt@Q#wa%46PN@l{$YdI@CRCZ|8jh{ZXgxkonxVs^NLoJ^HZU(P}BP`ptAs-SWL6Pbr zbFaAEPOgUxM8*=0*%2fQu{@iMn9U>NgVD1lro(d63Jq$39jqXVCcLG|qOD0_FQlsG zkRBcyegqz?Or@sPGSsxZuUJhC;hqUQB#{7SaQBScBzWYyc&Cwhu28NJt)-ICcqB|^ z%&;R~bi|jw;BHjj9F1D&B`qkAxW(LwCzf{X-5JNdo<)xmbLf>W*)WJbl8|H}F=`YX zw?XmRptS8Sg2k>`v@LvxVH#3qC?25EPz&rYUX%gHSn8MtGD3NJP!I8<0?LPcj40=$txp$wmeG)oi#YY0ff$zmz^Yyk-{8O8-g z+E4@;ZX<(P%!?!6y{aSGx6_O-jho9-ymqkRx%_Zlw?EPg_13zhS93Uc&P{FC2AVvqtsr zbyz|J^j6BK51jA1D*)eH&%88^2<*5D@H+@Fg8!$pc5yGnL9iELC9OEzhiS)TjjtdT z4X79c($G2%ly@Z9s_=~z+)umUJG%a#@PE<9zl@zR;XeHWtb=}2XJqN(NAsWW%nFk% ziiUHSm!&Fkr-C8Eoy?g@yD@1al6=-X9$A45LJ4$<@jj$pGZHL73mVO8oX`bmx#EIm zv)bTeGvBrM1UqbL@T5qr57?6F*8&YzSQG>#(t-yxRNS<*Vpr-{UzZ-?Px`%H8APio86PG2mnI6x-E%eXZoG{Z&>;jFUNK{Knb6vuo_>wy~cQey_Q8hir_!$CgXz zhBKF@6xz3R+o}MX5^>|`A?Dp$%i0?48c^rA1mj#`F)b?1K4$?0eA_`aWHT=eF`HGv zyw9o@?45ch*>78eZYs-Y5-=i&ukn;5u+_gXud)Q|=soqTN|v&1d_y8AN~K_3vIttI z>t;Pt4$R#QK$*ir=3AUv#2g1#-6?)g@wdPH01W4$SZbk=uX1dxT1C123Jc?xqV!ME zeO|TwOYvgx5+9~MWi_?Z`dm%PoxM+K(Aq2d^i-f;-7Tzh3mGKkUZ?eR$;(F2fT#+5 z0HK#fqP>^r^6{~Bi}P~-(ykvX2H^aT%>v4fg%0i26K^@tVP|b-M>t0>slL7W`4C;@@ftkZy@z=w9`PV~e9mp?{4}bU{throw TypeError(t)};var ke=(t,e,r)=>e in t?Me(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r;var U=(t,e,r)=>ke(t,typeof e!="symbol"?e+"":e,r),re=(t,e,r)=>e.has(t)||ue("Cannot "+r);var s=(t,e,r)=>(re(t,e,"read from private field"),r?r.call(t):e.get(t)),c=(t,e,r)=>e.has(t)?ue("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,r),n=(t,e,r,a)=>(re(t,e,"write to private field"),a?a.call(t,r):e.set(t,r),r),p=(t,e,r)=>(re(t,e,"access private method"),r);import{aQ as Ie,g as Te,X as Le,v as Ve,aR as _e,Y as q,ao as we,U as M,N as k,o as B,aS as pe,b as xe,ab as Be,ad as Ce,aT as ge,ai as Y,J as me,aU as se,ar as ie,ay as He,aV as ve,aW as We,aX as ye,aY as Pe,aZ as qe,a_ as G,a$ as Z,b0 as be,b1 as ze,b2 as Re,az as Se,ag as Ue,aw as ae,T as K,n as $e,ae as je,b3 as $,E as Je,M as Qe,b4 as Xe,b5 as Ge,F as Ze,b6 as Ke,G as et,b7 as ne,V as tt,O as Ne,ax as rt,Q as st,b8 as fe,R as j,b9 as it,av as at,ba as nt,al as ft,p as ht,af as ot,bb as lt,a as ct}from"./CpWkWWOo.js";import{d as dt}from"./CHOnp4oo.js";function ut(t){let e=0,r=we(0),a;return()=>{Ie()&&(Te(r),Le(()=>(e===0&&(a=Ve(()=>t(()=>_e(r)))),e+=1,()=>{q(()=>{e-=1,e===0&&(a==null||a(),a=void 0,_e(r))})})))}}var _t=Je|Qe;function pt(t,e,r,a){new gt(t,e,r,a)}var E,z,m,L,g,R,T,w,S,V,A,C,H,W,N,ee,o,De,Ae,Oe,he,Q,X,oe;class gt{constructor(e,r,a,h){c(this,o);U(this,"parent");U(this,"is_pending",!1);U(this,"transform_error");c(this,E);c(this,z,k?M:null);c(this,m);c(this,L);c(this,g);c(this,R,null);c(this,T,null);c(this,w,null);c(this,S,null);c(this,V,0);c(this,A,0);c(this,C,!1);c(this,H,new Set);c(this,W,new Set);c(this,N,null);c(this,ee,ut(()=>(n(this,N,we(s(this,V))),()=>{n(this,N,null)})));var i;n(this,E,e),n(this,m,r),n(this,L,f=>{var u=B;u.b=this,u.f|=pe,a(f)}),this.parent=B.b,this.transform_error=h??((i=this.parent)==null?void 0:i.transform_error)??(f=>f),n(this,g,xe(()=>{if(k){const f=s(this,z);Be();const u=f.data===Ce;if(f.data.startsWith(ge)){const d=JSON.parse(f.data.slice(ge.length));p(this,o,Ae).call(this,d)}else u?p(this,o,Oe).call(this):p(this,o,De).call(this)}else p(this,o,he).call(this)},_t)),k&&n(this,E,M)}defer_effect(e){qe(e,s(this,H),s(this,W))}is_rendered(){return!this.is_pending&&(!this.parent||this.parent.is_rendered())}has_pending_snippet(){return!!s(this,m).pending}update_pending_count(e){p(this,o,oe).call(this,e),n(this,V,s(this,V)+e),!(!s(this,N)||s(this,C))&&(n(this,C,!0),q(()=>{n(this,C,!1),s(this,N)&&Ue(s(this,N),s(this,V))}))}get_effect_pending(){return s(this,ee).call(this),Te(s(this,N))}error(e){var r=s(this,m).onerror;let a=s(this,m).failed;if(!r&&!a)throw e;s(this,R)&&(ae(s(this,R)),n(this,R,null)),s(this,T)&&(ae(s(this,T)),n(this,T,null)),s(this,w)&&(ae(s(this,w)),n(this,w,null)),k&&(K(s(this,z)),$e(),K(je()));var h=!1,i=!1;const f=()=>{if(h){Ge();return}h=!0,i&&Xe(),s(this,w)!==null&&ie(s(this,w),()=>{n(this,w,null)}),p(this,o,X).call(this,()=>{se.ensure(),p(this,o,he).call(this)})},u=l=>{try{i=!0,r==null||r(l,f),i=!1}catch(d){$(d,s(this,g)&&s(this,g).parent)}a&&n(this,w,p(this,o,X).call(this,()=>{se.ensure();try{return Y(()=>{var d=B;d.b=this,d.f|=pe,a(s(this,E),()=>l,()=>f)})}catch(d){return $(d,s(this,g).parent),null}}))};q(()=>{var l;try{l=this.transform_error(e)}catch(d){$(d,s(this,g)&&s(this,g).parent);return}l!==null&&typeof l=="object"&&typeof l.then=="function"?l.then(u,d=>$(d,s(this,g)&&s(this,g).parent)):u(l)})}}E=new WeakMap,z=new WeakMap,m=new WeakMap,L=new WeakMap,g=new WeakMap,R=new WeakMap,T=new WeakMap,w=new WeakMap,S=new WeakMap,V=new WeakMap,A=new WeakMap,C=new WeakMap,H=new WeakMap,W=new WeakMap,N=new WeakMap,ee=new WeakMap,o=new WeakSet,De=function(){try{n(this,R,Y(()=>s(this,L).call(this,s(this,E))))}catch(e){this.error(e)}},Ae=function(e){const r=s(this,m).failed;r&&n(this,w,Y(()=>{r(s(this,E),()=>e,()=>()=>{})}))},Oe=function(){const e=s(this,m).pending;e&&(this.is_pending=!0,n(this,T,Y(()=>e(s(this,E)))),q(()=>{var r=n(this,S,document.createDocumentFragment()),a=me();r.append(a),n(this,R,p(this,o,X).call(this,()=>(se.ensure(),Y(()=>s(this,L).call(this,a))))),s(this,A)===0&&(s(this,E).before(r),n(this,S,null),ie(s(this,T),()=>{n(this,T,null)}),p(this,o,Q).call(this))}))},he=function(){try{if(this.is_pending=this.has_pending_snippet(),n(this,A,0),n(this,V,0),n(this,R,Y(()=>{s(this,L).call(this,s(this,E))})),s(this,A)>0){var e=n(this,S,document.createDocumentFragment());He(s(this,R),e);const r=s(this,m).pending;n(this,T,Y(()=>r(s(this,E))))}else p(this,o,Q).call(this)}catch(r){this.error(r)}},Q=function(){this.is_pending=!1;for(const e of s(this,H))ve(e,We),ye(e);for(const e of s(this,W))ve(e,Pe),ye(e);s(this,H).clear(),s(this,W).clear()},X=function(e){var r=B,a=Re,h=Se;G(s(this,g)),Z(s(this,g)),be(s(this,g).ctx);try{return e()}catch(i){return ze(i),null}finally{G(r),Z(a),be(h)}},oe=function(e){var r;if(!this.has_pending_snippet()){this.parent&&p(r=this.parent,o,oe).call(r,e);return}n(this,A,s(this,A)+e),s(this,A)===0&&(p(this,o,Q).call(this),s(this,T)&&ie(s(this,T),()=>{n(this,T,null)}),s(this,S)&&(s(this,E).before(s(this,S)),n(this,S,null)))};const vt=["touchstart","touchmove"];function yt(t){return vt.includes(t)}const I=Symbol("events"),Fe=new Set,le=new Set;function bt(t,e,r,a={}){function h(i){if(a.capture||ce.call(e,i),!i.cancelBubble)return Ke(()=>r==null?void 0:r.call(this,i))}return t.startsWith("pointer")||t.startsWith("touch")||t==="wheel"?q(()=>{e.addEventListener(t,h,a)}):e.addEventListener(t,h,a),h}function Rt(t,e,r,a,h){var i={capture:a,passive:h},f=bt(t,e,r,i);(e===document.body||e===window||e===document||e instanceof HTMLMediaElement)&&Ze(()=>{e.removeEventListener(t,f,i)})}function St(t,e,r){(e[I]??(e[I]={}))[t]=r}function Nt(t){for(var e=0;e{throw F});throw D}}finally{t[I]=e,delete t.currentTarget,Z(x),G(P)}}}function Dt(t,e){var r=e==null?"":typeof e=="object"?e+"":e;r!==(t.__t??(t.__t=t.nodeValue))&&(t.__t=r,t.nodeValue=r+"")}function Et(t,e){return Ye(t,e)}function At(t,e){ne(),e.intro=e.intro??!1;const r=e.target,a=k,h=M;try{for(var i=tt(r);i&&(i.nodeType!==Ne||i.data!==rt);)i=st(i);if(!i)throw fe;j(!0),K(i);const f=Ye(t,{...e,anchor:i});return j(!1),f}catch(f){if(f instanceof Error&&f.message.split(` +`).some(u=>u.startsWith("https://svelte.dev/e/")))throw f;return f!==fe&&console.warn("Failed to hydrate: ",f),e.recover===!1&&it(),ne(),at(r),j(!1),Et(t,e)}finally{j(a),K(h)}}const J=new Map;function Ye(t,{target:e,anchor:r,props:a={},events:h,context:i,intro:f=!0,transformError:u}){ne();var l=void 0,d=nt(()=>{var x=r??e.appendChild(me());pt(x,{pending:()=>{}},v=>{ht({});var _=Se;if(i&&(_.c=i),h&&(a.$$events=h),k&&dt(v,null),l=t(v,a)||{},k&&(B.nodes.end=M,M===null||M.nodeType!==Ne||M.data!==ot))throw lt(),fe;ct()},u);var P=new Set,D=v=>{for(var _=0;_{var O;for(var v of P)for(const b of[e,document]){var _=J.get(b),y=_.get(v);--y==0?(b.removeEventListener(v,ce),_.delete(v),_.size===0&&J.delete(b)):_.set(v,y)}le.delete(D),x!==r&&((O=x.parentNode)==null||O.removeChild(x))}});return de.set(l,d),l}let de=new WeakMap;function Ot(t,e){const r=de.get(t);return r?(de.delete(t),r(e)):Promise.resolve()}export{St as a,Nt as d,Rt as e,At as h,Et as m,Dt as s,Ot as u}; diff --git a/apps/dashboard/build/_app/immutable/chunks/BlVfL1ME.js.br b/apps/dashboard/build/_app/immutable/chunks/BlVfL1ME.js.br new file mode 100644 index 0000000000000000000000000000000000000000..75ea48d603ab5cf38484e5f24da852c8588455ac GIT binary patch literal 3142 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 gPY3ASv<@}StL+PtDJY+U4V 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 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/DMu1Byux.js b/apps/dashboard/build/_app/immutable/chunks/BnXDGOmJ.js similarity index 61% rename from apps/dashboard/build/_app/immutable/chunks/DMu1Byux.js rename to apps/dashboard/build/_app/immutable/chunks/BnXDGOmJ.js index 8908737..227886d 100644 --- a/apps/dashboard/build/_app/immutable/chunks/DMu1Byux.js +++ b/apps/dashboard/build/_app/immutable/chunks/BnXDGOmJ.js @@ -1 +1 @@ -import{D as s,F as v,y as o,a3 as c,a7 as b,a8 as m,a9 as h,I as y}from"./CvjSAYrz.js";function _(e,r,f=!1){if(e.multiple){if(r==null)return;if(!b(r))return m();for(var a of e.options)a.selected=r.includes(i(a));return}for(a of e.options){var t=i(a);if(h(t,r)){a.selected=!0;return}}(!f||r!==void 0)&&(e.selectedIndex=-1)}function q(e){var r=new MutationObserver(()=>{_(e,e.__value)});r.observe(e,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["value"]}),c(()=>{r.disconnect()})}function p(e,r,f=r){var a=new WeakSet,t=!0;s(e,"change",u=>{var l=u?"[selected]":":checked",n;if(e.multiple)n=[].map.call(e.querySelectorAll(l),i);else{var d=e.querySelector(l)??e.querySelector("option:not([disabled])");n=d&&i(d)}f(n),v!==null&&a.add(v)}),o(()=>{var u=r();if(e===document.activeElement){var l=y??v;if(a.has(l))return}if(_(e,u,t),t&&u===void 0){var n=e.querySelector(":checked");n!==null&&(u=i(n),f(u))}e.__value=u,t=!1}),q(e)}function i(e){return"__value"in e?e.__value:e.value}export{p as b}; +import{Z as s,_ as v,W as o,F as c,a7 as b,a8 as m,a9 as h,a0 as y}from"./CpWkWWOo.js";function d(e,r,f=!1){if(e.multiple){if(r==null)return;if(!b(r))return m();for(var a of e.options)a.selected=r.includes(i(a));return}for(a of e.options){var t=i(a);if(h(t,r)){a.selected=!0;return}}(!f||r!==void 0)&&(e.selectedIndex=-1)}function q(e){var r=new MutationObserver(()=>{d(e,e.__value)});r.observe(e,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["value"]}),c(()=>{r.disconnect()})}function p(e,r,f=r){var a=new WeakSet,t=!0;s(e,"change",u=>{var l=u?"[selected]":":checked",n;if(e.multiple)n=[].map.call(e.querySelectorAll(l),i);else{var _=e.querySelector(l)??e.querySelector("option:not([disabled])");n=_&&i(_)}f(n),v!==null&&a.add(v)}),o(()=>{var u=r();if(e===document.activeElement){var l=y??v;if(a.has(l))return}if(d(e,u,t),t&&u===void 0){var n=e.querySelector(":checked");n!==null&&(u=i(n),f(u))}e.__value=u,t=!1}),q(e)}function i(e){return"__value"in e?e.__value:e.value}export{p as b}; diff --git a/apps/dashboard/build/_app/immutable/chunks/BnXDGOmJ.js.br b/apps/dashboard/build/_app/immutable/chunks/BnXDGOmJ.js.br new file mode 100644 index 0000000000000000000000000000000000000000..ca545db530a207e79c23c442bd42c121634ba738 GIT binary patch literal 516 zcmV+f0{i_N<^y14)0umg2|W0uJH_Fru9UXbPBq^Rrls)y|L>>X^8i25ca5q=CB2Py zh94(3(55KgtvwM!Qdfzs{od?S8nGT+@87++_G$_%(a{T0&}BKLc({tmjz+LWV_2ZT z{&V793UzQ+zN}wfZVI)k#Z>6?3^Y}gvp>LonS)l&VwSjKhMR_c1PzK>0u`3Nw*{Pf zWH$DS+|$aiJjTj)pR2#8(O5!^uVl!MbqgCCYrA1OT3TrV4VB&gYQ7)vpK##kyItio z-+GP*C?#lx*a7bk(Af%>mEc$WeXGe;+hCd-No%|UKtAjpQq?L9le*_{TB%g4fTkWx z^z&Zh6F;E3O;VL^V<6tF>|jpG*8OrwshnP=vSkfG09;M2jEGt(i(-1(?Dm6h zsBu8I22BDf9YHN063%V7JrW;B?@LU?>U>x|mNHgxmO+OO zsQ^G*IxSa#Iv1F^H(;}c>*_T$y8L%^)RE4|Y7y74L8j!+(UH81o699l$&3!B?Wlm`w8Q&{X^$q#YJ(JqLk@$?aEGSRA`x#?D%zD(WN GP4@tl!~#kH literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/BnXDGOmJ.js.gz b/apps/dashboard/build/_app/immutable/chunks/BnXDGOmJ.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..4aac3c20031318d54ced3326fdc56982ac197547 GIT binary patch literal 585 zcmV-P0=E4hiwFP!000026J=9PkJB&^z4I#)A0k^arab|TOob3DA%XU=he}jceyL-gk5#>-?5W^Eafzr@tc|VW+t-jjP=K#nQ)n-+hlsWO2*K;WGX7&C%dEKL$WOu zACuivF-!J&Xsl@wd-tVV9agJ*!+twdHbGZj8lBY`sHF|h=j13G46F^x%TB@QTF!M) zidgW$>M}<19k%4;XDudWV=V54%|vFJ44COsSw{qOprGu>~?%rET5gz2b?!AFE;1AH?q!Vq$nc&Gw_?P;fcSUli?!u5yRBL zat(j7AHj30!< zs=d&^0MQVOC7j}6iPmTJ8?-=+Y7f-`YDCAyz1pni>kVr~$10&ze0U6CpC86lV?W1` zB2C>TF{<}IG!H9Do7qVX?|WV`-Bv1FI;4GI?N%4(jo)(g!-Zg z{Bk5?qW(|Nby|_`g&z*_6eHsX2SSF+S@4h+F^{a%NnKYb(}7J4&#Kyg(B(=K}x$YSI`r literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js b/apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js new file mode 100644 index 0000000..26597bd --- /dev/null +++ b/apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js @@ -0,0 +1 @@ +var x=t=>{throw TypeError(t)};var B=(t,e,n)=>e.has(t)||x("Cannot "+n);var a=(t,e,n)=>(B(t,e,"read from private field"),n?n.call(t):e.get(t)),c=(t,e,n)=>e.has(t)?x("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,n);import{o as I}from"./GG5zm9kr.js";import{s as u,g as f,h as d}from"./CpWkWWOo.js";import{w as G}from"./BeMFXnHE.js";new URL("sveltekit-internal://");function ae(t,e){return t==="/"||e==="ignore"?t:e==="never"?t.endsWith("/")?t.slice(0,-1):t:e==="always"&&!t.endsWith("/")?t+"/":t}function oe(t){return t.split("%25").map(decodeURI).join("%25")}function ie(t){for(const e in t)t[e]=decodeURIComponent(t[e]);return t}function le({href:t}){return t.split("#")[0]}function W(...t){let e=5381;for(const n of t)if(typeof n=="string"){let r=n.length;for(;r;)e=e*33^n.charCodeAt(--r)}else if(ArrayBuffer.isView(n)){const r=new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let s=r.length;for(;s;)e=e*33^r[--s]}else throw new TypeError("value must be a string or TypedArray");return(e>>>0).toString(36)}new TextEncoder;new TextDecoder;function X(t){const e=atob(t),n=new Uint8Array(e.length);for(let r=0;r((t instanceof Request?t.method:(e==null?void 0:e.method)||"GET")!=="GET"&&b.delete(U(t)),z(t,e));const b=new Map;function ce(t,e){const n=U(t,e),r=document.querySelector(n);if(r!=null&&r.textContent){r.remove();let{body:s,...l}=JSON.parse(r.textContent);const o=r.getAttribute("data-ttl");return o&&b.set(n,{body:s,init:l,ttl:1e3*Number(o)}),r.getAttribute("data-b64")!==null&&(s=X(s)),Promise.resolve(new Response(s,l))}return window.fetch(t,e)}function ue(t,e,n){if(b.size>0){const r=U(t,n),s=b.get(r);if(s){if(performance.now()o)}function s(o){n=!1,e.set(o)}function l(o){let i;return e.subscribe(h=>{(i===void 0||n&&h!==i)&&o(i=h)})}return{notify:r,set:s,subscribe:l}}const D={v:()=>{}};function Ae(){const{set:t,subscribe:e}=G(!1);let n;async function r(){clearTimeout(n);try{const s=await fetch(`${M}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!s.ok)return!1;const o=(await s.json()).version!==F;return o&&(t(!0),D.v(),clearTimeout(n)),o}catch{return!1}}return{subscribe:e,check:r}}function Q(t,e,n){return t.origin!==Y||!t.pathname.startsWith(e)?!0:n?t.pathname!==location.pathname:!1}function Re(t){}const H=new Set(["load","prerender","csr","ssr","trailingSlash","config"]);[...H];const Z=new Set([...H]);[...Z];let E,O,T;const ee=I.toString().includes("$$")||/function \w+\(\) \{\}/.test(I.toString());var _,m,w,p,v,y,k,A,P,R,V,S,j;ee?(E={data:{},form:null,error:null,params:{},route:{id:null},state:{},status:-1,url:new URL("https://example.com")},O={current:null},T={current:!1}):(E=new(P=class{constructor(){c(this,_,u({}));c(this,m,u(null));c(this,w,u(null));c(this,p,u({}));c(this,v,u({id:null}));c(this,y,u({}));c(this,k,u(-1));c(this,A,u(new URL("https://example.com")))}get data(){return f(a(this,_))}set data(e){d(a(this,_),e)}get form(){return f(a(this,m))}set form(e){d(a(this,m),e)}get error(){return f(a(this,w))}set error(e){d(a(this,w),e)}get params(){return f(a(this,p))}set params(e){d(a(this,p),e)}get route(){return f(a(this,v))}set route(e){d(a(this,v),e)}get state(){return f(a(this,y))}set state(e){d(a(this,y),e)}get status(){return f(a(this,k))}set status(e){d(a(this,k),e)}get url(){return f(a(this,A))}set url(e){d(a(this,A),e)}},_=new WeakMap,m=new WeakMap,w=new WeakMap,p=new WeakMap,v=new WeakMap,y=new WeakMap,k=new WeakMap,A=new WeakMap,P),O=new(V=class{constructor(){c(this,R,u(null))}get current(){return f(a(this,R))}set current(e){d(a(this,R),e)}},R=new WeakMap,V),T=new(j=class{constructor(){c(this,S,u(!1))}get current(){return f(a(this,S))}set current(e){d(a(this,S),e)}},S=new WeakMap,j),D.v=()=>T.current=!0);function Ue(t){Object.assign(E,t)}export{be as H,_e as N,ge as P,he as S,ye as a,J as b,Ae as c,le as d,ie as e,pe as f,ve as g,ae as h,Q as i,N as j,oe as k,fe as l,ue as m,O as n,Y as o,E as p,ce as q,me as r,we as s,de as t,ke as u,Ue as v,Re as w}; diff --git a/apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js.br b/apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js.br new file mode 100644 index 0000000000000000000000000000000000000000..c787776ec69fae4e81b591e8f5c1b5ee138c48b3 GIT binary patch literal 2617 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 bJ^W#^(=~J5km*RNPk9_Z8a{jye|^8W0 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 KYkT#O82|tx*1Pfm literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/BsvCUYx-.js b/apps/dashboard/build/_app/immutable/chunks/BsvCUYx-.js deleted file mode 100644 index 7857d5a..0000000 --- a/apps/dashboard/build/_app/immutable/chunks/BsvCUYx-.js +++ /dev/null @@ -1 +0,0 @@ -import{aH as N,k as v,x as u,aI as w,M as p,aJ as T,aK as x,m as d,w as i,aL as y,ab as b,aM as A,v as L,aN as C}from"./CvjSAYrz.js";var h;const m=((h=globalThis==null?void 0:globalThis.window)==null?void 0:h.trustedTypes)&&globalThis.window.trustedTypes.createPolicy("svelte-trusted-html",{createHTML:e=>e});function D(e){return(m==null?void 0:m.createHTML(e))??e}function g(e){var a=N("template");return a.innerHTML=D(e.replaceAll("","")),a.content}function n(e,a){var r=p;r.nodes===null&&(r.nodes={start:e,end:a,a:null,t:null})}function P(e,a){var r=(a&T)!==0,f=(a&x)!==0,s,c=!e.startsWith("");return()=>{if(d)return n(i,null),i;s===void 0&&(s=g(c?e:""+e),r||(s=u(s)));var t=f||w?document.importNode(s,!0):s.cloneNode(!0);if(r){var _=u(t),o=t.lastChild;n(_,o)}else n(t,t);return t}}function H(e,a,r="svg"){var f=!e.startsWith(""),s=(a&T)!==0,c=`<${r}>${f?e:""+e}`,t;return()=>{if(d)return n(i,null),i;if(!t){var _=g(c),o=u(_);if(s)for(t=document.createDocumentFragment();u(o);)t.appendChild(u(o));else t=u(o)}var l=t.cloneNode(!0);if(s){var E=u(l),M=l.lastChild;n(E,M)}else n(l,l);return l}}function R(e,a){return H(e,a,"svg")}function F(e=""){if(!d){var a=v(e+"");return n(a,a),a}var r=i;return r.nodeType!==A?(r.before(r=v()),L(r)):C(r),n(r,r),r}function I(){if(d)return n(i,null),i;var e=document.createDocumentFragment(),a=document.createComment(""),r=v();return e.append(a,r),n(a,r),e}function $(e,a){if(d){var r=p;((r.f&y)===0||r.nodes.end===null)&&(r.nodes.end=i),b();return}e!==null&&e.before(a)}export{$ as a,R as b,I as c,n as d,P as f,F as t}; diff --git a/apps/dashboard/build/_app/immutable/chunks/BsvCUYx-.js.br b/apps/dashboard/build/_app/immutable/chunks/BsvCUYx-.js.br deleted file mode 100644 index 85a4fbbd67a8ce3d2ca3bcf8dd64ae4bf9d81c49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 719 zcmV;=0xG6n!-GoAl_Uc_C}RdsnMh;)qkYE2?$2=##N`@b~(nYTcxqOoWK7_%*t zO)cG8(S8SfAf*G)E#f&VWpojd_{Q2?H;ivQ(x?^AXpxwbxyglddLaLBt9$R^F0i0+ z8YpR=>jn_G*DZ7CkPbWqPH2|t?hnDE<1B{nPoHKM z(C2Wn_kD6O^Q0j^1vqG?Fq1~a3N+*FYZ5x7B*60?_x3E!_a==o{QJa>DL<1c$YE(X z6oQbVbE)%q%KoK zCN<-vuz3*CO_k@j!0f$a!rY|pKDB7}RB$4?H~9OgVQBeieFDhs^`HwSMl(^vfV@f| z4YJT7>X>oJa}SDKQYY#U1j%hSfYKB^q89Q6?pEG;F3ZTr?AMm}zNe&#snY9wEod&w9$m_1#z>l1Ec- z!GEotwTtbIg>J-xv2_Hv`i}yRSbb>;kr4KvNKD}ufiLB;J8=-sFY~%Nap_F2@&RVH z$mAG<24E*AX0dk!K46F*ovAork@A8IQmH?1CA**pSw)p{1+N;J;c<%9j5%`YW2H(q z+EnQ?JOc<0tQmS*4H+a8dD1d~A!oC~-I_3;;{kqtY2FSmQRu~r#VYg1f`Gy!UxwZln8>M5P?w=!w!OQo)Kj^0H?cqOH6ZfvuV;= z>QcC^SRy1lK BSw#Q< diff --git a/apps/dashboard/build/_app/immutable/chunks/BsvCUYx-.js.gz b/apps/dashboard/build/_app/immutable/chunks/BsvCUYx-.js.gz deleted file mode 100644 index 332d14ab36c874cda6c9982f90b4ad8891c41952..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 800 zcmV+*1K<1~iwFP!000026OB|+Z`(Kwe&4T1j3SUQ*6VXzB`C5L-PRUGFTi0>onq68 zH(3rOIcYEPe?Lk};&!{koge(!6h-p;M5?OSjd449Gmv(04?jI@;Mqe9^0UV++<91o z{NiyA@~g*Zs67<0^-zJl_4opE;c)>n?7D)Dhg*>M9%o%?nmS28%r-y%xcX-PN`KfS z+ekB5WqG5m8`Ofal~}4~A=P|USs`?*)O6ES#o%Jx+tY2Oi)PE;uCG#OTI;ZwzpT;n z(df4gZyeIxpmg}qs49P9iQS-bcz*CWU%6T(u!}x7^Sj$IiV1c+D_fnrs?mdw4EfHW zYmH|0+e+%R-$!12I>qj^Z|V1W)>7QF#9_Tw&) z!$|`4KBs4ra1Jshuj4T}n)9I$7f|}|=lE?Q7eh=#K>KIqRb2a1|i;L~uZGGAGg zjcT)E$?_?V!}j;c!R+^BY?df1C7MMHXe>$H;kvzXCXk!7N$c>7+6Y7nEpWyDKpaOMLP`y&{ zF?P{mCF&W~?0v2oiiG6#l#AnxY#6>z`svV&T9x{~i~U#~?Xj!0|cf|{F(88)!*mA|5g~}uRgP;4og%#gd&cm;^7pCNvI~ks|(^R zN)-w^jWHue<>-a3JaMt#A7(hED2Ku3{bUDg#bI$u*?Cdo_~TI*Nk{e^?*B7?IZJqq eS9iGfbI|dAfACPkwFlQ_@BRjh5avuX1^@tV^quSg diff --git a/apps/dashboard/build/_app/immutable/chunks/Bz1l2A_1.js.br b/apps/dashboard/build/_app/immutable/chunks/Bz1l2A_1.js.br deleted file mode 100644 index 34ab9ac1b519e8d390df757f918eb8378e4a4d75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 315 zcmV-B0mS|r76Jf_!g2587Oh2m3_86o-QdB7pG2WzQz?S2 zj3f(mY?E7Vc(LRCM&WN5C(XU@)_eDV{5?WPWaseIAcKDr{WL*0!a9pJUT#-}E1Veb zbTvtop_Mly_FbDzcxY{!imNv_O%Zj=u{>U@1{vlK&261r2J5p%B9Ow?!XOC}s^+FA7o$5huCvaB zB7EQhy{=PRli^x!Ts3^|?QXI7;9v&f7zF4S1Z?XwtU>_awxd{MM>S*tP_C&I9JoGk Na6feT{w#H7?gGncmTLe2 diff --git a/apps/dashboard/build/_app/immutable/chunks/Bz1l2A_1.js.gz b/apps/dashboard/build/_app/immutable/chunks/Bz1l2A_1.js.gz deleted file mode 100644 index 6ede0fdb86a83dff50c3580bb973d26d817baebf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 343 zcmV-d0jT~TiwFP!000026J?S?Zo?oDMfW`g$--ik5lz>KN@?0&pz5Nks%YY1$BB(C zz)>2DyBF*xU3B%BKkz>qsG6>|exM5@$4aDC;tuI4F~_lNkk*M6(sSY#%Y+W;CGmvs z345g1#A7II+swuN`gC|(eb|dQxVbEPll!VQ?99EIJ;0E+#(74nM6F2FqL)>{XBw>b zy*0Ado)wCNdOUFw4pP^{kYuBl=+qG8WU*0up7xEsI(q-=HrhH_w3bhG%PPYx*w6NB zrj(1wGM=E4gz@AOr(a),_|o)}finally{E&&(l(!0),d(s))}}export{T as h}; diff --git a/apps/dashboard/build/_app/immutable/chunks/C4h_mRt2.js.br b/apps/dashboard/build/_app/immutable/chunks/C4h_mRt2.js.br new file mode 100644 index 0000000..75d6e99 --- /dev/null +++ b/apps/dashboard/build/_app/immutable/chunks/C4h_mRt2.js.br @@ -0,0 +1,2 @@ +v`)wKքMڜ˿Q@ƺW vEYtcG.h2DJКdS $gdD1,Jy>U`+& +՟xSZnsJDyIm;P#Y6EaR$GW7;}ED+t&Uv?Vy%lhn_L;?9TXf|-6)qb zaE){gHXXW}Vv#2@78Tv zINV)-kjzx4GXV+<4yUP%BN+W}tTatS(XLKDSm*%}RmuI(0ib@&U{LJGgp>2pgwPM` fdAWJmJtwv}N7C=*%$IYWCUx@%heXSicL4wZ&c}bP literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/C6HuKgyx.js b/apps/dashboard/build/_app/immutable/chunks/C6HuKgyx.js new file mode 100644 index 0000000..9e9eafc --- /dev/null +++ b/apps/dashboard/build/_app/immutable/chunks/C6HuKgyx.js @@ -0,0 +1 @@ +import{s as c,g as l}from"./BeMFXnHE.js";import{F as o,G as b,H as a,I as p,g as d,h as g}from"./CpWkWWOo.js";let s=!1,i=Symbol();function y(e,n,r){const u=r[n]??(r[n]={store:null,source:p(void 0),unsubscribe:a});if(u.store!==e&&!(i in r))if(u.unsubscribe(),u.store=e??null,e==null)u.source.v=void 0,u.unsubscribe=a;else{var t=!0;u.unsubscribe=c(e,f=>{t?u.source.v=f:g(u.source,f)}),t=!1}return e&&i in r?l(e):d(u.source)}function m(){const e={};function n(){o(()=>{for(var r in e)e[r].unsubscribe();b(e,i,{enumerable:!1,value:!0})})}return[e,n]}function I(e){var n=s;try{return s=!1,[e(),s]}finally{s=n}}export{y as a,I as c,m as s}; diff --git a/apps/dashboard/build/_app/immutable/chunks/C6HuKgyx.js.br b/apps/dashboard/build/_app/immutable/chunks/C6HuKgyx.js.br new file mode 100644 index 0000000000000000000000000000000000000000..7f962dd5db7606de37f35a4b7308e75e9b187b94 GIT binary patch literal 357 zcmV-r0h<0BdIDf%)n@xI(_Noz$)z=sA8{<9Th0+gng470ffd=gMD!23&|Zbk1~}Xs z4tN%YG~HCBSE28QnrfD@v(F?3mu=!L5^qJ@8Jrxz(?+ZPB)@Nc^YPj`Bn=%&yiozY zgC%_!wV+QcOb2V)nX^SwfC}N8&~%V8(-l+;C+{$8W!&|d<>tnRy|*`BjOf~57?45>miv2n zAj}sCv(`pTE9XN>1-#J0FsxWEr0jRJ`_B~!ZTQZn_dxYVZQ;H{8+1q`?mB%Uxw)xx z_WlHdY8{)RBPlrpKPST0k*6ESbO3;SXC-9BU{?srD4w*ush1$MCo4w{4VNcTewU;% zsr-&Zhb5hjgv?}f^a=8^tQk&p8do+2}-(3a2V7(`ki2ZHhDR$f7j~|)td;g$gt6za`xG^l@gfbjgz(IN}>(}l~fa7 zD`_lpOmF12C~yMija3>l>4cz0IbB0`z(>V*Xhx`$##N@)yn?I@BwA3F&Wc=s1c8CWE5r-GQ-$B%b$mrbjl^p?6AF<{%9CW2up4qgj4`TgPS^_T+7G z#)lAFi{L@myg{V#P*joI>g3 z1q3#Fd*5+h#cZ5y&5{_p!a!Ud2>>yONpQ>dv2X_Y2*m lQJTo+vJ|58hRG1%uYWV$%`2&Co4|zp;UB}@S0sA^007-Ly|MrR literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/CGEBXrjl.js b/apps/dashboard/build/_app/immutable/chunks/CGEBXrjl.js new file mode 100644 index 0000000..040e765 --- /dev/null +++ b/apps/dashboard/build/_app/immutable/chunks/CGEBXrjl.js @@ -0,0 +1 @@ +import{J as z,b as fe,aa as re,N as k,T as L,V as ie,ab as le,g as Z,ac as ue,ad as se,ae as $,R as q,U as F,O as oe,af as ve,ag as y,_ as te,ah as T,ai as Y,aj as de,ak as ce,A as pe,a7 as _e,al as U,am as he,an as ge,I as Ee,ao as j,ap as me,aq as ne,ar as ae,as as V,Y as Te,at as Ae,au as Ce,av as we,aw as Ie,Q as Ne}from"./CpWkWWOo.js";function ke(e,i){return i}function Se(e,i,l){for(var t=[],g=i.length,s,u=i.length,c=0;c{if(s){if(s.pending.delete(E),s.done.add(E),s.pending.size===0){var o=e.outrogroups;B(U(s.done)),o.delete(s),o.size===0&&(e.outrogroups=null)}}else u-=1},!1)}if(u===0){var f=t.length===0&&l!==null;if(f){var v=l,n=v.parentNode;we(n),n.append(v),e.items.clear()}B(i,!f)}else s={pending:new Set(i),done:new Set},(e.outrogroups??(e.outrogroups=new Set)).add(s)}function B(e,i=!0){for(var l=0;l{var a=l();return _e(a)?a:a==null?[]:U(a)}),o,d=!0;function C(){r.fallback=n,xe(r,o,u,i,t),n!==null&&(o.length===0?(n.f&T)===0?ne(n):(n.f^=T,M(n,null,u)):ae(n,()=>{n=null}))}var N=fe(()=>{o=Z(E);var a=o.length;let S=!1;if(k){var x=ue(u)===se;x!==(a===0)&&(u=$(),L(u),q(!1),S=!0)}for(var _=new Set,w=te,R=ce(),p=0;ps(u)):(n=Y(()=>s(ee??(ee=z()))),n.f|=T)),a>_.size&&de(),k&&a>0&&L($()),!d)if(R){for(const[O,D]of c)_.has(O)||w.skip_effect(D.e);w.oncommit(C),w.ondiscard(()=>{})}else C();S&&q(!0),Z(E)}),r={effect:N,items:c,outrogroups:null,fallback:n};d=!1,k&&(u=F)}function H(e){for(;e!==null&&(e.f&Ae)===0;)e=e.next;return e}function xe(e,i,l,t,g){var h,O,D,J,Q,X,G,K,P;var s=(t&Ce)!==0,u=i.length,c=e.items,f=H(e.effect.first),v,n=null,E,o=[],d=[],C,N,r,a;if(s)for(a=0;a0){var b=(t&re)!==0&&u===0?l:null;if(s){for(a=0;a{var m,W;if(E!==void 0)for(r of E)(W=(m=r.nodes)==null?void 0:m.a)==null||W.apply()})}function Re(e,i,l,t,g,s,u,c){var f=(u&he)!==0?(u&ge)===0?Ee(l,!1,!1):j(l):null,v=(u&me)!==0?j(g):null;return{v:f,i:v,e:Y(()=>(s(i,f??l,v??g,c),()=>{e.delete(t)}))}}function M(e,i,l){if(e.nodes)for(var t=e.nodes.start,g=e.nodes.end,s=i&&(i.f&T)===0?i.nodes.start:l;t!==null;){var u=Ne(t);if(s.before(t),t===g)return;t=u}}function A(e,i,l){i===null?e.effect.first=l:i.next=l,l===null?e.effect.last=i:l.prev=i}export{He as e,ke as i}; diff --git a/apps/dashboard/build/_app/immutable/chunks/CGEBXrjl.js.br b/apps/dashboard/build/_app/immutable/chunks/CGEBXrjl.js.br new file mode 100644 index 0000000000000000000000000000000000000000..f66f2f9a93c9e2fea6c5382bd8c23c51e5744fd6 GIT binary patch literal 1804 zcmV+n2lMzFO%MQ#!g23|OKY20B4RN@l37#3)$0paERUFtme)x!L$1}|b+$CKy+9`0 zvj2U4oF=F2yLFZ|fr>LB0x7Y^pmP7Wrd7`V!V##x2zSPntY~Kb?qD~-vjv9TLsE%5 zdY)Wm8g;-5oQQ1YfzuhEd2pBs)MUBpn!E}Wh)m>6P>9zp~ib7haz2gxj;!1k7bLuy0>kou$vTS9(x~~)$>BWqOmyK$xRmO^l|+JTd&S$ca{)K< z%)qUa!JX5?J(;Wh!EUmD!nJRef7!)#cYVFp<@x$qh<#m`PRV1_CEgp$aSANdzQ^nS zk&SpvdV!9iVlh@4c+%{@9F5>Yf9Q>Enn9f00AURUd z-d+vgiuttOBdr?3ZY^5$?akFW&SvA>FTM9TKs_XJ34O0L1O1ddh(+&l^B7@8^fhHdutC_$xYMth=9SD=bMGafD zkwdzrW+0~rl{#NE16t2JnybR>C(7zfnX1=7yhy40BV&t#Z zy7L^tg*S}~s~9eoj0DxxEgKZl!>l{6Glrq$2!%gq-$Bq<0J-u2zIZYMOLew%zf%4m zvzJd6!s(DkX_yHLGtwA~&TLX5CH3^vI?{PoTC#mJ(Yd?SldqURPT=2Mw=Lywmc+tS{j#2Aj=b5}#HI)T%1dF-g0vG|`++ zVPOa7tZCS|n_-gWvQL%5mih_e;wE0f7GMQ)U0W-lPnkKhM4187&UC8)d+lMmP*vm} zzeWu{1ET4sm-sg`k`CFKq3NpG%D(~#CIp9bFYL$r(is0~w&i&Jd_KU~{M&9{`xeWO zzHsV{MZ^Vt_SHUyJp*g(-r;rNMR@f5xBlvx!zj&OJV`;stm>fE`)EPk&~cPkOmo*2 zg&wkNRMmqh8L`u4*!al|X@BZ~qJ23n%-$r9(*aZTyYcYM>n=LL-Gk*LP(R&r%P|++ z^M+F{xr53oC*bX!>0c)hxL$8HnPyH4SGol9aWK->)70Tak(C`8H?%|%At>$Jk!@Y%7axxiV zSBHmmR5+^lhwEAO$bkaewI}`^(URb4giv)qX@-UDJb^d$mkSPcF%48Ih*mUS(B1Gc zja3XVrYan{tsS#elJj-U_t~oE*H*P5B~pI))P-QKhn5a^70_dAAR5{z1IY_G83t%H zF_uWUlq4`q)Y^^iiwD-f$vXYUruaA(r*Pg#v&$A)3HIv7vFGn4{IUdMvs=nRDXac) zs1PC%amvUtid5!Jl%+oxVK9yIjX)TxxB^6wZ5eG!WM0I3M#b+X0lvZH9H0AqN|mae ze$!Q87BZ#$NllB13pvfE`L#Y3xRJTB1-HGqYwDFB5Mz;D7ng09nO*S%y1(>Nr(uoW zugxyfN-KFy^Mi8PlKf4s1*F4iEA{p7%jRj=L+`ys&OFLMd|br@f*lA?HcR$FOFyIw zCZn|q_1Ohtyox=VPrIw8#tqiB7O^t&8cA!4^Lcm9$yyVPtu@3*PI(APdt|5~I?ejX zd|eM^HT3eGTg$#5p8}h6J@jmkPTUOeEcu?p4ii;`$DaFwg4&S4@PYqjD7!uAb)sQmJ>1jS}NmIb_u%Zzx>hgTe=XL$-JyY=oW9iIT-znbI# literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/CGEBXrjl.js.gz b/apps/dashboard/build/_app/immutable/chunks/CGEBXrjl.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..1efc1863dbdcfdbbe857fe2b746cf07ef9d5f9f7 GIT binary patch literal 1948 zcmV;N2V?jjiwFP!000026OCAHbJMyK{(gT&dWP{x!ye!E)19#^G9?5k&=k@_;dF8{ zsx2pO9NYLUfzD~HJy9PQR>XJ;&WNTs@gHL5$V9|^2Dv7>#EF=gg@SXUW1L8cxd)jNUE{=e zVq#=6Vk9y-F<;=DR*&O?m@{NbVn)bR#B7k+5Oc2J6VZvPgDhG9VgGxS-mGqJE))Ac z|HBQ+*ek*$9;_5o5b|B7iZY7_Vco4<=@p3hE=V#~p(%y9oxwtccBJA(v4kAT{lF8) zu6Md{z30#QE>gu{EW%rF=1RrJz_@s^3j>yO{cEQx_QQB#`wAsdfJ1KkNvv$?`)1Ti zxggE9qvLF%4PRb%n7FklJx%-lRW@abnkhI6;#J3wQiyiC{aT!Itu2qz)LHVaR zsp05^*JxI`*As}M@yi?$9SOb9MX|t$R3d^{RCX#e6&I7lSMEl!m_uyKl&ohJ2W5wa zTIaSGDVZ@|zhogC1>7jl#jf$viPZ+|C%I}+T-GFlYJ;)0Zq`f-=$EPYf^k6QwRhLtxR!@ z&+$QUlv|3`@B<4K#(_Ik6O_?1jC}T!abB-5tcr1$#v)ZrV}&NAh;X?9=3Ft! zhtiQI5yRV=^BHGqOf~rE=ic%WLp0lgjG{Z~twao4#WIvC(VYU*)1(q{k@RvrWU(Ds z*Ie^4CDNgp|B7q4U@>U(N^}I_92+@jHxWT&dLsTp2)o9EqzgAz#FaQYp&+eH zkhY>!tR#)Oa<^y}lNy0&St*_|4j*t8zB7a;Tv00PHkI=>@vsrtl%~SNKthTsNKd7k zJ{Ko^hv9u~#|X>oA1M_=qG-aG1u3bNR`Ob(Yg8DE&qZ>Z&frcI>>N@KOW_a6O~W`EvCBALh3Q-cf$|Dm!RmC_QcM-|z#o>5QiNnB z2nTQucaS2;sMUb~@Idl*@F1=^cy>-oVTodM4e>i&snS$sZdpe$I)WyOZ#wunqa3mQ zu&;?zZR&$L$QN_nAuP+M&|$FT3q0`ydqyT5`5d)OP3?F|oENv3@M@L>1CP(`rOeqS ze|Xr~eJ@|3m+r<+VlP>*!-9=C(8v#SPiDS>M%`3CLe#yoER6dx2SN+NI1@W_k~0C_ zG#n3lrS511wy1XE+C|i#kl~caUg5uG%Gm9yJ<>6t)|t}acDceP8mn#5mX_LY-u9~A zfOHAyIlO~U@D<*`d-$kfk_%Q?BUAQ=mq63;urZ(^w(-ag!Ys$qtDvoONa!l@>1PBJ z$UwUKb|AYY+9*#;R}zdzc!|gvOvHkXKvI+p5GUMLz_PAn(MNVE5M!Cfe9oITQ6-^2 zIChq{Y-S!FF736Fd6`k(*%;w5e$+-Ytc70;p?m9ZjX7w{P2_oppTT;7=sA$#>&Mq% z#$j!)!ES=W(zr>nCRk>sD`n_*z%Q`1>5xX;C1~lKU5R)Y>l8bIOLAQzBAFK&4!tpk zEX@>NR)*rTVe|nMPb9QRR4)>vCAytwh?*EO!(?#9f$X}Xf{sPjOE#gxSjJt9OA*GU zs#_PoXctjMtV5AgPTvXk>Nh!k)ywHSY&k)=eJZ0}D6y`yBZ?WNvO> zm+=o|s@7m1MY&4>-Drg{Z8Bkky)n!bwj86n#W+tv;%jCfY}0D09=Iqe0VPGJ$()+? zPDLn*CdP-Q>%<4TGo99b0?C(7ts8W0hq%n;tiqI3kBTh7UT>#mz9f!d5j3!%M?_-< z?=&1#dSdn&EA-yR2}077Ww`r4>#+A`q?hHoeOa)w-c4L4-(_=&iVIlB>T{hMa9?y0$A`y$ zADdqLCBaH-X#zJyc42Pe;aITH}`u*((6Y0o-NFDb5ZXqCxFnYKsn}l z!*cwb2!=!4Hykcdqj{Ki*9TSvzE1ZxUbG){x=xIn`)|8u#?A|wp%dL0YXd(3@Qug9 z{R=tl3pe});function O(e){return(m==null?void 0:m.createHTML(e))??e}function g(e){var a=M("template");return a.innerHTML=O(e.replaceAll("","")),a.content}function n(e,a){var r=T;r.nodes===null&&(r.nodes={start:e,end:a,a:null,t:null})}function R(e,a){var r=(a&p)!==0,f=(a&b)!==0,s,c=!e.startsWith("");return()=>{if(d)return n(i,null),i;s===void 0&&(s=g(c?e:""+e),r||(s=o(s)));var t=f||y?document.importNode(s,!0):s.cloneNode(!0);if(r){var _=o(t),u=t.lastChild;n(_,u)}else n(t,t);return t}}function D(e,a,r="svg"){var f=!e.startsWith(""),s=(a&p)!==0,c=`<${r}>${f?e:""+e}`,t;return()=>{if(d)return n(i,null),i;if(!t){var _=g(c),u=o(_);if(s)for(t=document.createDocumentFragment();o(u);)t.appendChild(o(u));else t=o(u)}var l=t.cloneNode(!0);if(s){var E=o(l),N=l.lastChild;n(E,N)}else n(l,l);return l}}function F(e,a){return D(e,a,"svg")}function H(e=""){if(!d){var a=v(e+"");return n(a,a),a}var r=i;return r.nodeType!==A?(r.before(r=v()),L(r)):C(r),n(r,r),r}function I(){if(d)return n(i,null),i;var e=document.createDocumentFragment(),a=document.createComment(""),r=v();return e.append(a,r),n(a,r),e}function $(e,a){if(d){var r=T;((r.f&w)===0||r.nodes.end===null)&&(r.nodes.end=i),x();return}e!==null&&e.before(a)}export{$ as a,F as b,I as c,n as d,R as f,H as t}; diff --git a/apps/dashboard/build/_app/immutable/chunks/CHOnp4oo.js.br b/apps/dashboard/build/_app/immutable/chunks/CHOnp4oo.js.br new file mode 100644 index 0000000000000000000000000000000000000000..e88d0d13bfc9cb800fbf4f2eee4f61879177f6ce GIT binary patch literal 723 zcmV;^0xbO-G6n#Q!g22sr`9%cQG~Qqby{Vn0cV7#nbb?EWmqfInq>F4XwH0%%au?V zphuSZ3Bv4_|9)-N&zlViEtN)v5NU1Yv8Z@6sbV1$3MZ*u4Y!Ertd!A3MB*1KoLA_p z7d^JZgMNdhkPFW$$v0f;svfQaj$YG%r=MIGL*QC>%;ABY;3lxvccyzj1hv7g;#j`#w2r&Xb1j6yRW%V5W$O6*S|FA_*PE zBfx9n_O_+@-V`y0f1kK9(@#q_lyPa;6@pOEwPxu#m3&(iXU1ye4L;wUKpvWdJla)& zPj+2#2-%odU@tIqu^NV2#Dik8_6GkEEFadN8BAlfL0hbBx3_^5A~|RLAcae)3$*Xd zxAfo=3uR<`8wZV7_V_CK^1q)Fgk;7k-8^u*sq*<%58J;SnbivRsfT8fYgUQ9p}&tB zhL(@kFX&slil5;znu!9jyh>1U4jrP78HdC|xLrw3)Q=0r^%_trA*2@asRfmH(aAFM zG5fXUeJ`?VCW-FnPfp*A2iT2> zX8P$%aB+PQ>q7~edR_Z(S}S_Hu@FQo=*<*x^_>()tiH4ikr2MX4VJJY_b%b{525Fm zdEJ~iA;N7R`q>uQANL0hz#exp$KIiKz~CO8$xN|GiQtB0>aUi`ZuBb4lqqL$tC1NV zr&!IHBlkWtp=6^?J^5eifeU*E=aUQGr>lz&& zjegkh&LJ-?N{_!A)s(L+b6Zp%&kr8wE8nUNcFE^ves?=YF~N=(^+uPzF?#U8knb$| zjn%AuUrC$y`^bw=r`VnLEyKRRT8cZCd2H8;Tr*yzSOb|iTB8kn1?9*sl0%7CO0n#6 zILUyX=k%LooP*3sIgi@+@ijw`DT5XB!sgmkNK(cMMU zcpvZU+jvZl)_f?$1=Qhvk=`AYVu*PR=pGxtN|hcdF)k*%re+mCP}Hn}kcLB3gvyd^ zRGSk^R!(sow|_tmcE2a1VUBYiTg8idzki)prrfkdJ8xnS-xDL|V0gjDbgs&1j28MX zD6dV`KT#adVIzF5r1P^?qpCu)C)n@~l|w4agFl^v?|KbB1r5Lo>XK!aqSZfT4DO9Y zrTBJvwzJ*jY*+WBy33Ez_znF3(TD6qe+izP10XYsmm8g;vlmW zfd=K4x`2;o^aRZ;5ZFHP7smfp|Bwg&TVasj`^-!mm#BD%MI1}T!zmDxSWSdC7sOeT zDi(AaV@8bXQMmHN#eRR7;hdrz2AlVj9jy(Ams83vh?2%1kGe=YvX^-OpM}d=!gadX d{const n=s()??null;e.ensure(n,n&&(o=>n(o,...a)))},t)}export{E as s}; diff --git a/apps/dashboard/build/_app/immutable/chunks/CJCPY1OL.js.br b/apps/dashboard/build/_app/immutable/chunks/CJCPY1OL.js.br new file mode 100644 index 0000000000000000000000000000000000000000..8c1474664d2ee8a946e9c4e9d6780ce8cecadd93 GIT binary patch literal 163 zcmV;U09^kYxd4DH4$L#--F*-##bsWaVOrdlD)@E_1@jVrpsMxGlUkotfTK&7m$1Gn zTD$x7Jjy)Rwk&8-Tb{JVIj0A?+t~KG6+!wn;sW=pG`VUMD`4C2e;T4}G90xUo)A)P z6(sMPe{_xH90e?FWrDl??Sr8|wH6j601U#n9fx((hF}GZqIq+#{~nDwu)%R)L=7-9 RK^*&M;|nD6EwroH;|EnAO{f3> literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/CJCPY1OL.js.gz b/apps/dashboard/build/_app/immutable/chunks/CJCPY1OL.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..b91f18a15a51f483cd5b13b41a3d7e5fb4952846 GIT binary patch literal 169 zcmV;a09OAWiwFP!000026E)7U3WG2dh2gzV5gg=R2AsSrg#xtYHEKGw(=>Sj_tF{y(BNYJ4lBQvhMi>f{H$a^79IPq`?D2t^ Xc*JDBd%&I;l05wYEND)(x&QzG+citx literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/CJsMJEun.js b/apps/dashboard/build/_app/immutable/chunks/CJsMJEun.js new file mode 100644 index 0000000..0b355f6 --- /dev/null +++ b/apps/dashboard/build/_app/immutable/chunks/CJsMJEun.js @@ -0,0 +1 @@ +import{W as S,X as h,v as k,Y as T,S as Y}from"./CpWkWWOo.js";function t(r,i){return r===i||(r==null?void 0:r[Y])===i}function x(r={},i,a,c){return S(()=>{var f,s;return h(()=>{f=s,s=[],k(()=>{r!==a(...s)&&(i(r,...s),f&&t(a(...f),r)&&i(null,...f))})}),()=>{T(()=>{s&&t(a(...s),r)&&i(null,...s)})}}),r}export{x as b}; diff --git a/apps/dashboard/build/_app/immutable/chunks/CJsMJEun.js.br b/apps/dashboard/build/_app/immutable/chunks/CJsMJEun.js.br new file mode 100644 index 0000000000000000000000000000000000000000..4f223100cff5742815073986bf0d88ac1720dc06 GIT binary patch literal 197 zcmV;$06PC0JOLoYG@W~w3CJ&9U~c51c3^l1sF$aj3x}R4z)@Q?Hc;B~#O+d_@V_$= z({Ze?cW6oVaG6Z9JIM|(4Y=0*+A{7^1XLML9qbrScl>V?fk~IQZ<)SlE^Y{!W`)iI?EhSffj%vGd#`$$q+sqNd3e7 g4J|nR$0^bQM}HmDvc|ZOAD^%O07>l9H9Y|U0Q3@WlmGw# literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/CNfQDikv.js b/apps/dashboard/build/_app/immutable/chunks/CNfQDikv.js deleted file mode 100644 index 81b3695..0000000 --- a/apps/dashboard/build/_app/immutable/chunks/CNfQDikv.js +++ /dev/null @@ -1 +0,0 @@ -import{Y as u,Z as v,_ as h,m as i,$ as g,a0 as f,B as A,a1 as S}from"./CvjSAYrz.js";const p=Symbol("is custom element"),N=Symbol("is html"),T=f?"link":"LINK",E=f?"progress":"PROGRESS";function k(r){if(i){var s=!1,a=()=>{if(!s){if(s=!0,r.hasAttribute("value")){var e=r.value;_(r,"value",null),r.value=e}if(r.hasAttribute("checked")){var o=r.checked;_(r,"checked",null),r.checked=o}}};r.__on_r=a,A(a),S()}}function l(r,s){var a=d(r);a.value===(a.value=s??void 0)||r.value===s&&(s!==0||r.nodeName!==E)||(r.value=s??"")}function _(r,s,a,e){var o=d(r);i&&(o[s]=r.getAttribute(s),s==="src"||s==="srcset"||s==="href"&&r.nodeName===T)||o[s]!==(o[s]=a)&&(s==="loading"&&(r[u]=a),a==null?r.removeAttribute(s):typeof a!="string"&&L(r).includes(s)?r[s]=a:r.setAttribute(s,a))}function d(r){return r.__attributes??(r.__attributes={[p]:r.nodeName.includes("-"),[N]:r.namespaceURI===v})}var c=new Map;function L(r){var s=r.getAttribute("is")||r.nodeName,a=c.get(s);if(a)return a;c.set(s,a=[]);for(var e,o=r,n=Element.prototype;n!==o;){e=g(o);for(var t in e)e[t].set&&a.push(t);o=h(o)}return a}export{l as a,k as r,_ as s}; diff --git a/apps/dashboard/build/_app/immutable/chunks/CNfQDikv.js.br b/apps/dashboard/build/_app/immutable/chunks/CNfQDikv.js.br deleted file mode 100644 index 5a2eda35ddaa74727a75f8d040540ef6ca697548..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 587 zcmV-R0<`@bR0KdQ3T$K2=udjqb7G=q5z|t3F%#cRHFeK2{S(211n9O}IJ<9Y{oMq| zr793pn%v+_OCXUfOa>aiSzdPF!Umjig5!dLR%&{uv)Q)W0A1nSU3tIPq6lh1fy5CM zy73bhrEv`E*-khE!77F8f6rMh`_Pv+|I{g8>w$0dw7gPZzw)K_NS8Ijx6hg(RqKDc zU0U55xysJ7*&8-MT$DED6>YqKAkhnS)NBCTzQeRh_R`d(navFwKJ3DRzkP;t0~6Qw zj-&i-mb_6)nIUfwENC5(+>qhit*g5B)?M|FFiA(0gk)ubScU4jDMv+ht7(XdKHkJ4 zZI(=r&33atX|O?xza5AD@A!R#kWzB7I-Q2&G{S2airz9QiH_`}YBcY7ymA!hIgUF`Y8h+Rm1&7kch%?S% zV4?@2;dn8*w<77HLEGB}LE6r#C?oGXjoV?n752z+bw#JQio1tFduY4Of1$D&S zBvnYXyg&vdVH73zzJ$*tNk%`-aa??5=e_=AXNY>%^<8YvxO|m_c4{(qVP7P^Zh*^ Zu;w6%%}iQ+TO4f9z3ynVby+{1+zAWiC6E9B diff --git a/apps/dashboard/build/_app/immutable/chunks/CNfQDikv.js.gz b/apps/dashboard/build/_app/immutable/chunks/CNfQDikv.js.gz deleted file mode 100644 index 470cb5e5a628c4c01ed0e260ae8ce2fb141ff24d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 628 zcmV-)0*n10iwFP!000026J1nMZ`v>re&4SM)`V=y%jheShuDOsY8{)Pd*~2CZn%(? z#ExtyTL<~?JBOs9eY)hkyYKEhpPdz@HtzHgNE=lAw>LH4d6V+On~cBr=D_8|+k}7i zX3ph}x9cV`x**}lFZI)U{$T!vPnJZnR@McjSU(q!I;SMFL0nmPV*K?soZ&@P$W8qYnnGMfB(D$Jf zz*R;C{zPOShy$Xp0dd-t+vy-_C`LZu3U8LJ6CJjcG5lKHqO!VSjh|;M6#NOk%W~LW z-*30KZ>Ed)g0Snu!(qfe1XV@2hmv&-%P98Zye6^PvMAApwj0fH7r7FP%bg4H8aeG} z7AYLQj@Svrf$AZ_1(^zf!NzSp;dm^=va%_4EYc#y$fmE@z~A=S$o(52`OzD5c{Xel Oz55UO?+r0k1ONcrNjI_p diff --git a/apps/dashboard/build/_app/immutable/chunks/CNjeV5xa.js.br b/apps/dashboard/build/_app/immutable/chunks/CNjeV5xa.js.br deleted file mode 100644 index 95f3b721109ff2854993b38cddb83338b9e61ea1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 225 zcmV<703QDvcmV+9(#^fg1pcXn9qy~c)axXMJhc$a+QDOOMyKG2Q#3O1Pa&j{9^xY@kz5H6n{;XL1LPS{$VOb%td2Lx07wYnO^@fV^ ztIUfA*(NWfemSRYPwA$HZ~p diff --git a/apps/dashboard/build/_app/immutable/chunks/CNjeV5xa.js.gz b/apps/dashboard/build/_app/immutable/chunks/CNjeV5xa.js.gz deleted file mode 100644 index 4beeba4e2a51aaa7100405f3e7b4a0640a131d51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 266 zcmV+l0rmbLiwFP!000026J?OWYQr!PMDP6y)dwSkk?%HYNJ~GU^i)a-sD8TeU0thNW6 Q?W5hpFE|GRuz3Lh0K!dx`2YX_ diff --git a/apps/dashboard/build/_app/immutable/chunks/CVpUe0w3.js b/apps/dashboard/build/_app/immutable/chunks/CVpUe0w3.js deleted file mode 100644 index 4a0c459..0000000 --- a/apps/dashboard/build/_app/immutable/chunks/CVpUe0w3.js +++ /dev/null @@ -1 +0,0 @@ -import{D as k,F as f,G as m,A as t,z as _,m as b,I as i}from"./CvjSAYrz.js";function E(e,a,v=a){var c=new WeakSet;k(e,"input",async r=>{var l=r?e.defaultValue:e.value;if(l=o(e)?u(l):l,v(l),f!==null&&c.add(f),await m(),l!==(l=a())){var h=e.selectionStart,d=e.selectionEnd,n=e.value.length;if(e.value=l??"",d!==null){var s=e.value.length;h===d&&d===n&&s>n?(e.selectionStart=s,e.selectionEnd=s):(e.selectionStart=h,e.selectionEnd=Math.min(d,s))}}}),(b&&e.defaultValue!==e.value||t(a)==null&&e.value)&&(v(o(e)?u(e.value):e.value),f!==null&&c.add(f)),_(()=>{var r=a();if(e===document.activeElement){var l=i??f;if(c.has(l))return}o(e)&&r===u(e.value)||e.type==="date"&&!r&&!e.value||r!==e.value&&(e.value=r??"")})}function S(e,a,v=a){k(e,"change",c=>{var r=c?e.defaultChecked:e.checked;v(r)}),(b&&e.defaultChecked!==e.checked||t(a)==null)&&v(e.checked),_(()=>{var c=a();e.checked=!!c})}function o(e){var a=e.type;return a==="number"||a==="range"}function u(e){return e===""?null:+e}export{S as a,E as b}; diff --git a/apps/dashboard/build/_app/immutable/chunks/CVpUe0w3.js.br b/apps/dashboard/build/_app/immutable/chunks/CVpUe0w3.js.br deleted file mode 100644 index 8cd42fe715030f22ab5102bdcad676eb1211fdd0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 457 zcmV;)0XF^{<^ur4QdRdXlf~ijk35)N!kH;`)|AO$lN%+s{y&$~8(<&l-T|K3-mN_> zz+M*h0tzhf5Hq*-l!Qf*&Nk26eid;bPTxL9em7d`_XeH*K(BAG*DFl4hoFDX{9)#+ zu`eITMf>)@z1qdjG{)w?IIGtqJigV4A)mg^Jlp1dv*fJCJJ)Dlj%_j49VpnkY#n3S z6RWfJ`j^eT(j?J8h6ltL7(Pl-EGpV})uix!1`F7PbkN@<2{A!jLa zqp5k|Ye+i4s`#KzV%~9GKyl6(O~T#x>Tb+G&HyB$1YjWAjR(h;DX`NA*h#HPI@|ng z?}vUqaMGQ~Wf zEy+V3+#|Fs(>TVbjK(>fMUwIFrK5`$ubwtX-U_h1CM&#bNK1&0+`9=F9!0rBRYiZ1 z6^EDSfq;;g6%Pd$sxfoFx3F2@%#6nl{17ZV#{IZa?Kwa4Ii|5T=JhLXqmSkZ)ScyY diff --git a/apps/dashboard/build/_app/immutable/chunks/CVpUe0w3.js.gz b/apps/dashboard/build/_app/immutable/chunks/CVpUe0w3.js.gz deleted file mode 100644 index 4faa38edb8df7abe12df9d8ceffe95c482f49ff4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 517 zcmV+g0{Zddz4upmIUrCGy{|>ADBV^)^t4i|o+1{;v9p+6 zVeB-C{oe~L`WyQ`tr;9E|@Z%>YZ_W5lwpi4i*jv>J$^OT)$htX>FV2V*c+Txv~f%H)e| zebEuhOh|@Jl2Ce((Fou@7)Tn|UOLb8WoTtJvm#gI2JDk>V&NPSrm7HPI@dg$+28UT zA%wAsqGi79h@wHc~{Qk$spI zb>IhQ=U5tJ7xtg)PZMzex{rql1OmXE7g6yhov-TUhN`W0g7;G)V&09WqWj6la`jXEYi*cQ)H zSbl2US~aJSQB(w7!v2&qzNi4Q+nAl&l zw~_W#nnUI|h(}8Bl1zAy)zt8d_*r?ZK7~98QT)c0Vsy|stsE5Ns4~{%UKBuBivyvn zyE;56hIpkdOw*f1!0etAKo!6wSO-Rr5>F4l z7Z(KvClfmN_B^)K8{>E8>Q(iPLDy>_tI48v%!~0PBy!3KF;*3Ton#nQ2Lqr?|D}%A zgKO2L8;5QX^}@Na6ac(PhKzh$rvU3uq0WiCw)iZMVoI6D%IO*F{*wG$QOMaeNw;=V ziAJouDpVO~OUfDYSXFtJ&293Dmyv5%oKlfhs)Fu+VKe)(WqGkrQ5ZmSB+52tDRw+9 zq&*scdwmm*To{v!h0p4y3aP3oAN{?orL){DO@waFcsB`+Vy@HprW+9@g%qo$(#C0h zK*lj3{z5|Fw~M*%;6Eh%25oM#?R7~Y`Y}r966=sbyVx~;$4D$?D|ifo zaiSHFtB*`}>+E`TJgMGF<*0eL_wR{iGZ8l(+>Cp{0l#Y3(f}^ zSo8r<2qT;dKdHD)vrK@^v#~r`tn&Pm)+jH$a#=&fSBvjmetJFO#v^L7OY-6>yCHK6 za*v~gy|5@`hd|+jYHW;bhG$)D(MA&ml`ZTuDMC*}LU&bw_Ur3xYlbVvtZ4TNS%(!3 zWVS*4Qnnnpfx=8GX^5;fO@8G;V5+3hrNkINGuQc4ewtCg{Zut?g=X4yPqMl|8)`{w zvMe`cZ={@5ep1y8OUaHCgOb7F+T^AfN0ljN83<>LmffmNM95j;K{KgkuX%j+a2CH$Q7p4rzcR|$wE#h3%wrX_5WI`xkz{%J7i z7d}-}&m-cO*e&b}B>g6HgbAy*FEPg8GDkb=Sioxjt&Uxq12xT1b5@lqt-;!)za~sS z%q`0e2c{nRC3i&_q3A=a=ECRp)cpv^eEy%GY%->0V;HDP?Pprl}tbOw}c?2$;zr(NT{Z!h9D+T z(nKc)qJ{FU@j?%-op_Oz3iwzK*DRMy8xHZieI4he)EJ0>U$ueAuYW%T{BC!JbE4K; GVax&t)9FM2 diff --git a/apps/dashboard/build/_app/immutable/chunks/Casl2yrL.js.gz b/apps/dashboard/build/_app/immutable/chunks/Casl2yrL.js.gz deleted file mode 100644 index 6192b6e8cf5c208a5c601b10123beea0568b5ece..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1643 zcmV-x29)_9iwFP!000026RlWVZ`(E$e&4T9)hv)&MYYqU@#HB+XE*48rS0N&FG1kQ z(vi(Z5(Sc~;~CoD+WUUl4npA-~6O}Nl5-4pBH z?Vt8~!!S#HL1>~~80Mxp-SBMAeMaWstgS2!JOK{L-KlYXV-6z_TI}|%x!Wsw1#SW> z?b1svuU2$F?Zo?nib%_HK2(X%d1hvlXf8q@+iSV0tB@|GrxwkCnSkgA$P zdU$B~5qPXJm6}$|P}B0hVl^>@doJvdL;{$>-E(e};EC(vokr$ZpX-Ju&cz{MjEwI0MQ3f1isbd<*2q|_932U{A>J=&C48yu% zKWpokU4t#wDcp=k`qM#wFuoY*7*FVIPk2MVBEnx9iUcot9P|msRXnC~DlG|gXH((% zE{o^rHetsQQ$~Q#7^IQ6hF~=6Nn~pRypcem44;KGOB4ZX2uQ-oVk!7+0SPb}#sx*% zPy`unBZFDYizDB?t|QsE(~K{T+pAK%cCg{O{BT{jKhg{J*1Drtdg}Qts(0QyJgjaW zY?54)`Q2!WTk1MqR5w`n2FtZlZCr1WZX|w=g3%I0MBpeKr2tMNA}dg!TXPz$9pvTP zpD9TUUHj*6O*bWDRNqKn^x>sx3wlBBAu#%8&TlQBMwDT?m&xgz!OJ`^95t?4qxugz zETI8XdMU2I}&VF_(lru=Uwm}UH?z`ziQ)O#?FLrpMC+>LBFXpvUKsI`Oo)eg-I4g z!@0}LQkA$mixRaQxilR0Jl*4e$YYwYQ^v7ZwDpt*I2Y>a)tmMiFn zGnb|m+P8GussNf2aqH+I=G|J$+8XT|Q0KPR*^wS%P)+f%;V?OW8KQArTa%Qm`&r1g+C` zvmPl2=57X{%wZw(Elw?Bj)SZ26u+nV+h2YFhVxJ?wNS`cIW|$PqTGIsh4D*K`lskV zuiE~#crkd14^yAAnp$Z+R#S3k?^7DI_KH3|6{uHt3+voM21&WsX+2%?vJo^OssbNC z=w*>;@8!9Cd@SAKyxhOC>&J=#IKN}FfU;wuLwohaTMl&CS)18W$k`DGH@qW|cxld2 z^SdEcEfwDsctA^LPb9O=(uM1uVj)!#ZgqUrABuB)5s9NCvyStbL9YcqnfT%1%D{&~ zj&Fs|+Y0+jOgMKIRxyw|@2u3zI83DDow0@ZWpVjyVo9Z(6-Hmd{lLZNTJyMik3;db zioWd;^wEh*uP4F&@tIbQeKJ!{UT%$f#qMb}$#L2FkL?p))q%|J%I=I^@juph zb&gdik?Gnr-<~}{throw TypeError(e)};var _n=(e,t,n)=>t in e?cn(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var de=(e,t,n)=>_n(e,typeof t!="symbol"?t+"":t,n),Ke=(e,t,n)=>t.has(e)||wt("Cannot "+n);var p=(e,t,n)=>(Ke(e,t,"read from private field"),n?n.call(e):t.get(e)),F=(e,t,n)=>t.has(e)?wt("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),z=(e,t,n,r)=>(Ke(e,t,"write to private field"),r?r.call(e,n):t.set(e,n),n),K=(e,t,n)=>(Ke(e,t,"access private method"),n);var vn=Array.isArray,dn=Array.prototype.indexOf,me=Array.prototype.includes,lr=Array.from,or=Object.defineProperty,Re=Object.getOwnPropertyDescriptor,pn=Object.getOwnPropertyDescriptors,hn=Object.prototype,wn=Array.prototype,kt=Object.getPrototypeOf,yt=Object.isExtensible;const yn=()=>{};function ur(e){return e()}function En(e){for(var t=0;t{e=r,t=s});return{promise:n,resolve:e,reject:t}}function cr(e,t){if(Array.isArray(e))return e;if(t===void 0||!(Symbol.iterator in e))return Array.from(e);const n=[];for(const r of e)if(n.push(r),n.length===t)break;return n}const A=2,De=4,Ie=8,Dt=1<<24,G=16,H=32,ve=64,mn=128,P=512,g=1024,R=2048,Y=4096,j=8192,Z=16384,oe=32768,je=65536,Et=1<<17,It=1<<18,Pe=1<<19,Pt=1<<20,_r=1<<25,ue=65536,Xe=1<<21,st=1<<22,W=1<<23,ae=Symbol("$state"),vr=Symbol("legacy props"),dr=Symbol(""),ne=new class extends Error{constructor(){super(...arguments);de(this,"name","StaleReactionError");de(this,"message","The reaction that called `getAbortSignal()` was re-run or destroyed")}};var Nt;const hr=!!((Nt=globalThis.document)!=null&&Nt.contentType)&&globalThis.document.contentType.includes("xml"),Ue=3,Ct=8;function gn(){throw new Error("https://svelte.dev/e/async_derived_orphan")}function wr(e,t,n){throw new Error("https://svelte.dev/e/each_key_duplicate")}function Tn(e){throw new Error("https://svelte.dev/e/effect_in_teardown")}function bn(){throw new Error("https://svelte.dev/e/effect_in_unowned_derived")}function An(e){throw new Error("https://svelte.dev/e/effect_orphan")}function Sn(){throw new Error("https://svelte.dev/e/effect_update_depth_exceeded")}function yr(){throw new Error("https://svelte.dev/e/hydration_failed")}function Er(e){throw new Error("https://svelte.dev/e/props_invalid_value")}function Rn(){throw new Error("https://svelte.dev/e/state_descriptors_fixed")}function On(){throw new Error("https://svelte.dev/e/state_prototype_fixed")}function Nn(){throw new Error("https://svelte.dev/e/state_unsafe_mutation")}function mr(){throw new Error("https://svelte.dev/e/svelte_boundary_reset_onerror")}const gr=1,Tr=2,br=4,Ar=8,Sr=16,Rr=1,Or=2,Nr=4,kr=8,xr=16,Dr=1,Ir=2,kn="[",xn="[!",Pr="[?",Dn="]",ft={},T=Symbol(),In="http://www.w3.org/1999/xhtml";function it(e){console.warn("https://svelte.dev/e/hydration_mismatch")}function Cr(){console.warn("https://svelte.dev/e/select_multiple_invalid_value")}function Fr(){console.warn("https://svelte.dev/e/svelte_boundary_reset_noop")}let Q=!1;function Mr(e){Q=e}let m;function ge(e){if(e===null)throw it(),ft;return m=e}function Lr(){return ge(te(m))}function jr(e){if(Q){if(te(m)!==null)throw it(),ft;m=e}}function Yr(e=1){if(Q){for(var t=e,n=m;t--;)n=te(n);m=n}}function Hr(e=!0){for(var t=0,n=m;;){if(n.nodeType===Ct){var r=n.data;if(r===Dn){if(t===0)return n;t-=1}else(r===kn||r===xn||r[0]==="["&&!isNaN(Number(r.slice(1))))&&(t+=1)}var s=te(n);e&&n.remove(),n=s}}function qr(e){if(!e||e.nodeType!==Ct)throw it(),ft;return e.data}function Ft(e){return e===this.v}function Pn(e,t){return e!=e?t==t:e!==t||e!==null&&typeof e=="object"||typeof e=="function"}function Mt(e){return!Pn(e,this.v)}let Be=!1;function Vr(){Be=!0}let S=null;function Ye(e){S=e}function Ur(e,t=!1,n){S={p:S,i:!1,c:null,e:null,s:e,x:null,l:Be&&!t?{s:null,u:null,$:[]}:null}}function Br(e){var t=S,n=t.e;if(n!==null){t.e=null;for(var r of n)Jt(r)}return t.i=!0,S=t.p,{}}function Ce(){return!Be||S!==null&&S.l===null}let re=[];function Lt(){var e=re;re=[],En(e)}function mt(e){if(re.length===0&&!Oe){var t=re;queueMicrotask(()=>{t===re&&Lt()})}re.push(e)}function Cn(){for(;re.length>0;)Lt()}function Fn(e){var t=w;if(t===null)return _.f|=W,e;if((t.f&oe)===0&&(t.f&De)===0)throw e;He(e,t)}function He(e,t){for(;t!==null;){if((t.f&mn)!==0){if((t.f&oe)===0)throw e;try{t.b.error(e);return}catch(n){e=n}}t=t.parent}throw e}const Mn=-7169;function E(e,t){e.f=e.f&Mn|t}function at(e){(e.f&P)!==0||e.deps===null?E(e,g):E(e,Y)}function jt(e){if(e!==null)for(const t of e)(t.f&A)===0||(t.f&ue)===0||(t.f^=ue,jt(t.deps))}function Ln(e,t,n){(e.f&R)!==0?t.add(e):(e.f&Y)!==0&&n.add(e),jt(e.deps),E(e,g)}const Me=new Set;let d=null,gt=null,b=null,N=[],Ge=null,Ze=!1,Oe=!1;var he,we,fe,ye,ke,xe,ie,U,Ee,D,We,Je,Qe,Yt;const dt=class dt{constructor(){F(this,D);de(this,"current",new Map);de(this,"previous",new Map);F(this,he,new Set);F(this,we,new Set);F(this,fe,0);F(this,ye,0);F(this,ke,null);F(this,xe,new Set);F(this,ie,new Set);F(this,U,new Map);de(this,"is_fork",!1);F(this,Ee,!1)}skip_effect(t){p(this,U).has(t)||p(this,U).set(t,{d:[],m:[]})}unskip_effect(t){var n=p(this,U).get(t);if(n){p(this,U).delete(t);for(var r of n.d)E(r,R),B(r);for(r of n.m)E(r,Y),B(r)}}process(t){var s;N=[],this.apply();var n=[],r=[];for(const f of t)K(this,D,Je).call(this,f,n,r);if(K(this,D,We).call(this)){K(this,D,Qe).call(this,r),K(this,D,Qe).call(this,n);for(const[f,a]of p(this,U))Ut(f,a)}else{for(const f of p(this,he))f();p(this,he).clear(),p(this,fe)===0&&K(this,D,Yt).call(this),gt=this,d=null,Tt(r),Tt(n),gt=null,(s=p(this,ke))==null||s.resolve()}b=null}capture(t,n){n!==T&&!this.previous.has(t)&&this.previous.set(t,n),(t.f&W)===0&&(this.current.set(t,t.v),b==null||b.set(t,t.v))}activate(){d=this,this.apply()}deactivate(){d===this&&(d=null,b=null)}flush(){if(this.activate(),N.length>0){if(Ht(),d!==null&&d!==this)return}else p(this,fe)===0&&this.process([]);this.deactivate()}discard(){for(const t of p(this,we))t(this);p(this,we).clear()}increment(t){z(this,fe,p(this,fe)+1),t&&z(this,ye,p(this,ye)+1)}decrement(t){z(this,fe,p(this,fe)-1),t&&z(this,ye,p(this,ye)-1),!p(this,Ee)&&(z(this,Ee,!0),mt(()=>{z(this,Ee,!1),K(this,D,We).call(this)?N.length>0&&this.flush():this.revive()}))}revive(){for(const t of p(this,xe))p(this,ie).delete(t),E(t,R),B(t);for(const t of p(this,ie))E(t,Y),B(t);this.flush()}oncommit(t){p(this,he).add(t)}ondiscard(t){p(this,we).add(t)}settled(){return(p(this,ke)??z(this,ke,xt())).promise}static ensure(){if(d===null){const t=d=new dt;Me.add(d),Oe||mt(()=>{d===t&&t.flush()})}return d}apply(){}};he=new WeakMap,we=new WeakMap,fe=new WeakMap,ye=new WeakMap,ke=new WeakMap,xe=new WeakMap,ie=new WeakMap,U=new WeakMap,Ee=new WeakMap,D=new WeakSet,We=function(){return this.is_fork||p(this,ye)>0},Je=function(t,n,r){t.f^=g;for(var s=t.first;s!==null;){var f=s.f,a=(f&(H|ve))!==0,l=a&&(f&g)!==0,i=l||(f&j)!==0||p(this,U).has(s);if(!i&&s.fn!==null){a?s.f^=g:(f&De)!==0?n.push(s):Fe(s)&&((f&G)!==0&&p(this,ie).add(s),Ae(s));var o=s.first;if(o!==null){s=o;continue}}for(;s!==null;){var c=s.next;if(c!==null){s=c;break}s=s.parent}}},Qe=function(t){for(var n=0;n1){this.previous.clear();var t=b,n=!0;for(const f of Me){if(f===this){n=!1;continue}const a=[];for(const[i,o]of this.current){if(f.current.has(i))if(n&&o!==f.current.get(i))f.current.set(i,o);else continue;a.push(i)}if(a.length===0)continue;const l=[...f.current.keys()].filter(i=>!this.current.has(i));if(l.length>0){var r=N;N=[];const i=new Set,o=new Map;for(const c of a)qt(c,l,i,o);if(N.length>0){d=f,f.apply();for(const c of N)K(s=f,D,Je).call(s,c,[],[]);f.deactivate()}N=r}}d=null,b=t}Me.delete(this)};let Te=dt;function jn(e){var t=Oe;Oe=!0;try{for(var n;;){if(Cn(),N.length===0&&(d==null||d.flush(),N.length===0))return Ge=null,n;Ht()}}finally{Oe=t}}function Ht(){Ze=!0;var e=null;try{for(var t=0;N.length>0;){var n=Te.ensure();if(t++>1e3){var r,s;Yn()}n.process(N),J.clear()}}finally{N=[],Ze=!1,Ge=null}}function Yn(){try{Sn()}catch(e){He(e,Ge)}}let M=null;function Tt(e){var t=e.length;if(t!==0){for(var n=0;n0)){J.clear();for(const s of M){if((s.f&(Z|j))!==0)continue;const f=[s];let a=s.parent;for(;a!==null;)M.has(a)&&(M.delete(a),f.push(a)),a=a.parent;for(let l=f.length-1;l>=0;l--){const i=f[l];(i.f&(Z|j))===0&&Ae(i)}}M.clear()}}M=null}}function qt(e,t,n,r){if(!n.has(e)&&(n.add(e),e.reactions!==null))for(const s of e.reactions){const f=s.f;(f&A)!==0?qt(s,t,n,r):(f&(st|G))!==0&&(f&R)===0&&Vt(s,t,r)&&(E(s,R),B(s))}}function Vt(e,t,n){const r=n.get(e);if(r!==void 0)return r;if(e.deps!==null)for(const s of e.deps){if(me.call(t,s))return!0;if((s.f&A)!==0&&Vt(s,t,n))return n.set(s,!0),!0}return n.set(e,!1),!1}function B(e){var t=Ge=e,n=t.b;if(n!=null&&n.is_pending&&(e.f&(De|Ie|Dt))!==0&&(e.f&oe)===0){n.defer_effect(e);return}for(;t.parent!==null;){t=t.parent;var r=t.f;if(Ze&&t===w&&(r&G)!==0&&(r&It)===0&&(r&oe)!==0)return;if((r&(ve|H))!==0){if((r&g)===0)return;t.f^=g}}N.push(t)}function Ut(e,t){if(!((e.f&H)!==0&&(e.f&g)!==0)){(e.f&R)!==0?t.d.push(e):(e.f&Y)!==0&&t.m.push(e),E(e,g);for(var n=e.first;n!==null;)Ut(n,t),n=n.next}}function Hn(e,t,n,r){const s=Ce()?lt:Bn;var f=e.filter(u=>!u.settled);if(n.length===0&&f.length===0){r(t.map(s));return}var a=w,l=qn(),i=f.length===1?f[0].promise:f.length>1?Promise.all(f.map(u=>u.promise)):null;function o(u){l();try{r(u)}catch(v){(a.f&Z)===0&&He(v,a)}et()}if(n.length===0){i.then(()=>o(t.map(s)));return}function c(){l(),Promise.all(n.map(u=>Un(u))).then(u=>o([...t.map(s),...u])).catch(u=>He(u,a))}i?i.then(c):c()}function qn(){var e=w,t=_,n=S,r=d;return function(f=!0){be(e),ee(t),Ye(n),f&&(r==null||r.activate())}}function et(e=!0){be(null),ee(null),Ye(null),e&&(d==null||d.deactivate())}function Vn(){var e=w.b,t=d,n=e.is_rendered();return e.update_pending_count(1),t.increment(n),()=>{e.update_pending_count(-1),t.decrement(n)}}function lt(e){var t=A|R,n=_!==null&&(_.f&A)!==0?_:null;return w!==null&&(w.f|=Pe),{ctx:S,deps:null,effects:null,equals:Ft,f:t,fn:e,reactions:null,rv:0,v:T,wv:0,parent:n??w,ac:null}}function Un(e,t,n){w===null&&gn();var s=void 0,f=ut(T),a=!_,l=new Map;return tr(()=>{var v;var i=xt();s=i.promise;try{Promise.resolve(e()).then(i.resolve,i.reject).finally(et)}catch(y){i.reject(y),et()}var o=d;if(a){var c=Vn();(v=l.get(o))==null||v.reject(ne),l.delete(o),l.set(o,i)}const u=(y,h=void 0)=>{if(o.activate(),h)h!==ne&&(f.f|=W,nt(f,h));else{(f.f&W)!==0&&(f.f^=W),nt(f,y);for(const[V,O]of l){if(l.delete(V),V===o)break;O.reject(ne)}}c&&c()};i.promise.then(u,y=>u(null,y||"unknown"))}),er(()=>{for(const i of l.values())i.reject(ne)}),new Promise(i=>{function o(c){function u(){c===s?i(f):o(s)}c.then(u,u)}o(s)})}function Gr(e){const t=lt(e);return rn(t),t}function Bn(e){const t=lt(e);return t.equals=Mt,t}function Gn(e){var t=e.effects;if(t!==null){e.effects=null;for(var n=0;n0&&!zt&&$n()}return t}function $n(){zt=!1;for(const e of tt)(e.f&g)!==0&&E(e,Y),Fe(e)&&Ae(e);tt.clear()}function Kr(e,t=1){var n=pe(e),r=t===1?n++:n--;return X(e,n),r}function $e(e){X(e,e.v+1)}function Kt(e,t){var n=e.reactions;if(n!==null)for(var r=Ce(),s=n.length,f=0;f{if(le===f)return l();var i=_,o=le;ee(null),Ot(f);var c=l();return ee(i),Ot(o),c};return r&&n.set("length",$(e.length)),new Proxy(e,{defineProperty(l,i,o){(!("value"in o)||o.configurable===!1||o.enumerable===!1||o.writable===!1)&&Rn();var c=n.get(i);return c===void 0?a(()=>{var u=$(o.value);return n.set(i,u),u}):X(c,o.value,!0),!0},deleteProperty(l,i){var o=n.get(i);if(o===void 0){if(i in l){const c=a(()=>$(T));n.set(i,c),$e(s)}}else X(o,T),$e(s);return!0},get(l,i,o){var y;if(i===ae)return e;var c=n.get(i),u=i in l;if(c===void 0&&(!u||(y=Re(l,i))!=null&&y.writable)&&(c=a(()=>{var h=Se(u?l[i]:T),V=$(h);return V}),n.set(i,c)),c!==void 0){var v=pe(c);return v===T?void 0:v}return Reflect.get(l,i,o)},getOwnPropertyDescriptor(l,i){var o=Reflect.getOwnPropertyDescriptor(l,i);if(o&&"value"in o){var c=n.get(i);c&&(o.value=pe(c))}else if(o===void 0){var u=n.get(i),v=u==null?void 0:u.v;if(u!==void 0&&v!==T)return{enumerable:!0,configurable:!0,value:v,writable:!0}}return o},has(l,i){var v;if(i===ae)return!0;var o=n.get(i),c=o!==void 0&&o.v!==T||Reflect.has(l,i);if(o!==void 0||w!==null&&(!c||(v=Re(l,i))!=null&&v.writable)){o===void 0&&(o=a(()=>{var y=c?Se(l[i]):T,h=$(y);return h}),n.set(i,o));var u=pe(o);if(u===T)return!1}return c},set(l,i,o,c){var ht;var u=n.get(i),v=i in l;if(r&&i==="length")for(var y=o;y$(T)),n.set(y+"",h))}if(u===void 0)(!v||(ht=Re(l,i))!=null&&ht.writable)&&(u=a(()=>$(void 0)),X(u,Se(o)),n.set(i,u));else{v=u.v!==T;var V=a(()=>Se(o));X(u,V)}var O=Reflect.getOwnPropertyDescriptor(l,i);if(O!=null&&O.set&&O.set.call(c,o),!v){if(r&&typeof i=="string"){var pt=n.get("length"),ze=Number(i);Number.isInteger(ze)&&ze>=pt.v&&X(pt,ze+1)}$e(s)}return!0},ownKeys(l){pe(s);var i=Reflect.ownKeys(l).filter(u=>{var v=n.get(u);return v===void 0||v.v!==T});for(var[o,c]of n)c.v!==T&&!(o in l)&&i.push(o);return i},setPrototypeOf(){On()}})}function bt(e){try{if(e!==null&&typeof e=="object"&&ae in e)return e[ae]}catch{}return e}function $r(e,t){return Object.is(bt(e),bt(t))}var At,Xn,Zn,$t,Xt;function Xr(){if(At===void 0){At=window,Xn=document,Zn=/Firefox/.test(navigator.userAgent);var e=Element.prototype,t=Node.prototype,n=Text.prototype;$t=Re(t,"firstChild").get,Xt=Re(t,"nextSibling").get,yt(e)&&(e.__click=void 0,e.__className=void 0,e.__attributes=null,e.__style=void 0,e.__e=void 0),yt(n)&&(n.__t=void 0)}}function qe(e=""){return document.createTextNode(e)}function Ve(e){return $t.call(e)}function te(e){return Xt.call(e)}function Zr(e,t){if(!Q)return Ve(e);var n=Ve(m);if(n===null)n=m.appendChild(qe());else if(t&&n.nodeType!==Ue){var r=qe();return n==null||n.before(r),ge(r),r}return t&&ct(n),ge(n),n}function Wr(e,t=!1){if(!Q){var n=Ve(e);return n instanceof Comment&&n.data===""?te(n):n}if(t){if((m==null?void 0:m.nodeType)!==Ue){var r=qe();return m==null||m.before(r),ge(r),r}ct(m)}return m}function Jr(e,t=1,n=!1){let r=Q?m:e;for(var s;t--;)s=r,r=te(r);if(!Q)return r;if(n){if((r==null?void 0:r.nodeType)!==Ue){var f=qe();return r===null?s==null||s.after(f):r.before(f),ge(f),f}ct(r)}return ge(r),r}function Wn(e){e.textContent=""}function Qr(){return!1}function es(e,t,n){return document.createElementNS(In,e,void 0)}function ct(e){if(e.nodeValue.length<65536)return;let t=e.nextSibling;for(;t!==null&&t.nodeType===Ue;)t.remove(),e.nodeValue+=t.nodeValue,t=e.nextSibling}function ts(e){Q&&Ve(e)!==null&&Wn(e)}let St=!1;function Jn(){St||(St=!0,document.addEventListener("reset",e=>{Promise.resolve().then(()=>{var t;if(!e.defaultPrevented)for(const n of e.target.elements)(t=n.__on_r)==null||t.call(n)})},{capture:!0}))}function _t(e){var t=_,n=w;ee(null),be(null);try{return e()}finally{ee(t),be(n)}}function ns(e,t,n,r=n){e.addEventListener(t,()=>_t(n));const s=e.__on_r;s?e.__on_r=()=>{s(),r(!0)}:e.__on_r=()=>r(!0),Jn()}function Zt(e){w===null&&(_===null&&An(),bn()),_e&&Tn()}function Qn(e,t){var n=t.last;n===null?t.last=t.first=e:(n.next=e,e.prev=n,t.last=e)}function q(e,t,n){var r=w;r!==null&&(r.f&j)!==0&&(e|=j);var s={ctx:S,deps:null,nodes:null,f:e|R|P,first:null,fn:t,last:null,next:null,parent:r,b:r&&r.b,prev:null,teardown:null,wv:0,ac:null};if(n)try{Ae(s)}catch(l){throw ce(s),l}else t!==null&&B(s);var f=s;if(n&&f.deps===null&&f.teardown===null&&f.nodes===null&&f.first===f.last&&(f.f&Pe)===0&&(f=f.first,(e&G)!==0&&(e&je)!==0&&f!==null&&(f.f|=je)),f!==null&&(f.parent=r,r!==null&&Qn(f,r),_!==null&&(_.f&A)!==0&&(e&ve)===0)){var a=_;(a.effects??(a.effects=[])).push(f)}return s}function Wt(){return _!==null&&!L}function er(e){const t=q(Ie,null,!1);return E(t,g),t.teardown=e,t}function rs(e){Zt();var t=w.f,n=!_&&(t&H)!==0&&(t&oe)===0;if(n){var r=S;(r.e??(r.e=[])).push(e)}else return Jt(e)}function Jt(e){return q(De|Pt,e,!1)}function ss(e){return Zt(),q(Ie|Pt,e,!0)}function fs(e){Te.ensure();const t=q(ve|Pe,e,!0);return(n={})=>new Promise(r=>{n.outro?sr(t,()=>{ce(t),r(void 0)}):(ce(t),r(void 0))})}function is(e){return q(De,e,!1)}function tr(e){return q(st|Pe,e,!0)}function as(e,t=0){return q(Ie|t,e,!0)}function ls(e,t=[],n=[],r=[]){Hn(r,t,n,s=>{q(Ie,()=>e(...s.map(pe)),!0)})}function os(e,t=0){var n=q(G|t,e,!0);return n}function us(e){return q(H|Pe,e,!0)}function Qt(e){var t=e.teardown;if(t!==null){const n=_e,r=_;Rt(!0),ee(null);try{t.call(null)}finally{Rt(n),ee(r)}}}function vt(e,t=!1){var n=e.first;for(e.first=e.last=null;n!==null;){const s=n.ac;s!==null&&_t(()=>{s.abort(ne)});var r=n.next;(n.f&ve)!==0?n.parent=null:ce(n,t),n=r}}function nr(e){for(var t=e.first;t!==null;){var n=t.next;(t.f&H)===0&&ce(t),t=n}}function ce(e,t=!0){var n=!1;(t||(e.f&It)!==0)&&e.nodes!==null&&e.nodes.end!==null&&(rr(e.nodes.start,e.nodes.end),n=!0),vt(e,t&&!n),Ne(e,0),E(e,Z);var r=e.nodes&&e.nodes.t;if(r!==null)for(const f of r)f.stop();Qt(e);var s=e.parent;s!==null&&s.first!==null&&en(e),e.next=e.prev=e.teardown=e.ctx=e.deps=e.fn=e.nodes=e.ac=null}function rr(e,t){for(;e!==null;){var n=e===t?null:te(e);e.remove(),e=n}}function en(e){var t=e.parent,n=e.prev,r=e.next;n!==null&&(n.next=r),r!==null&&(r.prev=n),t!==null&&(t.first===e&&(t.first=r),t.last===e&&(t.last=n))}function sr(e,t,n=!0){var r=[];tn(e,r,!0);var s=()=>{n&&ce(e),t&&t()},f=r.length;if(f>0){var a=()=>--f||s();for(var l of r)l.out(a)}else s()}function tn(e,t,n){if((e.f&j)===0){e.f^=j;var r=e.nodes&&e.nodes.t;if(r!==null)for(const l of r)(l.is_global||n)&&t.push(l);for(var s=e.first;s!==null;){var f=s.next,a=(s.f&je)!==0||(s.f&H)!==0&&(e.f&G)!==0;tn(s,t,a?n:!1),s=f}}}function cs(e){nn(e,!0)}function nn(e,t){if((e.f&j)!==0){e.f^=j,(e.f&g)===0&&(E(e,R),B(e));for(var n=e.first;n!==null;){var r=n.next,s=(n.f&je)!==0||(n.f&H)!==0;nn(n,s?t:!1),n=r}var f=e.nodes&&e.nodes.t;if(f!==null)for(const a of f)(a.is_global||t)&&a.in()}}function _s(e,t){if(e.nodes)for(var n=e.nodes.start,r=e.nodes.end;n!==null;){var s=n===r?null:te(n);t.append(n),n=s}}let Le=!1,_e=!1;function Rt(e){_e=e}let _=null,L=!1;function ee(e){_=e}let w=null;function be(e){w=e}let C=null;function rn(e){_!==null&&(C===null?C=[e]:C.push(e))}let k=null,x=0,I=null;function fr(e){I=e}let sn=1,se=0,le=se;function Ot(e){le=e}function fn(){return++sn}function Fe(e){var t=e.f;if((t&R)!==0)return!0;if(t&A&&(e.f&=~ue),(t&Y)!==0){for(var n=e.deps,r=n.length,s=0;se.wv)return!0}(t&P)!==0&&b===null&&E(e,g)}return!1}function an(e,t,n=!0){var r=e.reactions;if(r!==null&&!(C!==null&&me.call(C,e)))for(var s=0;s{e.ac.abort(ne)}),e.ac=null);try{e.f|=Xe;var c=e.fn,u=c();e.f|=oe;var v=e.deps,y=d==null?void 0:d.is_fork;if(k!==null){var h;if(y||Ne(e,x),v!==null&&x>0)for(v.length=x+k.length,h=0;h{throw TypeError(e)};var _n=(e,t,n)=>t in e?cn(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var de=(e,t,n)=>_n(e,typeof t!="symbol"?t+"":t,n),Ke=(e,t,n)=>t.has(e)||wt("Cannot "+n);var p=(e,t,n)=>(Ke(e,t,"read from private field"),n?n.call(e):t.get(e)),F=(e,t,n)=>t.has(e)?wt("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),z=(e,t,n,r)=>(Ke(e,t,"write to private field"),r?r.call(e,n):t.set(e,n),n),K=(e,t,n)=>(Ke(e,t,"access private method"),n);var vn=Array.isArray,dn=Array.prototype.indexOf,me=Array.prototype.includes,lr=Array.from,or=Object.defineProperty,Re=Object.getOwnPropertyDescriptor,pn=Object.getOwnPropertyDescriptors,hn=Object.prototype,wn=Array.prototype,kt=Object.getPrototypeOf,yt=Object.isExtensible;const yn=()=>{};function ur(e){return e()}function En(e){for(var t=0;t{e=r,t=s});return{promise:n,resolve:e,reject:t}}function cr(e,t){if(Array.isArray(e))return e;if(t===void 0||!(Symbol.iterator in e))return Array.from(e);const n=[];for(const r of e)if(n.push(r),n.length===t)break;return n}const A=2,De=4,Ie=8,Dt=1<<24,G=16,H=32,ve=64,mn=128,P=512,g=1024,R=2048,Y=4096,j=8192,Z=16384,oe=32768,je=65536,Et=1<<17,It=1<<18,Pe=1<<19,Pt=1<<20,_r=1<<25,ue=65536,Xe=1<<21,st=1<<22,W=1<<23,ae=Symbol("$state"),vr=Symbol("legacy props"),dr=Symbol(""),ne=new class extends Error{constructor(){super(...arguments);de(this,"name","StaleReactionError");de(this,"message","The reaction that called `getAbortSignal()` was re-run or destroyed")}};var Nt;const hr=!!((Nt=globalThis.document)!=null&&Nt.contentType)&&globalThis.document.contentType.includes("xml"),Ue=3,Ct=8;function gn(){throw new Error("https://svelte.dev/e/async_derived_orphan")}function wr(e,t,n){throw new Error("https://svelte.dev/e/each_key_duplicate")}function Tn(e){throw new Error("https://svelte.dev/e/effect_in_teardown")}function bn(){throw new Error("https://svelte.dev/e/effect_in_unowned_derived")}function An(e){throw new Error("https://svelte.dev/e/effect_orphan")}function Sn(){throw new Error("https://svelte.dev/e/effect_update_depth_exceeded")}function yr(){throw new Error("https://svelte.dev/e/hydration_failed")}function Er(e){throw new Error("https://svelte.dev/e/props_invalid_value")}function Rn(){throw new Error("https://svelte.dev/e/state_descriptors_fixed")}function On(){throw new Error("https://svelte.dev/e/state_prototype_fixed")}function Nn(){throw new Error("https://svelte.dev/e/state_unsafe_mutation")}function mr(){throw new Error("https://svelte.dev/e/svelte_boundary_reset_onerror")}const gr=1,Tr=2,br=4,Ar=8,Sr=16,Rr=1,Or=2,Nr=4,kr=8,xr=16,Dr=1,Ir=2,kn="[",xn="[!",Pr="[?",Dn="]",ft={},T=Symbol(),In="http://www.w3.org/1999/xhtml";function it(e){console.warn("https://svelte.dev/e/hydration_mismatch")}function Cr(){console.warn("https://svelte.dev/e/select_multiple_invalid_value")}function Fr(){console.warn("https://svelte.dev/e/svelte_boundary_reset_noop")}let Q=!1;function Mr(e){Q=e}let m;function ge(e){if(e===null)throw it(),ft;return m=e}function Lr(){return ge(te(m))}function jr(e){if(Q){if(te(m)!==null)throw it(),ft;m=e}}function Yr(e=1){if(Q){for(var t=e,n=m;t--;)n=te(n);m=n}}function Hr(e=!0){for(var t=0,n=m;;){if(n.nodeType===Ct){var r=n.data;if(r===Dn){if(t===0)return n;t-=1}else(r===kn||r===xn||r[0]==="["&&!isNaN(Number(r.slice(1))))&&(t+=1)}var s=te(n);e&&n.remove(),n=s}}function qr(e){if(!e||e.nodeType!==Ct)throw it(),ft;return e.data}function Ft(e){return e===this.v}function Pn(e,t){return e!=e?t==t:e!==t||e!==null&&typeof e=="object"||typeof e=="function"}function Mt(e){return!Pn(e,this.v)}let Be=!1;function Vr(){Be=!0}let S=null;function Ye(e){S=e}function Ur(e,t=!1,n){S={p:S,i:!1,c:null,e:null,s:e,x:null,l:Be&&!t?{s:null,u:null,$:[]}:null}}function Br(e){var t=S,n=t.e;if(n!==null){t.e=null;for(var r of n)Jt(r)}return t.i=!0,S=t.p,{}}function Ce(){return!Be||S!==null&&S.l===null}let re=[];function Lt(){var e=re;re=[],En(e)}function mt(e){if(re.length===0&&!Oe){var t=re;queueMicrotask(()=>{t===re&&Lt()})}re.push(e)}function Cn(){for(;re.length>0;)Lt()}function Fn(e){var t=w;if(t===null)return _.f|=W,e;if((t.f&oe)===0&&(t.f&De)===0)throw e;He(e,t)}function He(e,t){for(;t!==null;){if((t.f&mn)!==0){if((t.f&oe)===0)throw e;try{t.b.error(e);return}catch(n){e=n}}t=t.parent}throw e}const Mn=-7169;function E(e,t){e.f=e.f&Mn|t}function at(e){(e.f&P)!==0||e.deps===null?E(e,g):E(e,Y)}function jt(e){if(e!==null)for(const t of e)(t.f&A)===0||(t.f&ue)===0||(t.f^=ue,jt(t.deps))}function Ln(e,t,n){(e.f&R)!==0?t.add(e):(e.f&Y)!==0&&n.add(e),jt(e.deps),E(e,g)}const Me=new Set;let d=null,gt=null,b=null,N=[],Ge=null,Ze=!1,Oe=!1;var he,we,fe,ye,ke,xe,ie,U,Ee,D,We,Je,Qe,Yt;const dt=class dt{constructor(){F(this,D);de(this,"current",new Map);de(this,"previous",new Map);F(this,he,new Set);F(this,we,new Set);F(this,fe,0);F(this,ye,0);F(this,ke,null);F(this,xe,new Set);F(this,ie,new Set);F(this,U,new Map);de(this,"is_fork",!1);F(this,Ee,!1)}skip_effect(t){p(this,U).has(t)||p(this,U).set(t,{d:[],m:[]})}unskip_effect(t){var n=p(this,U).get(t);if(n){p(this,U).delete(t);for(var r of n.d)E(r,R),B(r);for(r of n.m)E(r,Y),B(r)}}process(t){var s;N=[],this.apply();var n=[],r=[];for(const f of t)K(this,D,Je).call(this,f,n,r);if(K(this,D,We).call(this)){K(this,D,Qe).call(this,r),K(this,D,Qe).call(this,n);for(const[f,a]of p(this,U))Ut(f,a)}else{for(const f of p(this,he))f();p(this,he).clear(),p(this,fe)===0&&K(this,D,Yt).call(this),gt=this,d=null,Tt(r),Tt(n),gt=null,(s=p(this,ke))==null||s.resolve()}b=null}capture(t,n){n!==T&&!this.previous.has(t)&&this.previous.set(t,n),(t.f&W)===0&&(this.current.set(t,t.v),b==null||b.set(t,t.v))}activate(){d=this,this.apply()}deactivate(){d===this&&(d=null,b=null)}flush(){if(this.activate(),N.length>0){if(Ht(),d!==null&&d!==this)return}else p(this,fe)===0&&this.process([]);this.deactivate()}discard(){for(const t of p(this,we))t(this);p(this,we).clear()}increment(t){z(this,fe,p(this,fe)+1),t&&z(this,ye,p(this,ye)+1)}decrement(t){z(this,fe,p(this,fe)-1),t&&z(this,ye,p(this,ye)-1),!p(this,Ee)&&(z(this,Ee,!0),mt(()=>{z(this,Ee,!1),K(this,D,We).call(this)?N.length>0&&this.flush():this.revive()}))}revive(){for(const t of p(this,xe))p(this,ie).delete(t),E(t,R),B(t);for(const t of p(this,ie))E(t,Y),B(t);this.flush()}oncommit(t){p(this,he).add(t)}ondiscard(t){p(this,we).add(t)}settled(){return(p(this,ke)??z(this,ke,xt())).promise}static ensure(){if(d===null){const t=d=new dt;Me.add(d),Oe||mt(()=>{d===t&&t.flush()})}return d}apply(){}};he=new WeakMap,we=new WeakMap,fe=new WeakMap,ye=new WeakMap,ke=new WeakMap,xe=new WeakMap,ie=new WeakMap,U=new WeakMap,Ee=new WeakMap,D=new WeakSet,We=function(){return this.is_fork||p(this,ye)>0},Je=function(t,n,r){t.f^=g;for(var s=t.first;s!==null;){var f=s.f,a=(f&(H|ve))!==0,l=a&&(f&g)!==0,i=l||(f&j)!==0||p(this,U).has(s);if(!i&&s.fn!==null){a?s.f^=g:(f&De)!==0?n.push(s):Fe(s)&&((f&G)!==0&&p(this,ie).add(s),Ae(s));var o=s.first;if(o!==null){s=o;continue}}for(;s!==null;){var c=s.next;if(c!==null){s=c;break}s=s.parent}}},Qe=function(t){for(var n=0;n1){this.previous.clear();var t=b,n=!0;for(const f of Me){if(f===this){n=!1;continue}const a=[];for(const[i,o]of this.current){if(f.current.has(i))if(n&&o!==f.current.get(i))f.current.set(i,o);else continue;a.push(i)}if(a.length===0)continue;const l=[...f.current.keys()].filter(i=>!this.current.has(i));if(l.length>0){var r=N;N=[];const i=new Set,o=new Map;for(const c of a)qt(c,l,i,o);if(N.length>0){d=f,f.apply();for(const c of N)K(s=f,D,Je).call(s,c,[],[]);f.deactivate()}N=r}}d=null,b=t}Me.delete(this)};let Te=dt;function jn(e){var t=Oe;Oe=!0;try{for(var n;;){if(Cn(),N.length===0&&(d==null||d.flush(),N.length===0))return Ge=null,n;Ht()}}finally{Oe=t}}function Ht(){Ze=!0;var e=null;try{for(var t=0;N.length>0;){var n=Te.ensure();if(t++>1e3){var r,s;Yn()}n.process(N),J.clear()}}finally{N=[],Ze=!1,Ge=null}}function Yn(){try{Sn()}catch(e){He(e,Ge)}}let M=null;function Tt(e){var t=e.length;if(t!==0){for(var n=0;n0)){J.clear();for(const s of M){if((s.f&(Z|j))!==0)continue;const f=[s];let a=s.parent;for(;a!==null;)M.has(a)&&(M.delete(a),f.push(a)),a=a.parent;for(let l=f.length-1;l>=0;l--){const i=f[l];(i.f&(Z|j))===0&&Ae(i)}}M.clear()}}M=null}}function qt(e,t,n,r){if(!n.has(e)&&(n.add(e),e.reactions!==null))for(const s of e.reactions){const f=s.f;(f&A)!==0?qt(s,t,n,r):(f&(st|G))!==0&&(f&R)===0&&Vt(s,t,r)&&(E(s,R),B(s))}}function Vt(e,t,n){const r=n.get(e);if(r!==void 0)return r;if(e.deps!==null)for(const s of e.deps){if(me.call(t,s))return!0;if((s.f&A)!==0&&Vt(s,t,n))return n.set(s,!0),!0}return n.set(e,!1),!1}function B(e){var t=Ge=e,n=t.b;if(n!=null&&n.is_pending&&(e.f&(De|Ie|Dt))!==0&&(e.f&oe)===0){n.defer_effect(e);return}for(;t.parent!==null;){t=t.parent;var r=t.f;if(Ze&&t===w&&(r&G)!==0&&(r&It)===0&&(r&oe)!==0)return;if((r&(ve|H))!==0){if((r&g)===0)return;t.f^=g}}N.push(t)}function Ut(e,t){if(!((e.f&H)!==0&&(e.f&g)!==0)){(e.f&R)!==0?t.d.push(e):(e.f&Y)!==0&&t.m.push(e),E(e,g);for(var n=e.first;n!==null;)Ut(n,t),n=n.next}}function Hn(e,t,n,r){const s=Ce()?lt:Bn;var f=e.filter(u=>!u.settled);if(n.length===0&&f.length===0){r(t.map(s));return}var a=w,l=qn(),i=f.length===1?f[0].promise:f.length>1?Promise.all(f.map(u=>u.promise)):null;function o(u){l();try{r(u)}catch(v){(a.f&Z)===0&&He(v,a)}et()}if(n.length===0){i.then(()=>o(t.map(s)));return}function c(){l(),Promise.all(n.map(u=>Un(u))).then(u=>o([...t.map(s),...u])).catch(u=>He(u,a))}i?i.then(c):c()}function qn(){var e=w,t=_,n=S,r=d;return function(f=!0){be(e),ee(t),Ye(n),f&&(r==null||r.activate())}}function et(e=!0){be(null),ee(null),Ye(null),e&&(d==null||d.deactivate())}function Vn(){var e=w.b,t=d,n=e.is_rendered();return e.update_pending_count(1),t.increment(n),()=>{e.update_pending_count(-1),t.decrement(n)}}function lt(e){var t=A|R,n=_!==null&&(_.f&A)!==0?_:null;return w!==null&&(w.f|=Pe),{ctx:S,deps:null,effects:null,equals:Ft,f:t,fn:e,reactions:null,rv:0,v:T,wv:0,parent:n??w,ac:null}}function Un(e,t,n){w===null&&gn();var s=void 0,f=ut(T),a=!_,l=new Map;return tr(()=>{var v;var i=xt();s=i.promise;try{Promise.resolve(e()).then(i.resolve,i.reject).finally(et)}catch(y){i.reject(y),et()}var o=d;if(a){var c=Vn();(v=l.get(o))==null||v.reject(ne),l.delete(o),l.set(o,i)}const u=(y,h=void 0)=>{if(o.activate(),h)h!==ne&&(f.f|=W,nt(f,h));else{(f.f&W)!==0&&(f.f^=W),nt(f,y);for(const[V,O]of l){if(l.delete(V),V===o)break;O.reject(ne)}}c&&c()};i.promise.then(u,y=>u(null,y||"unknown"))}),er(()=>{for(const i of l.values())i.reject(ne)}),new Promise(i=>{function o(c){function u(){c===s?i(f):o(s)}c.then(u,u)}o(s)})}function Gr(e){const t=lt(e);return rn(t),t}function Bn(e){const t=lt(e);return t.equals=Mt,t}function Gn(e){var t=e.effects;if(t!==null){e.effects=null;for(var n=0;n0&&!zt&&$n()}return t}function $n(){zt=!1;for(const e of tt)(e.f&g)!==0&&E(e,Y),Fe(e)&&Ae(e);tt.clear()}function Kr(e,t=1){var n=pe(e),r=t===1?n++:n--;return X(e,n),r}function $e(e){X(e,e.v+1)}function Kt(e,t){var n=e.reactions;if(n!==null)for(var r=Ce(),s=n.length,f=0;f{if(le===f)return l();var i=_,o=le;ee(null),Ot(f);var c=l();return ee(i),Ot(o),c};return r&&n.set("length",$(e.length)),new Proxy(e,{defineProperty(l,i,o){(!("value"in o)||o.configurable===!1||o.enumerable===!1||o.writable===!1)&&Rn();var c=n.get(i);return c===void 0?a(()=>{var u=$(o.value);return n.set(i,u),u}):X(c,o.value,!0),!0},deleteProperty(l,i){var o=n.get(i);if(o===void 0){if(i in l){const c=a(()=>$(T));n.set(i,c),$e(s)}}else X(o,T),$e(s);return!0},get(l,i,o){var y;if(i===ae)return e;var c=n.get(i),u=i in l;if(c===void 0&&(!u||(y=Re(l,i))!=null&&y.writable)&&(c=a(()=>{var h=Se(u?l[i]:T),V=$(h);return V}),n.set(i,c)),c!==void 0){var v=pe(c);return v===T?void 0:v}return Reflect.get(l,i,o)},getOwnPropertyDescriptor(l,i){var o=Reflect.getOwnPropertyDescriptor(l,i);if(o&&"value"in o){var c=n.get(i);c&&(o.value=pe(c))}else if(o===void 0){var u=n.get(i),v=u==null?void 0:u.v;if(u!==void 0&&v!==T)return{enumerable:!0,configurable:!0,value:v,writable:!0}}return o},has(l,i){var v;if(i===ae)return!0;var o=n.get(i),c=o!==void 0&&o.v!==T||Reflect.has(l,i);if(o!==void 0||w!==null&&(!c||(v=Re(l,i))!=null&&v.writable)){o===void 0&&(o=a(()=>{var y=c?Se(l[i]):T,h=$(y);return h}),n.set(i,o));var u=pe(o);if(u===T)return!1}return c},set(l,i,o,c){var ht;var u=n.get(i),v=i in l;if(r&&i==="length")for(var y=o;y$(T)),n.set(y+"",h))}if(u===void 0)(!v||(ht=Re(l,i))!=null&&ht.writable)&&(u=a(()=>$(void 0)),X(u,Se(o)),n.set(i,u));else{v=u.v!==T;var V=a(()=>Se(o));X(u,V)}var O=Reflect.getOwnPropertyDescriptor(l,i);if(O!=null&&O.set&&O.set.call(c,o),!v){if(r&&typeof i=="string"){var pt=n.get("length"),ze=Number(i);Number.isInteger(ze)&&ze>=pt.v&&X(pt,ze+1)}$e(s)}return!0},ownKeys(l){pe(s);var i=Reflect.ownKeys(l).filter(u=>{var v=n.get(u);return v===void 0||v.v!==T});for(var[o,c]of n)c.v!==T&&!(o in l)&&i.push(o);return i},setPrototypeOf(){On()}})}function bt(e){try{if(e!==null&&typeof e=="object"&&ae in e)return e[ae]}catch{}return e}function $r(e,t){return Object.is(bt(e),bt(t))}var At,Xn,Zn,$t,Xt;function Xr(){if(At===void 0){At=window,Xn=document,Zn=/Firefox/.test(navigator.userAgent);var e=Element.prototype,t=Node.prototype,n=Text.prototype;$t=Re(t,"firstChild").get,Xt=Re(t,"nextSibling").get,yt(e)&&(e.__click=void 0,e.__className=void 0,e.__attributes=null,e.__style=void 0,e.__e=void 0),yt(n)&&(n.__t=void 0)}}function qe(e=""){return document.createTextNode(e)}function Ve(e){return $t.call(e)}function te(e){return Xt.call(e)}function Zr(e,t){if(!Q)return Ve(e);var n=Ve(m);if(n===null)n=m.appendChild(qe());else if(t&&n.nodeType!==Ue){var r=qe();return n==null||n.before(r),ge(r),r}return t&&ct(n),ge(n),n}function Wr(e,t=!1){if(!Q){var n=Ve(e);return n instanceof Comment&&n.data===""?te(n):n}if(t){if((m==null?void 0:m.nodeType)!==Ue){var r=qe();return m==null||m.before(r),ge(r),r}ct(m)}return m}function Jr(e,t=1,n=!1){let r=Q?m:e;for(var s;t--;)s=r,r=te(r);if(!Q)return r;if(n){if((r==null?void 0:r.nodeType)!==Ue){var f=qe();return r===null?s==null||s.after(f):r.before(f),ge(f),f}ct(r)}return ge(r),r}function Wn(e){e.textContent=""}function Qr(){return!1}function es(e,t,n){return document.createElementNS(In,e,void 0)}function ct(e){if(e.nodeValue.length<65536)return;let t=e.nextSibling;for(;t!==null&&t.nodeType===Ue;)t.remove(),e.nodeValue+=t.nodeValue,t=e.nextSibling}function ts(e){Q&&Ve(e)!==null&&Wn(e)}let St=!1;function Jn(){St||(St=!0,document.addEventListener("reset",e=>{Promise.resolve().then(()=>{var t;if(!e.defaultPrevented)for(const n of e.target.elements)(t=n.__on_r)==null||t.call(n)})},{capture:!0}))}function _t(e){var t=_,n=w;ee(null),be(null);try{return e()}finally{ee(t),be(n)}}function ns(e,t,n,r=n){e.addEventListener(t,()=>_t(n));const s=e.__on_r;s?e.__on_r=()=>{s(),r(!0)}:e.__on_r=()=>r(!0),Jn()}function Zt(e){w===null&&(_===null&&An(),bn()),_e&&Tn()}function Qn(e,t){var n=t.last;n===null?t.last=t.first=e:(n.next=e,e.prev=n,t.last=e)}function q(e,t,n){var r=w;r!==null&&(r.f&j)!==0&&(e|=j);var s={ctx:S,deps:null,nodes:null,f:e|R|P,first:null,fn:t,last:null,next:null,parent:r,b:r&&r.b,prev:null,teardown:null,wv:0,ac:null};if(n)try{Ae(s)}catch(l){throw ce(s),l}else t!==null&&B(s);var f=s;if(n&&f.deps===null&&f.teardown===null&&f.nodes===null&&f.first===f.last&&(f.f&Pe)===0&&(f=f.first,(e&G)!==0&&(e&je)!==0&&f!==null&&(f.f|=je)),f!==null&&(f.parent=r,r!==null&&Qn(f,r),_!==null&&(_.f&A)!==0&&(e&ve)===0)){var a=_;(a.effects??(a.effects=[])).push(f)}return s}function Wt(){return _!==null&&!L}function er(e){const t=q(Ie,null,!1);return E(t,g),t.teardown=e,t}function rs(e){Zt();var t=w.f,n=!_&&(t&H)!==0&&(t&oe)===0;if(n){var r=S;(r.e??(r.e=[])).push(e)}else return Jt(e)}function Jt(e){return q(De|Pt,e,!1)}function ss(e){return Zt(),q(Ie|Pt,e,!0)}function fs(e){Te.ensure();const t=q(ve|Pe,e,!0);return(n={})=>new Promise(r=>{n.outro?sr(t,()=>{ce(t),r(void 0)}):(ce(t),r(void 0))})}function is(e){return q(De,e,!1)}function tr(e){return q(st|Pe,e,!0)}function as(e,t=0){return q(Ie|t,e,!0)}function ls(e,t=[],n=[],r=[]){Hn(r,t,n,s=>{q(Ie,()=>e(...s.map(pe)),!0)})}function os(e,t=0){var n=q(G|t,e,!0);return n}function us(e){return q(H|Pe,e,!0)}function Qt(e){var t=e.teardown;if(t!==null){const n=_e,r=_;Rt(!0),ee(null);try{t.call(null)}finally{Rt(n),ee(r)}}}function vt(e,t=!1){var n=e.first;for(e.first=e.last=null;n!==null;){const s=n.ac;s!==null&&_t(()=>{s.abort(ne)});var r=n.next;(n.f&ve)!==0?n.parent=null:ce(n,t),n=r}}function nr(e){for(var t=e.first;t!==null;){var n=t.next;(t.f&H)===0&&ce(t),t=n}}function ce(e,t=!0){var n=!1;(t||(e.f&It)!==0)&&e.nodes!==null&&e.nodes.end!==null&&(rr(e.nodes.start,e.nodes.end),n=!0),vt(e,t&&!n),Ne(e,0),E(e,Z);var r=e.nodes&&e.nodes.t;if(r!==null)for(const f of r)f.stop();Qt(e);var s=e.parent;s!==null&&s.first!==null&&en(e),e.next=e.prev=e.teardown=e.ctx=e.deps=e.fn=e.nodes=e.ac=null}function rr(e,t){for(;e!==null;){var n=e===t?null:te(e);e.remove(),e=n}}function en(e){var t=e.parent,n=e.prev,r=e.next;n!==null&&(n.next=r),r!==null&&(r.prev=n),t!==null&&(t.first===e&&(t.first=r),t.last===e&&(t.last=n))}function sr(e,t,n=!0){var r=[];tn(e,r,!0);var s=()=>{n&&ce(e),t&&t()},f=r.length;if(f>0){var a=()=>--f||s();for(var l of r)l.out(a)}else s()}function tn(e,t,n){if((e.f&j)===0){e.f^=j;var r=e.nodes&&e.nodes.t;if(r!==null)for(const l of r)(l.is_global||n)&&t.push(l);for(var s=e.first;s!==null;){var f=s.next,a=(s.f&je)!==0||(s.f&H)!==0&&(e.f&G)!==0;tn(s,t,a?n:!1),s=f}}}function cs(e){nn(e,!0)}function nn(e,t){if((e.f&j)!==0){e.f^=j,(e.f&g)===0&&(E(e,R),B(e));for(var n=e.first;n!==null;){var r=n.next,s=(n.f&je)!==0||(n.f&H)!==0;nn(n,s?t:!1),n=r}var f=e.nodes&&e.nodes.t;if(f!==null)for(const a of f)(a.is_global||t)&&a.in()}}function _s(e,t){if(e.nodes)for(var n=e.nodes.start,r=e.nodes.end;n!==null;){var s=n===r?null:te(n);t.append(n),n=s}}let Le=!1,_e=!1;function Rt(e){_e=e}let _=null,L=!1;function ee(e){_=e}let w=null;function be(e){w=e}let C=null;function rn(e){_!==null&&(C===null?C=[e]:C.push(e))}let k=null,x=0,I=null;function fr(e){I=e}let sn=1,se=0,le=se;function Ot(e){le=e}function fn(){return++sn}function Fe(e){var t=e.f;if((t&R)!==0)return!0;if(t&A&&(e.f&=~ue),(t&Y)!==0){for(var n=e.deps,r=n.length,s=0;se.wv)return!0}(t&P)!==0&&b===null&&E(e,g)}return!1}function an(e,t,n=!0){var r=e.reactions;if(r!==null&&!(C!==null&&me.call(C,e)))for(var s=0;s{e.ac.abort(ne)}),e.ac=null);try{e.f|=Xe;var c=e.fn,u=c();e.f|=oe;var v=e.deps,y=d==null?void 0:d.is_fork;if(k!==null){var h;if(y||Ne(e,x),v!==null&&x>0)for(v.length=x+k.length,h=0;h=nQAdo}5T;_&jsnB`^X{(!)V04n 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 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/CvjSAYrz.js.gz b/apps/dashboard/build/_app/immutable/chunks/CpWkWWOo.js.gz similarity index 93% rename from apps/dashboard/build/_app/immutable/chunks/CvjSAYrz.js.gz rename to apps/dashboard/build/_app/immutable/chunks/CpWkWWOo.js.gz index f9539eb7b56dd1addd321ba091e843c90f57f633..c32160089832d604f3969066f57ac387442152f8 100644 GIT binary patch delta 535 zcmV+y0_gqROWsScq$7W`aw{sgo`{#|l-=4B_XR#*iud%~7hm!5N_>;}JP?wKUyGcc zZ^VMSy%j&``%rwRcJIWY!smN2qw*thM&-xi13pf~K2@KJ6RJKFimE?|WBNW95q)2X zTY6rKF+M(uEBd?=2?6~{MD+YD#x&d)kTOqm4q4>%r@5C!^{9YXL%aO==ImhB7znq8x1Ai*^x#UcI z;*t;I374FUF%MjLA`* z2lNe=Hhqu97y8b`93Q#(NS_mNN6+u#8$Amy@dO{GNNH3h-ca#WOz3+iUeaiDaZ2U) Z;+&ofkOfp^$!l@OZQcmURd2;tE;$shxXn9p$S?0j&Z{^QANl223}~IviP-0oQ}KyQ&cqWg z`5?wT;JG;CaV}cKC0AXF1A2ZG=k&Z1FX{P7e4*!Oal~D}h(7oDDkQ)3M4tzX#1X&r z#dm%ghsAxBIaE3O?=>&JCX8BDsK5@EH3y3%#;2k zGk?B#O)dI6qDRkN@s|4bpNTOI+y7m>=9fQ2kAUm{DL!+_Un1s`zr}(}{t+>c`>#m2 zDgwogUi#uQzYN5X+YH48%{373sP|BOrKc31=oyO%)!&NG_!tRA{Sq;t>TlvZRo{s- zdZyw7KE~n;RcAs`aV|d6_e31i^Sk&)&n`kd!AB`l8dZrmR6G^8)NLll_?U|;`n(qj XHCqV6{nn3l@PGavTQi+|e_#Lr-UtyP diff --git a/apps/dashboard/build/_app/immutable/chunks/CtkE7HV2.js.br b/apps/dashboard/build/_app/immutable/chunks/CtkE7HV2.js.br deleted file mode 100644 index a56c52e1d8ad137eeb8072240d9dfefda57368df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 817 zcmV-11J3*#3J3s<)J``BmvpJBdzOi&+rRvQAiIP4)H1nMn0%>&J^~Vx12Jq%nkfp9 z(!nv)t+hlZT+1l&67Y#1Y>Gqthd7-Z8YFb{pN%*>R+;tLgxYoNH1YUV zuKJ&cj(I))q^3SE%G&vmJ@c;C1=sp_zz7US&ht$mFTvC#X{wRLrx3m0Flz%6UNg7% z)KGe%75=$A6jP)&P3I;o<`Oc;n}D4juULiR0{pzWtYqJH&@P{9-@VM79}JH6@^?>d z@}Ig9G0_`nNy}vRPIiy_=YBHizJx_-ln2L}`QFv1TiQ64*ze#P^QAnW*5yos`q{-V zVQBtE$4=S|I15T7r)uYx7Be8fjTLJWX!tEerBp-K+o=r{$3!jOjB>L?A#9S^oO6i& z$se&sIlKo8f#JA!GK9Gbcr=dN0f`(_1O@Ll^i6V}BA|DJZ|8&*P=7xH{i8$fXnMwi z2k!>VMoL%&i*t;9z>li6jf4DlB|c0>a{qRJQhAwyf?4~@CH77P+1 zy+COrGTZ7zV$E&2yk%9Af1VtgSy~Wnkb!otoy+h_yg_7lV5(kj*sZOuvlA>9vAXix zms`G=I2g!YZ@1U0XixUBsCIV9a?+yO806QeL;+{6U>2lU%y*sp*M20CQs*e@{97(J zHU{+R-e4Fw{)B zO6L%$vv3taLR1;ys{60uyLUPveGxU=u11fI1aZ!iZM&U~mR037QtgW(YZ4qQ>~J6>~@{bT4KAMR_7BoOsxuD^E( zw&HLT?H{hKSlCH>M`ZO|{Z7t5dD@6|s|84O!2NMY9ao(AfJu6=z z-PaEirng&EXCjp~&1J$}0Cn6LW8t?a?0kav6E6~Z2v!7?5u4&1Ywu@2Q z367_LmNv-lJE!KU1SiZ+{17WJl@hM#@bB!E(-Lu#GB^>WvRPAU3O03QuQ^oGI8Z@!7)uGp=pd{0=H+?Gl;$Ri&}hKi81xuFC#Vm?MMTC3kdP6$?-_ z(;qUC8L;qnYkr9Oi!S`@k3WZ3O?HQJnM7E{ZUL1N3W;jwff%B@SH<9G_X7 zAL173xd!q)x&Zro7&Wp@gHZ$R+CDS>>mha?(RnRyy`n9=*GD-I@4ObbUfyc&9irTK x3%~o9{L($)oIE-MWbVw8th(p@%9(=PIHSp}GZm?vsoUvSe*@k7w+{;l008mD&1C=p diff --git a/apps/dashboard/build/_app/immutable/chunks/CvjSAYrz.js.br b/apps/dashboard/build/_app/immutable/chunks/CvjSAYrz.js.br deleted file mode 100644 index d9d1dd524b820297e9472983b536586edbcdde41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8733 zcmV+&BI4Z}eqd3QGTOR`irJxvs7l>8p>+X0#PF2)M^k0GsaE^Zu)MPP5`y^gY>w-4 zB4O)8ru+SoW%kB3j*ua@H&d-AP9v$G@tq}SDTsKqIic1~NR85yLtP0<{D zne8)*$)hd#9i`nGPh{ZehX;hcMSu;b(o`Sg#|pe^m0-Hg502DQ?O&_bb`pYvH(vDO zo3E-6dC7E!v z>P|R=(BCPBLboAiTK(q%Hr@F)OlzN{?Y_C0*v24)&`+A}Rra>wQ(FkSE>S*_iO0WV zU&=~Ke=g%Dr~zq39RU3L+f`WzR1$jf^d@8j`!sh}Kj87(B}Co6(4aS7y}&vO+62J9 zTTizF4n4c8{M{Ox-CC8<>gro+p!VL|A&*AeD+%13@H;<6`?&%z$GR~3`8ns&n^D`5 zaB5$+KHYfJjGk1L(yHKr(&h#2?gOv!KLCWr#twiuZ!bMAE%)s%#z&PRacPZKj()FI zXhf?t-oFRyD=)zZ3HR-;Szlx?!{cR$3_Uy^P2bB4c=to3ssLeYp#iB>zag>7D`KwR zrG9Aql5pLvve~D}kG&(h&AIbYqVZ|Qd6gLd6qqLUHTmRYZ?dtU_L)CQ{?|1Y?z2>@ zvb}0(9-ckyquf?)I-PFz6geFG=fd^-;Fjyt&8tQKnyWWMD%zgZXU?)-o&ZH;7P|HI z$XU`1zfh%9pRgLNt&jEw^*iS@4h8N6gEb@P%|EPq9)>AxUkCD3g?k-R_`!Ood!m?` z?}6+tjP!cf{&f8WP*LGW467t>0)KMk+bSZ>YjHA1g`dxSmxZ!&?PHnm`V=;-(*U4o zp7ivVoyI-KNr%&q-SZzotapY1Az?v@1k8}6Qoi)TxRtZt6+QhF*RXpU*Q9g{S&>lwQuG3P_TI0{P+7;`pQc^`!-~HS$_g~h@ z76V)E9H8>GSQ;ddk>laM8zA02Wv=RtjbwftGAC*77)(qLk_PmqJ&&9<^{ zuJj(vzh7UAe+u7iCgU{WZPS_yC09wzH03}?(T{<86+js`SUmt ztA{W(>**tT82WFRE)DdlC@7i%R;SGuqaO4nU-Zku=HotdNtyNSsqJj{ zPR#7EJjHMb&l4}QI&ppN>74X_!K9S4LE08;`8yc9DCHAzC?n(=X%DXjkXR5g6( zRbUUkA~YAGWIC*q(gu=s-naocna6S2_V_e!l)3rb<0HbVpX+frRlglcA7?$?!*p`z zKnP%UK0zcdpGWHX0MqB;7*w&-4R6v5QDCk1{0@}Zc&UC_F}n(}M7uHtW>9@>05t#Gja^_l$ic3^=|ch2`xv)aS_?u;U-_;{uKk?{6(&V!co z-J0Vx*Wify`1fkX+UuO+UH@bLm~3|<&?^I|<#pmtjG35#KNdJY;SWh_fchXKHycU^ zW}t!d((MWhDRd`#$KOi9D>Cqf+1jIHp(~t-GOCo0i0Ij4voiLxQbcH)^4kR+2@8?3A?1u%ro(c z*GqsZWuSwnf9$tsh7BqC?esF?-lA;4!`AnT+tdM+?BB94$ln&e{$9WN8^?cPibUiM z+7d7>M8K1UA)G{Ppyggg_*GySr~j@-kkUL$W6zIIej$L+v$E$Y4shKaMARlABVp^( zddg|rpd;^i++tvG)*Tk*cM&WplP(ksb4C(<+dDuz#@#?|Jp+8s zBiZTr&jvb+&9o;m%1aUYOpUnbt4Lwy?5e{>cSPzHMgv=6ffIJ@J5Xd^hjD4B@-}dv zf+bY!!6e5TU-Fu=#P$s;ZddEveQ4AHE)6w@l+U(JC}1qzCrP+(!u`2QnC*2(y7^

f7`=wN*p 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 HJ^u3qlaCn0 diff --git a/apps/dashboard/build/_app/immutable/chunks/Bhad70Ss.js b/apps/dashboard/build/_app/immutable/chunks/Cx-f-Pzo.js similarity index 74% rename from apps/dashboard/build/_app/immutable/chunks/Bhad70Ss.js rename to apps/dashboard/build/_app/immutable/chunks/Cx-f-Pzo.js index 9cdeb4b..7aa0a02 100644 --- a/apps/dashboard/build/_app/immutable/chunks/Bhad70Ss.js +++ b/apps/dashboard/build/_app/immutable/chunks/Cx-f-Pzo.js @@ -1 +1 @@ -import{a as y}from"./BKuqSeVd.js";import{m as r}from"./CvjSAYrz.js";function a(t,e,f,i){var l=t.__style;if(r||l!==e){var s=y(e);(!r||s!==t.getAttribute("style"))&&(s==null?t.removeAttribute("style"):t.style.cssText=s),t.__style=e}return i}export{a as s}; +import{a as y}from"./BKuqSeVd.js";import{N as r}from"./CpWkWWOo.js";function a(t,e,f,i){var l=t.__style;if(r||l!==e){var s=y(e);(!r||s!==t.getAttribute("style"))&&(s==null?t.removeAttribute("style"):t.style.cssText=s),t.__style=e}return i}export{a as s}; diff --git a/apps/dashboard/build/_app/immutable/chunks/Cx-f-Pzo.js.br b/apps/dashboard/build/_app/immutable/chunks/Cx-f-Pzo.js.br new file mode 100644 index 0000000000000000000000000000000000000000..12a7516c1914f848b7305d9dd2da799c456082b8 GIT binary patch literal 163 zcmV;U09^kY{r~`EV4i&?Q5}x_9X&wn?)t+~?)JSTPTIoOJnGA$z(PpV8$OpUBjusQ zlIXS%`02pqAb(+AFzuna29H0VcCdsZk6U5Y&+Pg1tEdeYvS$M}WRtuOxzh8mmxQO3 zgk-z#Iix57VD6NK3@C|&OxPX$KQj_c^)N-@IN2#mU1qIsW*g)s_WU-8jyZLuqgek{ R363IY$q~#Uhx6LYApsJmQj!1w literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/Cx-f-Pzo.js.gz b/apps/dashboard/build/_app/immutable/chunks/Cx-f-Pzo.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..ab5d4cbf40018fffc8879da58de6dfd3398c79e1 GIT binary patch literal 200 zcmV;(05|_1iwFP!000026J^iA3c@f92H?9-QFo9QM!h?Vs7FB$iaW~GOsd_gNh*$Q z@2*bNgSYVK`w6kd#Ut05$VgOej=qTWa5@jy6>JXrL{VbjV(}9A5wlBrPSd6DL>|gL zTVIMyatv`ETUFmO6wa{TZiy=giOnT8jq4i&?{var f,s;return h(()=>{f=s,s=[],k(()=>{r!==a(...s)&&(i(r,...s),f&&t(a(...f),r)&&i(null,...f))})}),()=>{A(()=>{s&&t(a(...s),r)&&i(null,...s)})}}),r}export{q as b}; diff --git a/apps/dashboard/build/_app/immutable/chunks/D3XWCg9-.js.br b/apps/dashboard/build/_app/immutable/chunks/D3XWCg9-.js.br deleted file mode 100644 index 623300e81db601fea6ba1b3447e02f27a899a1d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 197 zcmV;$06PC0JOLoYx1ZC`D4_hiSJ3NaD+oCNQcVi9%TvvTLr)aos4W^BC~bM-cBxPJ z->yYOJt@GnL2nd?73xL{70&xj09>W}E2P){K3_r;SH%DV%8sUOl| zzL0I(YKBAlkl-2dJS8EmJ`E(whelTBlKEc-2pf=sRxnkob8F@QDEfut=KA+qSDRx3 diff --git a/apps/dashboard/build/_app/immutable/chunks/D3XWCg9-.js.gz b/apps/dashboard/build/_app/immutable/chunks/D3XWCg9-.js.gz deleted file mode 100644 index bf30bd0c2948cdd7d3e0d8dba999d1ccf0ceaf68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 229 zcmV)zylC)TxAKedAuKic2X;BndZuj(7*1B$mfO3qYS49%g}P2{t?u.source.v=a:d(u.source,a)}),t=!1}return e&&i in r?l(e):p(u.source)}function m(){const e={};function n(){o(()=>{for(var r in e)e[r].unsubscribe();g(e,i,{enumerable:!1,value:!0})})}return[e,n]}function N(e){var n=s;try{return s=!1,[e(),s]}finally{s=n}}export{y as a,N as c,m as s}; diff --git a/apps/dashboard/build/_app/immutable/chunks/D81f-o_I.js.br b/apps/dashboard/build/_app/immutable/chunks/D81f-o_I.js.br deleted file mode 100644 index 47ef78b1510fc231f0d5b5a4882426e477163143..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmV-)0gL_{egYtjlrA@9w5hYb%ars)1+men<+|7&%`zPANa}M zr6M$PQ97~VZaCms6w)m7N^k|yUF_^PMwA)^hpTqs1q&~tbk`~u;%Wcve3qDTnoZAI z^fgusu1D5Ta5I=>3f>B#vp1*gU}6J!C#A7q({=CTkM3KQEWHK$mz47#5@(~X^5-20 z8S2nRjae+c6?b3eXE=mKXG<2Zlt=XBsSw@_^##((^yaI?iCkZu`P}uH<@nf#+{=yE zAsP?Q5Rkw*%W#;$6Xt1vtFu(l*_w~Z+2cgZgR_#kuw?&21OALaDByuz4ntLeis4F& z0(3~LdFfOd$nkNd^I-*oYL2$i(PY)Y(21~h^s&Y?Z2*u5R!CeI?g~Nq>VBHu)+q?( zWaWcH{jd_{Uy?w^%D-^vu&A>yA@h?ycmjE3HViNHvfEi8aZkA~Hp9h_Q|X#ruyIbd S(&2Vn5YUs|7^Q z7@`YU<0AgOU^i{EIy}xj_uPjXP8NN1L^{&(Ljj$7w8Pc<=5POWeE5F6U%$AkS}jER zqfjiDKMVF;{wmlmktcpEu;=o3!NXbTetdbp`-iWykOohjSlx0Zo~NO;nzFhNrt``g zGEv}$Ba59i&XXW;Yj#aT3yA2vMW{^BnmZe?gQ}&YReQ2wJQx>R*P&{m>JzI~Ps4f+ zSP22w*DI=sG6Wf$f4{throw TypeError(i)};var D=(i,e,s)=>e in i?B(i,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):i[e]=s;var w=(i,e,s)=>D(i,typeof e!="symbol"?e+"":e,s),y=(i,e,s)=>e.has(i)||g("Cannot "+s);var t=(i,e,s)=>(y(i,e,"read from private field"),s?s.call(i):e.get(i)),l=(i,e,s)=>e.has(i)?g("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(i):e.set(i,s),M=(i,e,s,a)=>(y(i,e,"write to private field"),a?a.call(i,s):e.set(i,s),s);import{F,aq as q,aw as k,ar as C,k as x,ai as A,m as S,w as j,ay as z,ak as E}from"./CvjSAYrz.js";var h,n,f,u,p,_,v;class I{constructor(e,s=!0){w(this,"anchor");l(this,h,new Map);l(this,n,new Map);l(this,f,new Map);l(this,u,new Set);l(this,p,!0);l(this,_,()=>{var e=F;if(t(this,h).has(e)){var s=t(this,h).get(e),a=t(this,n).get(s);if(a)q(a),t(this,u).delete(s);else{var c=t(this,f).get(s);c&&(t(this,n).set(s,c.effect),t(this,f).delete(s),c.fragment.lastChild.remove(),this.anchor.before(c.fragment),a=c.effect)}for(const[r,o]of t(this,h)){if(t(this,h).delete(r),r===e)break;const d=t(this,f).get(o);d&&(k(d.effect),t(this,f).delete(o))}for(const[r,o]of t(this,n)){if(r===s||t(this,u).has(r))continue;const d=()=>{if(Array.from(t(this,h).values()).includes(r)){var b=document.createDocumentFragment();z(o,b),b.append(x()),t(this,f).set(r,{effect:o,fragment:b})}else k(o);t(this,u).delete(r),t(this,n).delete(r)};t(this,p)||!a?(t(this,u).add(r),C(o,d,!1)):d()}}});l(this,v,e=>{t(this,h).delete(e);const s=Array.from(t(this,h).values());for(const[a,c]of t(this,f))s.includes(a)||(k(c.effect),t(this,f).delete(a))});this.anchor=e,M(this,p,s)}ensure(e,s){var a=F,c=E();if(s&&!t(this,n).has(e)&&!t(this,f).has(e))if(c){var r=document.createDocumentFragment(),o=x();r.append(o),t(this,f).set(e,{effect:A(()=>s(o)),fragment:r})}else t(this,n).set(e,A(()=>s(this.anchor)));if(t(this,h).set(a,e),c){for(const[d,m]of t(this,n))d===e?a.unskip_effect(m):a.skip_effect(m);for(const[d,m]of t(this,f))d===e?a.unskip_effect(m.effect):a.skip_effect(m.effect);a.oncommit(t(this,_)),a.ondiscard(t(this,v))}else S&&(this.anchor=j),t(this,_).call(this)}}h=new WeakMap,n=new WeakMap,f=new WeakMap,u=new WeakMap,p=new WeakMap,_=new WeakMap,v=new WeakMap;export{I as B}; diff --git a/apps/dashboard/build/_app/immutable/chunks/DE4u6cUg.js.br b/apps/dashboard/build/_app/immutable/chunks/DE4u6cUg.js.br deleted file mode 100644 index 7325bd7bbea2329527d467d2e24083a7e25e700d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 878 zcmV-!1Cjh2y$Aq|(!}zU4_PaDi6N_*TD3e*x1&{RVNN)Au2k7sG2;B3Uz_&+j0@^8 z@=E_-WjynMh16YA`u6*&O<9+n{jb;abvh{lDN;a+$KW;xC`ke?;(3f{om3N0yZ)=n zU~g&3xIU3J(!UyYp}l&XA9p`aQ*>A1VkIp7&t0V?ae($FuH3pZT@wZm+Ic%F=X}UI z+}o%jqKznwe^S+3VK9X9nO-%E%~=Y!vY>yJr%F9k8-1EIybr9_a#P2DTg4ztiBe{w zZU(&FeLB_15SKIhWE-`rlc_R;Tqu*p_azU=OJJt-9(B~7>^h283omw zDN{fekzVu&v>?m7n;y8jyH8`9v@jk^%O6mSqW`so;%P55V1af$lxuYTtZU{mbKVZ&lfY`kjKz zz=?^5bM){+pW69)b9WTtpj8L;Vv+q+=j9ehYzPMn^5n<;4^pg|H3z|@&L?9jG3yXC z8lJWGYE|}--p6t(ql`9SGe!V|(4cgL`XYfK7P5DM5beN008+!GcOWoFH-iKeJ6GU+ z#+{!_&ChYVmb+kzxFJQ?+DOUTau>)~F@)-3qUp-(p{Re~IEFZ(`b`p8jDbyXG4R|| zUUyTc+jXd6VwAtL2YXeWz?HH^?i)F;EfAhRVl7@HTNEfj$S7GVmjY433-m@O*Q5f( zByytrG>8UqSn+yyGASCjRK(Hab|E`KVf4Hl_wX`H)w7Gxf;N0}PFB%6LWIS89#Jv~ zAzcmDVBth-4U+Mu!qp2j$>dIB{6s=2)gTGq=wLj~zQ4(io>>7Af04d>?- za10i4h*%uzSWLwUv1E_PK8pT|j(s#!5(#-PVxTT$5dfd!-oR7LMjpc&-VeYrA=XcT z1Ul4U*7a%qFyhN7-dH+_A=w@=#i;nK0a#%W zH#s7P?90#3bzagX$XoB>AVC#ob9IK%L%aNdL?&SaJF$s1%p8mK>y24IS@vr2 E1ocX&kpKVy diff --git a/apps/dashboard/build/_app/immutable/chunks/DE4u6cUg.js.gz b/apps/dashboard/build/_app/immutable/chunks/DE4u6cUg.js.gz deleted file mode 100644 index a0d41690dc4fb49f1b0182037e4bef1e32782463..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 995 zcmV<9104JxiwFP!000026NObvZ{s!)zV}ziIs_zkpl+`gv_|42z#f7YNP(hQEDTy2 z*|a55At^hKqyOF^Z9N<#+k-&Okn{S!;czE(aF_hK++b>>40BoGUs~0u?IGUL-YSvF zx1(KawGaM2)cBya(oFK!@7^a&0)pYmHwsQw404G@7IH8%6Q!ak$k`O56r5heBxODvbDgHmavO;H7^N--p-1edXb1S;$w6x(OCGmOZ`DWq{BU3pLE zm>@=pI{?X_y2@M3#5r%W9lIeAWLYb1kB=Z;0%3v|5PP?7fxw}44qLapf{<>#h0-n0 z;16v;9NhW_!k>C*9c*Fr`+T=~zWrCfMH>@(nAcE24h__>fL)vx!kFOukvhOw-K3V9 zhl)uiU-@y*>{=QK352!MA&-lbf;`|pcoKE5sjf8nm8S6;Lb2D>Kv6nj0gUiFx(qRS zjAhR3IU4s&BIkb7B!k}3j)ZBas!l2gWzGbDp%2bm4X4XfphdTfg+cEu?JV=&GQGKB zgF8o$fi%KAr~B7?%SYa5H`iiSVr3%&)6Unj$RdrU+94wgIv<@7jFy;Fo3X*b<=#7Q zX_I*#erQlXsqOko`SAjeb8O8)CrN^QN%v$Md($BMP?F+tMkQ@o_IVMCe;&L#1$TkW z`}=^V<3w{#CRSDr_R&3yWN@psI7F@qM~VAcVi@OrqSlhoGR#0o-SM7I?jWwgX5|rbnm1Z>DumK zP2*}JW^Ax?Lx7CtluibdKRBOejJIvuH}ekA4dsu7AwR=pl3&9U4{QiXM{MMrn*lpP znGv(UXiq`RQpH0LCJ0a6?K6Z*Wg6;8H!?j7B6)-~d0_qqnVXx*0L25mZ97#k%8AePj@O25*^bCga+3;8J&7US3j!?)0cw&iUmaaVG`P$e?@&h%+cJ z8$NTliUxI4nXRlBr*v4!ry{yk#Gg6IKXuY^_0d%@&<_n6UOhU!AfFQn!|sxPF)g|r(>F~0gI?7Mq{ R?%Mdb{{UOtI&8iO006O!>U97B diff --git a/apps/dashboard/build/_app/immutable/chunks/DMu1Byux.js.br b/apps/dashboard/build/_app/immutable/chunks/DMu1Byux.js.br deleted file mode 100644 index 1248e871f7690375b89966249d75bb39c5375f2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 518 zcmV+h0{Q(L<^y14Rn@=GW$O?~fMv(Fz|L{yYPaH%Ek|Bi)!)x;^LIbQrLA)r8H7KxW2iKY#r5fUxkiV<&x~dYNk6nfj&Bg89GZ3 z>1heCg1DE8cW%0I@9Mo;^SD+<=<{F5siH#SJ=}~6$k|zRx)On#5Bmri6tzB7So+Zn z(0F9lMr9G@Y*-#G+a8zd?`bqfVDXgor0xYY6{lJS za@t@?e%@<5iFc`P`>86oF%WN7bugz)@~Osk>wX8MR8FtrY*Ygf09VsDkBD0-i>y3t zcDt81)HtA9Lrw}Q9Yw926V6Sgy-=S=?^`7*`Kr4E(91td&iv4fF5#GyvJphhmrFIY24&JACfZY8pr IXKp%}Eq6QiXaE2J diff --git a/apps/dashboard/build/_app/immutable/chunks/DMu1Byux.js.gz b/apps/dashboard/build/_app/immutable/chunks/DMu1Byux.js.gz deleted file mode 100644 index 84039b9e00b2c355fa3f88b9289f75a4f289d1c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 587 zcmV-R0<`@fiwFP!000026J=9PZ`&{oz3*4pIv5h5X)Six7DEe)Z3PN!*dd2u2!cYf z=tZq8rTXxirT*`e>?G~76HV%oe2=76x3w0vDM-G0`VN$o&;a<2x6t*pZ*=;WCiC`WyGyx=cOqoVU2_7pf2&t#+ zA!nXt?Q^BTGb}gT;6PKi{flDd#W8)rW&8BxO3r($WN|^ND$zdzZ;XUT{`!&(C#eq@ zrUs51_+5O9LFD-NwFlRO!nYUv01~HE7plEYlPP6;UR+CEyh&q zu2M)7sz?pm!&qDLGfV=^=jSmrEpcXSz{{jgtaTzn5UCB9Ri&^@DzPE7FQ==jD#3)5 zxKH}2o#v9;Megvpe&C!-+r$n`U?PpDhc6nkM-G~I^Ld|- zRgs^LWK1;w33{GZqI=?pV>-pexW$o>;dB-}=0#j4*7>BKSEurUO$^Whij*l}e#)Ey Z8|?s(<8Qqkf83#d^%ue1pX}!Y003VuA6@_e diff --git a/apps/dashboard/build/_app/immutable/chunks/DObx9JW_.js b/apps/dashboard/build/_app/immutable/chunks/DObx9JW_.js deleted file mode 100644 index 5667ae5..0000000 --- a/apps/dashboard/build/_app/immutable/chunks/DObx9JW_.js +++ /dev/null @@ -1 +0,0 @@ -import{k as y,b as o,H as u,l as _,m as t,C as g,o as l,q as i,v as d,w as m,x as p}from"./CvjSAYrz.js";function C(n,r){let s=null,E=t;var a;if(t){s=m;for(var e=p(document.head);e!==null&&(e.nodeType!==g||e.data!==n);)e=l(e);if(e===null)i(!1);else{var f=l(e);e.remove(),d(f)}}t||(a=document.head.appendChild(y()));try{o(()=>r(a),u|_)}finally{E&&(i(!0),d(s))}}export{C as h}; diff --git a/apps/dashboard/build/_app/immutable/chunks/DObx9JW_.js.br b/apps/dashboard/build/_app/immutable/chunks/DObx9JW_.js.br deleted file mode 100644 index 11ad62dad0bad34a0b7f04567ff07c04bda5cab8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 264 zcmV+j0r&nJb^%}4C^w=@(k_Qx&6#itU9)lCw>+39=YKZF6>T7R5Xt+9FG^9fG-4%sakD zBE6}k5QB)48x9E}8J<-0ry-*C>AydAQu0>!v3I3nNvD|KVx%00kjr^t3FU{6kS{Ir zY$$Ok4iRxEd`MwoGE+t3#i3BQTVO?~0@?)C8An#el7tQk`49q2J@BDqj~*;^io=43 z+REp)JH8-)0i{3KI8Eg^f_3OSGJEI%5vk0(ApyX{F$W8!YBX@#&eiacz=MSbe<%>A OiCfO`Hvg}GdYS>#7JE?u diff --git a/apps/dashboard/build/_app/immutable/chunks/DObx9JW_.js.gz b/apps/dashboard/build/_app/immutable/chunks/DObx9JW_.js.gz deleted file mode 100644 index decf3502d74a9b793bab43a1ff28a3f833de2768..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 278 zcmV+x0qOo9iwFP!000026IIYnPs1<_2H-otqT6Azr6|BT3KFU&afb`1DJ(9_$VW-j zveNdyQ*S3ukL1L!ExXXBT&Azebk!(6m?U19UU=pp0#iiIe2T<)@y$3fFjo99L0p)2 zX>tl%d0!9b*XQ^AE6?3lHGMo5mts{z6d5N^rRsF-y%&33)L?RDlxv{i)ajs_l!0rc zTd?Wa2Z}|W$XHag(bvA+4oJpi>1}Me_Bqcattp1zQ6Xs$gq%tG)`1Q-k86PMXyWkZ z_Jd@mkOl%278+cZGS6W2zp>J^Ek#?OoVPFnBC3+dDFL8<%3x6R^8uH}MdSTA?bqej cVGo?x;TlPo>zS`NJT2<(4`~1ZmUjUF0Aufk!T%g_60qHr=&l)XY5KSJ`Sz?Kz@Wye&3jIm+schyT+BV z-JMYQvzhw0Tx{9(_d8Lvf>lLXEv6x0vmoih}R?rH&~QcNS}tCtm< z+>Ke$5+De833ViV#rW)M09R{^+y5rtaZILChWZkwXIl_)Aw&GNLrUdnG2zSzA`7si j8bFglDy5(;3#Gq!#aKPiI|COH8~7jscx5#>3waV_v#SK8ZJaP6XBb97!K>^ z1wYS(OZ|=@^z6t%Zl#lrOcKRuFvz?Hwb|^viE(8*TZ7|a9DSj+%SCHF1lY5?3ru>& z=iex5USy0i2CB8x5Fu<6Szex_N+GI>lh%Fm{vH(CE)4cBwb{if(s){if(s.pending.delete(E),s.done.add(E),s.pending.size===0){var o=e.outrogroups;Y(U(s.done)),o.delete(s),o.size===0&&(e.outrogroups=null)}}else u-=1},!1)}if(u===0){var f=t.length===0&&l!==null;if(f){var v=l,n=v.parentNode;Ae(n),n.append(v),e.items.clear()}Y(i,!f)}else s={pending:new Set(i),done:new Set},(e.outrogroups??(e.outrogroups=new Set)).add(s)}function Y(e,i=!0){for(var l=0;l{var a=l();return _e(a)?a:a==null?[]:U(a)}),o,d=!0;function w(){r.fallback=n,xe(r,o,u,i,t),n!==null&&(o.length===0?(n.f&T)===0?ne(n):(n.f^=T,M(n,null,u)):ae(n,()=>{n=null}))}var N=fe(()=>{o=Z(E);var a=o.length;let S=!1;if(R){var x=ue(u)===se;x!==(a===0)&&(u=$(),q(u),L(!1),S=!0)}for(var _=new Set,A=te,b=ce(),p=0;ps(u)):(n=V(()=>s(ee??(ee=z()))),n.f|=T)),a>_.size&&de(),R&&a>0&&q($()),!d)if(b){for(const[D,F]of c)_.has(D)||A.skip_effect(F.e);A.oncommit(w),A.ondiscard(()=>{})}else w();S&&L(!0),Z(E)}),r={effect:N,items:c,outrogroups:null,fallback:n};d=!1,R&&(u=O)}function H(e){for(;e!==null&&(e.f&Ce)===0;)e=e.next;return e}function xe(e,i,l,t,g){var h,D,F,X,G,J,K,P,Q;var s=(t&we)!==0,u=i.length,c=e.items,f=H(e.effect.first),v,n=null,E,o=[],d=[],w,N,r,a;if(s)for(a=0;a0){var k=(t&re)!==0&&u===0?l:null;if(s){for(a=0;a{var m,W;if(E!==void 0)for(r of E)(W=(m=r.nodes)==null?void 0:m.a)==null||W.apply()})}function be(e,i,l,t,g,s,u,c){var f=(u&he)!==0?(u&ge)===0?Ee(l,!1,!1):j(l):null,v=(u&me)!==0?j(g):null;return{v:f,i:v,e:V(()=>(s(i,f??l,v??g,c),()=>{e.delete(t)}))}}function M(e,i,l){if(e.nodes)for(var t=e.nodes.start,g=e.nodes.end,s=i&&(i.f&T)===0?i.nodes.start:l;t!==null;){var u=Ne(t);if(s.before(t),t===g)return;t=u}}function C(e,i,l){i===null?e.effect.first=l:i.next=l,l===null?e.effect.last=i:l.prev=i}export{He as e,Re as i}; diff --git a/apps/dashboard/build/_app/immutable/chunks/DTnG8poT.js.br b/apps/dashboard/build/_app/immutable/chunks/DTnG8poT.js.br deleted file mode 100644 index 53ec356070318f66b034b9cfe371bf4a321a9df0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1803 zcmV+m2lV(GP7nZ$!g23|OKX=UB0@1jl36oj=IfgjG}_6Y3v6Z21>hXFI%ZF6TL1n0 zyb4$Kz30uC(wc(;NodwPm7-kMh?Yg7q$yIKv z4p@N`D_eQsrp8APkHrDiQO#=h>IyOtqdN>+?36eQUok3FJQ&Juyaz@gH^d&SR)%)S2%=? zraZY(l?e}2y0F=_CfcGUY|{ensrJH-ycX%o<<`-(*ZLROrLtS>#b93jVr-?v#E&n(1>(hD?n zGv?+BBOe#{FGnMI!Sis?7MtX=fzsOqQ2#I3vKyRprGgIr&uUDxK~pd}SkV9fbHrLa zsddG17ztaINKr?J`#V6JioLI$dIX?iNla4Rs?7kMRtjK4FO)2UOBJ{Ooce1*v z?AVY^$cLg;fm*uS+r2oYd>n0yB!L8F`I&SNlJAy*|K>Zk!v4n@0}2JYjowCDv&uXf zEYmsz2jtItPN)9QZEZZbZWb`!QwAQ?`$L6-aJ!r<3_d2?j|Lx&;F|7(-#1FcL$CKlT{sllVz*t-MEPnj2jq#r*Ep}#imIpcJ|CEad-ooX3QbtNU zGVG$-{&F7!{s8B=|7!=87va(Q5&g9v4r6IH@*o5ev!sJsZ`{H>;ggg zH%`PRXqFQd{vZOiz_@yXLI`x&?qdc(OQ4j-ef|Kcg1uli9oDj-x!sqSt^Z+=JwbwY zYoMJu~iC*J}$&eW*Tp(bf{oiotd_3#WBSP z*ZIkD1iZN4CYO?J+s&@hSXVfMHEz{rV4jmM-E9tho z)I-J8oytGt6`J{|&T1_5lXiZLC;WW951xdxOrNFdf%8ysiPRF6eSO++>eeiPXj(}B z?K6?$sNN5*Ch3_qIo4~5gJY!?#xn?`nnY-pneBXoA5Si4tm~qxDU}gTDcWGV5j?GS z3{dVWi~qJ(5DI@E}sc6{Ku zu9FNk^75TGmw!V(MHZ)e$o794F*Crr*BoSec?<~`&pV<_JOQ`eh#>#~ diff --git a/apps/dashboard/build/_app/immutable/chunks/DTnG8poT.js.gz b/apps/dashboard/build/_app/immutable/chunks/DTnG8poT.js.gz deleted file mode 100644 index 0a7fc9c86d7ba8fb2da169fd8b2b726c0bf29f2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1948 zcmV;N2V?jjiwFP!000026OCAHZ`(K${(is0Srh_^&gzm6ivy&vhMOjB+D+Of>DvZA zgO(^;iA*Vai(5zk{boo>meX|izL-ODNX|U-%#d=t%F?{t+>T^1`T=ulA_Y>CkSkbG zdjT~ycd(`=#%ZIMC|FSY7s!Cx3MWDm3KSFx&)|-lKjEI5_i#i_in9?3H40{f?{Gp* ziTx!BS0H0*KZCrXHpB^IV4&bLwHXflhlCjl2??J-8dH}zph;Mu@COOUD5NCZfXt{} z;eatqqmYvzQ7A}w2`|n0*e^*qLZKqz9tDHJ1O?;FsRFa>xoV<3UH#_%`>4LToP5iF zxHrXbepKn8j8i?jP)tG0H@PaST#w?WpSd(Mknl~E=B!3jN^w1fg^1lm=|#DO0;+8% z5c_^`xbTDL&-o@%<>*+%*TK}6iX8*v;>9M8Si#M&n<*W}df|o&HBo^>;fASJt_(xl z>okh^hY~{U^9@;$3gxC%nWu|9t+K-Z#y&B-l5VXW!kGnqjoSnTAA zBR=~(;3&Tm7vnn?E5w0&bqmVTGEPGFgK^$mAgqdUpY*jk0FFhbnBfWyN|E4nOU#*K zl8>b)Z6LtRM9{vOFE=h=8*ShUweeL_*A6V*%WR?$xb2TuoU5#-1Gu> zf&9GX{&LKgZtXbVsew~eabw$yX~EoaCT^vR+c=x4C{jU*GnkzoTZ*}20fghqQ;L|Z z1n~e);TAF^8I>9cA09~GjUL1mhrli9P*|ec%uxK+WU91TSvby~Mn}*@@!5c1Fp3e| zc84c%%1yH|2l--VDum;N1Ra7UU*L{+>=~J~7jishZgVF{bx~fwf|F?)jRHP%m$G25 z_`}1*9eR0!UiuR^)j_&i#U;DvK)o<70-1-F8cmz|NKyaNaS-=?4#XCuaV|D?C+{3g z(eMHoq`GGq*sdz<#Vmq1(burQz@uJy=`;=I7rtD(ztNa-pG>E|BK zAqVN3+kxzsXrnx=d`UFE$4f*`;an`(JxD^y67ih73RvE!Ec(b^3FKIAIA8F#Ow?%{ zj`qE!E8CHWhga@O$)d_B?(7)par~%^=9mjV8AA8g-x{-1m|Ns|&!5q1gzVYT;j72j zV9sG>ufcwRU}@bXtcjMntx7q%9q}_PZ3fbW`$R1hvrD1J+JxAPeA4R!k;tMnbQtsz zvMg74S=kn+tzb4FJh7okYRx1GMx$SOgsjn!TOo%_4rJFQCA1d#AlSqTYZ>pNfu$PceAQkl0>wKT3XN}qP2qe zC+uW;YS&pS%-YroV$zdoxcNWxaPVfNm*uK^S+du=@6MiguRC;CSTlB1{^|WmZtiv4 zY}shpmJyCSEH#xRC);b@CX3xX>%cIK>cL0Uqk$F;tNu;YuX+T%eE?(~AJKr*7p+CN zRPft(p5vI8@;LFjCvjmBwgvOl7EJa|u(u+^g85|jz8z%myKP1Gf8OV#U>|-N z&7k{|V3o79z>QH{*jspftXP5{9`xB6ylX!a&gpo=4R@~a5b8pSYZu&l{throw TypeError(i)};var F=(i,e,s)=>e in i?D(i,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):i[e]=s;var w=(i,e,s)=>F(i,typeof e!="symbol"?e+"":e,s),y=(i,e,s)=>e.has(i)||g("Cannot "+s);var t=(i,e,s)=>(y(i,e,"read from private field"),s?s.call(i):e.get(i)),l=(i,e,s)=>e.has(i)?g("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(i):e.set(i,s),M=(i,e,s,a)=>(y(i,e,"write to private field"),a?a.call(i,s):e.set(i,s),s);import{_ as x,aq as q,aw as k,ar as C,J as A,ai as B,N as J,U as N,ay as S,ak as U}from"./CpWkWWOo.js";var h,n,f,u,p,_,v;class E{constructor(e,s=!0){w(this,"anchor");l(this,h,new Map);l(this,n,new Map);l(this,f,new Map);l(this,u,new Set);l(this,p,!0);l(this,_,()=>{var e=x;if(t(this,h).has(e)){var s=t(this,h).get(e),a=t(this,n).get(s);if(a)q(a),t(this,u).delete(s);else{var c=t(this,f).get(s);c&&(t(this,n).set(s,c.effect),t(this,f).delete(s),c.fragment.lastChild.remove(),this.anchor.before(c.fragment),a=c.effect)}for(const[r,o]of t(this,h)){if(t(this,h).delete(r),r===e)break;const d=t(this,f).get(o);d&&(k(d.effect),t(this,f).delete(o))}for(const[r,o]of t(this,n)){if(r===s||t(this,u).has(r))continue;const d=()=>{if(Array.from(t(this,h).values()).includes(r)){var b=document.createDocumentFragment();S(o,b),b.append(A()),t(this,f).set(r,{effect:o,fragment:b})}else k(o);t(this,u).delete(r),t(this,n).delete(r)};t(this,p)||!a?(t(this,u).add(r),C(o,d,!1)):d()}}});l(this,v,e=>{t(this,h).delete(e);const s=Array.from(t(this,h).values());for(const[a,c]of t(this,f))s.includes(a)||(k(c.effect),t(this,f).delete(a))});this.anchor=e,M(this,p,s)}ensure(e,s){var a=x,c=U();if(s&&!t(this,n).has(e)&&!t(this,f).has(e))if(c){var r=document.createDocumentFragment(),o=A();r.append(o),t(this,f).set(e,{effect:B(()=>s(o)),fragment:r})}else t(this,n).set(e,B(()=>s(this.anchor)));if(t(this,h).set(a,e),c){for(const[d,m]of t(this,n))d===e?a.unskip_effect(m):a.skip_effect(m);for(const[d,m]of t(this,f))d===e?a.unskip_effect(m.effect):a.skip_effect(m.effect);a.oncommit(t(this,_)),a.ondiscard(t(this,v))}else J&&(this.anchor=N),t(this,_).call(this)}}h=new WeakMap,n=new WeakMap,f=new WeakMap,u=new WeakMap,p=new WeakMap,_=new WeakMap,v=new WeakMap;export{E as B}; diff --git a/apps/dashboard/build/_app/immutable/chunks/DdEqwvdI.js.br b/apps/dashboard/build/_app/immutable/chunks/DdEqwvdI.js.br new file mode 100644 index 0000000000000000000000000000000000000000..4a2afa5feadd751669987b3997c9b809ae19970b GIT binary patch literal 883 zcmV-(1C0C|!UzD2!nWn}QNvuS9!!NY%}iZYtuIg7xec|}=z+Sg5S=`Ot!=99SvKi~5k3-pk#H^NZU3E<=Jx%i51zug3Kw_q^M7tl9FYt=9fI@0om~S%Gxoe4oOAs! z={U4`e!z|>_#Ry~>X04L9pkC7*^0inDIN2x0wyOys&lKQVJgHS)mDz~_-~V6vN)7- zBjO7D^Gg%N^aJK98o!KxZDM4qSZN9cG^YZ2iD$S*#34S%mP2z2SXsAZ>5vAK8trjI zX_yiPSx|aOAYy|oAK3v{w{Byzgbk!*t(L)yhL^1b$75e;1|Fth3AU4sN-#9O49RH# z4g=xsH~H88kW%{|yW-d4p5AoTLM}EyL0-X4=}2bh~uDm%@tY{Qd5-6)NXcBnLt06~}yhx#ue2w=VUF^pIYcoP88q@}3@Tp{5= z1C82kxv%K?O?hfLLER({;-Iu?>ZVI2Ta!3o*20Q*ajBTpQz_Dwj-!VO+%GJs`}h(? z7hT7Zbow#|-)=*e3AevFg3(S+5J{C?*>?)YTZA;`jHMWl?2+IAy$8$ETvifAy^zS$ zUEu=IBrxI38iat@>v)=2rbJ=Bia4Wg*OXON@Epv!DK9CHwl7J{z^ssSO)jMJ5hyGX zIUiDyDCt_v99~$ol_D7&D%{bar5^5b;x__HnOrVO-Wa5G`Tj~04U-;-MwGh;=x9eg z3|3kYA*y|_iD-#x#1g29UGgEnrv;QEr3BGC0dQzIEE)181|}F@HmFM^<3eB#wf#u- zF7y26L^v!W_JEDHfxA((5$lYK>>$~NR2mN}(#eFrOBtYUdQ)`psj748(4_qN JCX{TMs8lyAY@ua$e^Qhg+e8tK|Fg7p6AKFqaknr&W#G?&B@(trD4h zJ=nEYyWszQjn`T$%_MLA?oGlZAQ+x}#XwepoLzav0js7&EtUmNCtn~{RW4UeFYmOp z-Tzh;4NgtVr}78>OpN!t8~onTpQXSm4{(x%W?wE<5zg>a7*5>@*pG6E*1}M7udgc> z&P7!z8-$+>_de}#j_v(#s8M7=u2mV-T5g5KAeUHVAqO)vQ7VdpoJ}!Wp`{-V#rsgR zA(F_lz^*YcqQu@|iRBV?P%4eIDXKtKDTd^f;4)T_K!rV_*gT+}VMIQTA&m>^%DX$o z1Tjk70Z9JTyS&9robo2yu^R$GmbKFMun2?+UO+s%^%=y@ts5YOXr05YTP{IJw|;|r zx7@;`Tkb*Z-TDAxFK+Qewol?y@m>MXrP7#Y~!>L#st>~Y6D|+ zlUnK^swkO!;fEcwYiS@PB-ToYJT8t3@_@VGPSm}odZ)?XX&SE~D0@u}6r~duzzD>H z%Mg>7Smw;0qH#|ra_%=xGUy%mNWgZg>Zo#f=1lNs`rx$HaJoSST6DWu81&B4&NA;U z(~Ao>xN{sCNF&U1x`e&AeB_OGb1haSRyHCq?R+hZEYeu2Ei$s8^U)E(Xo)%X8XF8; z?!EJtHks$)hX(bNdatjPAI|VN#nv2jk|fBNbXhjBHx05kB`F?fRMLiJ9~Ytc$HA*( za2LqDz7A+QPBiCaVrA7}AKkM^2A5ikedL;Ol(-)#hH)OrDlM7}y$?^tGRaihcob7A z$KusVyg6aTc>KT=EIBMAQP)^y?29Xam<2=|nINo)H?wwR4 zUE3Y3X=Y8tj16{f5|GiH(#c@*FXz*Y@wRRIX5Iq2$^4cue_c zGhinuGh+4+?J0;^s(9$Z1mUi`eTGn}OhX;%=B8&sBrlLAkIdg7b8#^lfH_{mL6!IS zl8&ZFbNzP`K_x_6tUC_XTL!Ub@Edc@WL$d=TN9C^CT+)3j4%Ej TyY>%M8~^hgukDYx!w3KXBrWNI literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/DfQhL-hC.js b/apps/dashboard/build/_app/immutable/chunks/DfQhL-hC.js deleted file mode 100644 index 3f77100..0000000 --- a/apps/dashboard/build/_app/immutable/chunks/DfQhL-hC.js +++ /dev/null @@ -1 +0,0 @@ -import{a4 as a,A as m,aG as q,aC as A}from"./CvjSAYrz.js";function _(e,t,n){if(e==null)return t(void 0),n&&n(void 0),a;const r=m(()=>e.subscribe(t,n));return r.unsubscribe?()=>r.unsubscribe():r}const f=[];function x(e,t){return{subscribe:z(e,t).subscribe}}function z(e,t=a){let n=null;const r=new Set;function i(u){if(q(e,u)&&(e=u,n)){const o=!f.length;for(const s of r)s[1](),f.push(s,e);if(o){for(let s=0;s{r.delete(s),r.size===0&&n&&(n(),n=null)}}return{set:i,update:b,subscribe:l}}function B(e,t,n){const r=!Array.isArray(e),i=r?[e]:e;if(!i.every(Boolean))throw new Error("derived() expects stores as input, got a falsy value");const b=t.length<2;return x(n,(l,u)=>{let o=!1;const s=[];let d=0,p=a;const y=()=>{if(d)return;p();const c=t(r?s[0]:s,l,u);b?l(c):p=typeof c=="function"?c:a},h=i.map((c,g)=>_(c,w=>{s[g]=w,d&=~(1<{d|=1<t=n)(),t}export{B as d,C as g,_ as s,z as w}; diff --git a/apps/dashboard/build/_app/immutable/chunks/DfQhL-hC.js.br b/apps/dashboard/build/_app/immutable/chunks/DfQhL-hC.js.br deleted file mode 100644 index ca2c57a6daffe46bec02c0a99214866a901f57fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 614 zcmV-s0-60AX9R$Z)L1P!yEavA&oVLje;#mw-6zRNskdiT8YNM(ax&=&OT$XXRv+GfMy00$b87PU+I9;(GeU;r*SnYl8e4BeNB6`9wV`mMo7?<80P>CfCm9GO z64Y!MZd@zow$nkM5?~e*si}sG50StA$g>g77B1XF9}u^g zx&}cC?>6xW^F(WK9HFBU&u4=~k0J2AQy5MHgWUsT#+4o*;TB*@$d_!)IvU@?tfXu_ z>qFsT{2}0GFMq(F+KGuUZ|*qU7WN~vP^p*QFZDR|;C*k6LyXJdcWNl1KfG?_>VE(P zfa>Xfny8aKVi=DA;TMAukMQEJ+QBj{-Zg4)|5Y)*1Kp#t%% zta(gpHl=!C#L8U*H7)^-HLw7x1rTnf7=L6!WY^^7Z4VV@YhEwQRLocR`}^az%1ojq zcf*xg160%^-+VzuyXti*+7I4Qt@%Gp7K;|iYkdGrgUqSV>?@{;3XxqNQwPJe)QRq4 ziM0brijAi<_IQtArwJiqflTj59N$EC2uLy6{VareNMbcTIxT%AX`!R~ZU86c7h2gM AtN;K2 diff --git a/apps/dashboard/build/_app/immutable/chunks/DfQhL-hC.js.gz b/apps/dashboard/build/_app/immutable/chunks/DfQhL-hC.js.gz deleted file mode 100644 index 3a516700e3d6845dafd07e13e3c2b899e834c1d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 654 zcmV;90&)ExiwFP!000026IE2fZlf>|z3*4JIiMNUVo9|ph#RHVYCoW-RfH-7CUHe< zYMZ19WxsuG5|Z{bV(fYI=Djg;*J|T>{)=!+I9-LXqx?^Z@034>xEgAsceD8C^ZxB+ z_1B!@H#^JfPL)n-MP5NrM-}$62Emx>ng)$j%$Dt*j%4?EsKH zir99AEsZP$1SHHZ^(OAr^=KKce#-!+W;jFDY@OdIeFRF_pHcej{q!{EZ{3FBS~4Cn zj(sB>QR5U>mP#DRi*Pr53EepEyD#c6iu~MN;N71qG`p+gMyQS3X04G?&aQ*CJ0vkm^pxVlT`Q zp0sWR_p-aK(FYP-`fZF?aaIW<_o4zM;-eL%v&1@Wgbmv)RogjAHrf$RYTno*+4H6o zGrag+Fn3XR@i3|M0g6K7z4jsmkG#Y4?5by;gZJ9f^!tY7R*lbd0wk%UV&@Gekj<*0M-FWC%9}m8RU2k%BpjE{F z!F;jUAk|TH1RTzmRi7+mhufp_+!J~XD|o>N>{qZw>iN+y*f4zAo@cNBII^4S!+Tfk o(J_U-zztsF@C$hg;#PG0V{GVa2$r5gI1Jg3|9}C$P-p}I0Ea{const n=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(r);if(n)return a.push({name:n[1],matcher:n[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const o=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(r);if(o)return a.push({name:o[1],matcher:o[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!r)return;const s=r.split(/\[(.+?)\](?!\])/);return"/"+s.map((c,l)=>{if(l%2){if(c.startsWith("x+"))return ct(String.fromCharCode(parseInt(c.slice(2),16)));if(c.startsWith("u+"))return ct(String.fromCharCode(...c.slice(2).split("-").map(_=>parseInt(_,16))));const h=ue.exec(c),[,u,w,f,d]=h;return a.push({name:f,matcher:d,optional:!!u,rest:!!w,chained:w?l===1&&s[0]==="":!1}),w?"([^]*?)":u?"([^/]*)?":"([^/]+?)"}return ct(c)}).join("")}).join("")}/?$`),params:a}}function de(t){return t!==""&&!/^\([^)]+\)$/.test(t)}function pe(t){return t.slice(1).split("/").filter(de)}function me(t,a,e){const r={},n=t.slice(1),o=n.filter(i=>i!==void 0);let s=0;for(let i=0;ih).join("/"),s=0),l===void 0)if(c.rest)l="";else continue;if(!c.matcher||e[c.matcher](l)){r[c.name]=l;const h=a[i+1],u=n[i+1];h&&!h.rest&&h.optional&&u&&c.chained&&(s=0),!h&&!u&&Object.keys(r).length===o.length&&(s=0);continue}if(c.optional&&c.chained){s++;continue}return}if(!s)return r}function ct(t){return t.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}function ge({nodes:t,server_loads:a,dictionary:e,matchers:r}){const n=new Set(a);return Object.entries(e).map(([i,[c,l,h]])=>{const{pattern:u,params:w}=he(i),f={id:i,exec:d=>{const _=u.exec(d);if(_)return me(_,w,r)},errors:[1,...h||[]].map(d=>t[d]),layouts:[0,...l||[]].map(s),leaf:o(c)};return f.errors.length=f.layouts.length=Math.max(f.errors.length,f.layouts.length),f});function o(i){const c=i<0;return c&&(i=~i),[c,t[i]]}function s(i){return i===void 0?i:[n.has(i),t[i]]}}function Ft(t,a=JSON.parse){try{return a(sessionStorage[t])}catch{}}function It(t,a,e=JSON.stringify){const r=e(a);try{sessionStorage[t]=r}catch{}}function _e(t){return t.filter(a=>a!=null)}function Et(t){return t instanceof wt||t instanceof yt?t.status:500}function we(t){return t instanceof yt?t.text:"Internal Error"}const ve=new Set(["icon","shortcut icon","apple-touch-icon"]),I=Ft(Kt)??{},M=Ft(qt)??{},P={url:Pt({}),page:Pt({}),navigating:ae(null),updated:ne()};function bt(t){I[t]=C()}function ye(t,a){let e=t+1;for(;I[e];)delete I[e],e+=1;for(e=a+1;M[e];)delete M[e],e+=1}function V(t,a=!1){return a?location.replace(t.href):location.href=t.href,new Promise(()=>{})}async function Bt(){if("serviceWorker"in navigator){const t=await navigator.serviceWorker.getRegistration(L||"/");t&&await t.update()}}function Tt(){}let kt,ht,Q,U,dt,b;const Z=[],tt=[];let v=null;function pt(){var t;(t=v==null?void 0:v.fork)==null||t.then(a=>a==null?void 0:a.discard()),v=null}const W=new Map,Mt=new Set,Ee=new Set,F=new Set;let g={branch:[],error:null,url:null},Vt=!1,et=!1,Ot=!0,H=!1,K=!1,Ht=!1,St=!1,Yt,E,R,O;const at=new Set,Ct=new Map;async function Fe(t,a,e){var o,s,i,c,l;(o=globalThis.__sveltekit_8fmifr)!=null&&o.data&&globalThis.__sveltekit_8fmifr.data,document.URL!==location.href&&(location.href=location.href),b=t,await((i=(s=t.hooks).init)==null?void 0:i.call(s)),kt=ge(t),U=document.documentElement,dt=a,ht=t.nodes[0],Q=t.nodes[1],ht(),Q(),E=(c=history.state)==null?void 0:c[N],R=(l=history.state)==null?void 0:l[B],E||(E=R=Date.now(),history.replaceState({...history.state,[N]:E,[B]:R},""));const r=I[E];function n(){r&&(history.scrollRestoration="manual",scrollTo(r.x,r.y))}e?(n(),await Ce(dt,e)):(await D({type:"enter",url:gt(b.hash?Ne(new URL(location.href)):location.href),replace_state:!0}),n()),Oe()}function be(){Z.length=0,St=!1}function zt(t){tt.some(a=>a==null?void 0:a.snapshot)&&(M[t]=tt.map(a=>{var e;return(e=a==null?void 0:a.snapshot)==null?void 0:e.capture()}))}function Gt(t){var a;(a=M[t])==null||a.forEach((e,r)=>{var n,o;(o=(n=tt[r])==null?void 0:n.snapshot)==null||o.restore(e)})}function jt(){bt(E),It(Kt,I),zt(R),It(qt,M)}async function Wt(t,a,e,r){let n;a.invalidateAll&&pt(),await D({type:"goto",url:gt(t),keepfocus:a.keepFocus,noscroll:a.noScroll,replace_state:a.replaceState,state:a.state,redirect_count:e,nav_token:r,accept:()=>{a.invalidateAll&&(St=!0,n=[...Ct.keys()]),a.invalidate&&a.invalidate.forEach(Te)}}),a.invalidateAll&&J().then(J).then(()=>{Ct.forEach(({resource:o},s)=>{var i;n!=null&&n.includes(s)&&((i=o.refresh)==null||i.call(o))})})}async function ke(t){if(t.id!==(v==null?void 0:v.id)){pt();const a={};at.add(a),v={id:t.id,token:a,promise:Xt({...t,preload:a}).then(e=>(at.delete(a),e.type==="loaded"&&e.state.error&&pt(),e)),fork:null}}return v.promise}async function lt(t){var e;const a=(e=await ot(t,!1))==null?void 0:e.route;a&&await Promise.all([...a.layouts,a.leaf].filter(Boolean).map(r=>r[1]()))}async function Jt(t,a,e){var n;g=t.state;const r=document.querySelector("style[data-sveltekit]");if(r&&r.remove(),Object.assign(x,t.props.page),Yt=new b.root({target:a,props:{...t.props,stores:P,components:tt},hydrate:e,sync:!1}),await Promise.resolve(),Gt(R),e){const o={from:null,to:{params:g.params,route:{id:((n=g.route)==null?void 0:n.id)??null},url:new URL(location.href),scroll:I[E]??C()},willUnload:!1,type:"enter",complete:Promise.resolve()};F.forEach(s=>s(o))}et=!0}function nt({url:t,params:a,branch:e,status:r,error:n,route:o,form:s}){let i="never";if(L&&(t.pathname===L||t.pathname===L+"/"))i="always";else for(const f of e)(f==null?void 0:f.slash)!==void 0&&(i=f.slash);t.pathname=se(t.pathname,i),t.search=t.search;const c={type:"loaded",state:{url:t,params:a,branch:e,error:n,route:o},props:{constructors:_e(e).map(f=>f.node.component),page:At(x)}};s!==void 0&&(c.props.form=s);let l={},h=!x,u=0;for(let f=0;fi(new URL(s))))return!0;return!1}function xt(t,a){return(t==null?void 0:t.type)==="data"?t:(t==null?void 0:t.type)==="skip"?a??null:null}function xe(t,a){if(!t)return new Set(a.searchParams.keys());const e=new Set([...t.searchParams.keys(),...a.searchParams.keys()]);for(const r of e){const n=t.searchParams.getAll(r),o=a.searchParams.getAll(r);n.every(s=>o.includes(s))&&o.every(s=>n.includes(s))&&e.delete(r)}return e}function Le({error:t,url:a,route:e,params:r}){return{type:"loaded",state:{error:t,url:a,route:e,params:r,branch:[]},props:{page:At(x),constructors:[]}}}async function Xt({id:t,invalidating:a,url:e,params:r,route:n,preload:o}){if((v==null?void 0:v.id)===t)return at.delete(v.token),v.promise;const{errors:s,layouts:i,leaf:c}=n,l=[...i,c];s.forEach(m=>m==null?void 0:m().catch(()=>{})),l.forEach(m=>m==null?void 0:m[1]().catch(()=>{}));const h=g.url?t!==rt(g.url):!1,u=g.route?n.id!==g.route.id:!1,w=xe(g.url,e);let f=!1;const d=l.map(async(m,p)=>{var A;if(!m)return;const y=g.branch[p];return m[1]===(y==null?void 0:y.loader)&&!Re(f,u,h,w,(A=y.universal)==null?void 0:A.uses,r)?y:(f=!0,Rt({loader:m[1],url:e,params:r,route:n,parent:async()=>{var z;const T={};for(let j=0;j{});const _=[];for(let m=0;mPromise.resolve({}),server_data_node:xt(o)}),i={node:await Q(),loader:Q,universal:null,server:null,data:null};return nt({url:e,params:n,branch:[s,i],status:t,error:a,route:null})}catch(s){if(s instanceof vt)return Wt(new URL(s.location,location.href),{},0);throw s}}async function Ae(t){const a=t.href;if(W.has(a))return W.get(a);let e;try{const r=(async()=>{let n=await b.hooks.reroute({url:new URL(t),fetch:async(o,s)=>Se(o,s,t).promise})??t;if(typeof n=="string"){const o=new URL(t);b.hash?o.hash=n:o.pathname=n,n=o}return n})();W.set(a,r),e=await r}catch{W.delete(a);return}return e}async function ot(t,a){if(t&&!_t(t,L,b.hash)){const e=await Ae(t);if(!e)return;const r=Pe(e);for(const n of kt){const o=n.exec(r);if(o)return{id:rt(t),invalidating:a,route:n,params:oe(o),url:t}}}}function Pe(t){return ie(b.hash?t.hash.replace(/^#/,"").replace(/[?#].+/,""):t.pathname.slice(L.length))||"/"}function rt(t){return(b.hash?t.hash.replace(/^#/,""):t.pathname)+t.search}function Qt({url:t,type:a,intent:e,delta:r,event:n,scroll:o}){let s=!1;const i=Ut(g,e,t,a,o??null);r!==void 0&&(i.navigation.delta=r),n!==void 0&&(i.navigation.event=n);const c={...i.navigation,cancel:()=>{s=!0,i.reject(new Error("navigation cancelled"))}};return H||Mt.forEach(l=>l(c)),s?null:i}async function D({type:t,url:a,popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s={},redirect_count:i=0,nav_token:c={},accept:l=Tt,block:h=Tt,event:u}){var j;const w=O;O=c;const f=await ot(a,!1),d=t==="enter"?Ut(g,f,a,t):Qt({url:a,type:t,delta:e==null?void 0:e.delta,intent:f,scroll:e==null?void 0:e.scroll,event:u});if(!d){h(),O===c&&(O=w);return}const _=E,m=R;l(),H=!0,et&&d.navigation.type!=="enter"&&P.navigating.set(ft.current=d.navigation);let p=f&&await Xt(f);if(!p){if(_t(a,L,b.hash))return await V(a,o);p=await Zt(a,{id:null},await Y(new yt(404,"Not Found",`Not found: ${a.pathname}`),{url:a,params:{},route:{id:null}}),404,o)}if(a=(f==null?void 0:f.url)||a,O!==c)return d.reject(new Error("navigation aborted")),!1;if(p.type==="redirect"){if(i<20){await D({type:t,url:new URL(p.location,a),popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s,redirect_count:i+1,nav_token:c}),d.fulfil(void 0);return}p=await Lt({status:500,error:await Y(new Error("Redirect loop"),{url:a,params:{},route:{id:null}}),url:a,route:{id:null}})}else p.props.page.status>=400&&await P.updated.check()&&(await Bt(),await V(a,o));if(be(),bt(_),zt(m),p.props.page.url.pathname!==a.pathname&&(a.pathname=p.props.page.url.pathname),s=e?e.state:s,!e){const k=o?0:1,G={[N]:E+=k,[B]:R+=k,[Nt]:s};(o?history.replaceState:history.pushState).call(history,G,"",a),o||ye(E,R)}const y=f&&(v==null?void 0:v.id)===f.id?v.fork:null;v=null,p.props.page.state=s;let S;if(et){const k=(await Promise.all(Array.from(Ee,$=>$(d.navigation)))).filter($=>typeof $=="function");if(k.length>0){let $=function(){k.forEach(st=>{F.delete(st)})};k.push($),k.forEach(st=>{F.add(st)})}g=p.state,p.props.page&&(p.props.page.url=a);const G=y&&await y;G?S=G.commit():(Yt.$set(p.props),fe(p.props.page),S=(j=ee)==null?void 0:j()),Ht=!0}else await Jt(p,dt,!1);const{activeElement:A}=document;await S,await J(),await J();let T=null;if(Ot){const k=e?e.scroll:n?C():null;k?scrollTo(k.x,k.y):(T=a.hash&&document.getElementById(te(a)))?T.scrollIntoView():scrollTo(0,0)}const z=document.activeElement!==A&&document.activeElement!==document.body;!r&&!z&&$e(a,!T),Ot=!0,p.props.page&&Object.assign(x,p.props.page),H=!1,t==="popstate"&&Gt(R),d.fulfil(void 0),d.navigation.to&&(d.navigation.to.scroll=C()),F.forEach(k=>k(d.navigation)),P.navigating.set(ft.current=null)}async function Zt(t,a,e,r,n){return t.origin===Dt&&t.pathname===location.pathname&&!Vt?await Lt({status:r,error:e,url:t,route:a}):await V(t,n)}function Ie(){let t,a={element:void 0,href:void 0},e;U.addEventListener("mousemove",i=>{const c=i.target;clearTimeout(t),t=setTimeout(()=>{o(c,q.hover)},20)});function r(i){i.defaultPrevented||o(i.composedPath()[0],q.tap)}U.addEventListener("mousedown",r),U.addEventListener("touchstart",r,{passive:!0});const n=new IntersectionObserver(i=>{for(const c of i)c.isIntersecting&&(lt(new URL(c.target.href)),n.unobserve(c.target))},{threshold:0});async function o(i,c){const l=$t(i,U),h=l===a.element&&(l==null?void 0:l.href)===a.href&&c>=e;if(!l||h)return;const{url:u,external:w,download:f}=ut(l,L,b.hash);if(w||f)return;const d=X(l),_=u&&rt(g.url)===rt(u);if(!(d.reload||_))if(c<=d.preload_data){a={element:l,href:l.href},e=q.tap;const m=await ot(u,!1);if(!m)return;ke(m)}else c<=d.preload_code&&(a={element:l,href:l.href},e=c,lt(u))}function s(){n.disconnect();for(const i of U.querySelectorAll("a")){const{url:c,external:l,download:h}=ut(i,L,b.hash);if(l||h)continue;const u=X(i);u.reload||(u.preload_code===q.viewport&&n.observe(i),u.preload_code===q.eager&<(c))}}F.add(s),s()}function Y(t,a){if(t instanceof wt)return t.body;const e=Et(t),r=we(t);return b.hooks.handleError({error:t,event:a,status:e,message:r})??{message:r}}function Be(t,a={}){return t=new URL(gt(t)),t.origin!==Dt?Promise.reject(new Error("goto: invalid URL")):Wt(t,a,0)}function Te(t){if(typeof t=="function")Z.push(t);else{const{href:a}=new URL(t,location.href);Z.push(e=>e.href===a)}}function Oe(){var a;history.scrollRestoration="manual",addEventListener("beforeunload",e=>{let r=!1;if(jt(),!H){const n=Ut(g,void 0,null,"leave"),o={...n.navigation,cancel:()=>{r=!0,n.reject(new Error("navigation cancelled"))}};Mt.forEach(s=>s(o))}r?(e.preventDefault(),e.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&jt()}),(a=navigator.connection)!=null&&a.saveData||Ie(),U.addEventListener("click",async e=>{if(e.button||e.which!==1||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.defaultPrevented)return;const r=$t(e.composedPath()[0],U);if(!r)return;const{url:n,external:o,target:s,download:i}=ut(r,L,b.hash);if(!n)return;if(s==="_parent"||s==="_top"){if(window.parent!==window)return}else if(s&&s!=="_self")return;const c=X(r);if(!(r instanceof SVGAElement)&&n.protocol!==location.protocol&&!(n.protocol==="https:"||n.protocol==="http:")||i)return;const[h,u]=(b.hash?n.hash.replace(/^#/,""):n.href).split("#"),w=h===it(location);if(o||c.reload&&(!w||!u)){Qt({url:n,type:"link",event:e})?H=!0:e.preventDefault();return}if(u!==void 0&&w){const[,f]=g.url.href.split("#");if(f===u){if(e.preventDefault(),u===""||u==="top"&&r.ownerDocument.getElementById("top")===null)scrollTo({top:0});else{const d=r.ownerDocument.getElementById(decodeURIComponent(u));d&&(d.scrollIntoView(),d.focus())}return}if(K=!0,bt(E),t(n),!c.replace_state)return;K=!1}e.preventDefault(),await new Promise(f=>{requestAnimationFrame(()=>{setTimeout(f,0)}),setTimeout(f,100)}),await D({type:"link",url:n,keepfocus:c.keepfocus,noscroll:c.noscroll,replace_state:c.replace_state??n.href===location.href,event:e})}),U.addEventListener("submit",e=>{if(e.defaultPrevented)return;const r=HTMLFormElement.prototype.cloneNode.call(e.target),n=e.submitter;if(((n==null?void 0:n.formTarget)||r.target)==="_blank"||((n==null?void 0:n.formMethod)||r.method)!=="get")return;const i=new URL((n==null?void 0:n.hasAttribute("formaction"))&&(n==null?void 0:n.formAction)||r.action);if(_t(i,L,!1))return;const c=e.target,l=X(c);if(l.reload)return;e.preventDefault(),e.stopPropagation();const h=new FormData(c,n);i.search=new URLSearchParams(h).toString(),D({type:"form",url:i,keepfocus:l.keepfocus,noscroll:l.noscroll,replace_state:l.replace_state??i.href===location.href,event:e})}),addEventListener("popstate",async e=>{var r;if(!mt){if((r=e.state)!=null&&r[N]){const n=e.state[N];if(O={},n===E)return;const o=I[n],s=e.state[Nt]??{},i=new URL(e.state[re]??location.href),c=e.state[B],l=g.url?it(location)===it(g.url):!1;if(c===R&&(Ht||l)){s!==x.state&&(x.state=s),t(i),I[E]=C(),o&&scrollTo(o.x,o.y),E=n;return}const u=n-E;await D({type:"popstate",url:i,popped:{state:s,scroll:o,delta:u},accept:()=>{E=n,R=c},block:()=>{history.go(-u)},nav_token:O,event:e})}else if(!K){const n=new URL(location.href);t(n),b.hash&&location.reload()}}}),addEventListener("hashchange",()=>{K&&(K=!1,history.replaceState({...history.state,[N]:++E,[B]:R},"",location.href))});for(const e of document.querySelectorAll("link"))ve.has(e.rel)&&(e.href=e.href);addEventListener("pageshow",e=>{e.persisted&&P.navigating.set(ft.current=null)});function t(e){g.url=x.url=e,P.page.set(At(x)),P.page.notify()}}async function Ce(t,{status:a=200,error:e,node_ids:r,params:n,route:o,server_route:s,data:i,form:c}){Vt=!0;const l=new URL(location.href);let h;({params:n={},route:o={id:null}}=await ot(l,!1)||{}),h=kt.find(({id:f})=>f===o.id);let u,w=!0;try{const f=r.map(async(_,m)=>{const p=i[m];return p!=null&&p.uses&&(p.uses=je(p.uses)),Rt({loader:b.nodes[_],url:l,params:n,route:o,parent:async()=>{const y={};for(let S=0;S{const i=history.state;mt=!0,location.replace(new URL(`#${r}`,location.href)),history.replaceState(i,"",t),a&&scrollTo(o,s),mt=!1})}else{const o=document.body,s=o.getAttribute("tabindex");o.tabIndex=-1,o.focus({preventScroll:!0,focusVisible:!1}),s!==null?o.setAttribute("tabindex",s):o.removeAttribute("tabindex")}const n=getSelection();if(n&&n.type!=="None"){const o=[];for(let s=0;s{if(n.rangeCount===o.length){for(let s=0;s{o=u,s=w});return i.catch(()=>{}),{navigation:{from:{params:t.params,route:{id:((l=t.route)==null?void 0:l.id)??null},url:t.url,scroll:C()},to:e&&{params:(a==null?void 0:a.params)??null,route:{id:((h=a==null?void 0:a.route)==null?void 0:h.id)??null},url:e,scroll:n},willUnload:!a,type:r,complete:i},fulfil:o,reject:s}}function At(t){return{data:t.data,error:t.error,form:t.form,params:t.params,route:t.route,state:t.state,status:t.status,url:t.url}}function Ne(t){const a=new URL(t);return a.hash=decodeURIComponent(t.hash),a}function te(t){let a;if(b.hash){const[,,e]=t.hash.split("#",3);a=e??""}else a=t.hash.slice(1);return decodeURIComponent(a)}export{Fe as a,Be as g,P as s}; diff --git a/apps/dashboard/build/_app/immutable/chunks/EM_PBt2C.js.br b/apps/dashboard/build/_app/immutable/chunks/EM_PBt2C.js.br deleted file mode 100644 index fdd9ab031d2b4c1b92f0e7673e5422f5933833d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7668 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 P{~!Mg{+G0>-%|hp2reun diff --git a/apps/dashboard/build/_app/immutable/chunks/FzvEaXMa.js b/apps/dashboard/build/_app/immutable/chunks/FzvEaXMa.js deleted file mode 100644 index 29ca25a..0000000 --- a/apps/dashboard/build/_app/immutable/chunks/FzvEaXMa.js +++ /dev/null @@ -1,2 +0,0 @@ -var Me=Object.defineProperty;var ue=t=>{throw TypeError(t)};var Ye=(t,e,r)=>e in t?Me(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r;var $=(t,e,r)=>Ye(t,typeof e!="symbol"?e+"":e,r),re=(t,e,r)=>e.has(t)||ue("Cannot "+r);var s=(t,e,r)=>(re(t,e,"read from private field"),r?r.call(t):e.get(t)),c=(t,e,r)=>e.has(t)?ue("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,r),n=(t,e,r,a)=>(re(t,e,"write to private field"),a?a.call(t,r):e.set(t,r),r),p=(t,e,r)=>(re(t,e,"access private method"),r);import{aP as Ie,g as we,z as Le,A as xe,aQ as _e,B as q,ao as me,w as M,m as Y,M as C,aR as pe,b as Be,ab as Ce,ad as He,aS as ge,ai as F,k as Te,aT as se,ar as ie,ay as Pe,aU as ve,aV as Ve,aW as ye,aX as We,aY as qe,aZ as Z,a_ as G,a$ as be,b0 as ze,b1 as Re,az as Se,ag as $e,aw as ae,v as K,n as je,ae as Ue,b2 as j,E as Je,l as Qe,b3 as Xe,b4 as Ze,a6 as Ge,a3 as Ke,b5 as et,b6 as ne,x as tt,C as Ae,ax as rt,o as st,b7 as fe,q as U,b8 as it,av as at,b9 as nt,al as ft,p as ht,af as ot,ba as lt,a as ct}from"./CvjSAYrz.js";import{d as dt}from"./BsvCUYx-.js";function ut(t){let e=0,r=me(0),a;return()=>{Ie()&&(we(r),Le(()=>(e===0&&(a=xe(()=>t(()=>_e(r)))),e+=1,()=>{q(()=>{e-=1,e===0&&(a==null||a(),a=void 0,_e(r))})})))}}var _t=Je|Qe;function pt(t,e,r,a){new gt(t,e,r,a)}var E,z,T,L,g,R,w,m,S,x,N,H,P,V,A,ee,o,De,Ne,Oe,he,Q,X,oe;class gt{constructor(e,r,a,h){c(this,o);$(this,"parent");$(this,"is_pending",!1);$(this,"transform_error");c(this,E);c(this,z,Y?M:null);c(this,T);c(this,L);c(this,g);c(this,R,null);c(this,w,null);c(this,m,null);c(this,S,null);c(this,x,0);c(this,N,0);c(this,H,!1);c(this,P,new Set);c(this,V,new Set);c(this,A,null);c(this,ee,ut(()=>(n(this,A,me(s(this,x))),()=>{n(this,A,null)})));var i;n(this,E,e),n(this,T,r),n(this,L,f=>{var u=C;u.b=this,u.f|=pe,a(f)}),this.parent=C.b,this.transform_error=h??((i=this.parent)==null?void 0:i.transform_error)??(f=>f),n(this,g,Be(()=>{if(Y){const f=s(this,z);Ce();const u=f.data===He;if(f.data.startsWith(ge)){const d=JSON.parse(f.data.slice(ge.length));p(this,o,Ne).call(this,d)}else u?p(this,o,Oe).call(this):p(this,o,De).call(this)}else p(this,o,he).call(this)},_t)),Y&&n(this,E,M)}defer_effect(e){qe(e,s(this,P),s(this,V))}is_rendered(){return!this.is_pending&&(!this.parent||this.parent.is_rendered())}has_pending_snippet(){return!!s(this,T).pending}update_pending_count(e){p(this,o,oe).call(this,e),n(this,x,s(this,x)+e),!(!s(this,A)||s(this,H))&&(n(this,H,!0),q(()=>{n(this,H,!1),s(this,A)&&$e(s(this,A),s(this,x))}))}get_effect_pending(){return s(this,ee).call(this),we(s(this,A))}error(e){var r=s(this,T).onerror;let a=s(this,T).failed;if(!r&&!a)throw e;s(this,R)&&(ae(s(this,R)),n(this,R,null)),s(this,w)&&(ae(s(this,w)),n(this,w,null)),s(this,m)&&(ae(s(this,m)),n(this,m,null)),Y&&(K(s(this,z)),je(),K(Ue()));var h=!1,i=!1;const f=()=>{if(h){Ze();return}h=!0,i&&Xe(),s(this,m)!==null&&ie(s(this,m),()=>{n(this,m,null)}),p(this,o,X).call(this,()=>{se.ensure(),p(this,o,he).call(this)})},u=l=>{try{i=!0,r==null||r(l,f),i=!1}catch(d){j(d,s(this,g)&&s(this,g).parent)}a&&n(this,m,p(this,o,X).call(this,()=>{se.ensure();try{return F(()=>{var d=C;d.b=this,d.f|=pe,a(s(this,E),()=>l,()=>f)})}catch(d){return j(d,s(this,g).parent),null}}))};q(()=>{var l;try{l=this.transform_error(e)}catch(d){j(d,s(this,g)&&s(this,g).parent);return}l!==null&&typeof l=="object"&&typeof l.then=="function"?l.then(u,d=>j(d,s(this,g)&&s(this,g).parent)):u(l)})}}E=new WeakMap,z=new WeakMap,T=new WeakMap,L=new WeakMap,g=new WeakMap,R=new WeakMap,w=new WeakMap,m=new WeakMap,S=new WeakMap,x=new WeakMap,N=new WeakMap,H=new WeakMap,P=new WeakMap,V=new WeakMap,A=new WeakMap,ee=new WeakMap,o=new WeakSet,De=function(){try{n(this,R,F(()=>s(this,L).call(this,s(this,E))))}catch(e){this.error(e)}},Ne=function(e){const r=s(this,T).failed;r&&n(this,m,F(()=>{r(s(this,E),()=>e,()=>()=>{})}))},Oe=function(){const e=s(this,T).pending;e&&(this.is_pending=!0,n(this,w,F(()=>e(s(this,E)))),q(()=>{var r=n(this,S,document.createDocumentFragment()),a=Te();r.append(a),n(this,R,p(this,o,X).call(this,()=>(se.ensure(),F(()=>s(this,L).call(this,a))))),s(this,N)===0&&(s(this,E).before(r),n(this,S,null),ie(s(this,w),()=>{n(this,w,null)}),p(this,o,Q).call(this))}))},he=function(){try{if(this.is_pending=this.has_pending_snippet(),n(this,N,0),n(this,x,0),n(this,R,F(()=>{s(this,L).call(this,s(this,E))})),s(this,N)>0){var e=n(this,S,document.createDocumentFragment());Pe(s(this,R),e);const r=s(this,T).pending;n(this,w,F(()=>r(s(this,E))))}else p(this,o,Q).call(this)}catch(r){this.error(r)}},Q=function(){this.is_pending=!1;for(const e of s(this,P))ve(e,Ve),ye(e);for(const e of s(this,V))ve(e,We),ye(e);s(this,P).clear(),s(this,V).clear()},X=function(e){var r=C,a=Re,h=Se;Z(s(this,g)),G(s(this,g)),be(s(this,g).ctx);try{return e()}catch(i){return ze(i),null}finally{Z(r),G(a),be(h)}},oe=function(e){var r;if(!this.has_pending_snippet()){this.parent&&p(r=this.parent,o,oe).call(r,e);return}n(this,N,s(this,N)+e),s(this,N)===0&&(p(this,o,Q).call(this),s(this,w)&&ie(s(this,w),()=>{n(this,w,null)}),s(this,S)&&(s(this,E).before(s(this,S)),n(this,S,null)))};const vt=["touchstart","touchmove"];function yt(t){return vt.includes(t)}const I=Symbol("events"),ke=new Set,le=new Set;function bt(t,e,r,a={}){function h(i){if(a.capture||ce.call(e,i),!i.cancelBubble)return et(()=>r==null?void 0:r.call(this,i))}return t.startsWith("pointer")||t.startsWith("touch")||t==="wheel"?q(()=>{e.addEventListener(t,h,a)}):e.addEventListener(t,h,a),h}function Rt(t,e,r,a,h){var i={capture:a,passive:h},f=bt(t,e,r,i);(e===document.body||e===window||e===document||e instanceof HTMLMediaElement)&&Ke(()=>{e.removeEventListener(t,f,i)})}function St(t,e,r){(e[I]??(e[I]={}))[t]=r}function At(t){for(var e=0;e{throw k});throw D}}finally{t[I]=e,delete t.currentTarget,G(B),Z(W)}}}function Dt(t,e){var r=e==null?"":typeof e=="object"?e+"":e;r!==(t.__t??(t.__t=t.nodeValue))&&(t.__t=r,t.nodeValue=r+"")}function Et(t,e){return Fe(t,e)}function Nt(t,e){ne(),e.intro=e.intro??!1;const r=e.target,a=Y,h=M;try{for(var i=tt(r);i&&(i.nodeType!==Ae||i.data!==rt);)i=st(i);if(!i)throw fe;U(!0),K(i);const f=Fe(t,{...e,anchor:i});return U(!1),f}catch(f){if(f instanceof Error&&f.message.split(` -`).some(u=>u.startsWith("https://svelte.dev/e/")))throw f;return f!==fe&&console.warn("Failed to hydrate: ",f),e.recover===!1&&it(),ne(),at(r),U(!1),Et(t,e)}finally{U(a),K(h)}}const J=new Map;function Fe(t,{target:e,anchor:r,props:a={},events:h,context:i,intro:f=!0,transformError:u}){ne();var l=void 0,d=nt(()=>{var B=r??e.appendChild(Te());pt(B,{pending:()=>{}},v=>{ht({});var _=Se;if(i&&(_.c=i),h&&(a.$$events=h),Y&&dt(v,null),l=t(v,a)||{},Y&&(C.nodes.end=M,M===null||M.nodeType!==Ae||M.data!==ot))throw lt(),fe;ct()},u);var W=new Set,D=v=>{for(var _=0;_{var O;for(var v of W)for(const b of[e,document]){var _=J.get(b),y=_.get(v);--y==0?(b.removeEventListener(v,ce),_.delete(v),_.size===0&&J.delete(b)):_.set(v,y)}le.delete(D),B!==r&&((O=B.parentNode)==null||O.removeChild(B))}});return de.set(l,d),l}let de=new WeakMap;function Ot(t,e){const r=de.get(t);return r?(de.delete(t),r(e)):Promise.resolve()}export{St as a,At as d,Rt as e,Nt as h,Et as m,Dt as s,Ot as u}; diff --git a/apps/dashboard/build/_app/immutable/chunks/FzvEaXMa.js.br b/apps/dashboard/build/_app/immutable/chunks/FzvEaXMa.js.br deleted file mode 100644 index 92f1bf81230f24b8738a219c113ad1287c1be68d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3127 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 Rc(F&*-;)vUDTzGS`x`S570Lhr diff --git a/apps/dashboard/build/_app/immutable/chunks/FzvEaXMa.js.gz b/apps/dashboard/build/_app/immutable/chunks/FzvEaXMa.js.gz deleted file mode 100644 index 1095b975f7871062a8552487479cde6d1ec5a7be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3508 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 iQzfutRVIiM>f{const n=o(e);if(typeof n=="function")return n})}function f(e){t===null&&c(),l(()=>()=>o(e))}function i(e){var n=e.l;return n.u??(n.u={a:[],b:[],m:[]})}export{f as a,l as o}; +import{aB as a,az as t,w as u,v as o}from"./CpWkWWOo.js";function c(e){throw new Error("https://svelte.dev/e/lifecycle_outside_component")}function l(e){t===null&&c(),u&&t.l!==null?i(t).m.push(e):a(()=>{const n=o(e);if(typeof n=="function")return n})}function f(e){t===null&&c(),l(()=>()=>o(e))}function i(e){var n=e.l;return n.u??(n.u={a:[],b:[],m:[]})}export{f as a,l as o}; diff --git a/apps/dashboard/build/_app/immutable/chunks/GG5zm9kr.js.br b/apps/dashboard/build/_app/immutable/chunks/GG5zm9kr.js.br new file mode 100644 index 0000000000000000000000000000000000000000..62d783214cfa5a333ac42b2c5f97dab1cec0f7e4 GIT binary patch literal 227 zcmV<90381tcmV*6)JFAI7G1izcbULHm9WEobr~IbY9Yb2uRxyG4xZBmRDOR$oHHiwygAC89x}7|af5x#T3IQqauDVWg5PQ;mz|?q`gi~ zq4AC=2K9=^;1}XxA+I6$z~~Wiie1~r87u-nz}!M>jRtjA7WO`2GzZu#pZ6U&r1kbk zv=^cf!X;~~O0l|0RfXI>UZb61So4ujDIRmRlZ@5kX;t1uBu@C8^+q#1PvCV91ihhY z9RO2s#BFzb`v0E2Aj=inUDuTEEJMZuxBU&r({9JIidA;+AI)cxF-x9-@5_hv^}+V~ P(f;8V(%EoLc>w?b9Ug<5 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/CtkE7HV2.js b/apps/dashboard/build/_app/immutable/chunks/MAY1QfFZ.js similarity index 96% rename from apps/dashboard/build/_app/immutable/chunks/CtkE7HV2.js rename to apps/dashboard/build/_app/immutable/chunks/MAY1QfFZ.js index dc8aa6c..bf47818 100644 --- a/apps/dashboard/build/_app/immutable/chunks/CtkE7HV2.js +++ b/apps/dashboard/build/_app/immutable/chunks/MAY1QfFZ.js @@ -1 +1 @@ -import{d as i,w as S}from"./DfQhL-hC.js";const b=200;function H(){const{subscribe:t,set:o,update:e}=S({connected:!1,events:[],lastHeartbeat:null,error:null});let n=null,a=null,d=0;function m(s){const c=s||(window.location.port==="5173"?`ws://${window.location.hostname}:3927/ws`:`ws://${window.location.host}/ws`);if((n==null?void 0:n.readyState)!==WebSocket.OPEN)try{n=new WebSocket(c),n.onopen=()=>{d=0,e(r=>({...r,connected:!0,error:null}))},n.onmessage=r=>{try{const l=JSON.parse(r.data);e(f=>{if(l.type==="Heartbeat")return{...f,lastHeartbeat:l};const $=[l,...f.events].slice(0,b);return{...f,events:$}})}catch(l){console.warn("[vestige] Failed to parse WebSocket message:",l)}},n.onclose=()=>{e(r=>({...r,connected:!1})),p(c)},n.onerror=()=>{e(r=>({...r,error:"WebSocket connection failed"}))}}catch(r){e(l=>({...l,error:String(r)}))}}function p(s){a&&clearTimeout(a);const c=Math.min(1e3*2**d,3e4);d++,a=setTimeout(()=>m(s),c)}function v(){a&&clearTimeout(a),n==null||n.close(),n=null,o({connected:!1,events:[],lastHeartbeat:null,error:null})}function h(){e(s=>({...s,events:[]}))}function w(s){e(c=>{const r=[s,...c.events].slice(0,b);return{...c,events:r}})}return{subscribe:t,connect:m,disconnect:v,clearEvents:h,injectEvent:w}}const u=H(),g=i(u,t=>t.connected),k=i(u,t=>t.events);i(u,t=>t.lastHeartbeat);const M=i(u,t=>{var o,e;return((e=(o=t.lastHeartbeat)==null?void 0:o.data)==null?void 0:e.memory_count)??0}),E=i(u,t=>{var o,e;return((e=(o=t.lastHeartbeat)==null?void 0:o.data)==null?void 0:e.avg_retention)??0}),T=i(u,t=>{var o,e;return((e=(o=t.lastHeartbeat)==null?void 0:o.data)==null?void 0:e.suppressed_count)??0}),W=i(u,t=>{var o,e;return((e=(o=t.lastHeartbeat)==null?void 0:o.data)==null?void 0:e.uptime_secs)??0});function _(t){if(!Number.isFinite(t)||t<0)return"—";const o=Math.floor(t/86400),e=Math.floor(t%86400/3600),n=Math.floor(t%3600/60),a=Math.floor(t%60);return o>0?e>0?`${o}d ${e}h`:`${o}d`:e>0?n>0?`${e}h ${n}m`:`${e}h`:n>0?a>0?`${n}m ${a}s`:`${n}m`:`${a}s`}export{E as a,k as e,_ as f,g as i,M as m,T as s,W as u,u as w}; +import{d as i,w as S}from"./BeMFXnHE.js";const b=200;function H(){const{subscribe:t,set:o,update:e}=S({connected:!1,events:[],lastHeartbeat:null,error:null});let n=null,a=null,d=0;function m(s){const c=s||(window.location.port==="5173"?`ws://${window.location.hostname}:3927/ws`:`ws://${window.location.host}/ws`);if((n==null?void 0:n.readyState)!==WebSocket.OPEN)try{n=new WebSocket(c),n.onopen=()=>{d=0,e(r=>({...r,connected:!0,error:null}))},n.onmessage=r=>{try{const l=JSON.parse(r.data);e(f=>{if(l.type==="Heartbeat")return{...f,lastHeartbeat:l};const $=[l,...f.events].slice(0,b);return{...f,events:$}})}catch(l){console.warn("[vestige] Failed to parse WebSocket message:",l)}},n.onclose=()=>{e(r=>({...r,connected:!1})),p(c)},n.onerror=()=>{e(r=>({...r,error:"WebSocket connection failed"}))}}catch(r){e(l=>({...l,error:String(r)}))}}function p(s){a&&clearTimeout(a);const c=Math.min(1e3*2**d,3e4);d++,a=setTimeout(()=>m(s),c)}function v(){a&&clearTimeout(a),n==null||n.close(),n=null,o({connected:!1,events:[],lastHeartbeat:null,error:null})}function h(){e(s=>({...s,events:[]}))}function w(s){e(c=>{const r=[s,...c.events].slice(0,b);return{...c,events:r}})}return{subscribe:t,connect:m,disconnect:v,clearEvents:h,injectEvent:w}}const u=H(),g=i(u,t=>t.connected),k=i(u,t=>t.events);i(u,t=>t.lastHeartbeat);const M=i(u,t=>{var o,e;return((e=(o=t.lastHeartbeat)==null?void 0:o.data)==null?void 0:e.memory_count)??0}),E=i(u,t=>{var o,e;return((e=(o=t.lastHeartbeat)==null?void 0:o.data)==null?void 0:e.avg_retention)??0}),T=i(u,t=>{var o,e;return((e=(o=t.lastHeartbeat)==null?void 0:o.data)==null?void 0:e.suppressed_count)??0}),W=i(u,t=>{var o,e;return((e=(o=t.lastHeartbeat)==null?void 0:o.data)==null?void 0:e.uptime_secs)??0});function _(t){if(!Number.isFinite(t)||t<0)return"—";const o=Math.floor(t/86400),e=Math.floor(t%86400/3600),n=Math.floor(t%3600/60),a=Math.floor(t%60);return o>0?e>0?`${o}d ${e}h`:`${o}d`:e>0?n>0?`${e}h ${n}m`:`${e}h`:n>0?a>0?`${n}m ${a}s`:`${n}m`:`${a}s`}export{E as a,k as e,_ as f,g as i,M as m,T as s,W as u,u as w}; diff --git a/apps/dashboard/build/_app/immutable/chunks/MAY1QfFZ.js.br b/apps/dashboard/build/_app/immutable/chunks/MAY1QfFZ.js.br new file mode 100644 index 0000000000000000000000000000000000000000..04a9af2449a93e253120fe0c8149b372b3657ba9 GIT binary patch literal 819 zcmV-31I+vz3J3rkhq2>jDdbNMjjqj9{rB@ylm$3Anoc%VbdFcnq$Sv!%89hq9>oHr z>=c(BaRURmSY_5{Q)<_- z^TgvL?A#9S^ zf^&%e$se&sIlKo8fzh~kI)a4?cr=dN0g0RxLBYF?e3M+H2KsL# zf6L{@CSU=r-{#pIPl%ao!Os~zWzeK)RA&NCgJDLR$ zhMFl?=^O%e7OnzFh$T$LM}d48W4)Q-@Vyz5XLlPgNJ-_)tXV3V zhjjQGTwnevuBP;}4kxh`+5`)BIvP!urHD-`MR0|1?H#o)7dlqy0wO~+m`IYcNVtIr z8a6{NNI+~LiH=SPY(N+t-9M0wYjXu$nFVkYi89LwC?%Eu+u%tCCJ@Zyyfq1XQ9ehy zs~^NnZ?~vQMItMj$(XwU>bNn+!kC(`N=L)tpne^-mf8rOLlcdEIsG`S^kekB z(8fjJNxDQxFu$vdjZBkZ6bY(;C(kouiQ^;2?qD&K@e>&O>5u6RHtM;yY@iBu4isY| zs1&jQ!4PKWwIxUZDRz!(N~t0*lp7t0gBzcjgVuZn%x2WCKr2VaexH51p#@jkE=Fx9 zIGzAn+912{jGE^HoG?4_L#)7*O1PrSSAEHvuKNRapAi>8+ZH}houx6L5n15L%lxjx zgQmfaRW4qmtZkIcfL2@y6y9$@n{)*a!6i>KNCG1Rzumn!LB}l$Nrs!2Zk$OCty2G? z(utLZ6jsm7@(PwmP>=6}#7NSmN&wOWd!g z+^}@`%iE;eew33W)&0kYcnPL$>YAkDvxWU)Qj}0|(0Vjl1p>>J3+cB+zj{$d03Aud@y>2HBp#Ll9^Vxm3^dSeC-zi;Gc%$@C4% z@Xcy&SFtQ@qq;h`Z%{{7ocdW zFH?~ku<&+kejRleUHI*1~oKm`^@;S$H;j^>$SM`iYE77ALTr}^;+C|d856zk8&)IH&xJUIho?#z;`+UNb+nVj4@qsg5!B`KY$n#m7;15(q_tqTYM0O5qg#{d8T literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/RBGf_S-E.js b/apps/dashboard/build/_app/immutable/chunks/RBGf_S-E.js deleted file mode 100644 index c284ce0..0000000 --- a/apps/dashboard/build/_app/immutable/chunks/RBGf_S-E.js +++ /dev/null @@ -1 +0,0 @@ -var x=t=>{throw TypeError(t)};var B=(t,e,n)=>e.has(t)||x("Cannot "+n);var a=(t,e,n)=>(B(t,e,"read from private field"),n?n.call(t):e.get(t)),c=(t,e,n)=>e.has(t)?x("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,n);import{o as I}from"./CNjeV5xa.js";import{s as u,g as f,h as d}from"./CvjSAYrz.js";import{w as G}from"./DfQhL-hC.js";new URL("sveltekit-internal://");function ae(t,e){return t==="/"||e==="ignore"?t:e==="never"?t.endsWith("/")?t.slice(0,-1):t:e==="always"&&!t.endsWith("/")?t+"/":t}function oe(t){return t.split("%25").map(decodeURI).join("%25")}function ie(t){for(const e in t)t[e]=decodeURIComponent(t[e]);return t}function le({href:t}){return t.split("#")[0]}function W(...t){let e=5381;for(const n of t)if(typeof n=="string"){let r=n.length;for(;r;)e=e*33^n.charCodeAt(--r)}else if(ArrayBuffer.isView(n)){const r=new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let s=r.length;for(;s;)e=e*33^r[--s]}else throw new TypeError("value must be a string or TypedArray");return(e>>>0).toString(36)}new TextEncoder;new TextDecoder;function X(t){const e=atob(t),n=new Uint8Array(e.length);for(let r=0;r((t instanceof Request?t.method:(e==null?void 0:e.method)||"GET")!=="GET"&&b.delete(U(t)),z(t,e));const b=new Map;function ce(t,e){const n=U(t,e),r=document.querySelector(n);if(r!=null&&r.textContent){r.remove();let{body:s,...l}=JSON.parse(r.textContent);const o=r.getAttribute("data-ttl");return o&&b.set(n,{body:s,init:l,ttl:1e3*Number(o)}),r.getAttribute("data-b64")!==null&&(s=X(s)),Promise.resolve(new Response(s,l))}return window.fetch(t,e)}function ue(t,e,n){if(b.size>0){const r=U(t,n),s=b.get(r);if(s){if(performance.now()o)}function s(o){n=!1,e.set(o)}function l(o){let i;return e.subscribe(h=>{(i===void 0||n&&h!==i)&&o(i=h)})}return{notify:r,set:s,subscribe:l}}const D={v:()=>{}};function Re(){const{set:t,subscribe:e}=G(!1);let n;async function r(){clearTimeout(n);try{const s=await fetch(`${M}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!s.ok)return!1;const o=(await s.json()).version!==F;return o&&(t(!0),D.v(),clearTimeout(n)),o}catch{return!1}}return{subscribe:e,check:r}}function Q(t,e,n){return t.origin!==Y||!t.pathname.startsWith(e)?!0:n?t.pathname!==location.pathname:!1}function Se(t){}const H=new Set(["load","prerender","csr","ssr","trailingSlash","config"]);[...H];const Z=new Set([...H]);[...Z];let E,O,T;const ee=I.toString().includes("$$")||/function \w+\(\) \{\}/.test(I.toString());var _,m,w,p,v,y,A,R,P,S,V,k,j;ee?(E={data:{},form:null,error:null,params:{},route:{id:null},state:{},status:-1,url:new URL("https://example.com")},O={current:null},T={current:!1}):(E=new(P=class{constructor(){c(this,_,u({}));c(this,m,u(null));c(this,w,u(null));c(this,p,u({}));c(this,v,u({id:null}));c(this,y,u({}));c(this,A,u(-1));c(this,R,u(new URL("https://example.com")))}get data(){return f(a(this,_))}set data(e){d(a(this,_),e)}get form(){return f(a(this,m))}set form(e){d(a(this,m),e)}get error(){return f(a(this,w))}set error(e){d(a(this,w),e)}get params(){return f(a(this,p))}set params(e){d(a(this,p),e)}get route(){return f(a(this,v))}set route(e){d(a(this,v),e)}get state(){return f(a(this,y))}set state(e){d(a(this,y),e)}get status(){return f(a(this,A))}set status(e){d(a(this,A),e)}get url(){return f(a(this,R))}set url(e){d(a(this,R),e)}},_=new WeakMap,m=new WeakMap,w=new WeakMap,p=new WeakMap,v=new WeakMap,y=new WeakMap,A=new WeakMap,R=new WeakMap,P),O=new(V=class{constructor(){c(this,S,u(null))}get current(){return f(a(this,S))}set current(e){d(a(this,S),e)}},S=new WeakMap,V),T=new(j=class{constructor(){c(this,k,u(!1))}get current(){return f(a(this,k))}set current(e){d(a(this,k),e)}},k=new WeakMap,j),D.v=()=>T.current=!0);function Ue(t){Object.assign(E,t)}export{be as H,_e as N,ge as P,he as S,ye as a,J as b,Re as c,le as d,ie as e,pe as f,ve as g,ae as h,Q as i,N as j,oe as k,fe as l,ue as m,O as n,Y as o,E as p,ce as q,me as r,we as s,de as t,Ae as u,Ue as v,Se as w}; diff --git a/apps/dashboard/build/_app/immutable/chunks/RBGf_S-E.js.br b/apps/dashboard/build/_app/immutable/chunks/RBGf_S-E.js.br deleted file mode 100644 index 76ee001467288882fcf074ab8dfb113044698196..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2618 zcmV-A3dQvsjTsRYq)kI;tUjGzh^%ykB(s;V%m4bt3eTeri@-^jvpA)6j(|DV*cV6Q zNxCX)XkPtO`cfz1F!-;z-pYgge+7=JaP<}DQkG;?g}c1>b~CqoFb!QN@FDl9%-I5x zY8`<>a%EMeI<*YtF4`=p)I0xJYF+D>Dh?0nbFzFmq)+cRqnj@VmHRq=2QE2 z+CB*kpHCs{vxGn6KJeczOh=Nla5fWAmYQ8NQMhXB3q&MVFburRe#fIJs-RtvAI%Vo zKVXvROm`U&N~7iF9H#~7JMsLbMV@EZ@BF!A-9H~$!Q+}7@i z-SML!r&9-srJ|JY8)V~3n8QwWUSQ0V1|X*DI4bpKXTm+urZj4MEu)Su1An6zdoJH5 zZbO-wsXe)ZU&bw`Q@_dq)!u^)*I+5MJsWH!HGv%K;N&hVH9_nZB`+3>IZOjd^X45$ zan9k3@XQpH?@Fh^PuZe)+fNyg{h3U4uv-}b4cb*kM#7Ou-7_!U1FzD$*JJ`_=~l#t zx?>2}q-4A+l5*E*I2^a-bCe+hM$V1;? z{Gf23q8L3^d|J`HQyF_M;el5n^m)D%rh|h* ziOQ*JHv#CyXxcUBXeW?8YOCov*@fX7$0%SQfJId#g`((4^r`_RBc0wsLVZd`Lwv*J zQFZglC6EUztuPM-07mEMx#T6Ml=wZ|Fo;o>hdQLk+~%R1 z&<1&!g`!fS++V>%5~~f7ZI_Ib>bOcQ^O~d_lLdrtj&H2j1ig>-z2;xnI4I=Tjn%gH z3{@p&yV|$kp^64i^+~kZcN6c4`$So)W|d#hMFl=5QQW=nyII`4b8CL*_AP-8lZa@J z_NG1VqzDv|RoT91Ga% zZz9)wcKR0DrqR;^O<+^^Cj3Qh8#0Si5;FS_>!`|}_-Sdb*HQP?SzcDfJ$O&>IQ9L!w;ce`(Rw!us7@{Y!5{RfVPolkA(( zaL}d$)&EE!qN2!i$;2xma{?ge-#zdV&5dW@5KyjmAS}|fs-H=B6m&@$++|X}qry;mr2EVF7mo_ssX{>_Yjl0Dd+oAI zWSIcaC{z#-tR=qD?9a93pV?|=nbkW^MM%Y}CCzDG>ops7 z6b#y{ba~!oRGIlQBVTU`jx39H9PMR?;?R^A(=V{T002GESUl7=*cP$I&^*VcGF*y` zW?W;1E8L2Dt)~RwQDj>!wyseM1JLCi{V%%)-Mm)5f!HL6C-9}+j?fnz;~W)3n9WP) z*ftFS3Rmmy6{Qiw+_+6qjo6DdeU{R1m#(U!@mJ^vWHDR8Thv%Vw~_&|H$lcwIP>Is z#7?e{Cf&)_=Iomk}& zXS>#UDs$FtX%S^dM122Y!(j5f&4@b4b1OS)Apw~lV{GV}OYP9}wG~gS`&6HQ^eM$N zErAv>$>8`iODshUTpX6?L@#7k;4RC(X7#F!qT4Yb?zr#}bzd~uflu3v0^}>wk zc?;p^$sn^i;8S%b0da`|tt{jTSnQalki_xq?dX`M_DTG66~QD`Ig4Z%vaq&G!sr|9 zzoIURyD(JQT$>7@k&zI$oKMhMk(6Xx%*o1D^4eu7i-TN>dW`addenfD!Y|}KcKoi^ znf;f(_AR27gAGqgr0BySGQWWt<};|F4SPYu^s0TW2ylBmmhkmirWcLR zCr9!KWLG>&v(8v0Fm<hjJHt1L+xc z&;kUGfiV2KonHx!+(J#u_Nlk)KqXjRR?7O?vz}n=@?H)SY7{#mSyXk~4GJUy{eMQQ zP=2KT&wA|3mbQN2d@hcj;UQxJ=9C2xVajpr*RF7|?8y;I`|Rq0%n}Do3#Y8P6=*I2 zkoFv=P2S?$xRrJ8O-HN0fFbVuTx{k?86Jz~eI)#fnNEDoe%*~v?3H?B4_=y%9U{#RHAI3!#K>z>% diff --git a/apps/dashboard/build/_app/immutable/chunks/RBGf_S-E.js.gz b/apps/dashboard/build/_app/immutable/chunks/RBGf_S-E.js.gz deleted file mode 100644 index 8f91368a50815d2273498df426c5001322cbd09c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2960 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 G82|tq@tLy# diff --git a/apps/dashboard/build/_app/immutable/chunks/V6gjw5Ec.js b/apps/dashboard/build/_app/immutable/chunks/V6gjw5Ec.js new file mode 100644 index 0000000..f9c6462 --- /dev/null +++ b/apps/dashboard/build/_app/immutable/chunks/V6gjw5Ec.js @@ -0,0 +1 @@ +import{k as L,l as D,P as T,g as P,c as B,h as b,m as Y,o as h,D as x,q as M,v as N,w as U,x as q,y as w,z,A as $,B as y,S as C,L as G}from"./CpWkWWOo.js";import{c as Z}from"./C6HuKgyx.js";function H(r,a,t,s){var o;var f=!U||(t&q)!==0,v=(t&M)!==0,E=(t&y)!==0,n=s,S=!0,g=()=>(S&&(S=!1,n=E?N(s):s),n),u;if(v){var O=C in r||G in r;u=((o=L(r,a))==null?void 0:o.set)??(O&&a in r?e=>r[a]=e:void 0)}var _,I=!1;v?[_,I]=Z(()=>r[a]):_=r[a],_===void 0&&s!==void 0&&(_=g(),u&&(f&&D(),u(_)));var i;if(f?i=()=>{var e=r[a];return e===void 0?g():(S=!0,e)}:i=()=>{var e=r[a];return e!==void 0&&(n=void 0),e===void 0?n:e},f&&(t&T)===0)return i;if(u){var R=r.$$legacy;return(function(e,l){return arguments.length>0?((!f||!l||R||I)&&u(l?i():e),e):i()})}var c=!1,d=((t&w)!==0?z:$)(()=>(c=!1,i()));v&&P(d);var m=h;return(function(e,l){if(arguments.length>0){const A=l?P(d):f&&v?B(e):e;return b(d,A),c=!0,n!==void 0&&(n=A),e}return Y&&c||(m.f&x)!==0?d.v:P(d)})}export{H as p}; diff --git a/apps/dashboard/build/_app/immutable/chunks/V6gjw5Ec.js.br b/apps/dashboard/build/_app/immutable/chunks/V6gjw5Ec.js.br new file mode 100644 index 0000000000000000000000000000000000000000..e9fafc8605294b59e6662e68a676fd2e75b4a8ed GIT binary patch literal 524 zcmV+n0`vVFxdR{^g-w|&{v}>s)>?@qNygnp@aZoN(Z2zfM|vsfidPd8eg$rhw)!uf z+g&z5bDvFSTd5xiwU^71&vP!{8_2%U0sx~fA}ONuXnv6-ncy?GhD1gneH?A`b~XJ4 z2^@C*>Eq*%ImU@TYwS_5=7%mSzL>aRL#2-d7YiaRiE$u-OPYzv=p4Z^-GY=Idd!`p z3Ht5saO^#w^wVi&)82L~I^t)$DsivIVI}>RgXu9k*R zL>9>fF(6ZeE&J>&R8b7n=iCK>odp@ogI=bu@`WYBm0vO%q-Eva;MVY}Y1HjlLj%~J zLrF?@8fm>~J*$>|@V7wSf>n@@!Kp?!U++JU-b&4>>37eIi3NF$`Xg!Uid1r3MWi~9>iX@MQa|9IpncsYwu7lr;J!e=7K0V3Z z{)_E@F;S2(jpj)U1*&+`$!pusg3RA=QL&b6XH}-`n)0@bCs(;3>-=*zgJ~7f6n;rG zUj2RCKQlTu+RMdaL89&^s&MQ0=AVxEkvqZSFW(V3+sR9i-+uw-fkgs0`9DMjEju;0 O?~Kro$6sXx=UM^=I0Cc) literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/V6gjw5Ec.js.gz b/apps/dashboard/build/_app/immutable/chunks/V6gjw5Ec.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..a76e9e06d4a8be68bad90a61477b02dfac7493ec GIT binary patch literal 566 zcmV-60?GX!iwFP!000026LphaPunmQhVS<)QdC*Cbd+^ByGV4fT0j&HDB?pEAXJ6a zNi$NX;KjO{WRz#H!%OumznCB2c35D3!LGENeJtOShH4QJ>tLPyP zphlxFI(-;2{Dv`Z#^20`6M4xC;S~b3fXYuIUUw@@@W@HDlQ+$& zrC%ZE8J?35ArN(yrn1hGxij!Gw@{^!l1~^5Y_(K)m_G(jsJyO5wA6G4XJ%QymXAg~ z;R7c-R42R{5@Cjj-3-Qx-fzuk7<1#$sEDy+l6)qFusI~;JCcdroprBlH$PWpm1{HF zHO#E6-0k;M6$jyF*P8E- zlq*QZb~h==<7%mNS-7dvak)4gNX~mv)AZ7&xo(;>!C1vpnHc-Z_z<2^Z5L`tCpkB# zQ?fUE-tyh+3mYxB-%Ke5#n=^}cY!T&@oziE`rlT>Hq3NUIzvn)weZZgYdPY^h1v)9 z%;zu^5K^-G&+yD^)$Ypf84JxHyL2PA?!3<3+M}jsGiq(G!5n8$2N7&xb{iRW{vYAzj}@O+@stDgT3E?w0u zoJ6oeyp%b4WTY>h|1!fIjEZFS*}e@oV*&+Dv4}8?ciwI{i-b;o$K27T+E;sOg_g#4 z=c8lXZtC9(=gXt2@+soC0!T0Is^w7U*yjvW3W8H8m_Io0oS`tfD+6e?c#fE_Uf0>= zZp^Z$071Y@nA?t#F+OWKfTp#@ul(dYj;F0wLH!h_XL}GQBt!i5LrT-r<05z=h%CU5 jY5tJM@39m$!Y+9b literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/aVbAZ-t7.js.gz b/apps/dashboard/build/_app/immutable/chunks/aVbAZ-t7.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..c6730504ecfbaee5bb4fd6d32250da3317cea92f GIT binary patch literal 281 zcmV+!0p|W6iwFP!000026K#;eN&_(vhVMQ_b`MJeA$sl-qWAQrMkX*NT1L4WvAX_S;L8FW+MC$_rvOA zwR#Fi!liyo5PCLnkd1V5Ba=jN*c)VCgIce*-o)6L&eq^~7)M`d?Q+pt?*r`E%?T#G zyFij&rT^8OYS+Ai$ve`?X>=I?M#3sCVwnj|6Q zA5ZNj>!W2^7pp2|4-_sSpDhi8o}Jfgby47}d8>Ik$&6#0;i5?SF*}~8KSCr$p>4h8 fMz&%?O9^wzWWSEr9p>xCslNIKHr1s%kO2Sy!{mYH literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/ciN1mm2W.js b/apps/dashboard/build/_app/immutable/chunks/ciN1mm2W.js deleted file mode 100644 index 1fa46c8..0000000 --- a/apps/dashboard/build/_app/immutable/chunks/ciN1mm2W.js +++ /dev/null @@ -1 +0,0 @@ -import{b as T,m as o,ab as b,E as h,ac as p,ax as v,ad as A,ae as E,v as R,q as l}from"./CvjSAYrz.js";import{B as g}from"./DE4u6cUg.js";function N(t,c,u=!1){o&&b();var n=new g(t),_=u?h:0;function i(a,r){if(o){const e=p(t);var s;if(e===v?s=0:e===A?s=!1:s=parseInt(e.substring(1)),a!==s){var f=E();R(f),n.anchor=f,l(!1),n.ensure(a,r),l(!0);return}}n.ensure(a,r)}T(()=>{var a=!1;c((r,s=0)=>{a=!0,i(s,r)}),a||i(!1,null)},_)}export{N as i}; diff --git a/apps/dashboard/build/_app/immutable/chunks/ciN1mm2W.js.br b/apps/dashboard/build/_app/immutable/chunks/ciN1mm2W.js.br deleted file mode 100644 index ea04e43dac4b4136915f901bf9d18f8b082c02e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 282 zcmV+#0phI&!IJQNy)-dvgGIKNMW}qYy%e zWO9Fsbk*uP2AdjO;{ZxrZ(45&K3C8g+pQrx@R@lywXEs`b}2+nZ+Q{6e*V`QBH1Ey z3y$l6AArUW1W1Jpp*jbYfvE9h+)FWt-Bgc+?Dt*V-2VWOk8>W|ENX@e&``@NU*N?m g#n7rAAlcg%gQ(F??BGr&?yqM=>xb}je|I;Y07DRrF#rGn diff --git a/apps/dashboard/build/_app/immutable/chunks/ciN1mm2W.js.gz b/apps/dashboard/build/_app/immutable/chunks/ciN1mm2W.js.gz deleted file mode 100644 index 70ccd9e37676718e890953cc5acbcf8987bc2adb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 319 zcmV-F0l@wriwFP!000026IGBuPs1<}#dkhM+M%+gQ%EJm(8yE;GO%Q z9sDO$r2g*sf)HZ*o!`B?d$Kz9#`>|&xXbo%LKxuFvxW+B04|U{@H27%{*K%Lm&ghR z#11|XU2Lp5&GYMr;rP6HwO{$s%}e!jI9NKWh8Q{uqn*zr>yvewbY*Ht#@MiStXN^S zN!4t*a;)dp$tUfJ%w4FRw@SBUNh$CdV~&nE->@oW*pY^U&bbx`V_5?oNdc1}wF_2G z0Z=PwX{8TV$M~-o_k>V(H!bApb}0z4kn*6IgaQ{const n=s()??null;e.ensure(n,n&&(o=>n(o,...a)))},t)}export{E as s}; diff --git a/apps/dashboard/build/_app/immutable/chunks/ckF4CxmX.js.br b/apps/dashboard/build/_app/immutable/chunks/ckF4CxmX.js.br deleted file mode 100644 index 76088d77144f85421999986730fbf4e1b20cfc21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmV;N0Av3fxd4ES)JFM7MzlDmpHV=`0FNlt)#ccwBTTg_y{G3<=DD_IL5te*q%F=l zJ;>e0w$H5y(ytL0xaWuuYrZhQux9l?Mca9Ie$RiktrpKhcxkL4pYNvK#pRN7e4#RH z)3)uf+u!s`Y0t+{;kf|7>uru1)eTSA8t{IfH$SJ}qcO=ORRxA3V5UtBu~)Ofb%8|A KU;ZlgSkD~pXjAC` diff --git a/apps/dashboard/build/_app/immutable/chunks/ckF4CxmX.js.gz b/apps/dashboard/build/_app/immutable/chunks/ckF4CxmX.js.gz deleted file mode 100644 index 1046007600670b1efdd6993589686add41e3d75d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 170 zcmV;b09F4ViwFP!000026E)7g3WG2dhT*+e5gg%#nGwPz!*mI{var l=r?e.defaultValue:e.value;if(l=o(e)?u(l):l,v(l),f!==null&&c.add(f),await m(),l!==(l=a())){var h=e.selectionStart,d=e.selectionEnd,n=e.value.length;if(e.value=l??"",d!==null){var s=e.value.length;h===d&&d===n&&s>n?(e.selectionStart=s,e.selectionEnd=s):(e.selectionStart=h,e.selectionEnd=Math.min(d,s))}}}),(b&&e.defaultValue!==e.value||t(a)==null&&e.value)&&(v(o(e)?u(e.value):e.value),f!==null&&c.add(f)),_(()=>{var r=a();if(e===document.activeElement){var l=i??f;if(c.has(l))return}o(e)&&r===u(e.value)||e.type==="date"&&!r&&!e.value||r!==e.value&&(e.value=r??"")})}function S(e,a,v=a){k(e,"change",c=>{var r=c?e.defaultChecked:e.checked;v(r)}),(b&&e.defaultChecked!==e.checked||t(a)==null)&&v(e.checked),_(()=>{var c=a();e.checked=!!c})}function o(e){var a=e.type;return a==="number"||a==="range"}function u(e){return e===""?null:+e}export{S as a,E as b}; diff --git a/apps/dashboard/build/_app/immutable/chunks/sZcqyNBA.js.br b/apps/dashboard/build/_app/immutable/chunks/sZcqyNBA.js.br new file mode 100644 index 0000000000000000000000000000000000000000..a7a27e79b8c1b1903e94f439c049a9724adff328 GIT binary patch literal 465 zcmV;?0WSU<=K}!5RMqxhrdW6oB%UdAjElamy{On}iqrc1Uruj;eWZH_cxGel)*KdK zFN=Bs1r~US*=Bq67!8b~<E#ng*siq0bC8JiuLE2XP=5iKIB4;d$!TU9Gjt|JCHE5 zMZ+_iKCyPuaQl~ezvP557h;#3q@8rdNwmy>YMByIXt)@;6m_}1GGfuB(9a2uMO-QM zP&6>7IdY@1dElmsTEQy+q)wt=a$P{O));xqC!hjI*ioxV6hxATR2SopvWs;=X zM#GW<5K9c#*hHzyY-an`mfG{7(Q|W7A|WUp&A%X;0q`MrI24VP8v%yJ6+@KGj{IQG zW+U^7<^-9QLy@l z;N=ck7W{?A3|@`{0$gI29288f#?0Z+LZ^W<(;r!~U68^u_Ro!KXT`DD1U2#$b9xiF H(J?;(aX;Z2 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/sZcqyNBA.js.gz b/apps/dashboard/build/_app/immutable/chunks/sZcqyNBA.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..a12746e0a230b38c34611927c9eaee3a18ba69ea GIT binary patch literal 518 zcmV+h0{Q(PiwFP!000026Kzw$j@uv*z4t2|R3T6i?Ku|f!z#zNhe%D;OGNN^?FQor zV{cb$|9gRuI7xf3o|$`vF9Dmm zvR#Y#=jYSzxZ8d2`0pO&)nJrsI+JY(Fv&(C>H8>cri6jlYzOkV1(zRv5;f*DIK*WC zW>jXyQ{-u33*aSGa?tLF)B~)6j{)tV}h}XZDZ$ zS_n~MTzW7V_fMuEk5xs_?yHKPuK#7#kF2lK)x2#CDOpeHJkOMo1IG7`d38zAG&v&a z#h?_V7?Y7CBQLRw%l|W!vOOU*4af#Jqa~rsP7N&>$E8;|!bU?_(KN}XD5}6zyq3M6 z6}8|7YvxcIW9#=X^`{BAdpm_gQ7IiDj91ow*GBBpmDhinhYjin0F#L`Do6DtZxyjx>^FC)2T?#xortZPoJR_a!3Fe37# zICr0)9r9~$gBjWbSTs#>Wn&x5-XZKw^ynHYf|&IunBh-+(A)4zCELVDJLez%0v!!Q I6X*i~0POGin*aa+ literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/entry/app.C-NL1yUd.js b/apps/dashboard/build/_app/immutable/entry/app.C-NL1yUd.js deleted file mode 100644 index e3fba45..0000000 --- a/apps/dashboard/build/_app/immutable/entry/app.C-NL1yUd.js +++ /dev/null @@ -1,2 +0,0 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../nodes/0.DHxskm8N.js","../chunks/Bzak7iHL.js","../chunks/CNjeV5xa.js","../chunks/CvjSAYrz.js","../chunks/FzvEaXMa.js","../chunks/BsvCUYx-.js","../chunks/ciN1mm2W.js","../chunks/DE4u6cUg.js","../chunks/DTnG8poT.js","../chunks/ckF4CxmX.js","../chunks/CNfQDikv.js","../chunks/DPl3NjBv.js","../chunks/BKuqSeVd.js","../chunks/CVpUe0w3.js","../chunks/D3XWCg9-.js","../chunks/D81f-o_I.js","../chunks/DfQhL-hC.js","../chunks/EM_PBt2C.js","../chunks/RBGf_S-E.js","../chunks/CtkE7HV2.js","../chunks/Bz1l2A_1.js","../chunks/Bhad70Ss.js","../chunks/Casl2yrL.js","../chunks/DzfRjky4.js","../chunks/DNjM5a-l.js","../assets/0.IIz8MMYb.css","../nodes/1.BgGPnSIe.js","../nodes/2.CD5F7bS_.js","../nodes/3.CQLLmTOU.js","../nodes/4.BSlP3-UA.js","../chunks/B_YDQCB6.js","../nodes/5.B300rRjT.js","../chunks/DMu1Byux.js","../assets/5.DQ_AfUnN.css","../nodes/6.B_eyyG0t.js","../chunks/DObx9JW_.js","../assets/6.BSSBWVKL.css","../nodes/7.br0Vbs-w.js","../assets/7.CCrNEDd3.css","../nodes/8.CDAVQcae.js","../nodes/9.DVbfK-u1.js","../assets/9.BBx09UGv.css","../nodes/10.Dp-knJux.js","../nodes/11.BLR7H2sn.js","../nodes/12.DZiW_IZ_.js","../nodes/13.DReyqY5Q.js","../assets/13.Bjd0S47S.css","../nodes/14.BpCacSGt.js","../nodes/15.DFbOY736.js","../assets/15.ChjqzJHo.css","../nodes/16.DMIuRZWa.js","../assets/16.BnHgRQtR.css","../nodes/17.PvQmHhRC.js","../nodes/18.Df4fIuu-.js","../nodes/19.CMsn8k5A.js"])))=>i.map(i=>d[i]); -var M=r=>{throw TypeError(r)};var Q=(r,t,e)=>t.has(r)||M("Cannot "+e);var l=(r,t,e)=>(Q(r,t,"read from private field"),e?e.call(r):t.get(r)),H=(r,t,e)=>t.has(r)?M("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(r):t.set(r,e),W=(r,t,e,n)=>(Q(r,t,"write to private field"),n?n.call(r,e):t.set(r,e),e);import{m as Z,ab as ut,b as ct,E as _t,ac as lt,ae as dt,v as ft,q as $,ax as vt,w as ht,h as F,X as pt,g as h,bb as gt,a6 as Et,a5 as Pt,p as yt,aA as Rt,aB as Ot,G as bt,f as L,d as At,a as Tt,s as X,e as Lt,r as Dt,u as x,t as It}from"../chunks/CvjSAYrz.js";import{h as Vt,m as wt,u as kt,s as xt}from"../chunks/FzvEaXMa.js";import"../chunks/Bzak7iHL.js";import{o as St}from"../chunks/CNjeV5xa.js";import{i as B}from"../chunks/ciN1mm2W.js";import{a as E,c as V,f as et,t as jt}from"../chunks/BsvCUYx-.js";import{B as Ct}from"../chunks/DE4u6cUg.js";import{b as S}from"../chunks/D3XWCg9-.js";import{p as q}from"../chunks/B_YDQCB6.js";function j(r,t,e){var n;Z&&(n=ht,ut());var i=new Ct(r);ct(()=>{var _=t()??null;if(Z){var s=lt(n),a=s===vt,m=_!==null;if(a!==m){var y=dt();ft(y),i.anchor=y,$(!1),i.ensure(_,_&&(u=>e(u,_))),$(!0);return}}i.ensure(_,_&&(u=>e(u,_)))},_t)}function Bt(r){return class extends qt{constructor(t){super({component:r,...t})}}}var P,d;class qt{constructor(t){H(this,P);H(this,d);var _;var e=new Map,n=(s,a)=>{var m=Pt(a,!1,!1);return e.set(s,m),m};const i=new Proxy({...t.props||{},$$events:{}},{get(s,a){return h(e.get(a)??n(a,Reflect.get(s,a)))},has(s,a){return a===pt?!0:(h(e.get(a)??n(a,Reflect.get(s,a))),Reflect.has(s,a))},set(s,a,m){return F(e.get(a)??n(a,m),m),Reflect.set(s,a,m)}});W(this,d,(t.hydrate?Vt:wt)(t.component,{target:t.target,anchor:t.anchor,props:i,context:t.context,intro:t.intro??!1,recover:t.recover,transformError:t.transformError})),(!((_=t==null?void 0:t.props)!=null&&_.$$host)||t.sync===!1)&>(),W(this,P,i.$$events);for(const s of Object.keys(l(this,d)))s==="$set"||s==="$destroy"||s==="$on"||Et(this,s,{get(){return l(this,d)[s]},set(a){l(this,d)[s]=a},enumerable:!0});l(this,d).$set=s=>{Object.assign(i,s)},l(this,d).$destroy=()=>{kt(l(this,d))}}$set(t){l(this,d).$set(t)}$on(t,e){l(this,P)[t]=l(this,P)[t]||[];const n=(...i)=>e.call(this,...i);return l(this,P)[t].push(n),()=>{l(this,P)[t]=l(this,P)[t].filter(i=>i!==n)}}$destroy(){l(this,d).$destroy()}}P=new WeakMap,d=new WeakMap;const Ft="modulepreload",Gt=function(r,t){return new URL(r,t).href},tt={},o=function(t,e,n){let i=Promise.resolve();if(e&&e.length>0){let s=function(u){return Promise.all(u.map(p=>Promise.resolve(p).then(R=>({status:"fulfilled",value:R}),R=>({status:"rejected",reason:R}))))};const a=document.getElementsByTagName("link"),m=document.querySelector("meta[property=csp-nonce]"),y=(m==null?void 0:m.nonce)||(m==null?void 0:m.getAttribute("nonce"));i=s(e.map(u=>{if(u=Gt(u,n),u in tt)return;tt[u]=!0;const p=u.endsWith(".css"),R=p?'[rel="stylesheet"]':"";if(!!n)for(let O=a.length-1;O>=0;O--){const c=a[O];if(c.href===u&&(!p||c.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${u}"]${R}`))return;const g=document.createElement("link");if(g.rel=p?"stylesheet":Ft,p||(g.as="script"),g.crossOrigin="",g.href=u,y&&g.setAttribute("nonce",y),document.head.appendChild(g),p)return new Promise((O,c)=>{g.addEventListener("load",O),g.addEventListener("error",()=>c(new Error(`Unable to preload CSS for ${u}`)))})}))}function _(s){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=s,window.dispatchEvent(a),!a.defaultPrevented)throw s}return i.then(s=>{for(const a of s||[])a.status==="rejected"&&_(a.reason);return t().catch(_)})},ae={};var Nt=et('

'),Ut=et(" ",1);function Yt(r,t){yt(t,!0);let e=q(t,"components",23,()=>[]),n=q(t,"data_0",3,null),i=q(t,"data_1",3,null),_=q(t,"data_2",3,null);Rt(()=>t.stores.page.set(t.page)),Ot(()=>{t.stores,t.page,t.constructors,e(),t.form,n(),i(),_(),t.stores.page.notify()});let s=X(!1),a=X(!1),m=X(null);St(()=>{const c=t.stores.page.subscribe(()=>{h(s)&&(F(a,!0),bt().then(()=>{F(m,document.title||"untitled page",!0)}))});return F(s,!0),c});const y=x(()=>t.constructors[2]);var u=Ut(),p=L(u);{var R=c=>{const b=x(()=>t.constructors[0]);var A=V(),w=L(A);j(w,()=>h(b),(T,D)=>{S(D(T,{get data(){return n()},get form(){return t.form},get params(){return t.page.params},children:(f,Wt)=>{var J=V(),at=L(J);{var st=I=>{const G=x(()=>t.constructors[1]);var k=V(),N=L(k);j(N,()=>h(G),(U,Y)=>{S(Y(U,{get data(){return i()},get form(){return t.form},get params(){return t.page.params},children:(v,Xt)=>{var K=V(),nt=L(K);j(nt,()=>h(y),(it,mt)=>{S(mt(it,{get data(){return _()},get form(){return t.form},get params(){return t.page.params}}),C=>e()[2]=C,()=>{var C;return(C=e())==null?void 0:C[2]})}),E(v,K)},$$slots:{default:!0}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),E(I,k)},ot=I=>{const G=x(()=>t.constructors[1]);var k=V(),N=L(k);j(N,()=>h(G),(U,Y)=>{S(Y(U,{get data(){return i()},get form(){return t.form},get params(){return t.page.params}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),E(I,k)};B(at,I=>{t.constructors[2]?I(st):I(ot,!1)})}E(f,J)},$$slots:{default:!0}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),E(c,A)},z=c=>{const b=x(()=>t.constructors[0]);var A=V(),w=L(A);j(w,()=>h(b),(T,D)=>{S(D(T,{get data(){return n()},get form(){return t.form},get params(){return t.page.params}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),E(c,A)};B(p,c=>{t.constructors[1]?c(R):c(z,!1)})}var g=At(p,2);{var O=c=>{var b=Nt(),A=Lt(b);{var w=T=>{var D=jt();It(()=>xt(D,h(m))),E(T,D)};B(A,T=>{h(a)&&T(w)})}Dt(b),E(c,b)};B(g,c=>{h(s)&&c(O)})}E(r,u),Tt()}const se=Bt(Yt),oe=[()=>o(()=>import("../nodes/0.DHxskm8N.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]),import.meta.url),()=>o(()=>import("../nodes/1.BgGPnSIe.js"),__vite__mapDeps([26,1,20,3,4,5,18,2,16,17]),import.meta.url),()=>o(()=>import("../nodes/2.CD5F7bS_.js"),__vite__mapDeps([27,1,3,5,9,7]),import.meta.url),()=>o(()=>import("../nodes/3.CQLLmTOU.js"),__vite__mapDeps([28,1,20,3,2,17,16,18]),import.meta.url),()=>o(()=>import("../nodes/4.BSlP3-UA.js"),__vite__mapDeps([29,1,2,3,4,5,6,7,10,13,24,19,16,8,30,15,23]),import.meta.url),()=>o(()=>import("../nodes/5.B300rRjT.js"),__vite__mapDeps([31,1,3,4,5,6,7,8,11,12,21,32,10,30,15,16,33]),import.meta.url),()=>o(()=>import("../nodes/6.B_eyyG0t.js"),__vite__mapDeps([34,1,3,4,5,6,7,8,35,10,11,12,24,21,30,15,16,18,2,36]),import.meta.url),()=>o(()=>import("../nodes/7.br0Vbs-w.js"),__vite__mapDeps([37,1,2,3,4,5,6,7,8,10,13,11,12,21,23,38]),import.meta.url),()=>o(()=>import("../nodes/8.CDAVQcae.js"),__vite__mapDeps([39,1,3,4,5,6,7,8,10,11,12,21,13,24]),import.meta.url),()=>o(()=>import("../nodes/9.DVbfK-u1.js"),__vite__mapDeps([40,1,20,3,4,5,6,7,8,21,12,15,16,19,23,10,11,30,41]),import.meta.url),()=>o(()=>import("../nodes/10.Dp-knJux.js"),__vite__mapDeps([42,1,2,3,4,5,6,7,8,10,11,12,21,13,32,15,16,18,14,30,23,20,24,19]),import.meta.url),()=>o(()=>import("../nodes/11.BLR7H2sn.js"),__vite__mapDeps([43,1,2,3,4,5,6,7,8,21,12,13,17,16,18,24,23,10,30,15]),import.meta.url),()=>o(()=>import("../nodes/12.DZiW_IZ_.js"),__vite__mapDeps([44,1,2,3,4,5,6,7,8,11,12,24]),import.meta.url),()=>o(()=>import("../nodes/13.DReyqY5Q.js"),__vite__mapDeps([45,1,2,3,4,5,6,7,8,10,11,12,21,13,32,24,23,46]),import.meta.url),()=>o(()=>import("../nodes/14.BpCacSGt.js"),__vite__mapDeps([47,1,2,3,4,5,6,7,8,10,11,12,21]),import.meta.url),()=>o(()=>import("../nodes/15.DFbOY736.js"),__vite__mapDeps([48,1,2,3,4,5,6,7,8,35,10,21,12,13,14,24,11,30,15,16,23,49]),import.meta.url),()=>o(()=>import("../nodes/16.DMIuRZWa.js"),__vite__mapDeps([50,1,2,3,4,5,6,7,8,11,12,24,10,21,30,15,16,23,51]),import.meta.url),()=>o(()=>import("../nodes/17.PvQmHhRC.js"),__vite__mapDeps([52,1,2,3,4,5,6,7,8,11,12,21,15,16,24,19,22,23]),import.meta.url),()=>o(()=>import("../nodes/18.Df4fIuu-.js"),__vite__mapDeps([53,1,2,3,4,5,6,7,8,21,12,24]),import.meta.url),()=>o(()=>import("../nodes/19.CMsn8k5A.js"),__vite__mapDeps([54,1,2,3,4,5,6,7,8,21,12,32,24,23]),import.meta.url)],ne=[],ie={"/":[3],"/(app)/activation":[4,[2]],"/(app)/contradictions":[5,[2]],"/(app)/dreams":[6,[2]],"/(app)/duplicates":[7,[2]],"/(app)/explore":[8,[2]],"/(app)/feed":[9,[2]],"/(app)/graph":[10,[2]],"/(app)/importance":[11,[2]],"/(app)/intentions":[12,[2]],"/(app)/memories":[13,[2]],"/(app)/patterns":[14,[2]],"/(app)/reasoning":[15,[2]],"/(app)/schedule":[16,[2]],"/(app)/settings":[17,[2]],"/(app)/stats":[18,[2]],"/(app)/timeline":[19,[2]]},rt={handleError:(({error:r})=>{console.error(r)}),reroute:(()=>{}),transport:{}},Ht=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.decode])),me=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.encode])),ue=!1,ce=(r,t)=>Ht[r](t);export{ce as decode,Ht as decoders,ie as dictionary,me as encoders,ue as hash,rt as hooks,ae as matchers,oe as nodes,se as root,ne as server_loads}; diff --git a/apps/dashboard/build/_app/immutable/entry/app.C-NL1yUd.js.br b/apps/dashboard/build/_app/immutable/entry/app.C-NL1yUd.js.br deleted file mode 100644 index fa9e751a2591060c9a1aeb543e3bf61eb8fa154c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3515 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 diff --git a/apps/dashboard/build/_app/immutable/entry/app.C-NL1yUd.js.gz b/apps/dashboard/build/_app/immutable/entry/app.C-NL1yUd.js.gz deleted file mode 100644 index 0bb9964fc1c7c990b8ce2d5f7767943f9cc1c640..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4017 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 XXvm@tenE~WwLks^$Ml<^iYWj9k|)2m diff --git a/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js b/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js new file mode 100644 index 0000000..e396d4a --- /dev/null +++ b/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js @@ -0,0 +1,2 @@ +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../nodes/0.COz2esg5.js","../chunks/Bzak7iHL.js","../chunks/GG5zm9kr.js","../chunks/CpWkWWOo.js","../chunks/BlVfL1ME.js","../chunks/CHOnp4oo.js","../chunks/B4yTwGkE.js","../chunks/DdEqwvdI.js","../chunks/CGEBXrjl.js","../chunks/CJCPY1OL.js","../chunks/A7po6GxK.js","../chunks/aVbAZ-t7.js","../chunks/BKuqSeVd.js","../chunks/sZcqyNBA.js","../chunks/CJsMJEun.js","../chunks/C6HuKgyx.js","../chunks/BeMFXnHE.js","../chunks/BHGLDPij.js","../chunks/BskPcZf7.js","../chunks/MAY1QfFZ.js","../chunks/BUoSzNdg.js","../chunks/Cx-f-Pzo.js","../chunks/BjdL4Pm2.js","../chunks/DzfRjky4.js","../chunks/DNjM5a-l.js","../assets/0.IIz8MMYb.css","../nodes/1.DJo7hfwf.js","../nodes/2.D-vKwnTC.js","../nodes/3.Caati8mq.js","../nodes/4.DJCab_le.js","../chunks/V6gjw5Ec.js","../nodes/5.C0AYWqwr.js","../chunks/BnXDGOmJ.js","../assets/5.DQ_AfUnN.css","../nodes/6.DTUGCA1p.js","../chunks/C4h_mRt2.js","../assets/6.BSSBWVKL.css","../nodes/7.jHtvjgRi.js","../assets/7.CCrNEDd3.css","../nodes/8.CgPowUzz.js","../nodes/9.BWaJ-VBd.js","../assets/9.BBx09UGv.css","../nodes/10.Btb56kL1.js","../nodes/11.WP3QAgOF.js","../nodes/12.DaxyVsV4.js","../nodes/13.D52bbIQQ.js","../assets/13.Bjd0S47S.css","../nodes/14.DUh3SXOF.js","../nodes/15.C7Fk4d1G.js","../assets/15.ChjqzJHo.css","../nodes/16.DeYkCVEo.js","../assets/16.BnHgRQtR.css","../nodes/17.CLL0vjL4.js","../nodes/18.CXHHR36X.js","../nodes/19.D4UHDxxJ.js","../nodes/20.BwEdZXUF.js","../assets/20.DKhUrxcR.css"])))=>i.map(i=>d[i]); +var Q=r=>{throw TypeError(r)};var X=(r,t,e)=>t.has(r)||Q("Cannot "+e);var l=(r,t,e)=>(X(r,t,"read from private field"),e?e.call(r):t.get(r)),H=(r,t,e)=>t.has(r)?Q("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(r):t.set(r,e),W=(r,t,e,n)=>(X(r,t,"write to private field"),n?n.call(r,e):t.set(r,e),e);import{N as Z,ab as ut,b as _t,E as ct,ac as lt,ae as dt,T as ft,R as $,ax as vt,U as ht,h as U,L as pt,g as h,bc as Et,G as gt,I as Pt,p as Rt,aA as yt,aB as Ot,$ as At,f as L,e as Tt,a as bt,s as z,d as Lt,r as It,u as x,t as Dt}from"../chunks/CpWkWWOo.js";import{h as Vt,m as wt,u as kt,s as xt}from"../chunks/BlVfL1ME.js";import"../chunks/Bzak7iHL.js";import{o as St}from"../chunks/GG5zm9kr.js";import{i as B}from"../chunks/B4yTwGkE.js";import{a as g,c as V,f as et,t as jt}from"../chunks/CHOnp4oo.js";import{B as Ct}from"../chunks/DdEqwvdI.js";import{b as S}from"../chunks/CJsMJEun.js";import{p as N}from"../chunks/V6gjw5Ec.js";function j(r,t,e){var n;Z&&(n=ht,ut());var i=new Ct(r);_t(()=>{var c=t()??null;if(Z){var s=lt(n),a=s===vt,m=c!==null;if(a!==m){var R=dt();ft(R),i.anchor=R,$(!1),i.ensure(c,c&&(u=>e(u,c))),$(!0);return}}i.ensure(c,c&&(u=>e(u,c)))},ct)}function Bt(r){return class extends Nt{constructor(t){super({component:r,...t})}}}var P,d;class Nt{constructor(t){H(this,P);H(this,d);var c;var e=new Map,n=(s,a)=>{var m=Pt(a,!1,!1);return e.set(s,m),m};const i=new Proxy({...t.props||{},$$events:{}},{get(s,a){return h(e.get(a)??n(a,Reflect.get(s,a)))},has(s,a){return a===pt?!0:(h(e.get(a)??n(a,Reflect.get(s,a))),Reflect.has(s,a))},set(s,a,m){return U(e.get(a)??n(a,m),m),Reflect.set(s,a,m)}});W(this,d,(t.hydrate?Vt:wt)(t.component,{target:t.target,anchor:t.anchor,props:i,context:t.context,intro:t.intro??!1,recover:t.recover,transformError:t.transformError})),(!((c=t==null?void 0:t.props)!=null&&c.$$host)||t.sync===!1)&&Et(),W(this,P,i.$$events);for(const s of Object.keys(l(this,d)))s==="$set"||s==="$destroy"||s==="$on"||gt(this,s,{get(){return l(this,d)[s]},set(a){l(this,d)[s]=a},enumerable:!0});l(this,d).$set=s=>{Object.assign(i,s)},l(this,d).$destroy=()=>{kt(l(this,d))}}$set(t){l(this,d).$set(t)}$on(t,e){l(this,P)[t]=l(this,P)[t]||[];const n=(...i)=>e.call(this,...i);return l(this,P)[t].push(n),()=>{l(this,P)[t]=l(this,P)[t].filter(i=>i!==n)}}$destroy(){l(this,d).$destroy()}}P=new WeakMap,d=new WeakMap;const Ut="modulepreload",qt=function(r,t){return new URL(r,t).href},tt={},o=function(t,e,n){let i=Promise.resolve();if(e&&e.length>0){let s=function(u){return Promise.all(u.map(p=>Promise.resolve(p).then(y=>({status:"fulfilled",value:y}),y=>({status:"rejected",reason:y}))))};const a=document.getElementsByTagName("link"),m=document.querySelector("meta[property=csp-nonce]"),R=(m==null?void 0:m.nonce)||(m==null?void 0:m.getAttribute("nonce"));i=s(e.map(u=>{if(u=qt(u,n),u in tt)return;tt[u]=!0;const p=u.endsWith(".css"),y=p?'[rel="stylesheet"]':"";if(!!n)for(let O=a.length-1;O>=0;O--){const _=a[O];if(_.href===u&&(!p||_.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${u}"]${y}`))return;const E=document.createElement("link");if(E.rel=p?"stylesheet":Ut,p||(E.as="script"),E.crossOrigin="",E.href=u,R&&E.setAttribute("nonce",R),document.head.appendChild(E),p)return new Promise((O,_)=>{E.addEventListener("load",O),E.addEventListener("error",()=>_(new Error(`Unable to preload CSS for ${u}`)))})}))}function c(s){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=s,window.dispatchEvent(a),!a.defaultPrevented)throw s}return i.then(s=>{for(const a of s||[])a.status==="rejected"&&c(a.reason);return t().catch(c)})},ae={};var Ft=et('
'),Gt=et(" ",1);function Yt(r,t){Rt(t,!0);let e=N(t,"components",23,()=>[]),n=N(t,"data_0",3,null),i=N(t,"data_1",3,null),c=N(t,"data_2",3,null);yt(()=>t.stores.page.set(t.page)),Ot(()=>{t.stores,t.page,t.constructors,e(),t.form,n(),i(),c(),t.stores.page.notify()});let s=z(!1),a=z(!1),m=z(null);St(()=>{const _=t.stores.page.subscribe(()=>{h(s)&&(U(a,!0),At().then(()=>{U(m,document.title||"untitled page",!0)}))});return U(s,!0),_});const R=x(()=>t.constructors[2]);var u=Gt(),p=L(u);{var y=_=>{const A=x(()=>t.constructors[0]);var T=V(),w=L(T);j(w,()=>h(A),(b,I)=>{S(I(b,{get data(){return n()},get form(){return t.form},get params(){return t.page.params},children:(f,Wt)=>{var K=V(),at=L(K);{var st=D=>{const q=x(()=>t.constructors[1]);var k=V(),F=L(k);j(F,()=>h(q),(G,Y)=>{S(Y(G,{get data(){return i()},get form(){return t.form},get params(){return t.page.params},children:(v,zt)=>{var M=V(),nt=L(M);j(nt,()=>h(R),(it,mt)=>{S(mt(it,{get data(){return c()},get form(){return t.form},get params(){return t.page.params}}),C=>e()[2]=C,()=>{var C;return(C=e())==null?void 0:C[2]})}),g(v,M)},$$slots:{default:!0}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),g(D,k)},ot=D=>{const q=x(()=>t.constructors[1]);var k=V(),F=L(k);j(F,()=>h(q),(G,Y)=>{S(Y(G,{get data(){return i()},get form(){return t.form},get params(){return t.page.params}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),g(D,k)};B(at,D=>{t.constructors[2]?D(st):D(ot,!1)})}g(f,K)},$$slots:{default:!0}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),g(_,T)},J=_=>{const A=x(()=>t.constructors[0]);var T=V(),w=L(T);j(w,()=>h(A),(b,I)=>{S(I(b,{get data(){return n()},get form(){return t.form},get params(){return t.page.params}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),g(_,T)};B(p,_=>{t.constructors[1]?_(y):_(J,!1)})}var E=Tt(p,2);{var O=_=>{var A=Ft(),T=Lt(A);{var w=b=>{var I=jt();Dt(()=>xt(I,h(m))),g(b,I)};B(T,b=>{h(a)&&b(w)})}It(A),g(_,A)};B(E,_=>{h(s)&&_(O)})}g(r,u),bt()}const se=Bt(Yt),oe=[()=>o(()=>import("../nodes/0.COz2esg5.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]),import.meta.url),()=>o(()=>import("../nodes/1.DJo7hfwf.js"),__vite__mapDeps([26,1,20,3,4,5,18,2,16,17]),import.meta.url),()=>o(()=>import("../nodes/2.D-vKwnTC.js"),__vite__mapDeps([27,1,3,5,9,7]),import.meta.url),()=>o(()=>import("../nodes/3.Caati8mq.js"),__vite__mapDeps([28,1,20,3,2,17,16,18]),import.meta.url),()=>o(()=>import("../nodes/4.DJCab_le.js"),__vite__mapDeps([29,1,2,3,4,5,6,7,10,13,24,19,16,8,30,15,23]),import.meta.url),()=>o(()=>import("../nodes/5.C0AYWqwr.js"),__vite__mapDeps([31,1,3,4,5,6,7,8,11,12,21,32,10,30,15,16,33]),import.meta.url),()=>o(()=>import("../nodes/6.DTUGCA1p.js"),__vite__mapDeps([34,1,3,4,5,6,7,8,35,10,11,12,24,21,30,15,16,18,2,36]),import.meta.url),()=>o(()=>import("../nodes/7.jHtvjgRi.js"),__vite__mapDeps([37,1,2,3,4,5,6,7,8,10,13,11,12,21,23,38]),import.meta.url),()=>o(()=>import("../nodes/8.CgPowUzz.js"),__vite__mapDeps([39,1,3,4,5,6,7,8,10,11,12,21,13,24]),import.meta.url),()=>o(()=>import("../nodes/9.BWaJ-VBd.js"),__vite__mapDeps([40,1,20,3,4,5,6,7,8,21,12,15,16,19,23,10,11,30,41]),import.meta.url),()=>o(()=>import("../nodes/10.Btb56kL1.js"),__vite__mapDeps([42,1,2,3,4,5,6,7,8,10,11,12,21,13,32,15,16,18,14,30,23,20,24,19]),import.meta.url),()=>o(()=>import("../nodes/11.WP3QAgOF.js"),__vite__mapDeps([43,1,2,3,4,5,6,7,8,21,12,13,17,16,18,24,23,10,30,15]),import.meta.url),()=>o(()=>import("../nodes/12.DaxyVsV4.js"),__vite__mapDeps([44,1,2,3,4,5,6,7,8,11,12,24]),import.meta.url),()=>o(()=>import("../nodes/13.D52bbIQQ.js"),__vite__mapDeps([45,1,2,3,4,5,6,7,8,10,11,12,21,13,32,24,23,46]),import.meta.url),()=>o(()=>import("../nodes/14.DUh3SXOF.js"),__vite__mapDeps([47,1,2,3,4,5,6,7,8,10,11,12,21]),import.meta.url),()=>o(()=>import("../nodes/15.C7Fk4d1G.js"),__vite__mapDeps([48,1,2,3,4,5,6,7,8,35,10,21,12,13,14,24,11,30,15,16,23,49]),import.meta.url),()=>o(()=>import("../nodes/16.DeYkCVEo.js"),__vite__mapDeps([50,1,2,3,4,5,6,7,8,11,12,24,10,21,30,15,16,23,51]),import.meta.url),()=>o(()=>import("../nodes/17.CLL0vjL4.js"),__vite__mapDeps([52,1,2,3,4,5,6,7,8,11,12,21,15,16,24,19,22,23]),import.meta.url),()=>o(()=>import("../nodes/18.CXHHR36X.js"),__vite__mapDeps([53,1,2,3,4,5,6,7,8,21,12,24]),import.meta.url),()=>o(()=>import("../nodes/19.D4UHDxxJ.js"),__vite__mapDeps([54,1,2,3,4,5,6,7,8,21,12,32,24,23]),import.meta.url),()=>o(()=>import("../nodes/20.BwEdZXUF.js"),__vite__mapDeps([55,1,2,3,4,5,6,7,8,35,10,11,12,21,13,32,14,18,16,56]),import.meta.url)],ne=[],ie={"/":[3],"/(app)/activation":[4,[2]],"/(app)/contradictions":[5,[2]],"/(app)/dreams":[6,[2]],"/(app)/duplicates":[7,[2]],"/(app)/explore":[8,[2]],"/(app)/feed":[9,[2]],"/(app)/graph":[10,[2]],"/(app)/importance":[11,[2]],"/(app)/intentions":[12,[2]],"/(app)/memories":[13,[2]],"/(app)/patterns":[14,[2]],"/(app)/reasoning":[15,[2]],"/(app)/schedule":[16,[2]],"/(app)/settings":[17,[2]],"/(app)/stats":[18,[2]],"/(app)/timeline":[19,[2]],"/waitlist":[20]},rt={handleError:(({error:r})=>{console.error(r)}),reroute:(()=>{}),transport:{}},Ht=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.decode])),me=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.encode])),ue=!1,_e=(r,t)=>Ht[r](t);export{_e as decode,Ht as decoders,ie as dictionary,me as encoders,ue as hash,rt as hooks,ae as matchers,oe as nodes,se as root,ne as server_loads}; diff --git a/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.br b/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.br new file mode 100644 index 0000000000000000000000000000000000000000..6e9072deefb0138be9ad099780892a82158ba53f GIT binary patch literal 3562 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 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.gz b/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..8b88be8df424986b174a5f333e7c3648c4122cb4 GIT binary patch literal 4069 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 X4q4d3&)U(n`p3TjIYU&1Qz`%eKHch} literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/entry/start.BLzz4N6-.js b/apps/dashboard/build/_app/immutable/entry/start.BLzz4N6-.js deleted file mode 100644 index 3b50d66..0000000 --- a/apps/dashboard/build/_app/immutable/entry/start.BLzz4N6-.js +++ /dev/null @@ -1 +0,0 @@ -import{a as r}from"../chunks/EM_PBt2C.js";import{w as t}from"../chunks/RBGf_S-E.js";export{t as load_css,r as start}; diff --git a/apps/dashboard/build/_app/immutable/entry/start.BLzz4N6-.js.br b/apps/dashboard/build/_app/immutable/entry/start.BLzz4N6-.js.br deleted file mode 100644 index 0dff7d12bafeb980074ff12698da4a1a963c8d26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmV-y0F(b4bpQw~3T!tu)H+Kq(qAN5JEv7ADKsfM_mGpFqsgvi46FB{WzbA_Ky(S`amI@8{yuh(0s*MY~ OuTfn3y%eERRH|tB6g#5>?E| MF!P}_ZyC@I02)y$jQ{`u diff --git a/apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js b/apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js new file mode 100644 index 0000000..f01b681 --- /dev/null +++ b/apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js @@ -0,0 +1 @@ +import{a as r}from"../chunks/BHGLDPij.js";import{w as t}from"../chunks/BskPcZf7.js";export{t as load_css,r as start}; diff --git a/apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js.br b/apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js.br new file mode 100644 index 0000000000000000000000000000000000000000..68a435b89750ca6a0216c3b882aa3750e4090ce7 GIT binary patch literal 106 zcmV-w0G0n6bpQyQ1$OI2>StO;F_lU2W_e51WP4FiZ3ID9>>JbE8=J{7A+uB{OG`C3 zIh~wePk6B_egOp(a2N;&9~e&DZ(tiGGDrIe%K!iX literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js.gz b/apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..0b2d810e0ccb6db40578d983afd868127e591dda GIT binary patch literal 107 zcmb2|=3oE;CgIa(bWiAOt@I1=&{const a=bt;return{page:{subscribe:a.page.subscribe},navigating:{subscribe:a.navigating.subscribe},updated:a.updated}},Ct={subscribe(a){return Mt().page.subscribe(a)}};var At=m('
');function Dt(a){const r=()=>H(nt,"$suppressedCount",i),[i,c]=Te();var f=rt(),M=ce(f);{var y=D=>{var x=At(),h=o(s(x),2),v=s(h);t(h),t(x),N(()=>_(v,`Actively forgetting ${r()??""} ${r()===1?"memory":"memories"}`)),u(D,x)};B(M,D=>{r()>0&&D(y)})}u(a,f),c()}var Tt=m(''),Et=m('
');function Ft(a,r){We(r,!1);const i=()=>H(ge,"$toasts",c),[c,f]=Te(),M={DreamCompleted:"✦",ConsolidationCompleted:"◉",ConnectionDiscovered:"⟷",MemoryPromoted:"↑",MemoryDemoted:"↓",MemorySuppressed:"◬",MemoryUnsuppressed:"◉",Rac1CascadeSwept:"✺",MemoryDeleted:"✕"};function y(v){return M[v]??"◆"}function D(v){ge.dismiss(v.id)}function x(v,l){(v.key==="Enter"||v.key===" ")&&(v.preventDefault(),ge.dismiss(l.id))}wt();var h=Et();De(h,5,i,v=>v.id,(v,l)=>{var b=Tt(),F=o(s(b),2),T=s(F),K=s(T),Q=s(K,!0);t(K);var V=o(K,2),X=s(V,!0);t(V),t(T);var Z=o(T,2),ne=s(Z,!0);t(Z),t(F),se(2),t(b),N(J=>{be(b,"aria-label",`${e(l).title??""}: ${e(l).body??""}. Click to dismiss.`),lt(b,`--toast-color: ${e(l).color??""}; --toast-dwell: ${e(l).dwellMs??""}ms;`),_(Q,J),_(X,e(l).title),_(ne,e(l).body)},[()=>y(e(l).type)]),re("click",b,()=>D(e(l))),re("keydown",b,J=>x(J,e(l))),Le("mouseenter",b,()=>ge.pauseDwell(e(l).id,e(l).dwellMs)),Le("mouseleave",b,()=>ge.resumeDwell(e(l).id)),Le("focus",b,()=>ge.pauseDwell(e(l).id,e(l).dwellMs)),Le("blur",b,()=>ge.resumeDwell(e(l).id)),u(v,b)}),t(h),u(a,h),Oe(),f()}Ye(["click","keydown"]);function we(a){const r=a.data;if(!r||typeof r!="object")return null;const i=r.timestamp??r.at??r.occurred_at;if(i==null)return null;if(typeof i=="number")return Number.isFinite(i)?i>1e12?i:i*1e3:null;if(typeof i!="string")return null;const c=Date.parse(i);return Number.isFinite(c)?c:null}const ze=10,vt=3e4,St=ze*vt;function It(a,r){const i=r-St,c=new Array(ze).fill(0);for(const M of a){if(M.type==="Heartbeat")continue;const y=we(M);if(y===null||yr)continue;const D=Math.min(ze-1,Math.floor((y-i)/vt));c[D]+=1}const f=Math.max(1,...c);return c.map(M=>({count:M,ratio:M/f}))}function Lt(a,r){const i=r-864e5;for(const c of a){if(c.type!=="DreamCompleted")continue;return(we(c)??r)>=i?c:null}return null}function Nt(a){if(!a||!a.data)return null;const r=a.data,i=typeof r.insights_generated=="number"?r.insights_generated:typeof r.insightsGenerated=="number"?r.insightsGenerated:null;return i!==null&&Number.isFinite(i)?i:null}function Rt(a,r){let i=null,c=null;for(const D of a)if(!i&&D.type==="DreamStarted"&&(i=D),!c&&D.type==="DreamCompleted"&&(c=D),i&&c)break;if(!i)return!1;const f=we(i)??r,M=r-300*1e3;return f=c}return!1}var Vt=m(' at risk',1),Bt=m('0 at risk',1),Gt=m(' at risk',1),Ht=m(' intentions',1),qt=m('— intentions'),zt=m('· insights',1),Pt=m(' Last dream: ',1),Wt=m('No recent dream'),Ot=m('
'),Yt=m('
DREAMING...
',1),Qt=m(''),Xt=m('
memories · avg retention
');function Zt(a,r){We(r,!0);const i=()=>H(ot,"$avgRetention",M),c=()=>H(xt,"$eventFeed",M),f=()=>H(it,"$memoryCount",M),[M,y]=Te(),D=j(()=>Math.round((i()??0)*100)),x=j(()=>(i()??0)>=.5);let h=ye(null);async function v(){try{const n=await Ue.retentionDistribution();if(Array.isArray(n.endangered)&&n.endangered.length>0){A(h,n.endangered.length,!0);return}const d=n.distribution??[];let $=0;for(const S of d){const W=/^(\d+)/.exec(S.range);if(!W)continue;const O=Number.parseInt(W[1],10);Number.isFinite(O)&&O<30&&($+=S.count??0)}A(h,$,!0)}catch{A(h,null)}}let l=ye(null);async function b(){var n;try{const d=await Ue.intentions("active");A(l,d.total??((n=d.intentions)==null?void 0:n.length)??0,!0)}catch{A(l,null)}}let F=ye(mt(Date.now()));const T=j(()=>{const n=c(),d=Lt(n,e(F)),$=d?we(d)??e(F):null,S=$!==null?e(F)-$:null;return{isDreaming:Rt(n,e(F)),recent:d,recentMsAgo:S,insights:Nt(d)}}),K=j(()=>It(c(),e(F))),Q=j(()=>Kt(c(),e(F)));st(()=>{v(),b();const n=setInterval(()=>{A(F,Date.now(),!0)},1e3),d=setInterval(()=>{v(),b()},6e4);return()=>{clearInterval(n),clearInterval(d)}});var V=Xt();let X;var Z=s(V),ne=s(Z),J=s(ne);let Ee;var Re=o(J,2);let Fe;t(ne);var Me=o(ne,2),w=s(Me,!0);t(Me);var k=o(Me,6);let p;var z=s(k);t(k),se(2),t(Z);var L=o(Z,4),I=s(L);{var ie=n=>{var d=Vt(),$=ce(d),S=s($,!0);t($),se(2),N(()=>_(S,e(h))),u(n,d)},Ce=n=>{var d=Bt();se(2),u(n,d)},xe=n=>{var d=Gt();se(2),u(n,d)};B(I,n=>{e(h)!==null&&e(h)>0?n(ie):e(h)===0?n(Ce,1):n(xe,!1)})}t(L);var g=o(L,4),q=s(g);{var P=n=>{var d=Ht(),$=ce(d);let S;var W=o($,2);let O;var Y=s(W,!0);t(W),se(2),N(()=>{S=G($,1,"inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,S,{"bg-node-pattern":e(l)>5,"animate-ping-slow":e(l)>5,"bg-muted":e(l)<=5}),O=G(W,1,"tabular-nums svelte-1kk3799",null,O,{"text-node-pattern":e(l)>5,"text-text":e(l)>0&&e(l)<=5,"text-muted":e(l)===0}),_(Y,e(l))}),u(n,d)},ve=n=>{var d=qt();u(n,d)};B(q,n=>{e(l)!==null?n(P):n(ve,!1)})}t(g);var oe=o(g,4),pe=s(oe);{var ue=n=>{var d=Pt(),$=o(ce(d),4),S=s($,!0);t($);var W=o($,2);{var O=Y=>{var Ae=zt(),Ie=o(ce(Ae),2),Be=s(Ie,!0);t(Ie),se(2),N(()=>_(Be,e(T).insights)),u(Y,Ae)};B(W,Y=>{e(T).insights!==null&&Y(O)})}N(Y=>_(S,Y),[()=>jt(e(T).recentMsAgo)]),u(n,d)},le=n=>{var d=Wt();u(n,d)};B(pe,n=>{e(T).recent&&e(T).recentMsAgo!==null?n(ue):n(le,!1)})}t(oe);var me=o(oe,4),ke=o(s(me),2);De(ke,21,()=>e(K),Ne,(n,d)=>{var $=Ot();N(S=>lt($,`height: ${S??""}%; opacity: ${e(d).count===0?.18:.5+e(d).ratio*.5};`),[()=>Math.max(10,e(d).ratio*100)]),u(n,$)}),t(ke),t(me);var Se=o(me,2);{var je=n=>{var d=Yt();se(2),u(n,d)};B(Se,n=>{e(T).isDreaming&&n(je)})}var Ke=o(Se,4);{var Ve=n=>{var d=Qt();u(n,d)};B(Ke,n=>{e(Q)&&n(Ve)})}t(V),N(()=>{X=G(V,1,"ambient-strip relative flex h-9 w-full items-center gap-0 overflow-hidden border-b border-synapse/15 bg-black/40 px-3 text-[11px] text-dim backdrop-blur-md svelte-1kk3799",null,X,{"ambient-flash":e(Q)}),Ee=G(J,1,"absolute inline-flex h-full w-full animate-ping rounded-full opacity-75 svelte-1kk3799",null,Ee,{"bg-recall":e(x),"bg-warning":!e(x)}),Fe=G(Re,1,"relative inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,Fe,{"bg-recall":e(x),"bg-warning":!e(x)}),_(w,f()),p=G(k,1,"svelte-1kk3799",null,p,{"text-recall":e(x),"text-warning":!e(x)}),_(z,`${e(D)??""}%`)}),u(a,V),Oe(),y()}const pt="vestige.theme",et="vestige-theme-light",$e=dt("dark"),Pe=dt(!0),tt=$t([$e,Pe],([a,r])=>a==="auto"?r?"dark":"light":a);function Jt(a){return a==="dark"||a==="light"||a==="auto"}function Ut(a){if(Jt(a)){$e.set(a);try{localStorage.setItem(pt,a)}catch{}}}function qe(){const a=ct($e);Ut(a==="dark"?"light":a==="light"?"auto":"dark")}function ea(){if(document.getElementById(et))return;const a=document.createElement("style");a.id=et,a.textContent=` +/* Vestige light-mode overrides — injected by theme.ts. + * Activated by [data-theme='light'] on . + * Tokens mirror the real names used in app.css so the cascade stays clean. */ +[data-theme='light'] { + /* Core surface palette (slate scale) */ + --color-void: #f8fafc; /* slate-50 — page background */ + --color-abyss: #f1f5f9; /* slate-100 */ + --color-deep: #e2e8f0; /* slate-200 */ + --color-surface: #f1f5f9; /* slate-100 */ + --color-elevated: #e2e8f0; /* slate-200 */ + --color-subtle: #cbd5e1; /* slate-300 */ + --color-muted: #94a3b8; /* slate-400 */ + --color-dim: #475569; /* slate-600 */ + --color-text: #0f172a; /* slate-900 */ + --color-bright: #020617; /* slate-950 */ +} + +/* Baseline body/html wiring — app.css sets these against the dark + * tokens; we just let the variables do the work. Reassert for clarity. */ +[data-theme='light'] html, +html[data-theme='light'] { + background: var(--color-void); + color: var(--color-text); +} + +/* Glass surfaces — recompose on a light canvas. The original alphas + * are tuned for dark; invert-and-tint for light so panels still read + * as elevated instead of vanishing. */ +[data-theme='light'] .glass { + background: rgba(255, 255, 255, 0.65); + border: 1px solid rgba(99, 102, 241, 0.12); + box-shadow: + inset 0 1px 0 0 rgba(255, 255, 255, 0.6), + 0 4px 24px rgba(15, 23, 42, 0.08); +} +[data-theme='light'] .glass-subtle { + background: rgba(255, 255, 255, 0.55); + border: 1px solid rgba(99, 102, 241, 0.1); + box-shadow: + inset 0 1px 0 0 rgba(255, 255, 255, 0.5), + 0 2px 12px rgba(15, 23, 42, 0.06); +} +[data-theme='light'] .glass-sidebar { + background: rgba(248, 250, 252, 0.82); + border-right: 1px solid rgba(99, 102, 241, 0.14); + box-shadow: + inset -1px 0 0 0 rgba(255, 255, 255, 0.4), + 4px 0 24px rgba(15, 23, 42, 0.08); +} +[data-theme='light'] .glass-panel { + background: rgba(255, 255, 255, 0.75); + border: 1px solid rgba(99, 102, 241, 0.14); + box-shadow: + inset 0 1px 0 0 rgba(255, 255, 255, 0.5), + 0 8px 32px rgba(15, 23, 42, 0.1); +} + +/* Halve glow intensity — neon accents stay recognizable without + * washing out on slate-50. */ +[data-theme='light'] .glow-synapse { + box-shadow: 0 0 10px rgba(99, 102, 241, 0.15), 0 0 30px rgba(99, 102, 241, 0.05); +} +[data-theme='light'] .glow-dream { + box-shadow: 0 0 10px rgba(168, 85, 247, 0.15), 0 0 30px rgba(168, 85, 247, 0.05); +} +[data-theme='light'] .glow-memory { + box-shadow: 0 0 10px rgba(59, 130, 246, 0.15), 0 0 30px rgba(59, 130, 246, 0.05); +} + +/* Ambient orbs are gorgeous on black and blinding on white. Tame them. */ +[data-theme='light'] .ambient-orb { + opacity: 0.18; + filter: blur(100px); +} + +/* Scrollbar recolor for the lighter surface. */ +[data-theme='light'] ::-webkit-scrollbar-thumb { + background: #cbd5e1; +} +[data-theme='light'] ::-webkit-scrollbar-thumb:hover { + background: #94a3b8; +} +`,document.head.appendChild(a)}function at(a){document.documentElement.dataset.theme=a}let ee=null,de=null,te=null,ae=null;function ta(){ee&&de&&ee.removeEventListener("change",de),ae==null||ae(),te==null||te(),ee=null,de=null,ae=null,te=null,ea();let a="dark";try{const r=localStorage.getItem(pt);(r==="dark"||r==="light"||r==="auto")&&(a=r)}catch{}return $e.set(a),ee=window.matchMedia("(prefers-color-scheme: dark)"),Pe.set(ee.matches),de=r=>Pe.set(r.matches),ee.addEventListener("change",de),at(ct(tt)),ae=tt.subscribe(at),te=$e.subscribe(()=>{}),()=>{ee&&de&&ee.removeEventListener("change",de),ee=null,de=null,ae==null||ae(),te==null||te(),ae=null,te=null}}var aa=m('');function sa(a){const r=()=>H($e,"$theme",i),[i,c]=Te(),f={dark:"Dark",light:"Light",auto:"Auto (system)"},M={dark:"light",light:"auto",auto:"dark"};let y=j(r),D=j(()=>M[e(y)]),x=j(()=>`Toggle theme: ${f[e(y)]} (click for ${f[e(D)]})`);var h=aa(),v=s(h),l=s(v);let b;var F=o(l,2);let T;var K=o(F,2);let Q;t(v),t(h),N(()=>{be(h,"aria-label",e(x)),be(h,"title",e(x)),be(h,"data-mode",e(y)),b=G(l,0,"icon svelte-1cmi4dh",null,b,{active:e(y)==="dark"}),T=G(F,0,"icon svelte-1cmi4dh",null,T,{active:e(y)==="light"}),Q=G(K,0,"icon svelte-1cmi4dh",null,Q,{active:e(y)==="auto"})}),re("click",h,function(...V){qe==null||qe.apply(this,V)}),u(a,h),c()}Ye(["click"]);var ra=m('
'),na=m('
'),ia=m(''),oa=m(' '),la=m('
',1),da=m(''),ca=m('
No matches
'),va=m('
esc
'),pa=m(" ",1);function La(a,r){We(r,!0);const i=()=>H(Ct,"$page",x),c=()=>H(_t,"$isConnected",x),f=()=>H(it,"$memoryCount",x),M=()=>H(ot,"$avgRetention",x),y=()=>H(kt,"$uptimeSeconds",x),D=()=>H(nt,"$suppressedCount",x),[x,h]=Te();let v=ye(!1),l=ye(""),b=ye(void 0),F=j(()=>i().url.pathname.startsWith(U)?i().url.pathname.slice(U.length)||"/":i().url.pathname),T=j(()=>e(F)==="/waitlist"||e(F).startsWith("/waitlist/"));st(()=>{e(T)||Je.connect();const w=ta();function k(p){if(e(T))return;if((p.metaKey||p.ctrlKey)&&p.key==="k"){p.preventDefault(),A(v,!e(v)),A(l,""),e(v)&&requestAnimationFrame(()=>{var I;return(I=e(b))==null?void 0:I.focus()});return}if(p.key==="Escape"&&e(v)){A(v,!1);return}if(p.target instanceof HTMLInputElement||p.target instanceof HTMLTextAreaElement)return;if(p.key==="/"){p.preventDefault();const I=document.querySelector('input[type="text"]');I==null||I.focus();return}const L={g:"/graph",m:"/memories",t:"/timeline",f:"/feed",e:"/explore",i:"/intentions",s:"/stats",r:"/reasoning",a:"/activation",d:"/dreams",c:"/schedule",p:"/importance",u:"/duplicates",x:"/contradictions",n:"/patterns"}[p.key.toLowerCase()];L&&!p.metaKey&&!p.ctrlKey&&!p.altKey&&(p.preventDefault(),Ze(`${U}${L}`))}return window.addEventListener("keydown",k),()=>{Je.disconnect(),window.removeEventListener("keydown",k),w()}});const K=[{href:"/graph",label:"Graph",icon:"◎",shortcut:"G"},{href:"/reasoning",label:"Reasoning",icon:"✦",shortcut:"R"},{href:"/memories",label:"Memories",icon:"◈",shortcut:"M"},{href:"/timeline",label:"Timeline",icon:"◷",shortcut:"T"},{href:"/feed",label:"Feed",icon:"◉",shortcut:"F"},{href:"/explore",label:"Explore",icon:"◬",shortcut:"E"},{href:"/activation",label:"Activation",icon:"◈",shortcut:"A"},{href:"/dreams",label:"Dreams",icon:"✧",shortcut:"D"},{href:"/schedule",label:"Schedule",icon:"◷",shortcut:"C"},{href:"/importance",label:"Importance",icon:"◎",shortcut:"P"},{href:"/duplicates",label:"Duplicates",icon:"◉",shortcut:"U"},{href:"/contradictions",label:"Contradictions",icon:"⚠",shortcut:"X"},{href:"/patterns",label:"Patterns",icon:"▦",shortcut:"N"},{href:"/intentions",label:"Intentions",icon:"◇",shortcut:"I"},{href:"/stats",label:"Stats",icon:"◫",shortcut:"S"},{href:"/settings",label:"Settings",icon:"⚙",shortcut:","}],Q=K.slice(0,5);function V(w,k){const p=k.startsWith(U)?k.slice(U.length)||"/":k;return w==="/graph"?p==="/"||p==="/graph":p.startsWith(w)}let X=j(()=>e(l)?K.filter(w=>w.label.toLowerCase().includes(e(l).toLowerCase())):K);function Z(w){A(v,!1),A(l,""),Ze(`${U}${w}`)}var ne=pa(),J=ce(ne);{var Ee=w=>{var k=rt(),p=ce(k);Xe(p,()=>r.children),u(w,k)},Re=w=>{var k=la(),p=o(ce(k),6),z=s(p),L=s(z),I=o(L,2);De(I,21,()=>K,Ne,(C,E)=>{const fe=j(()=>V(e(E).href,i().url.pathname));var R=ra(),he=s(R),Ge=s(he,!0);t(he);var _e=o(he,2),He=s(_e,!0);t(_e);var Qe=o(_e,2),ut=s(Qe,!0);t(Qe),t(R),N(()=>{be(R,"href",`${U??""}${e(E).href??""}`),G(R,1,`flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all duration-200 text-sm + ${e(fe)?"bg-synapse/15 text-synapse-glow border border-synapse/30 shadow-[0_0_12px_rgba(99,102,241,0.15)] nav-active-border":"text-dim hover:text-text hover:bg-white/[0.03] border border-transparent"}`),_(Ge,e(E).icon),_(He,e(E).label),_(ut,e(E).shortcut)}),u(C,R)}),t(I);var ie=o(I,2),Ce=s(ie);t(ie);var xe=o(ie,2),g=s(xe),q=s(g),P=o(q,2),ve=s(P,!0);t(P);var oe=o(P,2),pe=s(oe);sa(pe),t(oe),t(g);var ue=o(g,2),le=s(ue),me=s(le);t(le);var ke=o(le,2),Se=s(ke);t(ke);var je=o(ke,2);{var Ke=C=>{var E=na(),fe=s(E);t(E),N(R=>_(fe,`up ${R??""}`),[()=>yt(y())]),u(C,E)};B(je,C=>{y()>0&&C(Ke)})}t(ue);var Ve=o(ue,2);{var n=C=>{var E=ia(),fe=s(E);Dt(fe),t(E),u(C,E)};B(Ve,C=>{D()>0&&C(n)})}t(xe),t(z);var d=o(z,2),$=s(d);Zt($,{});var S=o($,2),W=s(S);Xe(W,()=>r.children),t(S),t(d);var O=o(d,2),Y=s(O),Ae=s(Y);De(Ae,17,()=>Q,Ne,(C,E)=>{const fe=j(()=>V(e(E).href,i().url.pathname));var R=oa(),he=s(R),Ge=s(he,!0);t(he);var _e=o(he,2),He=s(_e,!0);t(_e),t(R),N(()=>{be(R,"href",`${U??""}${e(E).href??""}`),G(R,1,`flex flex-col items-center gap-0.5 px-3 py-2 rounded-lg transition-all min-w-[3.5rem] + ${e(fe)?"text-synapse-glow":"text-muted"}`),_(Ge,e(E).icon),_(He,e(E).label)}),u(C,R)});var Ie=o(Ae,2);t(Y),t(O),t(p);var Be=o(p,2);Ft(Be,{}),N(C=>{be(L,"href",`${U??""}/graph`),G(q,1,`w-2 h-2 rounded-full ${c()?"bg-recall animate-pulse-glow":"bg-decay"}`),_(ve,c()?"Connected":"Offline"),_(me,`${f()??""} memories`),_(Se,`${C??""}% retention`)},[()=>(M()*100).toFixed(0)]),re("click",Ce,()=>{A(v,!0),A(l,""),requestAnimationFrame(()=>{var C;return(C=e(b))==null?void 0:C.focus()})}),re("click",Ie,()=>{A(v,!0),A(l,""),requestAnimationFrame(()=>{var C;return(C=e(b))==null?void 0:C.focus()})}),u(w,k)};B(J,w=>{e(T)?w(Ee):w(Re,!1)})}var Fe=o(J,2);{var Me=w=>{var k=va(),p=s(k),z=s(p),L=o(s(z),2);ft(L),gt(L,g=>A(b,g),()=>e(b)),se(2),t(z);var I=o(z,2),ie=s(I);De(ie,17,()=>e(X),Ne,(g,q)=>{var P=da(),ve=s(P),oe=s(ve,!0);t(ve);var pe=o(ve,2),ue=s(pe,!0);t(pe);var le=o(pe,2),me=s(le,!0);t(le),t(P),N(()=>{_(oe,e(q).icon),_(ue,e(q).label),_(me,e(q).shortcut)}),re("click",P,()=>Z(e(q).href)),u(g,P)});var Ce=o(ie,2);{var xe=g=>{var q=ca();u(g,q)};B(Ce,g=>{e(X).length===0&&g(xe)})}t(I),t(p),t(k),re("keydown",k,g=>{g.key==="Escape"&&A(v,!1)}),re("click",k,g=>{g.target===g.currentTarget&&A(v,!1)}),re("keydown",L,g=>{g.key==="Enter"&&e(X).length>0&&Z(e(X)[0].href)}),ht(L,()=>e(l),g=>A(l,g)),u(w,k)};B(Fe,w=>{e(v)&&!e(T)&&w(Me)})}u(a,ne),Oe(),h()}Ye(["click","keydown"]);export{La as component}; diff --git a/apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js.br b/apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js.br new file mode 100644 index 0000000000000000000000000000000000000000..830faa721499cab582f9683667ecb270514005ba GIT binary patch literal 8213 zcmV+wAnM;6qi0bB8wbERZg@ncECpyeU>l>*ez=4TX--$C)A=YFsIytO$U`!L`L?uaQcDx0iF)(+eQtLi z_v;!WB^X+9%|SU=tp0WSo&0=ZjYqSWtYk>K$VDl&y};ro%Aj)*n(`HqxNr%b` zR=!KqKD0sm5$>n+_bw9^PkGz{k*{9gz7s92le7*`-Ou-#kwSI#b(QVv=5!7*va(;@Z&ILaUvz#Cnsfo} z9XKAcY|Beh0{uHA{+*5LZgg-mJ8t*H6+FI)pIM)u+bnH7uk#*kdo;Fwzgkzcr_ZbO zc2W{9NDS`JIsGM5mbqe;=PcHpm|5tJs5jtgF`%gj)oC!E1=c6`3Wp*scFAtH$f37$ z`1ga~sU+C6yuIXrz>R2^8_(*OQGcF;QE*IL>6vE9OMHaaym{Lu@6a(kL6W>X+=h9Rfuf;n!B+juMj(a zdzb3lOL6IgL!XJG2=ZpdZgjZU&y=c|z~$f!s5AOqdd#Mn=`A!9e5@WtqLf!^@*CQHU)cw_(PIQ#UAie>!F2R*L1FsM7 zsHanYibEIlZ^J-3XQO%Gwf z&5TvmJhf4DnOgKzO~UV8c2|N$zGIsq9A&Ds+ZMXIqB8N)eZh8We_=tl$b9E)Y*>X> zS-${n(v>~=7yDo4%8oL|&-xA6)i5kfq19OAC2v2zPfZc3K1nAjY>hJRN9#?7uCO*MA>XY;$%swo6s9JwCp-zv(U zru1Wbx4Jt?tSxmvtMlm;ytFBcosHpBeFCa-H2sNj4v!sjME(=xERJ1y_%&rA<};X$ z&%*W?AQ82O~1?A24#NQ`(V3WZ7HDdTC$IhyO7EA zNBan#x2Q0BXnB9s9EQ(YPw)sdcdzBLyAD8Xw9q2GtjCiv&=vfyjf&1jLc-TAp9~W4 zcqxjUD7xkB98K`j$R}IM@4{V%=h|y}`&ysc;l(&(MdR++o=}0=?U{IOnK_k$+CLZr z^<884q7;B$>KKo9a%;Y}#)-NX0o+bEeD)UxSKGqQJyz+`{fRd!hg49Hz(l_wISt4S z=h#L6V%mG8xsns?oenl27^3Jeh_y8udS+2SLWO0;-+Cc%gy4KFoKVCF8NMet+nUpI zO|Ib4@u+%?qG>*#hDr~YlS^=1pMfrdFjT^%sahU!(W>>eDXrX-qXY4y5-(#-Q+I|R zu!%yM!X!HAmx&_{{%`d8TRiu|O6#>=%{utCU-*0IeD9An5knn4Aq^2p2;mFA^I){D zL$U%d@Z2Ar{%7t?Jgk4AaTl8#p*!Di1c8B0tr;6@aVTa>8J`ZNq@@n5U%{Qz*|H8} zQayvO*IVoW>MP!IxxcKDOCUP9<{DEqIHe_e%QRaWg;?;gJ z&$w^zFV$|;^mVj_jlFJ(NJe}X$_4f$rN+`?PcYQfHd)TNHhM)kb@T+*-t2j(uX)!} zem*Pr$O@dxZ!?}U__ry2$lmQGKMt{JIdaprmC+05TmNoh8yJUt9pOoGp0}uE_YsRI z25S_Dgx_I%&1~=LNS=@Z4{cpk9)4XSwby^nX;GEG);KBf=Ae0uTA+vNyxM0% zYJCEqD$JZpr_nj)7fQ&%3a5u_*;opLTcNQp2y+2P;SlEa^R{r@m(OC|es^49 z*2i|U7AxDlhe^g0-$m^9A}Ud*)lgU%CgapbRPS3pZlEzSuve1X_UP5MQttiK(Vw@n z&7rdi=Z8LnAWGGC9G)q7d4AnIuVs&pzVz%M+=f;-*U9N=cOUts5drG$iTRW6<9+=A z!WGsoUfJ;Hk$zD*=vgl*J@*0Ql_w82eZ=tZ~l>=wVqpXbeZ zPnh=aFDJbOJ7lgL@UWK&{uMo7qbVA2=4VuL-1kTX`$Hoh<_{0pd4f`1oI5s@Ny}Zg z^)=Sj|L9yAAg`psI!qybpe`-Mbsx9GV6ynlL1d-)a(b+W+l1AM$`fPK#nT5q;h9VI zx%OF=bz?@(tumyzVBp=Iwu`7`%LjsOIBcyPp2j2bZ(|)h-*cOMfQBXNgzI_blzQAl zmwBZ+&Ky{F@n#H9P5&#chuoH%R5XW4GuNU=e&a0aD64bp8<)Y!z4ihcw}iLGm;PlG zUGQ0@(|EC6p%`3ILk4Lvyh;2w#7I>yxi*lJS+Cp@$9ObNUR8C8#0I-vpNenLt)sD{ zLww5k=c|hb^Mna-&oOAoPWSAMQ3kW+07Sja<9z#|Kwf_$f+PKUyJiirMT&XgZA4-I z@9Eg+vKvO_sPUq_=EVfr(uhkV9uC4|$&5k4vxr8(@)DK{NjyfHOam!M#LGx!$ON5; zR3Hdc5`}hVGW;4fj|PGb#>pmw0Cq-ziCy#>xGy{wWz$iPs-yD-9}3`U8Mc9JI31!2 zRN~-IK6J3i;54IV+i$nocaZ%G+t@wDsxStNr@y{QUqgfOzKPD3+_b8xKT|oH(22bl zzG{|Cf*hmM8*pv4?0T_r=8$Rd_KivcV!V*H*w@Ba54h&r`(H*@@@&8SmuPHNZbW>C zFYE5OS^+UPFLKZqr(voKe9sQuv0eZ9`8OWB86Wnq9mn#8$@ky+mp}M-e3=_7`?*GN zjwli#-f{4C^sK({!5C&wTHgKS?@@-EI!g2X7FOkN?~KRu0?cK14xSS5s~joCM1hWf z1S5%94sD3HMzC&s(4im8hPa>QYoxCMpo_IzDS*&FEXw`sKVUQW?fN#vq-yrj<}fn! zLN+jAEFg}Wq=5m`Gs64~oN{yEW+l!SzY_w7?^duG1E?k#_v=>ht<;7%jCF*LGlN~Y zVcW>=Kv=TIEfEAhhoQA+f5+ETE) zlr*Anj|LnbxQvRsMj=wHBw(77N#~11DRPn}fC%SV?EOaRVNW zk#T~8qU~Dvm>A0Qdfs6flT*8(ac){V=Wi}))ftwlIjfn77IL{0Efn&4u64ZDI`NZj;5 ze})}YYBkxa{M`&!VGEoq(`U=cPYSjpR!QTU;mSP9ZRdY-CL;FU*-AD2UeS0T+2dXd zehg*xVA`t;bhd70_@?cn5}*g zMLH%V)}8^!Jv*z2>OVXSMXtdh&)8h1Avp#jQba++QjFyA6L*Foaj}=YJa7QYQNy)X zM(#Qg?R!TJH$J1Cu3s$**N_C?+tW%xj?D`i_q_Rc7LQ1_QnmDCW)R44t)80KA5(;b zM(x9Wm3#XhBQVYtUa`mQb716t0POBN5lfS=KIn@ooC%y5?O*se><7PYj1a*sn&T zEgx}vfublczZwP){C<}Uvh#RzQ?2%1N3x$$VUPPL29`>vp+Jh#oZs3tFfp< zG{lggkU}QTRdEgN?!Y6$c3A4t_j4{BF>rmY!xKZfv<1`&@26ZcFu)a>+k2VvcbZ0f z2zGYc#5rL!FEuh=o2iGGtdxj=Pk6ckp??MTaarZ0=N~ zh&h@^QCf1RHPj+<48bxKf<+exycuudfinrOHxJH#VbM}z&5aM41%}Qa)KFMZ3rnLv z^dLg1MtAU{;M@sICjK5`N{r0Wq5?U9*j;s8mnBadZwT*Ku1Hic!)Yd6hdFqS$w?x) zzc_9wSMSp)>qjoVH#XNR`7oak;QOj;_i3JO_lk_GMjyIf()7qM(@TfPmw35Qi7+sA zKxqTe*2=q-0-W1wBI693IEV(I z2DOqaDX1*yuOuOVGD1-Q84}VBOg;2aPk~tgxm5$f570BALdNuxn>}z^eA+a*K|ID3 z4IWl)c@K6n_(~6Ca~>H=4`-GVHV+P@M*(wb2JQX4Ojxb!qpE(wHwn0?gj`f2R#$_*VS7parAhZ_U9)AU ztiZSiMJH~DRCcYXJ12W&2p@@OtKJsA1nY|h_L$Ft+}II+>Q-!$c)E{?UPKW)j5+K0 zHA|Xp95Tz!0n37?p>K_-KvX6gliMm0fAj>M<4k0Z!!F6IHundWOz8=cJ=s#v-Z*sh z6+$azh8=SuI4^Hc5iY%db7k%Tp)P(hpuMbyN2e#Z>&tvcU|4<5O;z}lBfx>i0L#cq zd}ab%Te#B=xg|h_9>;iXe1|sr^41Onik-O$g!y^xIV}r%KE9_aF$3fQ&3I5OT zmf@WVor8RS!gQu-q`S>Kw2G|ymif_svybLJThZ|{%oJ^%-FlR*ksDsK(RhWvpC;t? z195W<;LKiW{RNB}tZM%8&0$c|XGTm{P!BM(q*a%P2`hBy;|V@@sMooQGQZ z*=Zq0Sh&-qW?O{*Ad7JYWJ2sgf|CkZ7sVy4fFe$x)opRodS0=ep##3aNxmUf_gpFL z?fr_9pJ1P#0eZV%MCq=$2DPs{BDWb#BVAg&$9v| zaTPL)mUGKy+EtfV!wQXTlNbm`LAL8a41=DL*oNFGDaP1vNYeRulhb#*2Erl4F^w+L zXshLkzaTC+;|g%zFR$B;^c) z3*yeRq+q_hAciPMtQ1G(8#BwyRnb>VMX+H#$fe0Qa59NA0n{!8f%}TxZ81ks>6a;< zB0l9GNC$f~fx~Eu>yPg@0t;8)o?NYXg?SHlEVu(rIp83}$ETQhf*4irrO!TjZqQ4c z!D`*{i&s>zV`h_x{OmxBQ0Z0Tmc&qAJl!WBo{`BI1w&&f6w08+Lh

CDc)DQO<{5 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 H#oK%X%7_i7 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js.gz b/apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..aa16a20ab1affa9c032719c09f688c17a458c84a GIT binary patch literal 9318 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 UECC2L-n{pJ0V&yQ$)slh06`KW*8l(j literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/0.DHxskm8N.js b/apps/dashboard/build/_app/immutable/nodes/0.DHxskm8N.js deleted file mode 100644 index bb4ce7e..0000000 --- a/apps/dashboard/build/_app/immutable/nodes/0.DHxskm8N.js +++ /dev/null @@ -1,86 +0,0 @@ -import"../chunks/Bzak7iHL.js";import{o as tt}from"../chunks/CNjeV5xa.js";import{f as de,d as o,e as s,r as t,t as I,p as Oe,a as Pe,n as W,g as e,s as ce,c as ut,h as C,u as B}from"../chunks/CvjSAYrz.js";import{s as y,d as Ye,a as Q,e as Ee}from"../chunks/FzvEaXMa.js";import{i as V}from"../chunks/ciN1mm2W.js";import{e as _e,i as Fe}from"../chunks/DTnG8poT.js";import{c as mt,a as h,f as x}from"../chunks/BsvCUYx-.js";import{s as ft}from"../chunks/ckF4CxmX.js";import{s as te,r as ht}from"../chunks/CNfQDikv.js";import{s as R}from"../chunks/DPl3NjBv.js";import{b as gt}from"../chunks/CVpUe0w3.js";import{b as bt}from"../chunks/D3XWCg9-.js";import{a as j,s as ye}from"../chunks/D81f-o_I.js";import{s as xt,g as Qe}from"../chunks/EM_PBt2C.js";import{b as U}from"../chunks/RBGf_S-E.js";import{s as at,m as st,e as kt,a as rt,w as Xe,u as _t,i as yt,f as wt}from"../chunks/CtkE7HV2.js";import{i as $t}from"../chunks/Bz1l2A_1.js";import{s as nt}from"../chunks/Bhad70Ss.js";import{t as ee}from"../chunks/Casl2yrL.js";import{a as Ze}from"../chunks/DNjM5a-l.js";import{d as Mt,w as it,g as ot}from"../chunks/DfQhL-hC.js";const Ct=()=>{const a=xt;return{page:{subscribe:a.page.subscribe},navigating:{subscribe:a.navigating.subscribe},updated:a.updated}},At={subscribe(a){return Ct().page.subscribe(a)}};var Dt=x('

');function Tt(a){const r=()=>j(at,"$suppressedCount",l),[l,u]=ye();var g=mt(),$=de(g);{var w=A=>{var _=Dt(),b=o(s(_),2),m=s(b);t(b),t(_),I(()=>y(m,`Actively forgetting ${r()??""} ${r()===1?"memory":"memories"}`)),h(A,_)};V($,A=>{r()>0&&A(w)})}h(a,g),u()}var Et=x(''),Ft=x('
');function St(a,r){Oe(r,!1);const l=()=>j(ee,"$toasts",u),[u,g]=ye(),$={DreamCompleted:"✦",ConsolidationCompleted:"◉",ConnectionDiscovered:"⟷",MemoryPromoted:"↑",MemoryDemoted:"↓",MemorySuppressed:"◬",MemoryUnsuppressed:"◉",Rac1CascadeSwept:"✺",MemoryDeleted:"✕"};function w(m){return $[m]??"◆"}function A(m){ee.dismiss(m.id)}function _(m,d){(m.key==="Enter"||m.key===" ")&&(m.preventDefault(),ee.dismiss(d.id))}$t();var b=Ft();_e(b,5,l,m=>m.id,(m,d)=>{var k=Et(),D=o(s(k),2),S=s(D),G=s(S),L=s(G,!0);t(G);var N=o(G,2),Z=s(N,!0);t(N),t(S);var H=o(S,2),q=s(H,!0);t(H),t(D),W(2),t(k),I(z=>{te(k,"aria-label",`${e(d).title??""}: ${e(d).body??""}. Click to dismiss.`),nt(k,`--toast-color: ${e(d).color??""}; --toast-dwell: ${e(d).dwellMs??""}ms;`),y(L,z),y(Z,e(d).title),y(q,e(d).body)},[()=>w(e(d).type)]),Q("click",k,()=>A(e(d))),Q("keydown",k,z=>_(z,e(d))),Ee("mouseenter",k,()=>ee.pauseDwell(e(d).id,e(d).dwellMs)),Ee("mouseleave",k,()=>ee.resumeDwell(e(d).id)),Ee("focus",k,()=>ee.pauseDwell(e(d).id,e(d).dwellMs)),Ee("blur",k,()=>ee.resumeDwell(e(d).id)),h(m,k)}),t(b),h(a,b),Pe(),g()}Ye(["click","keydown"]);function ve(a){const r=a.data;if(!r||typeof r!="object")return null;const l=r.timestamp??r.at??r.occurred_at;if(l==null)return null;if(typeof l=="number")return Number.isFinite(l)?l>1e12?l:l*1e3:null;if(typeof l!="string")return null;const u=Date.parse(l);return Number.isFinite(u)?u:null}const qe=10,lt=3e4,It=qe*lt;function Lt(a,r){const l=r-It,u=new Array(qe).fill(0);for(const $ of a){if($.type==="Heartbeat")continue;const w=ve($);if(w===null||wr)continue;const A=Math.min(qe-1,Math.floor((w-l)/lt));u[A]+=1}const g=Math.max(1,...u);return u.map($=>({count:$,ratio:$/g}))}function Nt(a,r){const l=r-864e5;for(const u of a){if(u.type!=="DreamCompleted")continue;return(ve(u)??r)>=l?u:null}return null}function Rt(a){if(!a||!a.data)return null;const r=a.data,l=typeof r.insights_generated=="number"?r.insights_generated:typeof r.insightsGenerated=="number"?r.insightsGenerated:null;return l!==null&&Number.isFinite(l)?l:null}function jt(a,r){let l=null,u=null;for(const A of a)if(!l&&A.type==="DreamStarted"&&(l=A),!u&&A.type==="DreamCompleted"&&(u=A),l&&u)break;if(!l)return!1;const g=ve(l)??r,$=r-300*1e3;return g<$?!1:u?(ve(u)??r)=u}return!1}var Bt=x(' at risk',1),Gt=x('0 at risk',1),Ht=x(' at risk',1),qt=x(' intentions',1),zt=x('— intentions'),Ot=x('· insights',1),Pt=x(' Last dream: ',1),Yt=x('No recent dream'),Wt=x('
'),Qt=x('
DREAMING...
',1),Xt=x(''),Zt=x('
memories · avg retention
');function Jt(a,r){Oe(r,!0);const l=()=>j(rt,"$avgRetention",$),u=()=>j(kt,"$eventFeed",$),g=()=>j(st,"$memoryCount",$),[$,w]=ye(),A=B(()=>Math.round((l()??0)*100)),_=B(()=>(l()??0)>=.5);let b=ce(null);async function m(){try{const n=await Ze.retentionDistribution();if(Array.isArray(n.endangered)&&n.endangered.length>0){C(b,n.endangered.length,!0);return}const v=n.distribution??[];let M=0;for(const i of v){const c=/^(\d+)/.exec(i.range);if(!c)continue;const p=Number.parseInt(c[1],10);Number.isFinite(p)&&p<30&&(M+=i.count??0)}C(b,M,!0)}catch{C(b,null)}}let d=ce(null);async function k(){var n;try{const v=await Ze.intentions("active");C(d,v.total??((n=v.intentions)==null?void 0:n.length)??0,!0)}catch{C(d,null)}}let D=ce(ut(Date.now()));const S=B(()=>{const n=u(),v=Nt(n,e(D)),M=v?ve(v)??e(D):null,i=M!==null?e(D)-M:null;return{isDreaming:jt(n,e(D)),recent:v,recentMsAgo:i,insights:Rt(v)}}),G=B(()=>Lt(u(),e(D))),L=B(()=>Vt(u(),e(D)));tt(()=>{m(),k();const n=setInterval(()=>{C(D,Date.now(),!0)},1e3),v=setInterval(()=>{m(),k()},6e4);return()=>{clearInterval(n),clearInterval(v)}});var N=Zt();let Z;var H=s(N),q=s(H),z=s(q);let ae;var ue=o(z,2);let we;t(q);var se=o(q,2),me=s(se,!0);t(se);var re=o(se,6);let ne;var Se=s(re);t(re),W(2),t(H);var ie=o(H,4),Ie=s(ie);{var fe=n=>{var v=Bt(),M=de(v),i=s(M,!0);t(M),W(2),I(()=>y(i,e(b))),h(n,v)},he=n=>{var v=Gt();W(2),h(n,v)},Le=n=>{var v=Ht();W(2),h(n,v)};V(Ie,n=>{e(b)!==null&&e(b)>0?n(fe):e(b)===0?n(he,1):n(Le,!1)})}t(ie);var J=o(ie,4),Ne=s(J);{var Re=n=>{var v=qt(),M=de(v);let i;var c=o(M,2);let p;var f=s(c,!0);t(c),W(2),I(()=>{i=R(M,1,"inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,i,{"bg-node-pattern":e(d)>5,"animate-ping-slow":e(d)>5,"bg-muted":e(d)<=5}),p=R(c,1,"tabular-nums svelte-1kk3799",null,p,{"text-node-pattern":e(d)>5,"text-text":e(d)>0&&e(d)<=5,"text-muted":e(d)===0}),y(f,e(d))}),h(n,v)},je=n=>{var v=zt();h(n,v)};V(Ne,n=>{e(d)!==null?n(Re):n(je,!1)})}t(J);var ge=o(J,4),Ke=s(ge);{var be=n=>{var v=Pt(),M=o(de(v),4),i=s(M,!0);t(M);var c=o(M,2);{var p=f=>{var T=Ot(),F=o(de(T),2),K=s(F,!0);t(F),W(2),I(()=>y(K,e(S).insights)),h(f,T)};V(c,f=>{e(S).insights!==null&&f(p)})}I(f=>y(i,f),[()=>Kt(e(S).recentMsAgo)]),h(n,v)},$e=n=>{var v=Yt();h(n,v)};V(Ke,n=>{e(S).recent&&e(S).recentMsAgo!==null?n(be):n($e,!1)})}t(ge);var oe=o(ge,4),Me=o(s(oe),2);_e(Me,21,()=>e(G),Fe,(n,v)=>{var M=Wt();I(i=>nt(M,`height: ${i??""}%; opacity: ${e(v).count===0?.18:.5+e(v).ratio*.5};`),[()=>Math.max(10,e(v).ratio*100)]),h(n,M)}),t(Me),t(oe);var xe=o(oe,2);{var Ce=n=>{var v=Qt();W(2),h(n,v)};V(xe,n=>{e(S).isDreaming&&n(Ce)})}var Ae=o(xe,4);{var Ve=n=>{var v=Xt();h(n,v)};V(Ae,n=>{e(L)&&n(Ve)})}t(N),I(()=>{Z=R(N,1,"ambient-strip relative flex h-9 w-full items-center gap-0 overflow-hidden border-b border-synapse/15 bg-black/40 px-3 text-[11px] text-dim backdrop-blur-md svelte-1kk3799",null,Z,{"ambient-flash":e(L)}),ae=R(z,1,"absolute inline-flex h-full w-full animate-ping rounded-full opacity-75 svelte-1kk3799",null,ae,{"bg-recall":e(_),"bg-warning":!e(_)}),we=R(ue,1,"relative inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,we,{"bg-recall":e(_),"bg-warning":!e(_)}),y(me,g()),ne=R(re,1,"svelte-1kk3799",null,ne,{"text-recall":e(_),"text-warning":!e(_)}),y(Se,`${e(A)??""}%`)}),h(a,N),Pe(),w()}const dt="vestige.theme",Je="vestige-theme-light",pe=it("dark"),ze=it(!0),Ue=Mt([pe,ze],([a,r])=>a==="auto"?r?"dark":"light":a);function Ut(a){return a==="dark"||a==="light"||a==="auto"}function ea(a){if(Ut(a)){pe.set(a);try{localStorage.setItem(dt,a)}catch{}}}function He(){const a=ot(pe);ea(a==="dark"?"light":a==="light"?"auto":"dark")}function ta(){if(document.getElementById(Je))return;const a=document.createElement("style");a.id=Je,a.textContent=` -/* Vestige light-mode overrides — injected by theme.ts. - * Activated by [data-theme='light'] on . - * Tokens mirror the real names used in app.css so the cascade stays clean. */ -[data-theme='light'] { - /* Core surface palette (slate scale) */ - --color-void: #f8fafc; /* slate-50 — page background */ - --color-abyss: #f1f5f9; /* slate-100 */ - --color-deep: #e2e8f0; /* slate-200 */ - --color-surface: #f1f5f9; /* slate-100 */ - --color-elevated: #e2e8f0; /* slate-200 */ - --color-subtle: #cbd5e1; /* slate-300 */ - --color-muted: #94a3b8; /* slate-400 */ - --color-dim: #475569; /* slate-600 */ - --color-text: #0f172a; /* slate-900 */ - --color-bright: #020617; /* slate-950 */ -} - -/* Baseline body/html wiring — app.css sets these against the dark - * tokens; we just let the variables do the work. Reassert for clarity. */ -[data-theme='light'] html, -html[data-theme='light'] { - background: var(--color-void); - color: var(--color-text); -} - -/* Glass surfaces — recompose on a light canvas. The original alphas - * are tuned for dark; invert-and-tint for light so panels still read - * as elevated instead of vanishing. */ -[data-theme='light'] .glass { - background: rgba(255, 255, 255, 0.65); - border: 1px solid rgba(99, 102, 241, 0.12); - box-shadow: - inset 0 1px 0 0 rgba(255, 255, 255, 0.6), - 0 4px 24px rgba(15, 23, 42, 0.08); -} -[data-theme='light'] .glass-subtle { - background: rgba(255, 255, 255, 0.55); - border: 1px solid rgba(99, 102, 241, 0.1); - box-shadow: - inset 0 1px 0 0 rgba(255, 255, 255, 0.5), - 0 2px 12px rgba(15, 23, 42, 0.06); -} -[data-theme='light'] .glass-sidebar { - background: rgba(248, 250, 252, 0.82); - border-right: 1px solid rgba(99, 102, 241, 0.14); - box-shadow: - inset -1px 0 0 0 rgba(255, 255, 255, 0.4), - 4px 0 24px rgba(15, 23, 42, 0.08); -} -[data-theme='light'] .glass-panel { - background: rgba(255, 255, 255, 0.75); - border: 1px solid rgba(99, 102, 241, 0.14); - box-shadow: - inset 0 1px 0 0 rgba(255, 255, 255, 0.5), - 0 8px 32px rgba(15, 23, 42, 0.1); -} - -/* Halve glow intensity — neon accents stay recognizable without - * washing out on slate-50. */ -[data-theme='light'] .glow-synapse { - box-shadow: 0 0 10px rgba(99, 102, 241, 0.15), 0 0 30px rgba(99, 102, 241, 0.05); -} -[data-theme='light'] .glow-dream { - box-shadow: 0 0 10px rgba(168, 85, 247, 0.15), 0 0 30px rgba(168, 85, 247, 0.05); -} -[data-theme='light'] .glow-memory { - box-shadow: 0 0 10px rgba(59, 130, 246, 0.15), 0 0 30px rgba(59, 130, 246, 0.05); -} - -/* Ambient orbs are gorgeous on black and blinding on white. Tame them. */ -[data-theme='light'] .ambient-orb { - opacity: 0.18; - filter: blur(100px); -} - -/* Scrollbar recolor for the lighter surface. */ -[data-theme='light'] ::-webkit-scrollbar-thumb { - background: #cbd5e1; -} -[data-theme='light'] ::-webkit-scrollbar-thumb:hover { - background: #94a3b8; -} -`,document.head.appendChild(a)}function et(a){document.documentElement.dataset.theme=a}let O=null,X=null,P=null,Y=null;function aa(){O&&X&&O.removeEventListener("change",X),Y==null||Y(),P==null||P(),O=null,X=null,Y=null,P=null,ta();let a="dark";try{const r=localStorage.getItem(dt);(r==="dark"||r==="light"||r==="auto")&&(a=r)}catch{}return pe.set(a),O=window.matchMedia("(prefers-color-scheme: dark)"),ze.set(O.matches),X=r=>ze.set(r.matches),O.addEventListener("change",X),et(ot(Ue)),Y=Ue.subscribe(et),P=pe.subscribe(()=>{}),()=>{O&&X&&O.removeEventListener("change",X),O=null,X=null,Y==null||Y(),P==null||P(),Y=null,P=null}}var sa=x('');function ra(a){const r=()=>j(pe,"$theme",l),[l,u]=ye(),g={dark:"Dark",light:"Light",auto:"Auto (system)"},$={dark:"light",light:"auto",auto:"dark"};let w=B(r),A=B(()=>$[e(w)]),_=B(()=>`Toggle theme: ${g[e(w)]} (click for ${g[e(A)]})`);var b=sa(),m=s(b),d=s(m);let k;var D=o(d,2);let S;var G=o(D,2);let L;t(m),t(b),I(()=>{te(b,"aria-label",e(_)),te(b,"title",e(_)),te(b,"data-mode",e(w)),k=R(d,0,"icon svelte-1cmi4dh",null,k,{active:e(w)==="dark"}),S=R(D,0,"icon svelte-1cmi4dh",null,S,{active:e(w)==="light"}),L=R(G,0,"icon svelte-1cmi4dh",null,L,{active:e(w)==="auto"})}),Q("click",b,function(...N){He==null||He.apply(this,N)}),h(a,b),u()}Ye(["click"]);var na=x('
'),ia=x('
'),oa=x(''),la=x(' '),da=x(''),ca=x('
No matches
'),va=x('
esc
'),pa=x('
',1);function La(a,r){Oe(r,!0);const l=()=>j(At,"$page",_),u=()=>j(yt,"$isConnected",_),g=()=>j(st,"$memoryCount",_),$=()=>j(rt,"$avgRetention",_),w=()=>j(_t,"$uptimeSeconds",_),A=()=>j(at,"$suppressedCount",_),[_,b]=ye();let m=ce(!1),d=ce(""),k=ce(void 0);tt(()=>{Xe.connect();const i=aa();function c(p){if((p.metaKey||p.ctrlKey)&&p.key==="k"){p.preventDefault(),C(m,!e(m)),C(d,""),e(m)&&requestAnimationFrame(()=>{var F;return(F=e(k))==null?void 0:F.focus()});return}if(p.key==="Escape"&&e(m)){C(m,!1);return}if(p.target instanceof HTMLInputElement||p.target instanceof HTMLTextAreaElement)return;if(p.key==="/"){p.preventDefault();const F=document.querySelector('input[type="text"]');F==null||F.focus();return}const T={g:"/graph",m:"/memories",t:"/timeline",f:"/feed",e:"/explore",i:"/intentions",s:"/stats",r:"/reasoning",a:"/activation",d:"/dreams",c:"/schedule",p:"/importance",u:"/duplicates",x:"/contradictions",n:"/patterns"}[p.key.toLowerCase()];T&&!p.metaKey&&!p.ctrlKey&&!p.altKey&&(p.preventDefault(),Qe(`${U}${T}`))}return window.addEventListener("keydown",c),()=>{Xe.disconnect(),window.removeEventListener("keydown",c),i()}});const D=[{href:"/graph",label:"Graph",icon:"◎",shortcut:"G"},{href:"/reasoning",label:"Reasoning",icon:"✦",shortcut:"R"},{href:"/memories",label:"Memories",icon:"◈",shortcut:"M"},{href:"/timeline",label:"Timeline",icon:"◷",shortcut:"T"},{href:"/feed",label:"Feed",icon:"◉",shortcut:"F"},{href:"/explore",label:"Explore",icon:"◬",shortcut:"E"},{href:"/activation",label:"Activation",icon:"◈",shortcut:"A"},{href:"/dreams",label:"Dreams",icon:"✧",shortcut:"D"},{href:"/schedule",label:"Schedule",icon:"◷",shortcut:"C"},{href:"/importance",label:"Importance",icon:"◎",shortcut:"P"},{href:"/duplicates",label:"Duplicates",icon:"◉",shortcut:"U"},{href:"/contradictions",label:"Contradictions",icon:"⚠",shortcut:"X"},{href:"/patterns",label:"Patterns",icon:"▦",shortcut:"N"},{href:"/intentions",label:"Intentions",icon:"◇",shortcut:"I"},{href:"/stats",label:"Stats",icon:"◫",shortcut:"S"},{href:"/settings",label:"Settings",icon:"⚙",shortcut:","}],S=D.slice(0,5);function G(i,c){const p=c.startsWith(U)?c.slice(U.length)||"/":c;return i==="/graph"?p==="/"||p==="/graph":p.startsWith(i)}let L=B(()=>e(d)?D.filter(i=>i.label.toLowerCase().includes(e(d).toLowerCase())):D);function N(i){C(m,!1),C(d,""),Qe(`${U}${i}`)}var Z=pa(),H=o(de(Z),6),q=s(H),z=s(q),ae=o(z,2);_e(ae,21,()=>D,Fe,(i,c)=>{const p=B(()=>G(e(c).href,l().url.pathname));var f=na(),T=s(f),F=s(T,!0);t(T);var K=o(T,2),ke=s(K,!0);t(K);var De=o(K,2),E=s(De,!0);t(De),t(f),I(()=>{te(f,"href",`${U??""}${e(c).href??""}`),R(f,1,`flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all duration-200 text-sm - ${e(p)?"bg-synapse/15 text-synapse-glow border border-synapse/30 shadow-[0_0_12px_rgba(99,102,241,0.15)] nav-active-border":"text-dim hover:text-text hover:bg-white/[0.03] border border-transparent"}`),y(F,e(c).icon),y(ke,e(c).label),y(E,e(c).shortcut)}),h(i,f)}),t(ae);var ue=o(ae,2),we=s(ue);t(ue);var se=o(ue,2),me=s(se),re=s(me),ne=o(re,2),Se=s(ne,!0);t(ne);var ie=o(ne,2),Ie=s(ie);ra(Ie),t(ie),t(me);var fe=o(me,2),he=s(fe),Le=s(he);t(he);var J=o(he,2),Ne=s(J);t(J);var Re=o(J,2);{var je=i=>{var c=ia(),p=s(c);t(c),I(f=>y(p,`up ${f??""}`),[()=>wt(w())]),h(i,c)};V(Re,i=>{w()>0&&i(je)})}t(fe);var ge=o(fe,2);{var Ke=i=>{var c=oa(),p=s(c);Tt(p),t(c),h(i,c)};V(ge,i=>{A()>0&&i(Ke)})}t(se),t(q);var be=o(q,2),$e=s(be);Jt($e,{});var oe=o($e,2),Me=s(oe);ft(Me,()=>r.children),t(oe),t(be);var xe=o(be,2),Ce=s(xe),Ae=s(Ce);_e(Ae,17,()=>S,Fe,(i,c)=>{const p=B(()=>G(e(c).href,l().url.pathname));var f=la(),T=s(f),F=s(T,!0);t(T);var K=o(T,2),ke=s(K,!0);t(K),t(f),I(()=>{te(f,"href",`${U??""}${e(c).href??""}`),R(f,1,`flex flex-col items-center gap-0.5 px-3 py-2 rounded-lg transition-all min-w-[3.5rem] - ${e(p)?"text-synapse-glow":"text-muted"}`),y(F,e(c).icon),y(ke,e(c).label)}),h(i,f)});var Ve=o(Ae,2);t(Ce),t(xe),t(H);var n=o(H,2);St(n,{});var v=o(n,2);{var M=i=>{var c=va(),p=s(c),f=s(p),T=o(s(f),2);ht(T),bt(T,E=>C(k,E),()=>e(k)),W(2),t(f);var F=o(f,2),K=s(F);_e(K,17,()=>e(L),Fe,(E,le)=>{var Te=da(),Be=s(Te),ct=s(Be,!0);t(Be);var Ge=o(Be,2),vt=s(Ge,!0);t(Ge);var We=o(Ge,2),pt=s(We,!0);t(We),t(Te),I(()=>{y(ct,e(le).icon),y(vt,e(le).label),y(pt,e(le).shortcut)}),Q("click",Te,()=>N(e(le).href)),h(E,Te)});var ke=o(K,2);{var De=E=>{var le=ca();h(E,le)};V(ke,E=>{e(L).length===0&&E(De)})}t(F),t(p),t(c),Q("keydown",c,E=>{E.key==="Escape"&&C(m,!1)}),Q("click",c,E=>{E.target===E.currentTarget&&C(m,!1)}),Q("keydown",T,E=>{E.key==="Enter"&&e(L).length>0&&N(e(L)[0].href)}),gt(T,()=>e(d),E=>C(d,E)),h(i,c)};V(v,i=>{e(m)&&i(M)})}I(i=>{te(z,"href",`${U??""}/graph`),R(re,1,`w-2 h-2 rounded-full ${u()?"bg-recall animate-pulse-glow":"bg-decay"}`),y(Se,u()?"Connected":"Offline"),y(Le,`${g()??""} memories`),y(Ne,`${i??""}% retention`)},[()=>($()*100).toFixed(0)]),Q("click",we,()=>{C(m,!0),C(d,""),requestAnimationFrame(()=>{var i;return(i=e(k))==null?void 0:i.focus()})}),Q("click",Ve,()=>{C(m,!0),C(d,""),requestAnimationFrame(()=>{var i;return(i=e(k))==null?void 0:i.focus()})}),h(a,Z),Pe(),b()}Ye(["click","keydown"]);export{La as component}; diff --git a/apps/dashboard/build/_app/immutable/nodes/0.DHxskm8N.js.br b/apps/dashboard/build/_app/immutable/nodes/0.DHxskm8N.js.br deleted file mode 100644 index f96e50abd4311aed2d9509bc999b2c89449f747c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8040 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

",1);function C(f,n){g(n,!1),h();var t=E(),r=d(t),c=s(r,!0);o(r);var a=_(r,2),u=s(a,!0);o(a),l(()=>{var e;p(c,i.status),p(u,(e=i.error)==null?void 0:e.message)}),x(f,t),v()}export{C as component}; diff --git a/apps/dashboard/build/_app/immutable/nodes/1.BgGPnSIe.js.br b/apps/dashboard/build/_app/immutable/nodes/1.BgGPnSIe.js.br deleted file mode 100644 index b89c6ec73173e68132a60e1fe1fb8795ca801f6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 345 zcmV-f0jB;Ni2`7p33d!++7LG432pCR_19ETGLseG7<9_PCk0B!4l13>)TJetz);GW8OJ8?SwasCU+PCy3*KTRRm>y&&P0hEeOs>$ccwi9}a0E_WAoQm=t1X zK}ZJ^vLSK*$oU?SQr00y(l~>Z4#pyaR3KDXqD50Gn5^I+rOw7%V;E(hafeicNjXvpxHD>xQnzO6;hoq6`+KR( diff --git a/apps/dashboard/build/_app/immutable/nodes/1.BgGPnSIe.js.gz b/apps/dashboard/build/_app/immutable/nodes/1.BgGPnSIe.js.gz deleted file mode 100644 index b9bcb3fed90b9759fe1a4d7afab0b3fbcec59aac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 382 zcmV-^0fGJ>iwFP!000026J?OWPlGTN#_#?W9r4g6PbRyVh@Ei+_23fYVxlKfp^OT& zq%C9_;eVI19p-lF*Szo7_r5++H%eR2_vdNR%F@hNdsg0w*Ej#yc%hiwULa;rG2~j+ z|HzV7v*-+F)A(>Ss@C!hCS%)Zv_ zl$-|b4%4qM;+ih{{NCMM#I4WCkJU?_Y;NL<5al@;uaozcT|^U^DrqeGq5YOy#I;r$ zlU{S%YKdxpDh%K}W0`Husd=ajLs0utt}Os!B7MK}jZ`Yo0)3kVdLOph&%F#%08Yzd^)U=6cd5-O|@KBLK4S`cVQ zj~zWmpu(8YW$zFkHaG=wj7y-wEnrT?;d6vi*;dtKr$mNs@3~)dW7w9HfxvFeG>+{s c8Tf8mXyg`}s&TuLOFM*DfBK6n$%+C10K}QJVE_OC diff --git a/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js b/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js new file mode 100644 index 0000000..748af3e --- /dev/null +++ b/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js @@ -0,0 +1 @@ +import"../chunks/Bzak7iHL.js";import{i as h}from"../chunks/BUoSzNdg.js";import{p as g,f as d,t as l,a as v,d as s,r as o,e as _}from"../chunks/CpWkWWOo.js";import{s as p}from"../chunks/BlVfL1ME.js";import{a as x,f as $}from"../chunks/CHOnp4oo.js";import{p as m}from"../chunks/BskPcZf7.js";import{s as k}from"../chunks/BHGLDPij.js";const b={get error(){return m.error},get status(){return m.status}};k.updated.check;const i=b;var E=$("

",1);function C(f,n){g(n,!1),h();var t=E(),r=d(t),c=s(r,!0);o(r);var a=_(r,2),u=s(a,!0);o(a),l(()=>{var e;p(c,i.status),p(u,(e=i.error)==null?void 0:e.message)}),x(f,t),v()}export{C as component}; diff --git a/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.br b/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.br new file mode 100644 index 0000000000000000000000000000000000000000..fc2f8d46c262921e8fb9a8b7b0812a8cc4d09664 GIT binary patch literal 331 zcmV-R0kr-bi2@+RDqG7xiNI&78q;MF^%JxI|K@uG@o3X_2v!=ESS=NB})2)%6KuvNSb=lpu!%_aok)H!2HHf9gZ7clB2dTMWV zi;A%YQvw}1_)wsP4jEF2U=aUk1&-o3@9pg_qB3&q0Lp(gua|C4D21uXQ|!p|yD(mj zsF*)MW!}B^X>L#%*#mRW&#sT}9an$jeLAMf&NA}9SJuxYFPPW41I%jZFHKc8!yvr* zd~)VD8=|9i-=N)ugE`bu*@jTta76;d?J>+9cpQam^3&ZKQLk{K!$YYhgr(q!`?fq dlf`XgKF{8HVANzHXOzT)QOA@zGKvomVg&skp_>2z literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.gz b/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..91c8b8218941e556e833d82a6d649b98aa9bd10c GIT binary patch literal 379 zcmV->0fhb^iwFP!000026J=0AOT#c2z56TT@Q}bq=R^?fGQm0AVd_A1;AO-#ZDZRc zB)*OS3C>yEi@bbU|rG>E&m-nZ2xr z%0B3LO1~Oeuiuop)p}I78d%QlUQSW;u+m{qZY_r!Mw@Nh^;1 ZLYHBoTzA`5Liskn_yg?{{U3?~000jivxWcw literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/10.Dp-knJux.js b/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js similarity index 99% rename from apps/dashboard/build/_app/immutable/nodes/10.Dp-knJux.js rename to apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js index 7ee36c5..cb871ff 100644 --- a/apps/dashboard/build/_app/immutable/nodes/10.Dp-knJux.js +++ b/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js @@ -1,4 +1,4 @@ -var Bc=Object.defineProperty;var zc=(i,t,e)=>t in i?Bc(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var kt=(i,t,e)=>zc(i,typeof t!="symbol"?t+"":t,e);import"../chunks/Bzak7iHL.js";import{o as jl,a as Zl}from"../chunks/CNjeV5xa.js";import{s as me,c as va,h as zt,g as B,p as ys,aB as kc,a as Es,e as yt,d as bt,n as Hc,r as xt,t as Ke,u as Gn,f as Kl,j as Vc}from"../chunks/CvjSAYrz.js";import{s as fe,d as $l,a as Fe}from"../chunks/FzvEaXMa.js";import{i as kn}from"../chunks/ciN1mm2W.js";import{e as _s,i as hr}from"../chunks/DTnG8poT.js";import{a as _e,f as Se,c as Gc}from"../chunks/BsvCUYx-.js";import{s as ve,r as xa}from"../chunks/CNfQDikv.js";import{s as Us}from"../chunks/DPl3NjBv.js";import{s as Sr}from"../chunks/Bhad70Ss.js";import{b as Ma}from"../chunks/CVpUe0w3.js";import{b as Jl}from"../chunks/DMu1Byux.js";import{s as Wc,a as Xc}from"../chunks/D81f-o_I.js";import{b as Do}from"../chunks/RBGf_S-E.js";import{b as Yc}from"../chunks/D3XWCg9-.js";import{p as vs}from"../chunks/B_YDQCB6.js";import{N as Sa}from"../chunks/DzfRjky4.js";import{i as qc}from"../chunks/Bz1l2A_1.js";import{a as gi}from"../chunks/DNjM5a-l.js";import{e as jc}from"../chunks/CtkE7HV2.js";/** +var Bc=Object.defineProperty;var zc=(i,t,e)=>t in i?Bc(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var kt=(i,t,e)=>zc(i,typeof t!="symbol"?t+"":t,e);import"../chunks/Bzak7iHL.js";import{o as jl,a as Zl}from"../chunks/GG5zm9kr.js";import{s as me,c as va,h as zt,g as B,p as ys,aB as kc,a as Es,d as yt,e as bt,n as Hc,r as xt,t as Ke,u as Gn,f as Kl,j as Vc}from"../chunks/CpWkWWOo.js";import{s as fe,d as $l,a as Fe}from"../chunks/BlVfL1ME.js";import{i as kn}from"../chunks/B4yTwGkE.js";import{e as _s,i as hr}from"../chunks/CGEBXrjl.js";import{a as _e,f as Se,c as Gc}from"../chunks/CHOnp4oo.js";import{s as ve,r as xa}from"../chunks/A7po6GxK.js";import{s as Us}from"../chunks/aVbAZ-t7.js";import{s as Sr}from"../chunks/Cx-f-Pzo.js";import{b as Ma}from"../chunks/sZcqyNBA.js";import{b as Jl}from"../chunks/BnXDGOmJ.js";import{s as Wc,a as Xc}from"../chunks/C6HuKgyx.js";import{b as Do}from"../chunks/BskPcZf7.js";import{b as Yc}from"../chunks/CJsMJEun.js";import{p as vs}from"../chunks/V6gjw5Ec.js";import{N as Sa}from"../chunks/DzfRjky4.js";import{i as qc}from"../chunks/BUoSzNdg.js";import{a as gi}from"../chunks/DNjM5a-l.js";import{e as jc}from"../chunks/MAY1QfFZ.js";/** * @license * Copyright 2010-2024 Three.js Authors * SPDX-License-Identifier: MIT diff --git a/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.br b/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.br new file mode 100644 index 0000000000000000000000000000000000000000..0115d29ca0b5455a0ddcd79a5bd6a51c72d358b8 GIT binary patch literal 124124 zcmYJ(Gn6RWvIWq#ZQHhO+qQk$wr$(CZQHhO_rKA9742w773>;oY0uuK19h0ZL!#1d z9@<^99nW{DU2I>6k{j6sr->Ze=MCKemFE*X?eE3@n44*l7dXe-rm_W#yvG>}sQx#) zN#F59z3dae8InK}N)$DfI9=vrg~J~LRLkYSLyD!cTLWDPo-8{IB7%o7A>lk?G6vHc zoy#kM*Q^=20W4A>a8Ju`c*MsGhBw->EeadMv8b#}7z--&fOU=nLEt{Z^LD5vbMW26 zmdo&P7en&ie-lZso`)~byH5J(!5UO3IJ?3=z;F1qA#Y{QKf>*ZRcLj$*b!!IkZ3k4 z7D0$Ya!xwfr*2QGIZ72Px~}XywwQeeS-3?vO_3VcrObl!1ew91DH0(D&NntZ~vj*HB8Ns8alR%<^ArZdy zM==I!nG&3w9v>r~@y7h?^G-h^`VOC}bTz;G$&P}(^kumYK6w)Kb%`$~hRVhG6^!kN zj@a;J`-l}#z6Xej@_D!(ORn{MR<%mgX2(16{&Z}Pg>R-$X~CKCp*Pn%rvqvVOLAGcXEQuWn8-IT~ zFE2eCm6u)i!p{m^1CW&W0tmu|B{@?vHEZaCiI@r`BF@0cq%npyv>#G-+MK3!gVHEe zBqOL2k8Cc#!nm+QDJ{C zr)pOlq?h>kslU1@O7(_;uBQ-dlZCW7r#AjV(m_cm4pem>k4GbX!jkGn8h53gj&8p> zKEd$-W0jxrK;D0qy{a|v>?ztKY-)sSbMDFE@O2c9fQ#we_xj3&Rj)#y_awB2iv4(z zyS%ebHy7}G*DE}_Nxyv}9?EvD4J{MK_SP6Mp~Jz0$^r}*z8Mui7n2OipZ-4*=Bcom zt&KL)9nX|Ng{)v%5S^rovF`1!E=-$6~X`Z=?Zfycf-$%+0HdhR$&Wddz zI%%`|zQ_B+X7eU$g1?5csh84Y3Wnf=_1~+gI*&F`cYkxk2zK0CU5ULOIG~7b`Z>%D zS^A|vYjx(6Czlb@o2AFoxtr3LB(sjPebWu#&|n+ErvU)4i3wY?cAJgAnNp_xlDYYb zwl!&~(F~VrATuukIFk_+$U0J8QT{={tT#96+FSiB z&f|+IOH#**bJOsI2wD*Cw&pLw(ynT)H{HA(p_|nQUlv|3yHgjqxHmIUt#79KLQJAs zi&O=Fz#j$_Sga6TAYv>oOP?DjM9ElwY4#pmZ|0m*#2MdYobUH&$e1pB0fAsJkLy+8*RWrb^?4GLrZk! z)oZU>ElR<1$AY_Qt(95 zc!6AXQZ1iqZb|W}%v>9+v%J2})-zArXObpns!%r!*I@mmFqlAsR-sPRiG{8rlFB;( zXIKPBK>p6i1nORbmN{m6nVRgU)f`$ij%2@Y?^fo1XWwTYac6vUcRd%o_!{n^2jpGo zJBkP(Glh+2h_^PuLmxg zh9vMsDEHpCmk=?3gRgcIl(7gvhiIY|7nqd}+xy|yAb(%GQde8OX9u?l@gRz#zJyhM zSfps!>WBn@@%mK1m_6$wU2oZ5Ot~iQP-f#ok>fy2fGE!>0*-S%bG*A=w+Rl25s~3C z&v7W%awHmTknt}uhgV9(!8$kVnSEZ#yDwI0#}p39daW~N>|Zx5K#&Yfl7D|b{5L<# z2qtaWQ7Ib|f)L6k(x0m({E!-6cP?a_s%^IfGJFS443yoebA&Chv@@>t70ZLx-?Z=D^szlnPw z!AejlP`MLT71Judl0cg|wqZ2ioD_Se#cJ%18`(#X_(2w?7?B9OPhm1&yBc)A`+_Vj zu?UHmHKx~1zc#jA=H{h$tw=)Q-YB3*pB}#ar7zvdw02$LED=UQ{0ze0`ZgQVgY%T? zol(y&8m@2<^8+SLZ$qbl_}VQ#S~q{F=^=)&(gLz{&ty+e-j>lal279DD)yCt{Gl^{ ze-}nON_%w-)qp@Go-w(YX^gZ#tGm~8NToEC!M%wPD@vnf@%h%(+qe&mZViZ4+i@9t z%$n>jM>&g``7j1wv#hV5x|<}nPgm1X{g0?R zFG;_PQ}%n-Frx&)@gQ=G!C3trrlR9eYweP(6pgh0?%vp5p)vwnUhaaVf@#DFw9XEp zuJun&YfU;z@#Z{ALbgRKTb%2vW``XS7xrwWKWPn2nw1T8oL4*>ft(-FasxVVuh(5V zyOqn0ada~lwZO$+|8uS0~%jA#B zjz7(<6wxP4mlcjEd~NdZ_vHOQi36+pUhdw+i8I>}EQ@;BWASCb&HwDD@1bs~0Dpj# zZQQ+oh<{vV+JaPMOJ;oD%~`)2+`U#~K(=?hY3_JNzBLirg|VxeqS)7fCtHJtoxi(2 zecdZyz&$UQ#J@GU`+k2_l1Yj|C{;)Q+O2Y3!WO`44Rvbu)b+Rc2ZE+eZYX;=WPh2} zJc*B%@HhIt_RQ@a3jnd7u3okdF7L4scA6cZ56-&AraFO-a~AY`y&lf$FBhue#h+W# z+*%+1Juvv4w8i1`3p~_?uiEvYhHM=3JEiWi*4Utguov0(;qU52^N&T(;_K&p_IGO9 z3%Tm=@-M=3EHOu+v5SZ0$ro#2e?IG9D3H_ZE$F3eT*eXa=DdcHJipqj?@YMGDOmD` z-Q2&=w)veQfdYWdHpS|2OUqB;k!IXURi?}qQK?4M06p6fX&4PfCJh6afHBu14dAS@ zq+94oG3d+9tFi<|3XAl65@;ax=+Vex(Fl`D=iz@xVz+SAgsTQ#xRH};BQyr&#Mqcc zOslM|Jkh#STHaQ{) zE2K90m?A7R&Jx=RCw($eSoLiZNcJG1m5LJQ*rG`4qMw|bLKcZ|9N6~@Po-O4MiiK8 zJ~qUNcwlRyODR$9s6oC=(Z9 zepBO}!l;n-`dWyG(I77S_wjLlQYEN1ORfLl0-#bmOOt|tT>*7!p$`t5#DV5`lVt27~+n2mSnq7P`yJP5;^B$y0VG=+Z&dTCh3 zar3W?Q+Zr;#(;P=47fyQ+~ubn>@Lci`=djcF?`$5XkBF-Fx9xxyIgiMpkAJX9v_@b zBwb-NL}gQB4IYq4hT=$w%C`DS8~~9l*^w}XZS}?29|C!@Jzfg?>Jw5R7}8Wnq9n%U z2ZdlTn2D}oS`5Zx}v$ERv+O1S^EF6>i=V{|Hs1qk45_* z3;zFX-~Y3>zl;I37ea68M~-oJ2Cy(gn_(<<*HcKT70a_rk#f!yMjvC}way;Aot}^w z{pDE;vrHS^cwdUzUjwQ?7S=;AVJYYLxpwMklx2;Y%b>KbA~)jsdPO>+<{^INN1&T` zhBtsS20f58N&Phtqr#5hY*pdbM3LynjWh~MF8~sCq+S>S9UeEs04($D4whEG1`PTi zAmYH6j}Srjh{t3Y-1Kk^>gkftW34kz>NS<7qk1fT>*vBnYwivOV;rFt3cEZ=c*x>= zD*$_1y)m&hsSrz-PZWu#t8X-hkHs16;x4edK9RYZyS3--KuxfHwR1%PvybvIEl98L zKT5Yrns2&E83Fs7(7GLPXmrDiO&kUHU6~dxo?_4+3RhUHK#OHi!?6+551O7`PjTV*|u_y5Ib14`{(qt3DO8j`%DuD{)pZH>*pIYc z0Z4%!>G)oGx_)V4WO}F1Kn4VqTpSPNNnQX#Ytv1|P?=zAwHpDtB}lv}PKo6Y z3if;7RT9tiHA)1%xF*fj49W;8hNRrFR3{eL5!n|gI5qB^%eaf@Ua={#@txavH?gzf zh(jXGXImx$!047)OQTlmzme#JP;SEiRo?Cp84Ztxm|Um4sg2JqxV3yeMqKU9Q0XTY z5GaJPNt^rB9r>j}Isamc>Vfca*5K@AG${YV9#7JcC~~Xh)qPoGX#x|$*AXfBPG+a3 zHEq63p0>|fWW?3n{60u*Eqe_slaX6JXW}FU+pIpY%}=VS8TGdGqcQ}};pUn2+gxc) z$~_6mNT}981LU9#ukP;~iHh^q+bJ~+cO>~ly73Z#<$<%xb-V3$iODGt(i0(f^d(I2 zxzj&8C{rx+wzy~L`FQ7!eWzO06;jz39cxpiR1nQ9Aa8pNn{E+v7+O7Ni@+O-mJqO+ z9ds?0AX}E4Zvvi6k>wMqnn4Ax%+;RD$Gb<|)RviY^Qpv)rS$ni%Tm>V1hl%0L-(c) zN@s>`){=p`9jL!%ECR+mJ4MdWRVw!Yq00mBcQmL0!b_fBBygM!DI1Hv{>9&V@3o(6 zLc;SQ_gpbD4GE!oi9}uo_lg=)$4>n%v-|bfX7Zm+elP3WDTj|SN=MMX9v5HILXi70 zN<6DLH!q)~dr+AeCKKqLM4CjrmwD2DtJZNPaM`gGZZdO8O~Mc6Hj9;>v%lSq*hJh0 zOc2>HjTBB&oQi;(NwDu#b|i_p4=!I5k+7OUBJ_bhc{p!p@r%2vo@$E2gTx~#QWBZf z$foaJvo$i}<%&|d@`JDSXQUU8Eu5^E51tt3@Z$=KuxLG?h!*xq3TJsX8$5RI%@0wY z5txo|%sKF&fkeas6UvpX`;~-h$h1(kNap1q{i^s_%xP2=VVr=l*4TLtTAJr!9e?I(bA zzXAQuGn$`*j0Zec6y_^NfPm_fGNCw2S)0wSZkMR- zMUg3QzNX!8mIDrvVXzFI-spP>J~P%zO}QEGQZ&>M(*aTuMnfQMM3vwcW;GMr*#F-D znKS`XAc7KOkO&&8!pMN`k6q>Ivk?C)4Msu$)va`Z_(yL9xL%P!P*A>@(Pq=;l*W6L z>&JF=kB{C#d~?7yuNW@A?mH+9Dm*R$M2_m%iY`)N{s^7zJ`eQBhdmrpF$Hfea`F$Z*5Zn5VDTNB+TFq6*a& zbDEs92F$!w5-3>w*VG=cM-U7w_}rxA6gHr?o_)A}!5<^%8b#S~18Q^dxIv=Nhl`sm zt2^k_X7?qd!0V~zDNJy&??9A0<70pIigq0nNzIf=j=Eu%Tg{}2mUhdw0VSHji47r= zGZ>WUk;;5oBIzOb7}iq+hMi7C7y3yB^CiIvA*gQI{rE6~Z|`cwYvqc^st z&uRd9m3P!ze2HWlVO%O|kLD4&jhK3L%lb@2%e%kxRZvQcENQzHY}fL*hs?JqgMV$X zP3z;0iv)++r;2{qt_#9SB;iym<*+^SmW}!$+8dGK+O z1dlU-#JL-?(dNK{T?}sfZ4z7eZwA}|>+9?0XgH5&2h`6~3tRq0JWdG079KL*6lvil ztkPsv0o^t%0pQW0d)-$$H(GwtSX*ZTxqjg^pgsyoWG*q9IwmX?Thcq?+Fgv&tk|}1 zlT9>Xqe-N1W|mNF{URxdRJFotiTpIqD#VjuLH{<0VPHe%BYt#N%vr7?Tn=@CnJgR| z&!l_5G>-3Db@V zIL`5Gl)jL_%c21HSa6ryZ+;ez*F!U2QmHg9zld7yygcl!oZTq7VR+~w`XWmB$1QO!sopgNHg$(v505A&<*hnj8_p{sWNGK%mfV5OR=XiG}KV(2v>(TpvyI@;L_oKWP zM|MiC`RL`*d`NBE^JAIc{79~^Q&$b^QRVG?YX*4zD0o)@uf^AHjiZ@2eR#%!_f1R= z+{*Awb%ZwdYj$ZX#nj`?b#Bxei{+(67$LtG*T(y6$=YdYgohQF_8#^rJ<|{b2IKs_ z1Q+DTR&Tt`0*bt)eJf$XPSsPFWh)RF^KZd)(yyMf-btU@hw2$W_A`Dm!bnw|Gb2Sg z{?7d0sAyRB6UvEK?mi(x-;(o{bXR$8>=3RQxzL2NcU%IFDEn4Qpz+c-@G(l)tX*@A ze;8n=6`9)+wOon>1O|NlwDa~IPqk{pk9y4E{Y?{|X$)JfBsrq3hsr;$$-BN8#J8x( z#jwmMyIUtCJ#^gPx41pJL-1SmIBvJ^gkYp;xaEwjY0)?pdnK@OLBH-&JZM_Ie`Tx>nZ3I_Yit0d z^gwgdw8j_CC1O8s%}^i*IgP6I!1NrS%^__^1q4*iDJtne`6vNCGHR!^;sSk3D#D^v zvzXsImoLhqxPe^Yr@=Y<^q`TO`bR-_Mhv@mSY4v;P0680(r1o6S$*Htifn2X>zXg? zoO*J{+?O zz2kS}tmY>M*buy9tad48V?4nnclA~?47cmeyr!nF$3g< zn_cW|co+u<(g2Wk{c7OyJy_cKAA}%rG;rPI@l9q$?>E`SvT!YAzrHKd0msSUKST^nZ>dPKO{epBP)tg!$k)Feer{E{L6t zsPuyr1YdSWs!AS|jT;~!+hf#5W?qGGBaK{gJ)Iu@%hR%IFEU3FXIa%=%Faa>t!8;z zKC5{b3S`dPpqWY*{cW=%PPrpnhBAE(6L3md5};V#$sy44E=b9MsV-?Vc?FrgsA1|9 z0Mj%scUa)0xo;iqoiCv!Dd1XvsL|(s;fG`ZQ-9V`==q*Nw%=RsKXk<^NZD}Enmdl? zLzQ83X#?V0dKW%|73Ox_#0Vi>9jnz|b)=w0-o^49;zh?Cz%2w#NdVN;x0DS60Z^(s zq{LW~e>8nmBJxV`AA~1ftHJ&iunP@#Z>xrnive9oZz*H6BhnRVOg?Er3GRumd$$j$x}A-kxgQ@ol)5zNv(#wMuUPT5W9lm}e0$ylz7VoIyH zh#C*=j{5HS)N9(<_eRRb6MS5~rg=^!jSQh{lR(i^Qaz*y|>Mk$lkzq1_~~ zz+?J24h)43hbdrbQ2`l7EC7VY1hMFWrGg(u%+f$YyK)I|D1n(vAvFH5drzs$>HJ`v z%8kTK-j82?DP8eR)?Y1QlpzVal*kpNIbSKJF!J26_3=_)MD%2I%=n6FR(i)tJD5=v z4o-C>I%`uf@YYdzC}G}Z{U3?I*J*pD(9+N2BMvZyt`U%P51K}vLfQN@b;zB!FthnW z+ESFD`4CXnLKMM+X+Uy3qFRCC*vgr=;!6HVRm=YOdTDI^14ER85(s{ZLUD7+GyyaL zLQ<0wiJ>s0YNTcnX(COFlt$T*UeY#VmPb{`H1bRTNcs*n7Dr*S-}Rf@64S`NZnWjDXe*-J)ch+XR9 z8w0o90EU9j2NBd+itLUS{X_F74I{KJDIEb|%J95UmbUo)6KP9ou;nikeE?%=$c?3@ zm=`aNQ|H*2#rb)GB~?K~C|M?G4k5aBGu&H5i_&>)Pw5))E9BAMzlcd)(7%${`oMaJ z1q%514oR{-kv9lSbxCjYScI9`&lodjY)}(AP3jpQo*!S>YOzXe~vSeqFjr z&E=@MR)TidHfYmyq7igL*G$nx+3?gS>pLG4HKu)C??@L2N?_`q=r7Vo5=cXLDAS#n z$kLy?rvU9b9|PG$RvaXR&vu!-@!(!{#&kZpOk%o6c=RwQl^#Y8JEKi+0%D?8a!f0O zrKmpQy@c^ucX@i6Z-nVD{xI$Eo!{q7EMBVNfq(qklxFID_y6q;(>-H+r#GA?`$pQX z*9%h#826QMhOzrHgVD$3^o&StGBJd=c_lSM zEpWd)rTOV`j_Bu-lb?*nTX&t*Gs1E{Yv%(?q_qMs^zcxnHj0u|Q*!S_&XvZf+?px>)Ynl zA8uS^X9o8n*n?;k*r*fNg3S;}?n0C@>8frc)Po7rBNWb`75WRTGPo1Tlu}1N3E2ah zcn-NGNed_CgqBSn{vBQWA4tsdA@DqV2-XvA%{8{SzKa_`hw2d^Xg_6_W3k7he`awg zE$a?dWTf11DCEoUn9v$=x<%f&tQ_hP0+IiSchl0vwg4%`rnP&kqY;BW7I-iqCCxma zHQ0{Fk4OI4(%@z~1nT^mxWcOrnN6vSAa_<10C-ZqZHPo^0wan4{IkL3>JOkBW%TAa z{+BNn@hDCr0J-d4hS|XOr1(R=NCO0*9}e|+$y1s9QtJ4EB!v_qo+feTtVFPj4xIp9 zUiFO;N5mx79jFxSB$EVMQ~)1v!W7xqXS&9>)FNIZt>9P9j&!0I6^oLQPd($bnGDYd z^fcU(q_wS1WvbQ9J=nrEi6+3L@au&K0jmG9k*$*tJy93TE<0Sx3!gQ^W0N4ikNfII zo(gM0*BZ%cxTK1Nk7~VV1tS+}ACK4D@(lY_WO1yL|C(TjG|!mEq?@gQ*U_a2JB$7i zP=;b>H&98eO|*j$Gl8YnvRB$Lki$b=74(|SBC!A}Xd4Mog$Ctaj*8^nzsz0ZLy5x@ zy)MMUJ_{cdNff30R(z8(3jTy@AE57}H*KTZJ9b&wv9w4(JsfAPPaJcN<)@*i0K*$` zFG$pXIxk-B17hHs#X&-Qp?kqXm+c_D;%)(%cCN?vvAhDTTcEm*h|8@ZmDW5Cs|q$v z9`XM4%kmj;=q=KmJ57*SFm_y}+7up17CBTp^OV~(4Aacv2s&#aK&9uCuHRsF3emFC_(=5)IfSm1q4!Erm_OlC0mkS5$i{ z&nzo-H|N4Mr>x|o6SVvrT@@b$t`svB-9)J+SPc<@#btDOhVdwYnk~sqtACd<5* z%Dth$5j8vu^~-0^(Ki`eVpRq|m;o7l6w+jW=m4cm^rdYnAI*mj=|cniseL$A z!#7`Ykz;t09^~AulZ?>%05Kii+I=PvVa~$_J$$G#`_p||^{H*eiM|O#UF{n09<*ur zGR-uOZL(es#=3c#M6iQxDP@dRbbR?#xX8j8e2!&c)VuOJ@Kp|bKmh=C9hvnjZli6E^hnPWry{o6!`BWUWT zo_Y6+kp5tJomDZ{n6JZwufu?^!-DZg7Tz<_N(ZI9bo+@(H975^inuu^Dm%^wS$7}YfA1O7G#sTe{is|Ayl%jEKSKW#ZRr zSRUC*UO@^U+i?-vKuED_Le|v73|ZtNG&-GBFNbynwf{L?XEh~w;jk^Hy%cmy<6rd$ zMSDg@OB8DYP}y3lZ=|$dVC5HKNHXhKjD)D^jK(_RyR27J&gpV=0y# z>s4@Pf@-G3mV`X#hddXO-guZgl&)@Cu64rsQq;J90FTmC_3>Iq99Y_UV`1~l$BZW3 z`SApRlv7~@`OuX+?HO#G$pnAX*B@Y0aLyJd(nIx5#8#L15^7{?4#oy|mcan?BtAl{5mr%V^B z>~6a@sA;*iS%h@`0|+J1AktQi;84cp1*j2D-+v5)r!b$VV-gI++G&6e1|d=YjxpJ0 ze-uWtlm3+~Y{q6_V`5=W@=_Q-ybz@z3n)+yGJnjYc;$moWU0g7HzS)xu8b z_>psU2Lu-gmv_IawW8o_8qDR5>HvT$G@ZKR+ehn~c(PTC;3 z$YX|+{bGcQ{EAM2Fmi(;byYJVo5kYOyMMBO|&&tUZB`{wTb-Vqo_bY(^hP5an@ z3d7pG6Te&ndpHkd7ND}(k{`Vz)NtLOj@84VMTl6QTQ1XgvtL0xH zn!@ncezm~zwJNI5Qn`WCMNRgD|GKj0-iK;+^?tpu`k}e9Aq)-bh5~TAVL-C z6ut35nn}^2C(#0J8iIfR?mQ>XoDY~bTM9Q_6;Ff7 zEazleslBTk7byf6Ls9EOyOx==z-ne-IJ#+<&d9g;@$IQzMt(0QrZaWb(0m31`wu1s z7Eg+;6tiJy47-bVX8f5@IqZ!&#P&_S+w~9B3ZDsaGfdeib$X>~(u%?Wt9<&p7}xPa zJZUC_tiIYN*n#M=hGSZXtv_n^RnWlkfO-u=Xj7R!jZmd;msSo`9r3$VKmH-<=!CD6M4+ zB*$YLtC7Dwfw8A2=#bnj*S3@Xl<_ZlTMw)!WjR-mPTY(iCzh@S6vq{ zK3iwL4Gzw-?BNEZDgdFTane-)!s-A9mT2-SeZeNm-}F%s{j9u*08!k-+T(G6`k_|@ z2nIqO8?^WYI2S>;zdui+p%iLb5;61?lCd&=cc|` zO`PsE({T{PtaF`n${^#*nUU^UdKEd?b|76!P$Vr=ao<8qdQ{RH<^bd23T$^ zrPNLdTq+S-Qp=skTI6B^@l%a!64H>M6*IwLg6b6pB4Hvcs%sdBydQAEatbSnm-!LV z`Nxs*I%6oPn9Khah!vpGm6qFQb;3`(@xgIEZ>C*Vh%#8ReTjG-0i^@3PWu_%>~yzq$e#bIInd zrgDe{OEKN2)*F1|30)Dr0;7XOH(BHBH0%J)f ziis{|p&-@MpMu`({gA-i(;CLE%11XDx<$?}phCZwE%6kPchmL$rnS4t>;O$}ur5$K z0?%P2&dg31i5;$x#)rHZk7QbiOlk;;z<;WbF{G6%sp3toe~9L6<*FKT6hV-g1-HvI z6d-q^Fzs+-AqsBI%Fn_Of6<$q&pu@F3&4>^Pjs(@o=JS08Xn8?D=CRd*gCYIBL&Kg zKA$VZl|AG3T3EhPy+|j|kw?QO5f)S|+`fPb7qz2w`F%P}|dMDv6$-2O4`(skv?y&Wn2C|}Gc7tAGs zMp?OcY?8?OC>SEbS|%0LV#=U8n(AP20?s@7GHEhQjoNZGX4RCy2npG(S?8`g%lh`% zxEKAQ?Di?Ur`fiV6Ha}K!D-LC|HFch%Lg!86G{%Q>muuG}T%$Fgt$(1Ow_rn;)Rfn$A_7KI$&kFpY=|X>P&2)XIimAmAUr60k%}PVQUm8ISjz z+CcA%v32ZMXuB*}zdIA=c^#57#M)Ro%0P62!C9(u5R?uh3PfW}Li3!irLG{;$Kd$M z2Vn*4o?-fre9?y1Dcevx8un`pKkmyvw(KhmRc;k{T}EyVF~tU*i`xxiLbzs+fNw_A z@VcboA($z*{T*48=V2X+&GmqDkF^rgCN8=X48b$B4g>Tupywy6IiA6SMFogRM~Ya1 zEJQNnwTemm)w|Blx#1OIh{}k1q2^~>J|b_&7XoYB{VAYQZ$*~Aky~k(fwsm(vvvMk^G6_0TID(Djf|4sb@3 zg})T04bbxlNwPQZJ`cFO&rNF=*y|stmJsd4X2>*?t_wI7p!x4-zYsa8#h>X?^Wseu z9R|{y6eGz^hKaODI@WLsQ_GCmP#yW?QYYwZZDX+Wz4*z9mHl4@452WU2Rj$-C5r%* z=4e9!ALlf$sF;M@Y}_}Jm1mliv;AX3Ug(`v$7t4ta!lCFDG!Y~d#AykCQj)J&KIM& zcs>8YXj8-Bw0)HYLG&-3nA+8uR?IlY=s|2G8zF~@21;T3Nf2N6W>vOBD_WZ6tnj(V zJU@8UISfzz3j*P+zB=9j9%F1n=vzD0FUeIUuuR~JMYw;Da+#N%f(mirf~LU?*Xo`6 z9vyFgD$FqF+!2ShHa4rm!wcL}^{{0{M;)h-G z+Oe!;k23M{0#im;p)$MT9tvuSU6_;dv^TIIlpj5UT$Yi@$~iG5eaK;fSi?@*=yO&k z)mMip3hPlbQnBJ)DS>d+>EV3{5`ku&YK*W`4^h=umR#T8X<5zFi^KWsX^+_#bDxd~ zSN87>8CbchWdWZmtYCj>Wi75BVVLBqwdzT{P8~+}S?m*Qic0eU#L3tSQXLZBDt?%~ z@>ThLNC3NjP)1AaHVO;dsw&$fgZzr4v+ok>6u(&jALZikm~1Br^X?v1)GA&OB;*rM z{_$VJ8+$|DmqQ{4V$Xwz^v$9g;K{Om?~@o%kKzOfF#S6pRH*@_LQ&KB^iuHH^BC-1 zS=Sx!@`RaKOu`L@#j0@}Axr>0cwgTRe3l~@>p5<5jP#yzU}sQ70?WtEn-s7CDcZ4G z)_z~=5YrOcdQiu+wAulE#&m#$X}j&odGOjAVFP~N76Qz!d@%pyrPIZVx%Hgofp*Z_ z!&2-}0C2eCHwI_Pg^TX`^WVP_m&usf_D7fE)XH-Jiwd2PAx-r@I6OKp9(3HV;=^Ek zu(It##GTvbJTUNHd>mYwJV-l)#1fvK8^bosz8hb~XD$_+l-6cI8YspA6az0pbf*Al zo$?T^cw#Ei{8y`?f42r|oA7n*p`C4oq+GFMB`R`bM@W$h(?ek!f=hs-fMQD$w1zcm zNniIANB7M^{lrncCV*?TV~tJaK@mY-8+UX++`c?N4j@w$z^zd*;RB#I7+1rft%jfn z49vT0kkByofeu{%y)4l%EJ9WU8FueoLQIBQy;+L$1=9SJ2yzPpzoH(+rv<^t5AZ8P~-t6(RE8~60uUYnt!V3?FF9qrmeD zfhfB*57}}1+8yibY(Cr79G-QQ`28!l0GK&&D(I(vyZWKK{Z+fQj`=%Jtb~@z5Uvr7 z5x_3!ya&JATv;ym9Q`zk9(7iQ5$xh+OhIF3DJmW#(c;1VzOY5h1LCzdgdbVID+-l6 zAEi^&d2iEHN6#kMr-HMJB@N}!}ka9e1xIk<0xCRhm8L|T&WNt`nky$6*Ur8 zflhl+XX9uG|E~35u4*`)pNb=PFOC=}k?T(QZh7N0bTS%hjd;7Fn`n^M(y8p`-%K^o zVSh>7>O07AL2yBEM7WoAz#cF~IF_S_7D0wcT7=0BUK6UZN`~27Uwn~?f%5K$Otq8t zX(<4V2=cuF!a@zXB_2T_*%=BVH>M)Iso-wVp4wlAY&dS_3r5P#xeA4&7N%9^3r-a0 znnOi{1a&RpqrieXI|()#(6L}nrBKme;XkFYDHupp7m!gf5-TVK0|+xBaiF4+)wS0l zO`2xlL~~&nx&Pr1nr^!6_#EqPS=5>t=ZZ-pi62$%UJfx#EbWNkhe>8&@iaG=Ergs_ zXf9E(l}(gpk5&+tJ>*!+9fi>%xeZyvBP$8ssR>ge)hi!4%_+;|WhVf7$kU)Bw%1a^ zyIPW4;fUyPJ}I#b!L<-Hu&Gd}DKIt@N?N;eLSR*)#fpw(b~aXxS|=^A1KWcF%Cmh9 zCapx8ii<~T9$eUnDj1uZ&Sgi8dxd+Us&JO)M^XhW+Clgp3~$MvYHh5+mKANSUr3j2 zD>$CFijbw!hF(>h2SfftJX6s8Rd*xUT(UP65P@?0!U$kWxhzY^9XI$EUtIugj4edw zC8VSGY^`^93dDpO7z5EnRS`V{`mu&T*(ykopgg85CJ7!$8X*ABt%i1gRjW~*`H*}q zN#KM|qB6gUEvpOqy?J^5{1kwFnT?9V52{DOXjTAr%{xazKMj~n6a%hTm~XYMrV?Y2 zn#4#3Z?AII5G)*o`f5WTw%jDZ#2U}!QB(?)ThK>>-6E2kPZmLM=0rTIp*l|pj|a#S zfm1*^Qh)^0rQ`KF@?4qlhJPe9Ae#s0y>)~(wcQg+m8fg33?K-6$8VIF(KMAAIH?d@MdM1 zxirA(Ibf&oQf~k~?UYL84%U`kta5GTiAMUTrPpM1Buc9Fc_=g0U1t^1LYnSI>#oyu z20Ei5XtlYx=>~IrrWj>~oT4&l)_RW~%o_R2)td=CdPjyX}402t`cOQA>e!3d6m?BnbucE*mf=V{0vj zAxa`kb2h7VyI`6v877lhD{#bq4S-qbJ;@cBPfVjdZY?N_-)R?ovFi;ZqDrl8(9%N3 zxlD~j)>bV;^+YMmDjUiq%My2gv@l9x23A*Ue{yx!>wfLy-o^MZO{u7DSzbzlXBPwn z9Pn+r!`LqC0(zJc(@H=pE?%g3P}t%-R-KM0M@#M3f+(Gk~Ciz=R$TN| zw7zsh4*$px&ut=eKO?n4U#HDvf>sjA{T$p%)vQs`Xq{YsHK6^pI}VL92Aff`bO*Kf z85yLwG>`smF8ELl3M|L7RYvEIJQfrY_vilsGeFG0qsyiH(1>XY;kmgQ?Hwt`+o485 zL+im?z0t<|Ci}W}992iyc+0l|cXH#!jw;P5*Lbd*?S7?HJbYt}ad0dRAazlDZM>=7 z*g2F=ah{GjMj;KBb;0i1csk&e-b!dCsX2W16furqu#0w-YrI_2GEML@s_bhIG5esV zT?pE;+&TpBwK4`p(OwjmkNxqgL`-cG3NUwr-L!>TfB;-d6aLNxoKyZ_Z<;ZeOd)@^ z#fGezh@mvg1~fO}6X|;gV~NwB{0D#m36Z+FH3F=DX#*v!6Z{b-8=G_~*&MP^=>HN4 zqmT-|UnmfOMDN1X{XpCdYmHyNg9cr_D4!(NWf*{G{{8plFOT_Yb$EEVT9cXJK##vO z@*lqwqpW8ah1rnvf8+lNJozHYY3GXnR~TW;GT##GA+{&YfCNGMRkSU*WY=w@uAm)S zDFhFRBHpEQqbP~#naF-WHnGcWXFmC9`GJo4;|;*3WdV?1AW7I5lY==1g4-v#t-Ux zf${coe3ImuREi)6%(7j>;fT7CBow$`y*}irdiDOt3v_1C4Gk^1_Z$bhO`i6=@}6i) z0mhj=bXJ-K%7vpK_Ut0#Cn+Lx83WvFJU}K#S?w?OHI|ZYg8GHs9NcM!?)qbbcT|A~ z7vwh9JTrIdOS0#d@6j1$qbwJl%;}WETGWTRBCzd_Okpys4*A@M%1v zM^7=B{Y~L!nfe9YIxIdXUA}yA!Ff%!;!=!0U}8(C+7w@QcL%dg*S_j%=wXnG0*nx8 zQ`z@;{^i?ROI7#d8PDpa07B6R_bH$;f1?!Ndj%kfPFRUQ%w3tie^DZ(I(P00)rr6e zu!43^z2W4y1k#RRIVlIH@EdTd8oX;`ByFZP$PZqcibd285j%n;)5UNCDO&%|L-xv-enoIPaP_ zAYUrt)Sda;(FM1e2_uv?wu6v~Aj~5>sQ0+PsZF{hcRvKAvX?@_hzUsY-irCxhnG@| zRoUyn7y2*3YAa1HUZ+mbvAmK`^b7{MYhhXNcfxKvg8fTL44GG$hlG&SghbbyUaI9e z!Q#H63F=Fp6JP*$jmofgwlyd|E(xif91->1=HTAycH8qU@GUgSs@KgB2eQbXFemrA zgE*U-`vsBr3%XgmZ-Z~eU%qYsvA?bFG7Jh|miDk4`<0bVPcRuUFYA0qUF1?w@bV5h z806Fa+glTzg`pZ`Ke1wCGzh;5eZorPQX_an1Sz57<3BN$pb;7^;?uXG2KDZW&$l&+ zbnUnXz>aO+r#;0GoCsRc{wM9|;^9H?#P-XK{Z9&H_3*1>TXSFLF()8oLX9q@__n7N zy8b8NuG@)l+2^kJN%hCw1Gpa7Uhy>BK6m|?vUP7=NpIO}AYJVz!_Z5*3}ujw>*?W2 zSntfFwEFks{syojR();t^8XJm8<&|HIAKr(*n`}%fiIt|K70St6W20AcB6i(rBk$*o#$9)KKj$P8t@f`KK?%MaH~?4 zxk?7o1wz9w)uB8WO!(TGd`G|g!wqE=ORFAW`rMOWH&o;6M@=wqu#g3a?ZcwFu8LfN zeu8#37MO1Fr_!krN%d$d#Yu;uSLJJ@El(#Da=lyjImu6(Wi7oYdL$n~v^(IH<~l_y zW;MMhCb1lZ(Ym&o<%Yyfv2C!Ip62*ep`Y;`E#Iy{CsJO4Q=&B}pOWZ<`0kDW)u>uB z1D4a_&n8w6=S8v2gQFQi^2lyfSWYKOfrZYoxLunS2bQr@X*(6di)d;sqXsMq@fF*m zO7ta$;>)>K7Xl|PdYPkZ0ZWYJr+LXIos0#dvq_h*(eRnG7Yg79fK2(KHKKA}t;`n= zD#hfbS-Pqr3=?qJ0>h`yWe>rAMRZ&&FJcuiht+sKZd z47EuBa&T8Ii8FDI5O|U+k>>qTZryw*9=LBEF}qi8=KP>Y3jQ|HTDZU!9Z6^G5Y6&S zQeh4ulK2vvBBu(6A`XPqmYfB@G{!E`C$$23fuRc;N=?ZMUjjGX9|lgBA9v4nB$VB4 zJUe4tCEHpU^T|Hk$OB34Cwa^VFDH9YG)Qh{N66r9e~AQy{U;&-j66V_>f)JHTZ_Iz z1IeE*Pd=_NxBwc4*5h~1q2w&^fWS^S8aq%o6hhm0bulEbej>Fo?LxdY5z@q?yfvYy zB@qKw5G;Uj&O#EvrNc`$#|~nfk#~!xb{uxIJ5q>~T7ZF19ed*=5R%ILcJHhbGqc%G zo>+wuW-5%{g&%X>b+o%eo6BSqEl#`+jU(6F6>OQ)VCJ_YLmS;lZaH|Nh&Sp7>(P_#i3nFO zgr27& z(8VwI<~6KOtw==71z`hcYa8V25$1lTGds+D(&^t4uPM`;^EKc72|nl&ON4JqI~kiX zZCBYqR)tCG0r?6x&d7~Ovq1L#Yudq&4r7+T+C4|Oh6fVB2S>@ z(shk6F5AN_mLBAvO>nn1oh^=RnZAVIgi9tmULL~VhG0BN>CrnE5Yr{zxj-UpBJNJW zo4)8ug>GNoUFtLyVp>Qtt#Vw}vmw%_WzE_R0yJ4`=FV}N!Zl;(Fiz~6sdEsgd(EL6 z9w`cIE}i3S#+~g~eS(OsJGq2La&tK4ifp1Bpc$#=KCoWJm$N?**dVE61D{c-gpzb! z@a#=!TrnR=)wO9Aly+&p`gC}tc!RZ^<5=&y*YqM&hBJc1Go76mR^V0Cm}B5Vpto6B zpiqL$QK?Vf%Wha;>}#vD1S55>VaL)Ng2riWArgF3ZX84UHg5kjC#JKFtSRV%M%F}e zL3^?vsSb0uq=winY>9o6zSYCWK`Mx{d2*xmpr+q_?x441EhOJZSGe!0eC8>Rpx>GPUC8fV z35JB?9p*wyHoV6-9~UK44oNgg0kuZcC*1<7~1gQia;Iy($K)!AkL zwR3D|c9hM&>q=JWrYX+L3#zo0NsiWoV?F;`>8#&ho9^IkMi0^H_Y55J2v+&#bq9~q z`XHDXu;w>MxNc=>!o>>S*2KQ^G9$QKE+6SzO-s;}lDZx(@2+2b*ZlSt9%lTM37gTD zb&aA|lSZHkX+MRzBP~Uznw%*He}11o1ubOyNL!jximnxFI_EL4n4kLB+`i_QA|)=hFxs9K_9rb zD%G`I$r;)JgMFmh+T?Bun2NNrmh1jYazX5v6=j|kIrn0noon&8B$j6TgGEG0A%Ou@ z3KoY6?tnTsYxGR>_uXYCo2t=K-;6WLTAmyznHq3Dp&mv&9pRH~8Qq+K7KkVFd!%;@ zFFELGH2IYiM27@6*L3W}PzuZleMpTI)>T)hz~>pSf%m+0ffjxaF}StYQFN~73jE6o+1~~%McZ`U1@L2H z)y*%lrfQ0em#NVAa)2h04@Zn5DB8iKAYd|3s$(rCOHytE#KXWn38LcD{f9OiK>nK4 zl%=}ybt?6JZ6(nRmr~~VwyBGpQfGNf58mui!uK2dBrd)pcCu9HqC;opa^4d?b}uh= z@A6!?vZ%IZu}Kgx`)E85C0V&VLVdI6tG!^5oSw5ktmQDC_a6(Cy$-ATu0K)r^Gr4u z>LgB~T+*ECRt{aWD`CrdKfb%>#O@i$8UM?&_vLfJmi#uQeg7SBl6brD+ep*xL26~m zk9)rBN#XwvYsSNZ>P5NDUzdCh>XP}}YKwQFq(q5tH#Gq zjcrzXbPFm$?Em=0DRS!Cq33fiiRmAil~K6Jpyn%&W?EOdAy#ltrzhQlL(g+@UnQPsD zsc}j7?|(zJT80sr-4^Ii%T3BF0|BT~u&CVMh%@u=?8G)MM4Kawyvm3F#K-$%IIfj- zoaJDOZJX-&ZinGlSUY~(WiqusdsRTH^WX7XM2;brK?nH>v-|RVj`0=GW))cfv@DJylX0{XRBfXRnPcmStB)Ln90-*Ed6!>*`Xha6u3zpGqvWm4oP0v8RdGq90!; zeEtUU=m+NF8TFp}GQ9Zn@xuJvT=&;KiMnzvip*U+arf2O7>CQUcPO`30#{n()?cIL zJ?)ogOai=%`#C2S-)hXx{;dPb(Z%APUK%V4)lvfLJ2D@k{2bB$42werx}Sd(eAd9h z*JKR5*T-%RBDb+?CBvT?w;=X7W7*t4YxsED5Uvj0eL8)%GTs{gjSj#*OkK-F6$>nB zH(E~xFXjx+_{>o`RtRoD&Y{BRnJ2JSDGW>b6@D;GRHK_o#gd6ql+b%TwY;t2^m*aj z%}rR*HaT#0TdF{gqhWjZM`ojH82FW{-ra*QICIB2V2p=nHk{^wW2`V0R|XW5}K_0*}M97mNGFy?yi=1 zERXrGUVK;RS*qssl!pNCw4I5Y`WmrvceYKXC4#jTn`v%#e=>l**A*Mh&JWm>m;B;P zV`H8c*G{uM3Fs;882DBmhIY`b+swqBaGI_#p9Y?(2(}Y*EiMF3bB$r2nBMYR2aS2k7Rs( zpd={=HDz%hB&r&vE`Alv1V3YJ{XHh#)S4y-xE5;Bf6s1e-#56;n&=Kt8bHX8GP9i{sjP5b)0wPV z$8XBj(BGdwu2!=Cb?06iA?+fdmmN5JaS6)^qXMIr@T#t|c8!L%)_-+lYGinaG71X4 z^xg@TP6XeFL6U=%&smv^B7i31rIbG2vEL9)Tkj-HB~Tnn!LQVgY6Op%BDB=x1d z>>Z!TZ_o*oR4ZWW+%p;;zI;&f8JRk>?X4_lCUbfoPu<@>s&{9de#E?i*JrNfH4gt>`FxDC`?HPzf5>#n zeK(IB+xfhs6UV7?S$`R^W=e!X8cJOFaU%Dh@AbMROef(<(5Ipl|@@|3pn?GdSGj*~lsb zGpRt*1|uZmuwOArQqLl$-KvV7Pge17`WLQ;yA!U?cIHKH5{D_Ok%6VJL{|7dQ zqjHv~V3ww|&UEobt052@qU8A{@7js!5Qe^Nt9pBsisu7m&CUx`^xAdjq9+EH1mGZ$ zn;-(XLZ#p&02ZiNY3*{Ur!OlA!_ zXJ7w`$B}__q&5PfZE>9i!nLHPn(QE9mdusPr{rh{SOf>F1PQu}vd0BpC=nE_dy9ZW z>xGFp8$5|pzV;{@Uk=3iW zW@D?6)OKd-)L#2;ulv3JsIstj>m8~ObLytm%L_`nmhe%MvUBn}6n{$%8bS8Zufe#o zz6&l?ala$2-y}Po2b>GG=huf8uw9C+QLkHHtCM*ER>O?@c}nQqD5 z+k1Z9R6_-L6Rdiu*j{v$>^?oo9k2XgkYB1?$+9IDkrryhAl~hGl9+c|68n14LBK?R zv67^TbXec#LO}yqvx#lZ5Uv#)<8lyYPcj*HRZEG1akXD;(JE>1YhI|_VhfgCbb&JU zkQ>sCKg8y?m}^PbMO{j`lptl$ldhQAZz_g~ zU%ksh!y4KM>x48YCvdR5C)r%*oadN>&t3Y|MJuOX*{s{lQuKG3Rl-N zw~)!wV~s5i-mkJlA zVvI-{OT$)BfSYKoP_*kRfV5G3^XPq;I1J;X0874{}D_h(Fu&Pz&yXvi-r|Bz7b0|=82$dFDbu4*8Oul z``iX=LXakzUqxL%$&$dR~{}nMTg1!N&#bJPm6&24E>PXFemxi zu8#|)tj!a9w7s~1sV@wg7h&J}H1+vGw>bOU>M8dFy%J;@^K(wuyeYw&@JDU+AK2dM zgMJZnlF&l_c~4&XzrmlQj8OEO-nUKrDSz_I&M2J{x;|-A?jlo(;b*7^@GXgqjHU@@ zHA35$$Y63q9@X#SnnPOirUdH?cQ1&{N)%=tk@b}#B1HG&zN2CSg~{dPdTH)-@)U6O|Nd#-*D z>i29lT3EOME-v59NB{N<6#s0TrNETg(%0iskoX-X!W?Ms8N8uDwNdoT&3rSH0joWG zl;?>3!P&Lt}S4m5e=w*11=g6n;Hyg!W7urrVoqELdU(p2_85XZJi-% z{yLavcgq)BAb1vxu@sQ6t?aCBn|a#TF-C+MTkCq7>G9`8#vKJ%AGmGf0-#ilRjbd+ zbb6R^O4Mk&ZarWZ)}zFJ@0t`F}0Ub*j+kOp%814sIZ%d zZ4Qf%@HGZ*YoC#>2i;6v5`W6x>0Q6#;1D@egsd$L?s(xEW5BFPP2iH74;tK)0#L_- zf$8k)-LJl{e1vzrw5NMj+6m;?0Skfd+)A8LM#7%P#Y50b3>>hi=QlN&uLBg+v0zB# z7fgn}u|PYPc8m*#5cokCH?U>|J%@{-D9f2SLwL_&tpnW*butC6B85J*XK?u@#JQW6PGuEFN>1l@xJlyAp1HiN5yY`T=5X;Pyl@wTUd-wXrWAiI z5nKzGokF8vuOni(Tj3sSwI(1YKC=u!piT&=8&F>wsd;o2#Ta^*+tuP}0?ypmjYoAB}r;yF)frj(H5^&`BNH z6Pe->h({>3G?*lExVWpEsQ^q;QB4qz5l}{hG7M^c2{)T*0Z`9wz7cv=dQfh#y1Tc5 zeLu@LG)L&Nrh)yeQKb%c;H*`B*EdHG7~|xT=+#6H4(%he zZcHeQubr(NMAz`i1a#e(&qf!U$zKZgKQj)8MZjkAa}&pSmExu;&m#9}U_pj90`V!* zh8}(%e@M7AY6B0MeVYIa(yh&siP5sndAPZgfqgGaazY3<`!OH_d5%fYSVm*c8pvHt z`iV0BfZ&YKsyoKK5V9*Bt z7n99rczmF8`V;vOl`zrvx@rb#oCnEk$KjxA_RNURO@%&~D~y+^WeJkSRv#EmniEJa51DeAOc6Pg!ohIf-R!5JyAC2CSsUsMVVp5CJ znDe{0A~3#w$un#b*T@pf=l_L1-??sl6#?>fDv`Kxo_#V)50QqJ^~O9K>;2c2S?(cf z&5Hc_{{L7cAL0-8`gAx&fDnqA=i<)D5W#|9-uX|C5gCs_ByRPm-}w$>tXojveB>#L zNGr{=_LyEr>&+V{*-b+&r6E#ZOV9vH;P14a_F97F0M8a>$@vFbA7PK()Y{m zp5Z;;*tYb?WiOxMN50V}gS{!}m=oB6)jSZvtM9GC#OhGiYbEz}Y=QlM5p#*&2ht$j z9G8n)jz3-gFP8ofF_-*j!W)EcPPq^$?`zEL81uv*l<1v@lrv->S)n|&(I!kG;t85} z0(G+cnX{>oos};}kV$UUbR60b(w!;43|96eM$&!Pmh`KazqU6(*L5f4Raj6n;z-U zK|55M_`YN`A0TsBZR3{@3`zkv;MajgQ^+RsPx?z+VGnBg`vci)emf2MaCvRj@|#gv z6s&9q?WeL~WJy8OfV9M^57Zpdj$=jKULJNeP==v4ro3V&NJbVf07&>^EHuc?HuO^5 zLw)6V!_}2vuh=DIrhvFuyiuesR#?B-YCG`juLI`<23uw+*;)SFg6C|ZFG%=<^syZ0 zlxh@SCA?h!B-{ki8Ok+MnLu7P5i6zHk2}0Xpez8x>Sw1qW-J@Xa-mcJo+{bGV&X?^ zbNtOgeKrTExNN_E-AZ`^HW~&@9NP*PVmHkt$RJuHyRuqb9h&DVNZu=G;C!BOS8U5q zq4J08d~>>g+Cqh`3Rk&Zhjyo?NP*};(V0`uB~^y?ph$q(D~jLKXC{tt9Xr=~p~-mp@mFPKl8olFS%E3^EU0W2mNqi}g}G zPRuHfy^FUak6Qfe%EYJ3B|p^?p=ykwzMOgDTU;9CfU>Ei1L}oOsT@%}ScC|o=1@Cj z5<@}CxkxXoUSh8$l(I5N(Os}16Vl~9Ho4$97Z`?O+3JJU!o_FU?9}}X1^un`&-opE z3hsn)X=L#cOXSOk54C!ihCPwm$3|Yv>=8b3=~9TJ1j;GdQV`X7>FrvZKP}RlVLKv6 zcI&fy{F${Up<0UI5U!w=a}P_@1Pa!9Oq8&*6yY-9DL&JKHcWjM2plzx?Wx zGOtB^>yMPjKZaVe81ZJI;TQMO$!G8=fq1Mh0+6r&-BSNUdK~U6ph9ggl2&`kIDnl^ zqxad-kPwEw&Mz7r5OyyODsArK_~+%?GC2%iTjW|W^PoY3JO(u>>d`RTgSD9}ohm5V znxX?w?GsX4x*g^{9cR?>1I_wV>Q}hU5Uu~_u(D&)v0MFWsU6|ukY;~?+%QZxDjw24t5FuESw#%{MbhvWNV$=qcG}nIOkKkFJ9Qjwd@83XrX5-t>0taO z=#;GVpm(~ZW`V+)*RM~e!Q-Zrd9SZY_}d|b%RsHxFiJajlV{DV&oBw-=sS{SP53A7 z$3EKZ4hg(Z(*Fi|=^N^8@DhwD*bDBZl}GEJQ^wj11~;cO7a?wM!#x+h%T}Y1TlWu0 z#Wru{V7Y#Gz~S4SSJ}SR^1NK!O?)nJO!~K|M0DYdy5B49!nh|F^QCH|2CQ(HDDFQS z*TRvY`Y^>$-Nnc0xEtOTIe@NPVEN zB|nF$`yya0UAqWvl!v~5!zJLK|0-D*xASiq%8jl{54S7GZXvF4^E-DE(fk z3ZpM}=#AAYuj2;~7e+^lD-Y6^S$Efr>w*-_0~J>85>&(Do*<>!Mi!(=?i`7dJ}*eZ zgiHMadQyxPc}RcVaencWaG1KxVSmL66zi^gZ&ENdAkLZ+5x}{K|qhipDq*t?k=O?WN?`(ORBSP^KQD zu(yrKIfB1emI_W24a;=3K+4y*{$X#oP6CJUONhvL7RS|OL5ncE2Y)J(#xZWkw*pSi z(HP240hSA_r5e$Y?spS}M)Xb^hq)c!3OYH^2+Joa@J$uTaaI#^RZo|!`9AND*yVcu zdI=&(M^(FYo&(VwT1}F;~Zb&reK|J=pOV;yg z1naSH%o64Cu)RV}rkiNr%ITAI`&X{dOeh5XG5=RC{(?r^TI$I4$|~{({nkY{H~%#` za%+33m;L2bgZjS+k(4U=i>j*?`#xSvT~%a>G2zPvBH*J#2OP2G5<(AH z)>;tOI%9kR(tB`Ty5tK|xmO6Opv~y!2c@l(kQ4#k!F+hh*vPV`y7dj9TgQ<##pARG zh&h1KR$!90^``$XsYMe`vS^3)sEy9~Yg9uanu^#aHky1-yDQp3+-#g)bWvGoyW5z{ zysMjXCzy5z^xPQf&($wt!`Eo#q8lhM%zBKYrxB+A0ba%L{2-}D2{cQUll0vm8@vPS z1lh!`cZDo`r17=1)~F4oiEk?nAJkR06=^6Flo4T{`!Jq2#3S6p{KlbG4c*!w0u?** z;<9^bJZEEwU??7fK;T2%s}CHj_R#bpVaz62!y^=(QJ>an16_$T;+vk5#;7GtkeBE+ zbXU~yqz%$|Pzp5jN=j}Gn3{S92)a)}ySp%-TMC+A6KW~J?U%xA3Xvvlt|-S5Ng8F7 zFp38!H>)>lW6KrJVTR(-_L6`uNKxcY+jwsWBpF9)@u>20h3bt`p?Ef);&hf(B+mA$ z2|0P~p;iXk$ND}hYzdEOY|o*E01R}CBEhLRuhBrA@|f7t6gJeX<1XhfbAH z2@M1Jd*%(Y#jBgWNTenw_j5Q+h^b+#pGsJ^F{lw_Vog&+sIYCO3TH`sJN#z3Xidq} zd_Ep~i7&rv+>awnJNO2(8n29M_QbY5L6_y$|eZQ-FCf3cse z^rW=EW=Ym!s&z=56Pn*Ejb=t>qh-@u@PSrardlgpxG_pOhB#XW1GzHv+o-DqzfH`= zyoOpSoq>`9yXA=Jo*#L7ey(nn=|S)K+n_8rX|m!FogQ|S4kUF%SC1bvZAWa_$dGm4 zxLS_$o@|zH0w{qsRvsr7U>3D}gWa6MDL%eBK?urbNJBF)T$jOt#F=5O( zdeM~|?hl-wx1#OuyDlIVrz~Jyi{d=3<8q{X-u77tQ{40x&I8YE3`O07(qCw*WBB7? z?ZW7OL>i-T$!n%n9K>f`vmPJhUv3e%iKimCp<<=B~GT#)h%fN1>?k; zBnMh9>&yg(T>JsPL`ersC4G{IOL1pJ_g;v^1Z;O`zqxQqRnMEZfT&61V@} zBc`f*p5{WBQ3}ZC%;|NuzMfEAaOI zJm=&eYX4`hOUYYxc5-zpPeF#7>q2^JNU zGe~BZZT!*c0vXXoW(e**rH^S&%cn}(k%U;At(qNEn>tC@w0Rn3Yb6|G>NWrUH$7dZ zW;D-m|C5N4Lq5um*(X#0UH;N-CC^s%mfr|3aL-z2Qr&!t%EJJ>?+^3Xi@e9~N_Uv? zhf$X%lzHh+%7dtbfw4$|jd3+`Ztxm5Ri~j-1BlAG)ktLmH8~EVw%^wOPT5 zFy@&!*7$@PHA#>U#3Y;>uyM&r?v1160`AF{Eq&-6ta%crcNgU(j5vKU>~#rL%|FfT zNfC-cFq4UE#p{wD!D!)W$E55)pjUi*#dkjL>9V?xPNds%9X{;?W%vNuY#02YPNXGS zF<~E9CzA=5p^j!CaT*^7@HCMuFbtWz{16c@caXEUdaSWe-ML({*j{@=4v*1O7`+j^ z{CPl~%l*15>ii$!Gi#)neOWUO<;1O{Gh>utD<{$+K!`%mQ0#ldVGmw%f1>(y%ZY&` zz7>o-;vpdYi+^P`5j`W;%CmmFF#BAJT}mAzhdJlG3#B)-av{MY+GdEfjmCpL^7LdE zwuv#66fMdQ+v;RV(cm4hX|4JW<9u8u0plur;75NVu;0Du9%LZ&43si-NPVG|eU|x- ztDdx`d8_34DOp5zL5ehI%<_0SSOQMQLa|T=rf|BV70E|1D(55CWN*2oIo7lOPWgN} za%P?!RF)!KSU8pLekI#3okm@9(tkGPzRb+$y}A$T&?8mS%I+=Fe%X7Jxh>{+2@^+{ z#uuBVSotK!X4>~Zu}C)&qS9|B7GTA}BAW8>8>S!i>k&KVIp+oUJx*(udBHaHYv)XS z_+q~;B99;bVDojB@I<1~A8(fo$oz(g_1-pZ6|1_u0gTm&zHxb8jjf9ab=oCbyb!f( z#Cj0FkR(`$U$zGCSyS{Kdl=160??n>^MH0dFS|?MXz+kfi$z0PMk{(=hI6r6}T3#>n z9C9a|W|t|#XmiuNyFu3?u1T0>GZQcy&RTQOYHy-Mtsu-X^iqt5rj}HtlOJGBrn zHGi;P{bgQPMQWU^PAn-f@lSDIjA@7+6iV5F6p!`xmkZT-F#fc1y~JNzxoPn?%GspY zzQW?yR&JXAW`akknR_ZyQLtgR1i~2yn*juKbHJZT5LxgDga9!V=^<)@VB-&}$C1Lv zvOr{D6K1C&Da88~8>#hrC_vM*FnhTH=$m>hISfuW!=#K%i6?MiqG_RcBA=6(G2f6L zz$%G06V>3|`NPR0KX9H(cL-(U9m8r01)2HM+zm>l0vX2|t{AffwoYfoWOyqS_4SZq zrXwKO#+}vz)6c3W&D1_fH7mgWJobk|HdUp6i56lrZqd7PM#^J8OCZ}iZN+H*_Hy!x z_t!w9Piog5e#|h`sd%y@;^lT7`W&AuD(*=G^TNt_OKoeBBzsU~osdenY`w18Pqn4^ zdCuET>7=vbSO>YNol^AL%MM;ch4e3e)6Ee0(G3#VG}HKQ%tWCFH&*0FH(lt?hHrlvqJbwKzccv(qJX8ey=AkOz`r<0Kl^I z*9sa*PbZ|=*sM*pQ4vZ4(&6&z>ucVjol1T%aT8oqxQ>2Najypf8$QS;`1F0O2qGw)b6q}U#gUZe(eEwZ?BG?1U z_B&|m@KVAccCw~h<9gJkVRbFdraBM>?o^x<$SIaY0)<^C7bt%?p-u!L$$=$}YF3w; zBvy1KJpeGa^6i^=>kdYgLA(_?Wy+2O71>kSlB&=M9F6s5iztXMBjQUze6el=oemOj z2Z~Rl<4gJ(t!qJljM_g9Hnnvp*?bCl(|PFKW%Rt5doxWKi&9yeU<@$1pAnS9<_Ktu zX|Eh%4+Cc!Z05k6%5Vx8(%Bj6Gh2|-reF?pcc5I3XLYH0f}w$gVW6krgh^bcvR;+bw}b@U zCIywQ2>)avojlPnUR(R4BDqM8iD?URmQ~~I6JvdDdCY0O?i44@z1I!f?IxF%KB&Cc zSYxWf-ys*IjQn40Vuns2)6#bc0U|8fK?N#M3$;*%GSopG(u{!RvIXZjLh&MRuNp%?xYF>SV$ie3P!Jr(V3OO`tMwL)6MDY3o(xwv z5)6u5F9JNu5Gg=uy;yX?0O^1~Nb&~@3cv|X{{iL0e(4APNotdR=fm2hssvEk01{GC zqOXNj2M>xB;|_CMD*OR}yKwXX{fYB*-C9}ObcnRb5O`^RT<%p0j5&Brd_y4MTy&55 zgCfWani$DV9smWy5Yz^~)7B6v&z8%G?~ zQx565vFj))eqDnOij;~$8ur&((K4Mvv*?$<*QBYGN6~ySgY)nhVZ(_B6Pc++k^VL% z{#LVs^T%p4bkh$%`jC%SKw8>W3q%_o2^(&XXd$+_9o4-;3bzwuAPVD?+XTWWww;HI zxaQc0I7a&V@!TFthgD{pZwPzE#agz+&Iwykb{*W z*Cs$>8>*~*X$2qFyMzf~s#hB9;eMfpeMDjKWWhgZBw-C1T)ALN`B01Lwl6C|N5v7X zS)@xc)JHL$%E9oV(~*!0F5eFSjOj|4b-$BwVK_E7n%ub^qQ`dO-e<{r_od4SY9Fzyq%NcGM(`+9?3^Tf{`E4cF>o$3|e+5;-@l`p+}`IX7vaeZZy zch(xv`w_^iRRMg%WyYX}RvXm!CWjM1+A9k>w3?B?FIl9348C#k^tHA;Wle-Oj0usr za5o=6YL|)c!3{Iy{rzBX6g>3&!f^o@xs#N);{@JHT}hs(wbIyKvtI|x?gnz@qK=hV z^*fcTT)#b8uxOj?_-bo0BkvhJjT>HnKJsA}Sb200=*0n0jyJe|?0?h&rS?KxJ=hnK zBL{`|{r!k`GnHC5W0W%>pM4KIyorx4C^*``(pj%qmHNd(f{w2y^WQ3I>8}lB^RK-5 zlIp*_cDIwb?IPio?3!?{bRr9^ui?;w2%H|5WlR5`bM z%RcAsNgrlF&R%vMis27;Qi}!cbB%p&IbCvNQKkm~j4?%9W^zI=tz#qnABa0ClqFsR zIR&QUYu(5~u)G9%& z@M9guR`cN8%m|J3i7Ykp*H#H&6Xu4EzW`+3oUw8QTs`E>IKp6da2;{Lme+B52G5Lf z$wUCy*>lSewf4e{(n4{IXz>S9pnJs+m|28#Be0f?vL0ruW`5lr?2jT9^;U^&Xq{RIp5ovAMg#VHDBg;mY13khvtPc#GrPMqr z-pw63EE83ybx6L)Wf#*GV0%4qa2hm2*KXU9VGN(@&ky1ow_G$N!-`$B0wcs)$Io5c zX!653k2CoI$OwKliqIy5lQ@Vnp}=ad^7)TIhOCB5yBx2?!H!3Oqr^yZ@38s4)}3WT zpnb^vJLP#EXI7n&*{&Ah_#Ge39q3~b>dqO;xA{;*>E_$9HEl5~TF_;)E$PTY5XXLu zyx2{Y`=Fn4ONu1Eo!2cz`CvoNT9!##;#@QVI%ZAMP3rOf>F*Lsy7=4+KvGF#$rN3N z5d=>xyuY{6GE@TRqmJy4FK`-j1{Nb0aeW1xg%mraByKVmKKTku!SLiLzx!i&mHZXT z&*SF7d#`Dg=Z=vN%V1fWpI6Vh((-GI7gr3YASi866rbrsA^uV5s0rC*)v|=hb(%=#NhEk1@Y)W`2MQcRx~Ra zRx|zsBBy4dOigho=1H)wnnnci3sD|@zTKu)GC=)>V3F%5ggd-#B^LK<=M8ekUx2jN zXUtogCxeqgcsv;S!>7=J2ty7u)r5;sz(EC14;~Wf3L$g=ML@d0ijJ1Uu#nYv?}mYL z>R}Y2%S8wHF2ynruZ2KPPi{1Y5Rsr7KY4}0gaau3bg5lnC=Jsp6{Q#l<76T^9b3>= z`O6NxMl|`;)FPC);A#5)oN@sEW_*wzSe%p}=AkP14h6i>Nk#58(*$Ny(9SlQEuQsa zyn4>f?tX(J&O!muDv1Q(!SEyx^37p*h#(m3jrvfa;=7OrX)%ZX1wY&5T{MgroJQX| z^2P9)O`pUouJ-OM>qQ^yPb^>6x~->r+Y?Wnb`Jk=xSOzeCAkENmx{Jt+!lJ%hHP6( zo$f?K7>mE^ELWu%Xu*yL4p0rZcER@hvTpT|GNMO_DdS3MBhSŎIh6hdUVhuVs_ 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 XSJrYfB9A)l>#~PiGL6L1Q2ajv#b^Yz literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.gz b/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..b707b9187153a201b2b39fc3f789bd761d1eb36e GIT binary patch literal 148777 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

T~BR;VS0!&8)c?wEV`b=17Oyk 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�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 H&+Z5S!PnkG literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/10.Dp-knJux.js.br b/apps/dashboard/build/_app/immutable/nodes/10.Dp-knJux.js.br deleted file mode 100644 index 5e25dbc768836013a7731988b29d72aa89796ed7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 124044 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

+ - - + + +{/if} -{#if showCommandPalette} +{#if showCommandPalette && !isMarketingRoute}
+ import { onMount } from 'svelte'; + import { base } from '$app/paths'; + + type SubmitState = 'idle' | 'submitting' | 'success' | 'error'; + type SupportMessage = { + role: 'bot' | 'user'; + content: string; + }; + + let canvas: HTMLCanvasElement; + let name = $state(''); + let email = $state(''); + let role = $state('solo'); + let priority = $state('sync'); + let notes = $state(''); + let companySite = $state(''); + let submitState = $state('idle'); + let submitMessage = $state(''); + let botQuestion = $state(''); + let botBusy = $state(false); + let botMessages = $state([ + { + role: 'bot', + content: 'Ask me about installing Vestige, whether heavy models are required, Solo vs Team Pro, sync, pricing, or what happens after you join the June list.' + } + ]); + + const waitlistEndpoint = import.meta.env.VITE_WAITLIST_ENDPOINT as string | undefined; + const supportBotEndpoint = import.meta.env.VITE_SUPPORT_BOT_ENDPOINT as string | undefined; + + const proofPoints = [ + { value: 'Local', label: 'SQLite memory, no hosted memory service' }, + { value: 'MCP', label: 'Claude Code, Cursor, Cline, Codex, Goose' }, + { value: 'June', label: 'Pro sync, backup, team memory early access' } + ]; + + const proTracks = [ + { + name: 'Solo Pro', + accent: '#22c55e', + copy: 'Multi-device sync, encrypted backups, managed updates, and a cleaner memory dashboard for developers living inside AI coding agents.' + }, + { + name: 'Team Pro', + accent: '#06b6d4', + copy: 'Shared project memory, admin review, audit trails, PostgreSQL-backed deployments, and async support for engineering teams.' + } + ]; + + const launchPillars = [ + 'Private by default', + 'Sync without lock-in', + 'Team memory controls', + 'Bot-assisted support' + ]; + + const supportPrompts = [ + { label: 'Install', prompt: 'How do I install Vestige and connect it to Claude Code?' }, + { label: 'No 20GB?', prompt: 'Do I need the Sanhedrin model or 20GB of RAM?' }, + { label: 'Solo vs Team', prompt: 'Should I choose Solo Pro or Team Pro?' }, + { label: 'Sync', prompt: 'How will Pro sync and backups work?' }, + { label: 'Pricing', prompt: 'How much will Vestige Pro cost?' }, + { label: 'Human help', prompt: 'When does a human get involved?' } + ]; + + onMount(() => { + const rawContext = canvas.getContext('2d'); + if (!rawContext) return; + const context: CanvasRenderingContext2D = rawContext; + + let frame = 0; + let width = 0; + let height = 0; + const nodeCount = 62; + const nodes = Array.from({ length: nodeCount }, (_, index) => ({ + x: Math.random(), + y: Math.random(), + vx: (Math.random() - 0.5) * 0.00016, + vy: (Math.random() - 0.5) * 0.00016, + phase: Math.random() * Math.PI * 2, + kind: index % 5 + })); + + function resize() { + const dpr = Math.min(window.devicePixelRatio || 1, 2); + width = window.innerWidth; + height = window.innerHeight; + canvas.width = Math.floor(width * dpr); + canvas.height = Math.floor(height * dpr); + canvas.style.width = `${width}px`; + canvas.style.height = `${height}px`; + context.setTransform(dpr, 0, 0, dpr, 0, 0); + } + + function draw(time: number) { + context.clearRect(0, 0, width, height); + const gradient = context.createLinearGradient(0, 0, width, height); + gradient.addColorStop(0, '#07100f'); + gradient.addColorStop(0.45, '#0b1221'); + gradient.addColorStop(1, '#15100a'); + context.fillStyle = gradient; + context.fillRect(0, 0, width, height); + + context.strokeStyle = 'rgba(148, 163, 184, 0.08)'; + context.lineWidth = 1; + for (let x = 0; x < width; x += 72) { + context.beginPath(); + context.moveTo(x, 0); + context.lineTo(x + Math.sin(time / 3000 + x) * 12, height); + context.stroke(); + } + for (let y = 0; y < height; y += 72) { + context.beginPath(); + context.moveTo(0, y); + context.lineTo(width, y + Math.cos(time / 3300 + y) * 12); + context.stroke(); + } + + for (const node of nodes) { + node.x += node.vx; + node.y += node.vy; + if (node.x < 0.04 || node.x > 0.96) node.vx *= -1; + if (node.y < 0.06 || node.y > 0.94) node.vy *= -1; + } + + for (let i = 0; i < nodes.length; i++) { + const a = nodes[i]; + const ax = a.x * width; + const ay = a.y * height; + for (let j = i + 1; j < nodes.length; j++) { + const b = nodes[j]; + const bx = b.x * width; + const by = b.y * height; + const dx = ax - bx; + const dy = ay - by; + const distance = Math.sqrt(dx * dx + dy * dy); + if (distance < 168) { + const alpha = (1 - distance / 168) * 0.18; + context.strokeStyle = `rgba(34, 197, 94, ${alpha})`; + context.beginPath(); + context.moveTo(ax, ay); + context.lineTo(bx, by); + context.stroke(); + } + } + } + + const colors = ['#22c55e', '#06b6d4', '#f59e0b', '#ef4444', '#a3e635']; + for (const node of nodes) { + const pulse = 0.5 + Math.sin(time / 900 + node.phase) * 0.5; + const x = node.x * width; + const y = node.y * height; + context.fillStyle = colors[node.kind]; + context.globalAlpha = 0.45 + pulse * 0.35; + context.beginPath(); + context.arc(x, y, 1.6 + pulse * 1.8, 0, Math.PI * 2); + context.fill(); + context.globalAlpha = 1; + } + + frame = requestAnimationFrame(draw); + } + + resize(); + window.addEventListener('resize', resize); + frame = requestAnimationFrame(draw); + + return () => { + cancelAnimationFrame(frame); + window.removeEventListener('resize', resize); + }; + }); + + function githubWaitlistUrl() { + const body = [ + '## Vestige Pro waitlist', + '', + `Plan: ${role}`, + `Priority: ${priority}`, + notes.trim() ? `Use case: ${notes.trim()}` : 'Use case:', + '', + 'Please do not include private email addresses in this public issue.' + ].join('\n'); + + return `https://github.com/samvallad33/vestige/issues/new?title=${encodeURIComponent('Vestige Pro waitlist')}&body=${encodeURIComponent(body)}`; + } + + async function joinWaitlist(event: SubmitEvent) { + event.preventDefault(); + submitState = 'submitting'; + submitMessage = ''; + + if (companySite.trim()) { + submitState = 'success'; + submitMessage = 'You are on the list.'; + return; + } + + if (!email.includes('@')) { + submitState = 'error'; + submitMessage = 'Enter an email so the early-access invite can reach you.'; + return; + } + + const payload = { + name: name.trim(), + email: email.trim(), + plan: role, + priority, + notes: notes.trim(), + source: 'vestige-pro-waitlist', + createdAt: new Date().toISOString() + }; + + if (!waitlistEndpoint) { + submitState = 'success'; + submitMessage = 'Email capture is ready for an endpoint. Opening the GitHub waitlist fallback with your email omitted.'; + window.open(githubWaitlistUrl(), '_blank', 'noopener,noreferrer'); + return; + } + + try { + const response = await fetch(waitlistEndpoint, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(payload) + }); + if (!response.ok) throw new Error(`Waitlist endpoint returned ${response.status}`); + submitState = 'success'; + submitMessage = 'You are on the June early-access list.'; + name = ''; + email = ''; + notes = ''; + } catch (error) { + submitState = 'error'; + submitMessage = error instanceof Error + ? error.message + : 'The waitlist endpoint did not accept the request.'; + } + } + + function localSupportAnswer(question: string) { + const query = question.toLowerCase(); + + if (/(install|setup|onboard|claude|cursor|cline|codex|connect)/.test(query)) { + return [ + 'Start with the open-source install:', + '1. `npm install -g vestige-mcp-server@latest`', + '2. Claude Code: `claude mcp add vestige vestige-mcp -s user`', + '3. Codex: `codex mcp add vestige -- vestige-mcp`', + 'Then test it by asking your agent to remember a preference, opening a fresh session, and asking for that preference back.' + ].join('\n'); + } + + if (/(sanhedrin|20gb|20 gb|ram|heavy|model|mlx|preflight|hook)/.test(query)) { + return 'No. The default Vestige path is the local MCP memory server. Sanhedrin, preflight hooks, and large local verifier models are optional. Pro should keep that promise: nobody should need a 20GB machine just to use memory.'; + } + + if (/(solo|team|plan|seat|buying)/.test(query)) { + return 'Choose Solo Pro if you want your own multi-device memory, backups, smoother updates, and personal support. Choose Team Pro if multiple people need shared project memory, admin controls, PostgreSQL-backed storage, audit trails, or team onboarding.'; + } + + if (/(sync|backup|device|dropbox|icloud|syncthing|postgres|postgresql|pg|central)/.test(query)) { + return 'Open-source Vestige should stay local-first. Pro is where guided sync, encrypted backups, conflict handling, and Team Pro PostgreSQL-backed storage belong. The important design rule: users own memory and can export it.'; + } + + if (/(price|pricing|cost|pay|billing|stripe|lemon|subscription|monthly|yearly)/.test(query)) { + return 'Pricing is not final yet. The current plan is simple: Solo Pro for individual developers, Team Pro for engineering teams. Join the waitlist so early users can shape pricing before the June launch.'; + } + + if (/(update|upgrade|curl|reinstall|version)/.test(query)) { + return 'Use `vestige update` for existing installs. The goal is that users should not need to keep copying curl commands just to stay current.'; + } + + if (/(privacy|local|cloud|telemetry|data|where.*stored|sqlite)/.test(query)) { + return 'Vestige core stores memory locally in SQLite and does not need a hosted memory service. Pro should add convenience around sync, backup, and teams without turning private local memory into a black box.'; + } + + if (/(support|bot|human|email|question|help|available|awake|discord)/.test(query)) { + return 'The support bot should answer common install, sync, plan, and onboarding questions instantly. Hard cases should escalate with context so a human teammate only handles the issues that actually need human judgment.'; + } + + if (/(waitlist|june|early|launch|invite|after)/.test(query)) { + return 'After you join the waitlist, the June early-access flow should invite you into the right lane: Solo Pro for personal memory, Team Pro for shared memory and admin controls. The bot will keep onboarding answers available while the launch scales.'; + } + + return 'I can help with install, updates, optional heavy models, Solo vs Team Pro, sync, backups, privacy, pricing, and support escalation. For now, the fastest next step is to join the waitlist and include your use case so the June onboarding can prioritize the right workflows.'; + } + + async function askSupportBot(event?: SubmitEvent, prompt?: string) { + event?.preventDefault(); + const question = (prompt ?? botQuestion).trim(); + if (!question || botBusy) return; + + botQuestion = ''; + botBusy = true; + botMessages = [...botMessages, { role: 'user', content: question }]; + + if (!supportBotEndpoint) { + botMessages = [...botMessages, { role: 'bot', content: localSupportAnswer(question) }]; + botBusy = false; + return; + } + + try { + const response = await fetch(supportBotEndpoint, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + question, + plan: role, + priority, + source: 'vestige-pro-waitlist', + history: botMessages.slice(-6) + }) + }); + if (!response.ok) throw new Error(`Support bot endpoint returned ${response.status}`); + const data = await response.json(); + botMessages = [ + ...botMessages, + { role: 'bot', content: String(data.answer ?? data.message ?? localSupportAnswer(question)) } + ]; + } catch { + botMessages = [ + ...botMessages, + { role: 'bot', content: localSupportAnswer(question) } + ]; + } finally { + botBusy = false; + } + } + + + + Vestige Pro Waitlist + + + +
+ + + +
+ + V + Vestige Pro + + +
+ +
+
+
+

June early access

+

Vestige Pro

+

+ The paid layer for developers and teams who already trust Vestige as local memory for AI agents. + Sync, backups, team memory, and bot-assisted support come next. +

+ + + +
+ {#each proofPoints as point} +
+ {point.value} + {point.label} +
+ {/each} +
+
+ +
+
+

Early access

+

Reserve a Pro seat

+
+ + + + + + + + + + + + + + + + {#if submitMessage} +

+ {submitMessage} +

+ {/if} +
+
+ +
+ {#each launchPillars as pillar} +
{pillar}
+ {/each} +
+ +
+
+

Why Pro exists

+

Two plans. One promise: agent memory you can depend on.

+
+
+ {#each proTracks as track} +
+
+

{track.name}

+

{track.copy}

+
+ {/each} +
+
+ +
+
+

Always-on answers

+

The support bot handles the first wave.

+

+ This is the first support layer: instant onboarding answers before anyone has to write an email. + It can run locally from the FAQ now and call a hosted support endpoint later. +

+
+
+
+ + Onboarding bot + {supportBotEndpoint ? 'Connected' : 'FAQ mode'} +
+ +
+ {#each botMessages as message} +
+ {#each message.content.split('\n') as line} +

{line}

+ {/each} +
+ {/each} + {#if botBusy} +
+

Checking the onboarding notes...

+
+ {/if} +
+ +
+ {#each supportPrompts as prompt} + + {/each} +
+ +
+ + +
+
+
+ +
+
+

May to June

+

The plan is simple.

+
+
    +
  1. + May + Get Vestige into every MCP, Claude Code, Cursor, local AI, Rust, and self-hosted channel that cares about agent memory. +
  2. +
  3. + June + Invite the first Solo Pro and Team Pro users into sync, backups, shared memory, PostgreSQL-backed deployments, and bot-assisted support. +
  4. +
  5. + After + Use paid feedback to turn Vestige from a beloved local tool into durable agent-memory infrastructure. +
  6. +
+
+
+
+ + diff --git a/crates/vestige-core/src/fts.rs b/crates/vestige-core/src/fts.rs index eae8ed8..efebb71 100644 --- a/crates/vestige-core/src/fts.rs +++ b/crates/vestige-core/src/fts.rs @@ -22,7 +22,8 @@ pub fn sanitize_fts5_terms(query: &str) -> Option { sanitized = sanitized .chars() .map(|c| match c { - '*' | ':' | '^' | '-' | '"' | '(' | ')' | '{' | '}' | '[' | ']' => ' ', + '*' | ':' | '^' | '-' | '"' | '(' | ')' | '{' | '}' | '[' | ']' | '.' | '/' | '\\' + | '=' | '@' => ' ', _ => c, }) .collect(); @@ -68,11 +69,13 @@ pub fn sanitize_fts5_query(query: &str) -> String { // Remove FTS5 special characters and operators let mut sanitized = limited.to_string(); - // Remove special characters: * : ^ - " ( ) + // Remove special characters: * : ^ - " ( ) and common identifier/path + // punctuation that FTS5 otherwise treats as syntax. sanitized = sanitized .chars() .map(|c| match c { - '*' | ':' | '^' | '-' | '"' | '(' | ')' | '{' | '}' | '[' | ']' => ' ', + '*' | ':' | '^' | '-' | '"' | '(' | ')' | '{' | '}' | '[' | ']' | '.' | '/' | '\\' + | '=' | '@' => ' ', _ => c, }) .collect(); diff --git a/crates/vestige-core/src/storage/migrations.rs b/crates/vestige-core/src/storage/migrations.rs index fae52ae..2c66a2d 100644 --- a/crates/vestige-core/src/storage/migrations.rs +++ b/crates/vestige-core/src/storage/migrations.rs @@ -64,6 +64,11 @@ pub const MIGRATIONS: &[Migration] = &[ description: "v2.1.1 Sync: tombstones for merge-capable portable storage", up: MIGRATION_V12_UP, }, + Migration { + version: 13, + description: "v2.1.2 Honest Memory: non-content purge tombstones", + up: MIGRATION_V13_UP, + }, ]; /// A database migration @@ -706,6 +711,30 @@ ON sync_tombstones(deleted_at); UPDATE schema_version SET version = 12, applied_at = datetime('now'); "#; +/// V13: non-content purge tombstones. +/// +/// `memory(action="purge")` permanently removes memory content and embeddings, +/// but keeps a content-free audit/sync record so users can verify that a memory +/// was removed without Vestige retaining the text it was told to forget. +const MIGRATION_V13_UP: &str = r#" +CREATE TABLE IF NOT EXISTS deletion_tombstones ( + memory_id TEXT PRIMARY KEY, + deleted_at TEXT NOT NULL, + reason TEXT, + node_type TEXT NOT NULL, + tags TEXT NOT NULL DEFAULT '[]', + edges_pruned INTEGER NOT NULL DEFAULT 0, + insights_rewritten INTEGER NOT NULL DEFAULT 0, + insights_deleted INTEGER NOT NULL DEFAULT 0, + children_orphaned INTEGER NOT NULL DEFAULT 0 +); + +CREATE INDEX IF NOT EXISTS idx_deletion_tombstones_deleted_at +ON deletion_tombstones(deleted_at); + +UPDATE schema_version SET version = 13, applied_at = datetime('now'); +"#; + /// Get current schema version from database pub fn get_current_version(conn: &rusqlite::Connection) -> rusqlite::Result { conn.query_row( @@ -755,17 +784,17 @@ mod tests { /// version after `apply_migrations` runs all migrations end-to-end, and /// neither of the dead tables V11 drops must exist afterwards. #[test] - fn test_apply_migrations_advances_to_v12_and_drops_dead_tables() { + fn test_apply_migrations_advances_to_v13_and_drops_dead_tables() { let conn = rusqlite::Connection::open_in_memory().expect("open in-memory"); // Pre-requisite: schema_version must be bootstrapped by V1. apply_migrations(&conn).expect("apply_migrations succeeds"); - // 1. schema_version advanced to V12 + // 1. schema_version advanced to V13 let version = get_current_version(&conn).expect("read schema_version"); assert_eq!( - version, 12, - "schema_version must be 12 after all migrations" + version, 13, + "schema_version must be 13 after all migrations" ); // 2. knowledge_edges is gone (V11 drops it) @@ -806,6 +835,19 @@ mod tests { sync_tombstone_rows, 1, "sync_tombstones table must be created by V12" ); + + // 5. deletion_tombstones exists (V13 creates it) + let deletion_tombstone_rows: i64 = conn + .query_row( + "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='deletion_tombstones'", + [], + |row| row.get(0), + ) + .expect("query sqlite_master"); + assert_eq!( + deletion_tombstone_rows, 1, + "deletion_tombstones table must be created by V13" + ); } /// V11 must be idempotent on replay — if the tables were already dropped @@ -827,6 +869,6 @@ mod tests { apply_migrations(&conn).expect("V11 replay must be idempotent"); let version = get_current_version(&conn).expect("read schema_version"); - assert_eq!(version, 12, "schema_version back at 12 after replay"); + assert_eq!(version, 13, "schema_version back at 13 after replay"); } } diff --git a/crates/vestige-core/src/storage/sqlite.rs b/crates/vestige-core/src/storage/sqlite.rs index ddc17dd..c89a31c 100644 --- a/crates/vestige-core/src/storage/sqlite.rs +++ b/crates/vestige-core/src/storage/sqlite.rs @@ -8,6 +8,7 @@ use directories::{BaseDirs, ProjectDirs}; use lru::LruCache; use rusqlite::types::{Type, Value, ValueRef}; use rusqlite::{Connection, OptionalExtension, params, params_from_iter}; +use std::collections::HashMap; use std::io::Write; #[cfg(all(feature = "embeddings", feature = "vector-search"))] use std::num::NonZeroUsize; @@ -199,6 +200,26 @@ pub struct PortableSyncReport { pub archive_format: String, } +/// Report returned by an irreversible content purge. +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PurgeReport { + /// Memory ID requested for purge. + pub memory_id: String, + /// Whether a live memory row was found and removed. + pub deleted: bool, + /// Non-content tombstone timestamp. + pub deleted_at: DateTime, + /// Number of graph edges removed by foreign-key cascade. + pub edges_pruned: i64, + /// Number of insight rows whose source list was rewritten. + pub insights_rewritten: i64, + /// Number of insight rows dropped because fewer than two source memories remained. + pub insights_deleted: i64, + /// Number of temporal-summary children detached from this parent. + pub children_orphaned: i64, +} + // ============================================================================ // STORAGE // ============================================================================ @@ -219,6 +240,7 @@ const PORTABLE_TABLES: &[&str] = &[ "dream_history", "retention_snapshots", "sync_tombstones", + "deletion_tombstones", ]; const PORTABLE_USER_DATA_TABLES: &[&str] = &[ @@ -236,6 +258,7 @@ const PORTABLE_USER_DATA_TABLES: &[&str] = &[ "dream_history", "retention_snapshots", "sync_tombstones", + "deletion_tombstones", ]; const DATA_DIR_ENV: &str = "VESTIGE_DATA_DIR"; @@ -1814,6 +1837,129 @@ impl Storage { Ok(rows > 0) } + /// Permanently purge a memory's content and embeddings. + /// + /// Unlike `delete_node`, purge also scrubs non-FK JSON references in + /// `insights.source_memories`, detaches temporal-summary children, and + /// writes a content-free deletion tombstone for audit/sync. + pub fn purge_node(&self, id: &str, reason: Option<&str>) -> Result { + let deleted_at = Utc::now(); + let mut writer = self + .writer + .lock() + .map_err(|_| StorageError::Init("Writer lock poisoned".into()))?; + let tx = writer.transaction()?; + + let node = tx + .prepare("SELECT * FROM knowledge_nodes WHERE id = ?1")? + .query_row(params![id], Self::row_to_node) + .optional()?; + + let Some(node) = node else { + return Ok(PurgeReport { + memory_id: id.to_string(), + deleted: false, + deleted_at, + edges_pruned: 0, + insights_rewritten: 0, + insights_deleted: 0, + children_orphaned: 0, + }); + }; + + let edges_pruned: i64 = tx.query_row( + "SELECT COUNT(*) FROM memory_connections WHERE source_id = ?1 OR target_id = ?1", + params![id], + |row| row.get(0), + )?; + + let insight_refs: Vec<(String, String)> = { + let mut stmt = tx.prepare( + "SELECT id, source_memories FROM insights WHERE source_memories LIKE ?1", + )?; + let pattern = format!("%{}%", id); + stmt.query_map(params![pattern], |row| Ok((row.get(0)?, row.get(1)?)))? + .filter_map(|row| row.ok()) + .collect() + }; + + let mut insights_rewritten = 0_i64; + let mut insights_deleted = 0_i64; + for (insight_id, source_json) in insight_refs { + let mut sources: Vec = serde_json::from_str(&source_json).unwrap_or_default(); + let before = sources.len(); + sources.retain(|source_id| source_id != id); + + if sources.len() == before { + continue; + } + + if sources.len() < 2 { + insights_deleted += + tx.execute("DELETE FROM insights WHERE id = ?1", params![insight_id])? as i64; + } else { + let rewritten = serde_json::to_string(&sources).unwrap_or_else(|_| "[]".into()); + insights_rewritten += tx.execute( + "UPDATE insights SET source_memories = ?1 WHERE id = ?2", + params![rewritten, insight_id], + )? as i64; + } + } + + let children_orphaned = tx.execute( + "UPDATE knowledge_nodes SET summary_parent_id = NULL WHERE summary_parent_id = ?1", + params![id], + )? as i64; + + let tags_json = serde_json::to_string(&node.tags).unwrap_or_else(|_| "[]".to_string()); + tx.execute( + "INSERT INTO deletion_tombstones ( + memory_id, deleted_at, reason, node_type, tags, + edges_pruned, insights_rewritten, insights_deleted, children_orphaned + ) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9) + ON CONFLICT(memory_id) DO UPDATE SET + deleted_at = excluded.deleted_at, + reason = excluded.reason, + node_type = excluded.node_type, + tags = excluded.tags, + edges_pruned = excluded.edges_pruned, + insights_rewritten = excluded.insights_rewritten, + insights_deleted = excluded.insights_deleted, + children_orphaned = excluded.children_orphaned", + params![ + id, + deleted_at.to_rfc3339(), + reason, + node.node_type, + tags_json, + edges_pruned, + insights_rewritten, + insights_deleted, + children_orphaned, + ], + )?; + + Self::record_sync_tombstone(&tx, "knowledge_nodes", id, "purge_node")?; + tx.execute("DELETE FROM knowledge_nodes WHERE id = ?1", params![id])?; + tx.commit()?; + + #[cfg(all(feature = "embeddings", feature = "vector-search"))] + if let Ok(mut index) = self.vector_index.lock() { + let _ = index.remove(id); + } + + Ok(PurgeReport { + memory_id: id.to_string(), + deleted: true, + deleted_at, + edges_pruned, + insights_rewritten, + insights_deleted, + children_orphaned, + }) + } + fn node_exists(conn: &Connection, id: &str) -> Result { let count: i64 = conn.query_row( "SELECT COUNT(*) FROM knowledge_nodes WHERE id = ?1", @@ -1897,6 +2043,202 @@ impl Storage { Ok(result) } + /// Concrete keyword/literal search that skips semantic expansion and + /// cognitive reranking. + /// + /// This path is for identifiers, paths, quoted strings, env vars, UUIDs, + /// and other exact user intent where "close enough" is wrong. + pub fn concrete_search_filtered( + &self, + query: &str, + limit: i32, + include_types: Option<&[String]>, + exclude_types: Option<&[String]>, + ) -> Result> { + let literal = Self::normalize_literal_query(query); + if literal.is_empty() { + return Ok(vec![]); + } + + let limit = limit.max(1) as usize; + let fetch_limit = ((limit * 10).min(500)) as i32; + let mut by_id: HashMap = HashMap::new(); + + if let Some(terms) = crate::fts::sanitize_fts5_terms(&literal) { + let reader = self + .reader + .lock() + .map_err(|_| StorageError::Init("Reader lock poisoned".into()))?; + let mut stmt = reader.prepare( + "SELECT n.*, rank AS fts_rank FROM knowledge_nodes n + JOIN knowledge_fts fts ON n.id = fts.id + WHERE knowledge_fts MATCH ?1 + ORDER BY rank + LIMIT ?2", + )?; + + let rows = stmt.query_map(params![terms, fetch_limit], |row| { + let node = Self::row_to_node(row)?; + let rank = row.get::<_, f64>("fts_rank").unwrap_or(0.0); + Ok((node, rank)) + })?; + + for (idx, row) in rows.enumerate() { + let (node, rank) = row?; + if !Self::node_matches_type_filters(&node, include_types, exclude_types) { + continue; + } + let base_score = (1.0 / (idx as f32 + 1.0)).max((-rank as f32).max(0.0)); + Self::upsert_concrete_result(&mut by_id, node, base_score, Some(base_score)); + } + } + + let escaped = Self::escape_like(&literal.to_lowercase()); + let pattern = format!("%{}%", escaped); + let prefix_pattern = format!("{}%", escaped); + { + let reader = self + .reader + .lock() + .map_err(|_| StorageError::Init("Reader lock poisoned".into()))?; + let mut stmt = reader.prepare( + "SELECT n.* FROM knowledge_nodes n + WHERE lower(n.id) = ?2 + OR lower(n.content) LIKE ?1 ESCAPE '\\' + OR lower(COALESCE(n.source, '')) LIKE ?1 ESCAPE '\\' + OR lower(n.tags) LIKE ?1 ESCAPE '\\' + ORDER BY + CASE + WHEN lower(n.id) = ?2 THEN 0 + WHEN lower(n.content) = ?2 THEN 1 + WHEN lower(n.content) LIKE ?3 ESCAPE '\\' THEN 2 + ELSE 3 + END, + n.updated_at DESC + LIMIT ?4", + )?; + + let rows = stmt.query_map( + params![pattern, literal.to_lowercase(), prefix_pattern, fetch_limit], + Self::row_to_node, + )?; + + for row in rows { + let node = row?; + if !Self::node_matches_type_filters(&node, include_types, exclude_types) { + continue; + } + if let Some(score) = Self::literal_match_score(&literal, &node) { + Self::upsert_concrete_result(&mut by_id, node, score, Some(score)); + } + } + } + + let mut results: Vec = by_id.into_values().collect(); + results.sort_by(|a, b| { + b.combined_score + .partial_cmp(&a.combined_score) + .unwrap_or(std::cmp::Ordering::Equal) + .then_with(|| b.node.updated_at.cmp(&a.node.updated_at)) + }); + results.truncate(limit); + Ok(results) + } + + fn upsert_concrete_result( + by_id: &mut HashMap, + node: KnowledgeNode, + score: f32, + keyword_score: Option, + ) { + by_id + .entry(node.id.clone()) + .and_modify(|existing| { + existing.combined_score = existing.combined_score.max(score); + existing.keyword_score = match (existing.keyword_score, keyword_score) { + (Some(a), Some(b)) => Some(a.max(b)), + (None, Some(b)) => Some(b), + (a, None) => a, + }; + }) + .or_insert(SearchResult { + node, + keyword_score, + semantic_score: None, + combined_score: score, + match_type: MatchType::Keyword, + }); + } + + fn normalize_literal_query(query: &str) -> String { + let trimmed = query.trim(); + if trimmed.len() >= 2 { + let bytes = trimmed.as_bytes(); + let quoted = (bytes[0] == b'"' && bytes[bytes.len() - 1] == b'"') + || (bytes[0] == b'\'' && bytes[bytes.len() - 1] == b'\''); + if quoted { + return trimmed[1..trimmed.len() - 1].trim().to_string(); + } + } + trimmed.to_string() + } + + fn escape_like(value: &str) -> String { + let mut escaped = String::with_capacity(value.len()); + for ch in value.chars() { + match ch { + '\\' | '%' | '_' => { + escaped.push('\\'); + escaped.push(ch); + } + _ => escaped.push(ch), + } + } + escaped + } + + fn literal_match_score(query: &str, node: &KnowledgeNode) -> Option { + let q = query.to_lowercase(); + let content = node.content.to_lowercase(); + let tags = node.tags.join(" ").to_lowercase(); + let source = node.source.as_deref().unwrap_or("").to_lowercase(); + let id = node.id.to_lowercase(); + + if id == q { + Some(3.0) + } else if content == q { + Some(2.5) + } else if content.starts_with(&q) { + Some(2.0) + } else if content.contains(&q) { + Some(1.6) + } else if source.contains(&q) { + Some(1.4) + } else if tags.contains(&q) { + Some(1.2) + } else { + None + } + } + + fn node_matches_type_filters( + node: &KnowledgeNode, + include_types: Option<&[String]>, + exclude_types: Option<&[String]>, + ) -> bool { + if let Some(includes) = include_types + && !includes.is_empty() + { + return includes.iter().any(|t| t == &node.node_type); + } + if let Some(excludes) = exclude_types + && !excludes.is_empty() + { + return !excludes.iter().any(|t| t == &node.node_type); + } + true + } + /// Get all nodes (paginated) pub fn get_all_nodes(&self, limit: i32, offset: i32) -> Result> { let reader = self @@ -6298,4 +6640,169 @@ mod tests { assert!(!results.is_empty()); assert!(results[0].node.content.contains("Neurons")); } + + #[test] + fn test_concrete_search_literal_identifier_lands_first() { + let storage = create_test_storage(); + + storage + .ingest(IngestInput { + content: "General OpenAI API setup notes without the exact env var".to_string(), + node_type: "fact".to_string(), + ..Default::default() + }) + .unwrap(); + let target = storage + .ingest(IngestInput { + content: "Set OPENAI_API_KEY before running the release smoke tests".to_string(), + node_type: "fact".to_string(), + ..Default::default() + }) + .unwrap(); + storage + .ingest(IngestInput { + content: "API keys should be handled carefully in shell profiles".to_string(), + node_type: "fact".to_string(), + ..Default::default() + }) + .unwrap(); + + let results = storage + .concrete_search_filtered("OPENAI_API_KEY", 10, None, None) + .unwrap(); + + assert!(!results.is_empty()); + assert_eq!(results[0].node.id, target.id); + assert_eq!(results[0].match_type, MatchType::Keyword); + assert!(results[0].semantic_score.is_none()); + } + + #[test] + fn test_purge_scrubs_insight_json_orphans_children_and_writes_tombstone() { + let storage = create_test_storage(); + let doomed = storage + .ingest(IngestInput { + content: "Sensitive purge target memory".to_string(), + node_type: "fact".to_string(), + tags: vec!["sensitive".to_string()], + ..Default::default() + }) + .unwrap(); + let other_a = storage + .ingest(IngestInput { + content: "Other source memory A".to_string(), + node_type: "fact".to_string(), + ..Default::default() + }) + .unwrap(); + let other_b = storage + .ingest(IngestInput { + content: "Other source memory B".to_string(), + node_type: "fact".to_string(), + ..Default::default() + }) + .unwrap(); + let child = storage + .ingest(IngestInput { + content: "Temporal summary child".to_string(), + node_type: "summary".to_string(), + ..Default::default() + }) + .unwrap(); + + { + let writer = storage.writer.lock().unwrap(); + writer + .execute( + "INSERT INTO memory_connections ( + source_id, target_id, strength, link_type, created_at, last_activated, activation_count + ) VALUES (?1, ?2, 0.9, 'semantic', ?3, ?3, 0)", + params![doomed.id, other_a.id, Utc::now().to_rfc3339()], + ) + .unwrap(); + writer + .execute( + "INSERT INTO insights ( + id, insight, source_memories, confidence, novelty_score, insight_type, generated_at + ) VALUES (?1, 'drop me', ?2, 0.9, 0.2, 'synthesis', ?3)", + params![ + Uuid::new_v4().to_string(), + serde_json::to_string(&vec![doomed.id.clone(), other_a.id.clone()]).unwrap(), + Utc::now().to_rfc3339() + ], + ) + .unwrap(); + writer + .execute( + "INSERT INTO insights ( + id, insight, source_memories, confidence, novelty_score, insight_type, generated_at + ) VALUES (?1, 'rewrite me', ?2, 0.9, 0.2, 'synthesis', ?3)", + params![ + Uuid::new_v4().to_string(), + serde_json::to_string(&vec![ + doomed.id.clone(), + other_a.id.clone(), + other_b.id.clone() + ]) + .unwrap(), + Utc::now().to_rfc3339() + ], + ) + .unwrap(); + writer + .execute( + "UPDATE knowledge_nodes SET summary_parent_id = ?1 WHERE id = ?2", + params![doomed.id, child.id], + ) + .unwrap(); + } + + let report = storage + .purge_node(&doomed.id, Some("user requested hard purge")) + .unwrap(); + assert!(report.deleted); + assert_eq!(report.edges_pruned, 1); + assert_eq!(report.insights_deleted, 1); + assert_eq!(report.insights_rewritten, 1); + assert_eq!(report.children_orphaned, 1); + assert!(storage.get_node(&doomed.id).unwrap().is_none()); + + let writer = storage.writer.lock().unwrap(); + let remaining_refs: Vec = writer + .prepare("SELECT source_memories FROM insights") + .unwrap() + .query_map([], |row| row.get(0)) + .unwrap() + .filter_map(|row| row.ok()) + .collect(); + assert_eq!(remaining_refs.len(), 1); + assert!(!remaining_refs[0].contains(&doomed.id)); + + let child_parent: Option = writer + .query_row( + "SELECT summary_parent_id FROM knowledge_nodes WHERE id = ?1", + params![child.id], + |row| row.get(0), + ) + .unwrap(); + assert!(child_parent.is_none()); + + let tombstone_count: i64 = writer + .query_row( + "SELECT COUNT(*) FROM deletion_tombstones WHERE memory_id = ?1 AND reason = ?2", + params![doomed.id, "user requested hard purge"], + |row| row.get(0), + ) + .unwrap(); + assert_eq!(tombstone_count, 1); + + let has_content_column: i64 = writer + .query_row( + "SELECT COUNT(*) FROM pragma_table_info('deletion_tombstones') WHERE name = 'content'", + [], + |row| row.get(0), + ) + .unwrap(); + assert_eq!(has_content_column, 0); + } } diff --git a/crates/vestige-mcp/src/server.rs b/crates/vestige-mcp/src/server.rs index 00c2bdd..6f3fd65 100644 --- a/crates/vestige-mcp/src/server.rs +++ b/crates/vestige-mcp/src/server.rs @@ -31,11 +31,9 @@ use vestige_core::Storage; /// Vestige without imposing one maintainer's workflow on strangers. /// /// The "full" variant is the composition mandate that enforces the -/// Composing / Never-composed / Recommendation response shape, names the -/// AIMO3 36/50 case study as the origin, and includes the "Vestige is -/// blocking this:" refusal phrase. It is load-bearing for Sam's own -/// decision-adjacent work but would misfire on trivial retrievals for a -/// general audience, so it is opt-in via `VESTIGE_SYSTEM_PROMPT_MODE=full`. +/// Composing / Never-composed / Recommendation response shape. It can misfire +/// on trivial retrievals for a general audience, so it is opt-in via +/// `VESTIGE_SYSTEM_PROMPT_MODE=full`. /// /// Anything other than `full` falls back to minimal. fn build_instructions() -> String { @@ -209,7 +207,7 @@ impl McpServer { /// Handle tools/list request async fn handle_tools_list(&self) -> Result { - // v2.0.5+: 24 tools (verified by the `tools.len() == 24` assertion in the + // v2.1.2+: 25 tools (verified by the `tools.len() == 25` assertion in the // handle_tools_list test below — the `suppress` tool landed in v2.0.5). // Deprecated tools still work via redirects in handle_tools_call. let tools = vec![ @@ -223,7 +221,7 @@ impl McpServer { }, ToolDescription { name: "memory".to_string(), - description: Some("Unified memory management tool. Actions: 'get' (retrieve full node), 'delete' (remove memory), 'state' (get accessibility state), 'promote' (thumbs up — increases retrieval strength), 'demote' (thumbs down — decreases retrieval strength, does NOT delete), 'edit' (update content in-place, preserves FSRS state).".to_string()), + description: Some("Unified memory management tool. Actions: 'get' (retrieve full node), 'purge' (irreversibly remove content/embeddings with confirm=true), 'delete' (legacy alias for purge), 'state' (get accessibility state), 'promote' (thumbs up — increases retrieval strength), 'demote' (thumbs down — decreases retrieval strength, does NOT delete), 'edit' (update content in-place, preserves FSRS state).".to_string()), input_schema: tools::memory_unified::schema(), }, ToolDescription { @@ -358,6 +356,11 @@ impl McpServer { description: Some("Alias for deep_reference. Connect the dots across memories with cognitive reasoning.".to_string()), input_schema: tools::cross_reference::schema(), }, + ToolDescription { + name: "contradictions".to_string(), + description: Some("Inspect memory disagreements directly. Scans a topic or recent memories for trust-weighted contradiction pairs using the same local logic as deep_reference.".to_string()), + input_schema: tools::contradictions::schema(), + }, // ================================================================ // ACTIVE FORGETTING (v2.0.5) — top-down suppression // Anderson et al. 2025 Nat Rev Neurosci + Davis Rac1 @@ -832,6 +835,9 @@ impl McpServer { tools::cross_reference::execute(&self.storage, &self.cognitive, request.arguments) .await } + "contradictions" => { + tools::contradictions::execute(&self.storage, request.arguments).await + } // ================================================================ // ACTIVE FORGETTING (v2.0.5) — top-down suppression @@ -1164,7 +1170,7 @@ impl McpServer { .unwrap_or("") .to_string(); match action { - "delete" => { + "delete" | "purge" => { self.emit(VestigeEvent::MemoryDeleted { id, timestamp: now }); } "promote" => { @@ -1505,8 +1511,8 @@ mod tests { let result = response.result.unwrap(); let tools = result["tools"].as_array().unwrap(); - // v2.0.5: 24 tools (4 unified + 1 core + 2 temporal + 5 maintenance + 2 auto-save + 3 cognitive + 1 restore + 1 session_context + 2 autonomic + 1 deep_reference + 1 cross_reference alias + 1 suppress) - assert_eq!(tools.len(), 24, "Expected exactly 24 tools in v2.0.5+"); + // v2.1.2: 25 tools (adds first-class contradictions surface) + assert_eq!(tools.len(), 25, "Expected exactly 25 tools in v2.1.2+"); let tool_names: Vec<&str> = tools.iter().map(|t| t["name"].as_str().unwrap()).collect(); @@ -1576,6 +1582,7 @@ mod tests { // Deep reference + cross_reference alias (v2.0.4) assert!(tool_names.contains(&"deep_reference")); assert!(tool_names.contains(&"cross_reference")); + assert!(tool_names.contains(&"contradictions")); // Active forgetting (v2.0.5) — Anderson 2025 + Davis Rac1 assert!(tool_names.contains(&"suppress")); diff --git a/crates/vestige-mcp/src/tools/contradictions.rs b/crates/vestige-mcp/src/tools/contradictions.rs new file mode 100644 index 0000000..33c0038 --- /dev/null +++ b/crates/vestige-mcp/src/tools/contradictions.rs @@ -0,0 +1,213 @@ +//! First-class contradiction surface. +//! +//! `deep_reference` already computes trust-weighted contradiction pairs while +//! answering a specific question. This tool exposes the same local logic as an +//! inspectable memory-health operation. + +use chrono::{DateTime, Utc}; +use serde::Deserialize; +use serde_json::Value; +use std::sync::Arc; + +use crate::tools::cross_reference::{appears_contradictory, compute_trust, topic_overlap}; +use vestige_core::{KnowledgeNode, Storage}; + +pub fn schema() -> Value { + serde_json::json!({ + "type": "object", + "properties": { + "topic": { + "type": "string", + "description": "Optional topic/query to scope contradiction detection. If omitted, scans recent memories." + }, + "since": { + "type": "string", + "description": "Optional RFC3339 timestamp; only memories updated after this time are considered." + }, + "min_trust": { + "type": "number", + "description": "Minimum trust score for both sides of a contradiction.", + "minimum": 0.0, + "maximum": 1.0, + "default": 0.3 + }, + "limit": { + "type": "integer", + "description": "Maximum memories to analyze before pairwise contradiction detection.", + "minimum": 2, + "maximum": 200, + "default": 50 + } + } + }) +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct ContradictionArgs { + topic: Option, + since: Option, + #[serde(alias = "min_trust")] + min_trust: Option, + limit: Option, +} + +pub async fn execute(storage: &Arc, args: Option) -> Result { + let args: ContradictionArgs = match args { + Some(value) => { + serde_json::from_value(value).map_err(|e| format!("Invalid arguments: {}", e))? + } + None => ContradictionArgs { + topic: None, + since: None, + min_trust: None, + limit: None, + }, + }; + + let limit = args.limit.unwrap_or(50).clamp(2, 200); + let min_trust = args.min_trust.unwrap_or(0.3).clamp(0.0, 1.0); + let since = match args.since.as_deref() { + Some(raw) => Some( + DateTime::parse_from_rfc3339(raw) + .map_err(|e| format!("Invalid since timestamp: {}", e))? + .with_timezone(&Utc), + ), + None => None, + }; + + let mut memories = if let Some(topic) = args.topic.as_deref().filter(|s| !s.trim().is_empty()) { + storage + .hybrid_search(topic, limit, 0.3, 0.7) + .map_err(|e| e.to_string())? + .into_iter() + .map(|result| result.node) + .collect::>() + } else { + storage.get_all_nodes(limit, 0).map_err(|e| e.to_string())? + }; + + if let Some(since) = since { + memories.retain(|memory| memory.updated_at >= since); + } + + let contradictions = find_contradictions(&memories, min_trust); + + Ok(serde_json::json!({ + "topic": args.topic, + "memoriesAnalyzed": memories.len(), + "minTrust": min_trust, + "contradictionsFound": contradictions.len(), + "contradictions": contradictions, + })) +} + +fn find_contradictions(memories: &[KnowledgeNode], min_trust: f64) -> Vec { + let mut contradictions = Vec::new(); + + for i in 0..memories.len() { + for j in (i + 1)..memories.len() { + let a = &memories[i]; + let b = &memories[j]; + let overlap = topic_overlap(&a.content, &b.content); + if overlap < 0.4 || !appears_contradictory(&a.content, &b.content) { + continue; + } + + let a_trust = trust_for(a); + let b_trust = trust_for(b); + if a_trust.min(b_trust) < min_trust { + continue; + } + + let (stronger, stronger_trust, weaker, weaker_trust) = if a_trust >= b_trust { + (a, a_trust, b, b_trust) + } else { + (b, b_trust, a, a_trust) + }; + + contradictions.push(serde_json::json!({ + "stronger": memory_card(stronger, stronger_trust), + "weaker": memory_card(weaker, weaker_trust), + "topicOverlap": overlap, + })); + } + } + + contradictions.sort_by(|a, b| { + let a_overlap = a["topicOverlap"].as_f64().unwrap_or(0.0); + let b_overlap = b["topicOverlap"].as_f64().unwrap_or(0.0); + b_overlap + .partial_cmp(&a_overlap) + .unwrap_or(std::cmp::Ordering::Equal) + }); + contradictions +} + +fn trust_for(memory: &KnowledgeNode) -> f64 { + compute_trust( + memory.retention_strength, + memory.stability, + memory.reps, + memory.lapses, + ) +} + +fn memory_card(memory: &KnowledgeNode, trust: f64) -> Value { + serde_json::json!({ + "id": memory.id.clone(), + "preview": memory.content.chars().take(200).collect::(), + "trust": (trust * 100.0).round() / 100.0, + "updatedAt": memory.updated_at.to_rfc3339(), + "tags": memory.tags.clone(), + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::TempDir; + use vestige_core::IngestInput; + + async fn test_storage() -> (Arc, TempDir) { + let dir = TempDir::new().unwrap(); + let storage = Storage::new(Some(dir.path().join("test.db"))).unwrap(); + (Arc::new(storage), dir) + } + + #[tokio::test] + async fn test_contradictions_reports_conflicting_memories() { + let (storage, _dir) = test_storage().await; + storage + .ingest(IngestInput { + content: + "For the release workflow we always run cargo test before publishing Vestige" + .to_string(), + node_type: "fact".to_string(), + ..Default::default() + }) + .unwrap(); + storage + .ingest(IngestInput { + content: + "Correction: for the release workflow we never run cargo test before publishing Vestige" + .to_string(), + node_type: "fact".to_string(), + ..Default::default() + }) + .unwrap(); + + let result = execute( + &storage, + Some(serde_json::json!({ + "topic": "release workflow cargo test Vestige", + "min_trust": 0.0 + })), + ) + .await + .unwrap(); + + assert_eq!(result["contradictionsFound"], 1); + assert!(result["contradictions"][0]["stronger"]["id"].is_string()); + } +} diff --git a/crates/vestige-mcp/src/tools/cross_reference.rs b/crates/vestige-mcp/src/tools/cross_reference.rs index de58994..e1a9128 100644 --- a/crates/vestige-mcp/src/tools/cross_reference.rs +++ b/crates/vestige-mcp/src/tools/cross_reference.rs @@ -58,7 +58,7 @@ struct DeepRefArgs { /// Compute trust score from FSRS-6 memory state. /// Higher = more trustworthy (frequently accessed, high retention, stable, few lapses). -fn compute_trust(retention: f64, stability: f64, reps: i32, lapses: i32) -> f64 { +pub(crate) fn compute_trust(retention: f64, stability: f64, reps: i32, lapses: i32) -> f64 { let retention_factor = retention * 0.4; let stability_factor = (stability / 30.0).min(1.0) * 0.2; let reps_factor = (reps as f64 / 10.0).min(1.0) * 0.2; @@ -384,7 +384,7 @@ const CORRECTION_SIGNALS: &[&str] = &[ "migrated to", ]; -fn appears_contradictory(a: &str, b: &str) -> bool { +pub(crate) fn appears_contradictory(a: &str, b: &str) -> bool { let a_lower = a.to_lowercase(); let b_lower = b.to_lowercase(); @@ -435,7 +435,7 @@ fn appears_contradictory(a: &str, b: &str) -> bool { false } -fn topic_overlap(a: &str, b: &str) -> f32 { +pub(crate) fn topic_overlap(a: &str, b: &str) -> f32 { let a_lower = a.to_lowercase(); let b_lower = b.to_lowercase(); let a_words: std::collections::HashSet<&str> = @@ -689,10 +689,10 @@ pub async fn execute( // it contains at least one of these terms. This catches the class of bug // where a high-trust, semantically-adjacent memory from an unrelated // domain beats the actual topic memory because the cross-encoder reranker - // over-weights token-level similarity (e.g. a Nightvision memory about - // "true positives + conservative thresholds" winning an "FSRS-6 trust + // over-weights token-level similarity (e.g. an unrelated security memory + // about "true positives + conservative thresholds" winning an "FSRS-6 trust // scoring" query because "trust" + "scoring" + "threshold" cluster in - // embedding space — even though the winning memory contains neither + // embedding space, even though the winning memory contains neither // "FSRS-6" nor anything about spaced repetition). const TOPIC_STOPWORDS: &[&str] = &[ "how", "what", "when", "where", "why", "who", "which", "does", "did", "is", "are", "was", @@ -1162,7 +1162,7 @@ mod tests { QueryIntent::Timeline ); assert_eq!( - classify_intent("How has the AIMO3 score evolved over time?"), + classify_intent("How has the benchmark score evolved over time?"), QueryIntent::Timeline ); } @@ -1194,7 +1194,7 @@ mod tests { #[test] fn test_intent_synthesis_default() { assert_eq!( - classify_intent("Tell me about Sam's projects"), + classify_intent("Tell me about the user's projects"), QueryIntent::Synthesis ); assert_eq!(classify_intent("What is Vestige?"), QueryIntent::Synthesis); diff --git a/crates/vestige-mcp/src/tools/dedup.rs b/crates/vestige-mcp/src/tools/dedup.rs index ec93721..ea3da25 100644 --- a/crates/vestige-mcp/src/tools/dedup.rs +++ b/crates/vestige-mcp/src/tools/dedup.rs @@ -288,6 +288,7 @@ mod tests { } #[test] + #[cfg(all(feature = "embeddings", feature = "vector-search"))] fn test_union_find() { let mut uf = UnionFind::new(5); uf.union(0, 1); diff --git a/crates/vestige-mcp/src/tools/memory_unified.rs b/crates/vestige-mcp/src/tools/memory_unified.rs index 2d73b6b..e524ac4 100644 --- a/crates/vestige-mcp/src/tools/memory_unified.rs +++ b/crates/vestige-mcp/src/tools/memory_unified.rs @@ -43,8 +43,8 @@ pub fn schema() -> Value { "properties": { "action": { "type": "string", - "enum": ["get", "get_batch", "delete", "state", "promote", "demote", "edit"], - "description": "Action to perform: 'get' retrieves full memory node, 'get_batch' retrieves multiple memories by IDs (use 'ids' array), 'delete' removes memory, 'state' returns accessibility state, 'promote' increases retrieval strength (thumbs up), 'demote' decreases retrieval strength (thumbs down), 'edit' updates content in-place (preserves FSRS state)" + "enum": ["get", "get_batch", "delete", "purge", "state", "promote", "demote", "edit"], + "description": "Action to perform: 'get' retrieves full memory node, 'get_batch' retrieves multiple memories by IDs (use 'ids' array), 'purge' permanently removes memory content and embeddings after confirm=true, 'delete' is a backwards-compatible alias for purge, 'state' returns accessibility state, 'promote' increases retrieval strength (thumbs up), 'demote' decreases retrieval strength (thumbs down), 'edit' updates content in-place (preserves FSRS state)" }, "id": { "type": "string", @@ -57,7 +57,12 @@ pub fn schema() -> Value { }, "reason": { "type": "string", - "description": "Why this memory is being promoted/demoted (optional, for logging). Only used with promote/demote actions." + "description": "Why this memory is being promoted/demoted/purged (optional, for logging)." + }, + "confirm": { + "type": "boolean", + "description": "Required for action='purge'. Purge permanently removes memory content and embeddings; only a non-content tombstone remains.", + "default": false }, "content": { "type": "string", @@ -75,6 +80,7 @@ struct MemoryArgs { id: Option, ids: Option>, reason: Option, + confirm: Option, content: Option, } @@ -110,13 +116,23 @@ pub async fn execute( match args.action.as_str() { "get" => execute_get(storage, &id).await, - "delete" => execute_delete(storage, &id).await, + "delete" => execute_purge(storage, &id, args.reason, true, "delete").await, + "purge" => { + execute_purge( + storage, + &id, + args.reason, + args.confirm.unwrap_or(false), + "purge", + ) + .await + } "state" => execute_state(storage, &id).await, "promote" => execute_promote(storage, cognitive, &id, args.reason).await, "demote" => execute_demote(storage, cognitive, &id, args.reason).await, "edit" => execute_edit(storage, &id, args.content).await, _ => Err(format!( - "Invalid action '{}'. Must be one of: get, get_batch, delete, state, promote, demote, edit", + "Invalid action '{}'. Must be one of: get, get_batch, delete, purge, state, promote, demote, edit", args.action )), } @@ -205,15 +221,39 @@ async fn execute_get_batch(storage: &Arc, ids: &[String]) -> Result, id: &str) -> Result { - let deleted = storage.delete_node(id).map_err(|e| e.to_string())?; +/// Permanently purge a memory and return cleanup details. +async fn execute_purge( + storage: &Arc, + id: &str, + reason: Option, + confirm: bool, + action: &str, +) -> Result { + if !confirm { + return Err( + "Purge is irreversible. Pass confirm=true to permanently remove memory content and embeddings." + .to_string(), + ); + } + + let report = storage + .purge_node(id, reason.as_deref()) + .map_err(|e| e.to_string())?; Ok(serde_json::json!({ - "action": "delete", - "success": deleted, + "action": action, + "success": report.deleted, "nodeId": id, - "message": if deleted { "Memory deleted successfully" } else { "Memory not found" }, + "message": if report.deleted { + "Memory purged permanently; content and embeddings removed. Non-content tombstone retained for sync/audit." + } else { + "Memory not found" + }, + "deletedAt": report.deleted_at.to_rfc3339(), + "edgesPruned": report.edges_pruned, + "insightsRewritten": report.insights_rewritten, + "insightsDeleted": report.insights_deleted, + "childrenOrphaned": report.children_orphaned, })) } @@ -469,13 +509,15 @@ mod tests { assert!(schema["properties"]["reason"].is_object()); assert_eq!(schema["required"], serde_json::json!(["action"])); assert!(schema["properties"]["ids"].is_object()); // get_batch support - // Verify all 7 actions are in enum + // Verify all 8 actions are in enum let actions = schema["properties"]["action"]["enum"].as_array().unwrap(); - assert_eq!(actions.len(), 7); + assert_eq!(actions.len(), 8); assert!(actions.contains(&serde_json::json!("get_batch"))); + assert!(actions.contains(&serde_json::json!("purge"))); assert!(actions.contains(&serde_json::json!("edit"))); assert!(actions.contains(&serde_json::json!("promote"))); assert!(actions.contains(&serde_json::json!("demote"))); + assert!(schema["properties"]["confirm"].is_object()); } // === INTEGRATION TESTS === @@ -609,6 +651,42 @@ mod tests { assert_eq!(value["found"], false); } + #[tokio::test] + async fn test_purge_requires_confirm() { + let (storage, _dir) = test_storage().await; + let id = ingest_memory(&storage).await; + let args = serde_json::json!({ "action": "purge", "id": id.clone() }); + let result = execute(&storage, &test_cognitive(), Some(args)).await; + assert!(result.is_err()); + assert!(result.unwrap_err().contains("confirm=true")); + assert!(storage.get_node(&id).unwrap().is_some()); + } + + #[tokio::test] + async fn test_purge_existing_memory() { + let (storage, _dir) = test_storage().await; + let id = ingest_memory(&storage).await; + let args = serde_json::json!({ + "action": "purge", + "id": id, + "confirm": true, + "reason": "test cleanup" + }); + let result = execute(&storage, &test_cognitive(), Some(args)).await; + assert!(result.is_ok()); + let value = result.unwrap(); + assert_eq!(value["action"], "purge"); + assert_eq!(value["success"], true); + assert!( + value["message"] + .as_str() + .unwrap() + .contains("purged permanently") + ); + assert_eq!(value["edgesPruned"], 0); + assert!(storage.get_node(&id).unwrap().is_none()); + } + #[tokio::test] async fn test_state_existing_memory() { let (storage, _dir) = test_storage().await; diff --git a/crates/vestige-mcp/src/tools/mod.rs b/crates/vestige-mcp/src/tools/mod.rs index b1331cf..260869e 100644 --- a/crates/vestige-mcp/src/tools/mod.rs +++ b/crates/vestige-mcp/src/tools/mod.rs @@ -38,6 +38,7 @@ pub mod graph; pub mod health; // v2.1: Cross-reference (connect the dots) +pub mod contradictions; pub mod cross_reference; // v2.0.5: Active Forgetting — Anderson 2025 + Davis Rac1 diff --git a/crates/vestige-mcp/src/tools/search_unified.rs b/crates/vestige-mcp/src/tools/search_unified.rs index d467e38..9faf961 100644 --- a/crates/vestige-mcp/src/tools/search_unified.rs +++ b/crates/vestige-mcp/src/tools/search_unified.rs @@ -87,6 +87,11 @@ pub fn schema() -> Value { "description": "precise: top results only (fast, token-efficient, skips activation/competition). balanced: full 7-stage cognitive pipeline (default). exhaustive: maximum recall with 5x overfetch, deep graph traversal, no competition suppression.", "enum": ["precise", "balanced", "exhaustive"], "default": "balanced" + }, + "concrete": { + "type": "boolean", + "description": "Force literal/concrete search. Skips semantic expansion, FSRS reweighting, spreading activation, and cognitive side effects. Auto-enabled for quoted strings, env vars, UUIDs, paths, and code identifiers.", + "default": false } }, "required": ["query"] @@ -114,6 +119,7 @@ struct SearchArgs { token_budget: Option, #[serde(alias = "retrieval_mode")] retrieval_mode: Option, + concrete: Option, } /// Execute unified search with 7-stage cognitive pipeline. @@ -173,6 +179,78 @@ pub async fn execute( } }; + let concrete = args + .concrete + .unwrap_or_else(|| is_literal_query(&args.query)); + if concrete { + let results = storage + .concrete_search_filtered( + &args.query, + limit, + args.include_types.as_deref(), + args.exclude_types.as_deref(), + ) + .map_err(|e| e.to_string())?; + + let ids: Vec<&str> = results.iter().map(|r| r.node.id.as_str()).collect(); + let _ = storage.strengthen_batch_on_access(&ids); + + let mut formatted: Vec = results + .iter() + .filter(|r| r.node.retention_strength >= min_retention) + .map(|r| format_search_result(r, detail_level)) + .collect(); + + let mut budget_expandable: Vec = Vec::new(); + let mut budget_tokens_used: Option = None; + if let Some(budget) = args.token_budget { + let budget = budget.clamp(100, 100000) as usize; + let budget_chars = budget * 4; + let mut used = 0; + let mut budgeted = Vec::new(); + + for result in &formatted { + let size = serde_json::to_string(result).unwrap_or_default().len(); + if used + size > budget_chars { + if let Some(id) = result.get("id").and_then(|v| v.as_str()) { + budget_expandable.push(id.to_string()); + } + continue; + } + used += size; + budgeted.push(result.clone()); + } + + budget_tokens_used = Some(used / 4); + formatted = budgeted; + } + + let mut response = serde_json::json!({ + "query": args.query, + "method": "concrete", + "retrievalMode": retrieval_mode, + "concrete": true, + "detailLevel": detail_level, + "total": formatted.len(), + "results": formatted, + }); + + if formatted.is_empty() { + response["hint"] = serde_json::json!( + "No concrete matches found. Try concrete=false or a broader natural-language query." + ); + } + if !budget_expandable.is_empty() { + response["expandable"] = serde_json::json!(budget_expandable); + } + if let Some(tokens) = budget_tokens_used { + response["tokenBudgetUsed"] = serde_json::json!(tokens); + response["tokenBudgetLimit"] = serde_json::json!(args.token_budget.unwrap()); + } + + return Ok(response); + } + // Favor semantic search — research shows 0.3/0.7 outperforms equal weights let keyword_weight = 0.3_f32; let semantic_weight = 0.7_f32; @@ -668,6 +746,41 @@ pub async fn execute( Ok(response) } +fn is_literal_query(query: &str) -> bool { + let trimmed = query.trim(); + if trimmed.len() >= 2 { + let bytes = trimmed.as_bytes(); + if (bytes[0] == b'"' && bytes[bytes.len() - 1] == b'"') + || (bytes[0] == b'\'' && bytes[bytes.len() - 1] == b'\'') + { + return true; + } + } + + if uuid::Uuid::parse_str(trimmed).is_ok() { + return true; + } + + let token_count = trimmed.split_whitespace().count(); + if token_count != 1 { + return false; + } + + let has_identifier_punctuation = trimmed + .chars() + .any(|c| matches!(c, '_' | '-' | '/' | '\\' | '.' | ':' | '=' | '@')); + if has_identifier_punctuation { + return true; + } + + let has_alpha = trimmed.chars().any(|c| c.is_ascii_alphabetic()); + has_alpha + && trimmed.contains('_') + && trimmed + .chars() + .all(|c| c.is_ascii_uppercase() || c.is_ascii_digit() || c == '_') +} + /// Format a search result based on the requested detail level. fn format_search_result(r: &vestige_core::SearchResult, detail_level: &str) -> Value { match detail_level { @@ -840,6 +953,97 @@ mod tests { assert!(result.unwrap_err().contains("Invalid arguments")); } + #[test] + fn test_literal_query_detection() { + assert!(is_literal_query("\"exact phrase\"")); + assert!(is_literal_query("OPENAI_API_KEY")); + assert!(is_literal_query("mlx_lm.server")); + assert!(is_literal_query("src/main.rs")); + assert!(is_literal_query("4da778e2-1111-4444-8888-123456789abc")); + assert!(!is_literal_query("how should memory search work")); + } + + #[tokio::test] + async fn test_concrete_search_env_var_lands_first() { + let (storage, _dir) = test_storage().await; + ingest_test_content( + &storage, + "General OpenAI setup and API key rotation guidance", + ) + .await; + let target = ingest_test_content( + &storage, + "Release smoke test requires OPENAI_API_KEY to be set in the shell", + ) + .await; + ingest_test_content( + &storage, + "Credentials should be stored outside the repository", + ) + .await; + + let args = serde_json::json!({ + "query": "OPENAI_API_KEY", + "limit": 5 + }); + let result = execute(&storage, &test_cognitive(), Some(args)) + .await + .unwrap(); + + assert_eq!(result["method"], "concrete"); + assert_eq!(result["concrete"], true); + assert_eq!(result["results"][0]["id"], target); + } + + #[tokio::test] + async fn test_concrete_search_uuid_lands_first() { + let (storage, _dir) = test_storage().await; + let uuid = "4da778e2-1111-4444-8888-123456789abc"; + ingest_test_content(&storage, "Several memories mention release identifiers").await; + let target = ingest_test_content( + &storage, + &format!("The migration bug is tracked by exact id {}", uuid), + ) + .await; + + let args = serde_json::json!({ + "query": uuid, + "limit": 5 + }); + let result = execute(&storage, &test_cognitive(), Some(args)) + .await + .unwrap(); + + assert_eq!(result["method"], "concrete"); + assert_eq!(result["results"][0]["id"], target); + } + + #[tokio::test] + async fn test_concrete_search_process_name_lands_first() { + let (storage, _dir) = test_storage().await; + ingest_test_content( + &storage, + "The local MLX server can expose an OpenAI-compatible endpoint", + ) + .await; + let target = ingest_test_content( + &storage, + "If mlx_lm.server is already running, do not start a second Sanhedrin backend", + ) + .await; + + let args = serde_json::json!({ + "query": "mlx_lm.server", + "limit": 5 + }); + let result = execute(&storage, &test_cognitive(), Some(args)) + .await + .unwrap(); + + assert_eq!(result["method"], "concrete"); + assert_eq!(result["results"][0]["id"], target); + } + // ======================================================================== // LIMIT CLAMPING TESTS // ======================================================================== diff --git a/crates/vestige-mcp/src/tools/session_context.rs b/crates/vestige-mcp/src/tools/session_context.rs index 56c615b..0a32ce4 100644 --- a/crates/vestige-mcp/src/tools/session_context.rs +++ b/crates/vestige-mcp/src/tools/session_context.rs @@ -546,13 +546,13 @@ mod tests { let (storage, _dir) = test_storage().await; ingest_test_content( &storage, - "Sam prefers Rust and TypeScript for all projects.", + "The user prefers Rust and TypeScript for all projects.", vec![], ) .await; let args = serde_json::json!({ - "queries": ["Sam preferences", "project context"] + "queries": ["user preferences", "project context"] }); let result = execute(&storage, &test_cognitive(), Some(args)).await; assert!(result.is_ok()); diff --git a/docs/COGNITIVE_SANDWICH.md b/docs/COGNITIVE_SANDWICH.md index 4b4661e..4ba4d1d 100644 --- a/docs/COGNITIVE_SANDWICH.md +++ b/docs/COGNITIVE_SANDWICH.md @@ -55,7 +55,7 @@ For each claim, it checks Vestige's `deep_reference` for high-trust contradictin |---|---| | TECHNICAL / EXISTENTIAL / TIMELINE | VETO if memory trust > 0.55 directly contradicts | | BIOGRAPHICAL / FINANCIAL / ACHIEVEMENT / ATTRIBUTION | VETO if contradicted OR if factual-shaped with zero supporting evidence (fail-closed) | -| **VAGUE-QUANTIFIER** | VETO on "a few wins / some prize money / most placed" without enumeration | +| **VAGUE-QUANTIFIER** | VETO on vague achievement or financial claims without enumeration | | **UNVERIFIED-POSITIVE** | VETO on specific named institutions/dates/employers not in evidence | False-positive guards (added v2.1.0 after dogfood): @@ -183,7 +183,7 @@ On M3 Max 14-core or M2/M1 Max: closer to 3–7s prompt processing, ~50–60 tok ## Architecture provenance -The Cognitive Sandwich originated April 2026 as a defense against the AIMO3 36/50 failure mode — Claude retrieving relevant memories but summarizing them instead of composing them into recommendations. The pre-cognitive layer enforces composition; the post-cognitive layer catches contradictions before they ship. +The Cognitive Sandwich originated April 2026 as a defense against a dogfood failure mode: Claude retrieved relevant memories but summarized them instead of composing them into a recommendation. The pre-cognitive layer enforces composition; the post-cognitive layer catches contradictions before they ship. Full architecture memory: search Vestige for `god-tier-plan` or `cognitive-sandwich` tags after install. diff --git a/docs/FAQ.md b/docs/FAQ.md index a5a8162..4c3047e 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -160,6 +160,8 @@ Accessibility is calculated as: `0.5 × retention + 0.3 × retrieval_strength + Memories are never deleted automatically. They fade from relevance but can be revived if accessed again (like human memory—"oh, I forgot about that!"). +If you explicitly want content gone, use `memory(action="purge", confirm=true)`. Purge permanently removes the memory content and embeddings, scrubs internal references, and keeps only a non-content tombstone so sync/audit can prove the deletion happened. + **To configure decay**: The FSRS-6 algorithm auto-tunes based on your usage patterns. Memories you access stay strong; memories you ignore fade. No manual tuning needed.
diff --git a/SECURITY.md b/SECURITY.md index cc46721..c130b7b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,7 +4,8 @@ | Version | Supported | | ------- | ------------------ | -| 2.0.x | :white_check_mark: | +| 2.1.x | :white_check_mark: | +| 2.0.x | Critical fixes only | | 1.x | :x: | ## Reporting a Vulnerability @@ -27,13 +28,13 @@ You can expect a response within 48 hours. Vestige is a **local MCP server** designed to run on your machine with your user permissions: -- **Trusted**: The MCP client (Claude Code/Desktop) that connects via stdio +- **Trusted**: The MCP client or local agent that connects via stdio - **Untrusted**: Content passed through MCP tool arguments (validated before use) ### What Vestige Does NOT Do -- ❌ Make network requests (except first-run model download from Hugging Face) -- ❌ Execute shell commands +- ❌ Make network requests during normal memory use, except first-run model download from Hugging Face +- ❌ Require telemetry, hosted memory storage, or a cloud account - ❌ Access files outside its data directory - ❌ Send telemetry or analytics - ❌ Phone home to any server diff --git a/agents/executioner.md b/agents/executioner.md index c65da41..7d00615 100644 --- a/agents/executioner.md +++ b/agents/executioner.md @@ -1,6 +1,6 @@ --- name: executioner -description: Optional Sanhedrin fallback verifier. Decomposes a draft into atomic claims, checks high-trust Vestige evidence, and returns a one-line pass/veto verdict. +description: Optional Sanhedrin fallback verifier. Decomposes a draft into check-worthy claims, checks high-trust durable Vestige evidence, and returns a pass/veto verdict. tools: mcp__vestige__deep_reference, mcp__vestige__memory, mcp__vestige__search model: claude-haiku-4-5-20251001 --- @@ -11,9 +11,9 @@ You are a one-turn verifier. You do not converse. You return exactly one line. # Job -Decompose the draft response into atomic claims, verify each claim against -high-trust Vestige memory when available, and veto only when the draft -contradicts memory or makes a sensitive user-specific assertion without +Decompose the draft response into check-worthy claims, verify each claim against +high-trust durable Vestige memory when available, and veto only when the draft +contradicts memory or makes a sensitive user-specific assertion without durable supporting evidence. # Claim Classes @@ -24,18 +24,22 @@ Check all relevant classes: 2. `BIOGRAPHICAL` — identity, role, location, employment, education. 3. `FINANCIAL` — costs, revenue, pricing, funding, prizes. 4. `ACHIEVEMENT` — releases, rankings, completions, scores, milestones. -5. `TEMPORAL` — dates, durations, ordering, deadlines. +5. `TIMELINE` — dates, durations, ordering, deadlines. 6. `QUANTITATIVE` — counts, percentages, metrics, measurements. 7. `ATTRIBUTION` — who said, decided, agreed, shipped, or committed. 8. `CAUSAL` — claimed causes and effects. 9. `COMPARATIVE` — better, most, fastest, more than, fewer than. 10. `EXISTENTIAL` — whether a file, feature, repo, or artifact exists. +11. `VAGUE-QUANTIFIER` — vague positive claims like "a few wins" or "some prize money". # Decision Rules - Veto direct contradiction with high-trust memory. - Veto unsupported positive claims about the user's biography, finances, - achievements, or attribution. + achievements, timeline, quantitative results, attribution, or vague + positive outcomes. +- Treat staged/current-turn evidence as context only. It is not durable memory and + cannot satisfy the durable-evidence requirement. - Do not veto purely stylistic disagreement. - Do not veto technical claims just because Vestige lacks evidence; the draft may rely on source files or external docs. diff --git a/apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.br b/apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.br deleted file mode 100644 index fcf318493a092fb1f4beea449765c766e93cd9f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7639 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 Fs&B181*QN1 diff --git a/apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.gz b/apps/dashboard/build/_app/immutable/chunks/BHGLDPij.js.gz deleted file mode 100644 index 150db2feabbf3a45e69d2ff4a85ac4e4b101a9ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8429 zcmVEh$f$B%Dv|4Z5HC%Whz771OEC-T*^U$f^I%_0#N$s~V{*Vp_tUY_s*FV~7E zcpWP~!Rt$2;^iq{;N_lYc$q0a!|Q?K*LYnj9^&;^PUA}yzoM2Ee~Z^ba*5Ym@))nB zs!TdX%zJw%bT~+@3a4*IYwz% zmV0+F%RDPpv5Zt+cp;Z;t>UEgOBJeRDMGGR3z^UMq!2wQmSoqx0Tr0!)0J4yWm$&T zGLTgu8}DVXqs-@vqR5M2?_eEPpQ}pcSJa-z)`e8dBHR1v>dk9kcaqFjo@;_tl^*Tw zUyl}_(mV=Pl4nBNiYv7z@0HA^9+YB$*x?C<~;T4SUXi-6JY7MLHEu}dA!}~O3 z1MicM|M2GShoS9ZK7{sTc9zeJIPosllU*5|I=F?AR zUd9ZGLw~U>V{e^>a~WjA(-EJCDvD(R58sb?zQDnTX|R9F3t6gQ|Aa?zm}GJaw-w_( z=;YWN{xSMH^a4yoBgyqhhTEg)jw9bWj=VXJygiN+Gmg{U<2W82(LkW>{lYYEMpcT! zFBfT|yki)ee>7m9M&4i_7Uq~4>I1=#N+PQl@st5+p`G+^-!r^M$ODBcKPD>ndiO^? zW(OZBPqVI%8|!Ht7Ekl3^cG=J$`_f!nrRYA?|a5i|C=$IdAqgcU$^G_e%+3lNbgZk zbHP}gx!%UQ6K19zi>1^gj~E~FCBNe{J{^g;zl-!UNB3!i==)1U_5C|X_Pap}EP8r) zSPoA{$gDkB6j+J7L67)hzR-nnb+&JZjT2CpBaZq zh4V59tIBPhDQz6ng4)N94-fZ&;h=doI{L(b!xRh_O4XGXtxATBr;d!rK*m{;!p8Ha zvQcdg)i_BNP0K>8E1rqE0iKJ@)=b1%0>in@lj+_G>!%V~?xa5hiGueD+$WDiKb6_F ziu=itIJM12A{-_os*#Fpm^>;+nnet)4-X?B=?}C%JoKQ5=^qO6H@BvI-ww2* zS=4R2hCyN<9o5D3Vq@w3(r&GyUfM{tI3ml7d6*`DN{_+#7ikFOJsu7}jYh}Uy!YwT z!C|lQ;cxizZ{Po``R>!PemQ(L8@1jK=>0#s@4wT<|IvIm^#6V|0P$XVZ1d?;qw9Ly z*AjLr$b&Layp+YQEXHXbPGOJmX+lN9Viiccjmw~@m{Sm_MXsdsLM!n04E1FO5=WMv z)Z)Y&CVU7IkjJADvkJzkrlsAMca;D&mM}gO>tq@v9K}p9bsA|bmRj;mN#u>~GQhSP zgBU7U#U*OrG8mq6kZuB|s-AcLgv75Y$kOSQX(yuN!T= zP+Dk-HhijOn8fwRX17`s#ddS!w&*mXCKPAkzQ~qo+ThJeYftSZ&|R2Ch!*eEX487H zQUhf$Rq(Hqle&#N`A{2F1%X%412qSX7^WJ$^$ZNVm5#xOy#(I%c(05BxJOH9NI!>* zMJgYud>O@$=oPTo3jt*RS+T(Yr28v;_-Y>BiuJNcgSX0CSE!5tw3_=YyiKkFRA$#f zC_SPBUoNJh0?n9#5UFa`xge^%K=MBI8q`{ma$#!}`%8 z-pkDfl~*5Bh_0x7O<15^J;`@CfC@=>qj;?NFZ?~9Dt=*9)9-+&xl)L$vCJ)TYP}>2 ztbH36d#dj#aVzNaK=04s)(2YOF#QtP)>pC2h~eAiLVuc+QCLhp#<=dmFyfEIhp)l~ zf2Ax-@`>Y4{>5+3l6dWXf-^;~ynoq*?9ojqNad|6YxBuZ`?!)SYhlk%TPKEe1kCt;#Hvap|mw=U8?1#{%#g45f#xDd66gk2J zi3^wjxHZpjO6Dh7qF8%v5)qa5q!KT{IbhhuN+1pZ)e3-? z|Kc71;KaZ${1^CtBD_ez41tYTB)(*)<7oJL#4iPav~QJ4hfhX)ve|eOaVdU)@6gp9 zG;iyeZF+@Oy)|maW@8-s2qqlb2rerQVA(?bLcADGMm3vfXi5WFUG1pI)AUl}lQxKZ z^DtY6X^-nq?{cs3?|I>`7^~#Kg9bFo_nt}*wwGiq@brrxyfu0Pf}TWK+#_ziR^A0_ zws`OwWFqhzta5uzSx4kBZl*e>nQ2=t!wvODHf7}nJgtAXO8i9gd;R%O60r(2N)Fg! z*H$gFZ~?kNF(Ah)6va>&Q3RAF#+OE+ql|s9Zu^4-9$P>i94Kpy^&<@i8x8x=KKAB> zNrxZzPZUG9T$UVpXjlz<57X3O`xm$DCTQ^cJX0WLM zhWdE_4DWfCYqo-yS$;*go%Ie|tj_IA&E|!iCIz6=ag;AJ1(+68$XMk!G7AbGMv+{o zfb`SWki9FCl9?F7-g#<_3kIsbSrYV13b+px6+(5a%{3`QzRwLuUPJ zp^>X}QrGE~uS;31u7FD9N9>hqmC7M1zDG_Uf(?ka5KyRqrJv`wAU?RU!a{)K*O_iK^o9YFgmV zf*l4^(|(#ZwUBjF8p}tL7tZC8i#58TG$c`Zur{{ewXbhDkv~AD@<4!H>*d%IVZfDx zfkrcgYj!FJqlE(0VuJyKWqy~W>HCbh5dcn0^aZI}2V~)BW1lL$#KBf7bA=O@$oJMtm%6DR}C8(>9T( zgievh-nji`tiK?L0`_5iN)9;Ob1C{GbVV3zJ(1yOd^J8;FRRZZfo36&#>hTz|JnyK zBX1zbLx=QC51Y-k7M}1n+iaRd!uxxo&}I{}2GNkLVr>`5EnQ9S(Jc`vzCo%w(*FaVz`33fg9`|E_w@$+vO`B8TEn+(}ZAX zFkl1OiRgjC_FrZR+>~J&01rgIdvvBy>SLvW*`Zv*N*V9s{t3CVZG>z8l;T~!W{kr_wb^7^M*(2KdzdAFm%4H-kxP`w zncrd@^r08zy(`%_>ePkvVL760u3y2^H>x!`94r5>4H}FrID4wZ*p6$$PO_%Wz0z(a zBXCrk8x#RIhRBWBa{v(f;UeWtvgi#$&5s(y)%_Uv6%yOhe$P3W4b|S#qz(SI>)&wG z5q8;8loN2<@nOUoR4cT~bnfj=Q-G2Hxnl%37vTe+fRj;&uMj8XO?b}GvEe>tolnwY z;lfJxJz10HB^d2mCM%LYRv_0xu(Ip3TN8h~GI#DGr;2O!%3E3)id0=8jW8cg0PYMN z@?t(DrmZo6(izrzr@;Zd;#i=z6K;L7Fu>-pfL}Af+Bp47=iE=UD?h44##1ud5+05E zr9*LZaW-%FI|p-&eAU)P$$0v$;sowHHC!Bvl<)w9iG}j$fsy90aCVSsYs);s1Ae{} zum`9#ibRc2K-^f|k!lA665pHig|!FINj%NlvFTL}PZl;6U=PO(l=W8asjPghnSc%V zK@iUPlE?gxd*@>Hpqe=MQU8FEKUf6-(7-lssA}xz!PPfPoMvIC@TVE|J2WjVI{O0X z?91at{|myMwn6ibdw&`=I~{)M`Zxa6O3%*vUA2u2K&H)yCnKv^Nh}#vO7FKQWK_0^ zd!l=$DL3XQH>PafW{18FS`9~TQgfKp{Bdf7wsV{trUVSvt=%GK7S_Gd4&GWpv}Y@#)V`YKPGWFbeut;y)Oz zaiO1^I`1XyoiQ&Rdz=rf<+d#l#|C(u@N;PF9=3a)0Xe;MGDnz&xhrGQT-Bs7^!#0U zlDon1E4~7|5zRES&NjAhwcW!bv3-4ia?#()X%~&*u4xB`;K|T)Krs?QGHUw0x+B|Gc(ZY%++`(Nh z07mI{36dOS0S9ZML62W*V*JvXb&DWGB%;NG9FRHXT=HbZx2RzlKrgr!6(xy^a;K<3 z|EvRkPB`$6+XU7Pm{P?>ez#X{t;%^T(@YzlxY>Us;S##d`y-+v3=LC2vauqC@M`%_ zPGYk}7diq1B&TUep!*RN0Za+>9=C2p8{z)3_GX&JtbtsIfVpx=7YvB~F+RTJ zdL+z_(zZ|3CKWH+D!veJ(M8fwLm8@}8`YTSuGBabM+G_AJ9w?3qLK4*Agz}53U+1< zM&C9A>WQ=w8d5EBoqF=ecgGk?YUH8}z8m>R^fIXZN=CxIbT%DDYwO;MMhd`Rbk%5; z9a-pJxAcp1(2=?fVfso^7yuRy_957zxA>e{uVHTda%By|67e4J9N38{NONt*z;d^I zX}%5R=V*UH%L2G1d$0&~Dl%64(h#jSO7I9bajGK|B|@zPrjBrkb~0rwc)hy(o-UsP z{AcJKGb{Ccvw2m=7E*DRdJ$mUQk!B)mq%@6#@Y;ve6axYSvDdwMIDdHI$@aH7#=11 z-8x~HM4U7NFAcyYcM3f+k}{Wl^qPqW&aAEGy(PX%SV zYM<_amTLx!rC4AYK&KqT%=Eg;uK%B2Tke=yZrCcO-`9hrJvwFU82#@s1kB`lBkr6u zuxN0?=i;)TLaFDtm=Z+5w8;=SxP3Q+!^5|Jof|^pXQupUS)iU0&5ByiF2u|RF2F9E z=}~F$I7SlHa;62bKES7(^%uh7mQdps^6Oc+h5WWs-ak+N$$PJJwf77b6pYNzct68? z%Dr~Gu=)(D#ITQ+DaZ{qKqC;qI5r1L6w#pA_Ew|qwAqCG4bUXAgPwkS2ZWQnP{jXS zyK5FMyyQSKktBKi{RvyQW09)mw5$;{NbLXbF4)=v2%_pO05q8Tvt>F<(hef5?1D6q z(7zl4Y%Yr-!lmhGFU|8s@82SS(9g_I>Bexe@u`Bsk?C#hQ{G zj>L`5cc7csY7~@J-^&NP5+(xs5+OUiVLGI0-t&*3eULly&1NON3BR;P#|k&&Lk^A^ zTn9Qgh-lu|DL;IRuBPQQO9Q|S_K{m``u&fn>rSzKqWo1z^7CgU+&*%)8>Hjt%4Xb)}^jt5p__$ zIb9%DcWp&zHRDIIvRt?7e;izij~EY{C%|Wc_nYz$P&S(C2o+mRfjug`FG6+$iC-`^ zt*Dlr3SI~^_VibLMkkU20)=Z%>>(76vV^D=9sw5b)To&i86Xm?*Qilr+FM6K#BB{9|34O%a++ z35)!stV?It7?`b%<;c*;WS#NMUuL;(&wT^9&DUTx%QDW>X@EoNT7F)_BP#_`aiHM& zJ>#*!LlvQKR+K`*?fgF7EfvzKjnSFVM=Vl|;5H3IQu#}c$I&pQIk@9UNOHN)Dgg_b z)*ujDxZ7-IZOd{he)Uqu$6|SS==|4$eA!D4C_MyV*yLt2W^@eXFS*(di1psJcf zQ_Y-u7Qmc>mfrL>uMzx`ByP){eIo%SXxZHABg&_Q3ck@v#8VtFYbMaMbw*jXd6pr3 zY+BC=vcday$_>VJdSTBR}oM;)l zk1}>pJLJ01AF~I8J>$;624KYklZklJpu;x z)qH~%;Zo&2Oeou;#cfh1lO#>lDgrLN1~o=QcgUpvPB0yzMVw5hG6P_Nl!8Vyp2?mn%go?X3E@$slDr}&aTG~6o%ZPN#C;_=To)wv=&x5H;H~_EwvJoT18uG zxl{*yD3OR`?H2ECHu_PaZHbeq(biO=5_^C7;;GH*LuK8c61MLeGH4N?yTxOyaS-!o zlvz4G9Yhug!pLuVVC*8}!Io+V0n9<7#_^;XNbkRC80cTXL1l30TZpj}TM* zmBe}e?$yg@c`-LDr*{+1%a2l6wAYlDiJk{(K`_q*h&Sp7Bo8tn=J9sYcQIc1PM6b&^u_0s}UW@thvN~DI|R9 z#6u%j@5u-jRA=`zrM^}IF42b$+rzs{;HKwlv%%x;I^~vHfw%Y8vxkxkkUeIoqwj*} zpewCd&Ha0x`zt&pmbIe@OOZXA^gD8SAxnYhQYYMpt3KKP}GDieUA zcNU~w=iZ|w7`L_0`b}eTt(xEexqUEvJ0HJKQu@NUvl@p;aa-VV%$NI)5S2$tMxmad@uuq;I_&5AXn*FLB?qi94BaQHfmC z@rT+ekfM0qY%u*I7B_fcJezuyaX71h8)o#=4#`wEyaY%FL#T5NW&lI#w7D^#yPqG} zTZm*hcgb-JD_<6r+D5Kuyb)idxdXB`a!4-BY0j}ubxXI2wUz2-g942tw<~edzj{3H zUu`G3t+?^;&xThc*3M~L?apai&=D^_72AOU9SMw?`z3|g9%Jg{rj6^|v?DeK0&O-^ z0+kVFPMvU@0tX_<;MsI5S7mDb0HNb5%_D|3u{khcGgf9K>t~&em9=$(T1J{Zl(6D3 z@^U*|Ho+)pCtx)mT+!eMFSS^q@9)11P=0GE-$POD`*YO&mo*{mH9{0SXfir+QQ zRW@=cb{<3Uwv(t^x!i-naKt)i6?W7yY2&Um9c9?}l;w40OgCmvH?+R#lUMq@L+b;o zx!va?Lhm3_D|{zn1{~64beqFXvLgn z7=QyrAW9ic>ymp~@fd(MIVGXjuvUc=kd*QsD3k*joxH#Y@#qvFg(lV7z)yXU7Jmtg z-hV(RN-FiCK140FoH=TjU9H3Tg4~=u+}V3&F#!xuFQLY@c!~lIdz-Iu-I;eYj=Ea~A*v zJDuSyD7G=rvvZJKxT+{C@CSr2Ehu{E8=lLh@I||H`xO>~J>M?UeBoMoGn>Jz>n8NG zso(hMo~(~1vrCtzG%NHQSFD-u^}Z4P(rBc0s0tXgWpTM5`T$i-5hJk#=De$%?n>HO z(tKSz7z2GY)ItNb>quxS)XpQJY4=Ddi75+u>FlS<0}$4>b#Lojz7tW6)LPwXynTp& z*BIjN7^Lk#Yo9zdDM&?q<}|6e4tatI(mq&_L-it@tER$0*roIjU>FCyKIo^lEO}+; zd^Zsd@l0llIe6^SN==GKO~1wvUboUd8!43TXWuA=a)(<-=j(x7s~aP^OrGqJ(n53z z>(SzJButW@b7%2?0H_vVZ1#F4RPTzI-%hgw*)f6;WamBo{const n=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(r);if(n)return a.push({name:n[1],matcher:n[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const o=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(r);if(o)return a.push({name:o[1],matcher:o[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!r)return;const s=r.split(/\[(.+?)\](?!\])/);return"/"+s.map((c,l)=>{if(l%2){if(c.startsWith("x+"))return ct(String.fromCharCode(parseInt(c.slice(2),16)));if(c.startsWith("u+"))return ct(String.fromCharCode(...c.slice(2).split("-").map(_=>parseInt(_,16))));const h=ue.exec(c),[,u,w,f,d]=h;return a.push({name:f,matcher:d,optional:!!u,rest:!!w,chained:w?l===1&&s[0]==="":!1}),w?"([^]*?)":u?"([^/]*)?":"([^/]+?)"}return ct(c)}).join("")}).join("")}/?$`),params:a}}function de(t){return t!==""&&!/^\([^)]+\)$/.test(t)}function pe(t){return t.slice(1).split("/").filter(de)}function me(t,a,e){const r={},n=t.slice(1),o=n.filter(i=>i!==void 0);let s=0;for(let i=0;ih).join("/"),s=0),l===void 0)if(c.rest)l="";else continue;if(!c.matcher||e[c.matcher](l)){r[c.name]=l;const h=a[i+1],u=n[i+1];h&&!h.rest&&h.optional&&u&&c.chained&&(s=0),!h&&!u&&Object.keys(r).length===o.length&&(s=0);continue}if(c.optional&&c.chained){s++;continue}return}if(!s)return r}function ct(t){return t.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}function ge({nodes:t,server_loads:a,dictionary:e,matchers:r}){const n=new Set(a);return Object.entries(e).map(([i,[c,l,h]])=>{const{pattern:u,params:w}=he(i),f={id:i,exec:d=>{const _=u.exec(d);if(_)return me(_,w,r)},errors:[1,...h||[]].map(d=>t[d]),layouts:[0,...l||[]].map(s),leaf:o(c)};return f.errors.length=f.layouts.length=Math.max(f.errors.length,f.layouts.length),f});function o(i){const c=i<0;return c&&(i=~i),[c,t[i]]}function s(i){return i===void 0?i:[n.has(i),t[i]]}}function Ft(t,a=JSON.parse){try{return a(sessionStorage[t])}catch{}}function It(t,a,e=JSON.stringify){const r=e(a);try{sessionStorage[t]=r}catch{}}function _e(t){return t.filter(a=>a!=null)}function bt(t){return t instanceof wt||t instanceof yt?t.status:500}function we(t){return t instanceof yt?t.text:"Internal Error"}const ve=new Set(["icon","shortcut icon","apple-touch-icon"]),I=Ft(Kt)??{},M=Ft(qt)??{},P={url:Pt({}),page:Pt({}),navigating:ae(null),updated:ne()};function Et(t){I[t]=C()}function ye(t,a){let e=t+1;for(;I[e];)delete I[e],e+=1;for(e=a+1;M[e];)delete M[e],e+=1}function V(t,a=!1){return a?location.replace(t.href):location.href=t.href,new Promise(()=>{})}async function Bt(){if("serviceWorker"in navigator){const t=await navigator.serviceWorker.getRegistration(L||"/");t&&await t.update()}}function Tt(){}let kt,ht,Q,U,dt,E;const Z=[],tt=[];let v=null;function pt(){var t;(t=v==null?void 0:v.fork)==null||t.then(a=>a==null?void 0:a.discard()),v=null}const G=new Map,Mt=new Set,be=new Set,F=new Set;let g={branch:[],error:null,url:null},Vt=!1,et=!1,Ot=!0,H=!1,K=!1,Ht=!1,St=!1,Yt,b,R,O;const at=new Set,Ct=new Map;async function Fe(t,a,e){var o,s,i,c,l;(o=globalThis.__sveltekit_10kbxme)!=null&&o.data&&globalThis.__sveltekit_10kbxme.data,document.URL!==location.href&&(location.href=location.href),E=t,await((i=(s=t.hooks).init)==null?void 0:i.call(s)),kt=ge(t),U=document.documentElement,dt=a,ht=t.nodes[0],Q=t.nodes[1],ht(),Q(),b=(c=history.state)==null?void 0:c[N],R=(l=history.state)==null?void 0:l[B],b||(b=R=Date.now(),history.replaceState({...history.state,[N]:b,[B]:R},""));const r=I[b];function n(){r&&(history.scrollRestoration="manual",scrollTo(r.x,r.y))}e?(n(),await Ce(dt,e)):(await D({type:"enter",url:gt(E.hash?Ne(new URL(location.href)):location.href),replace_state:!0}),n()),Oe()}function Ee(){Z.length=0,St=!1}function zt(t){tt.some(a=>a==null?void 0:a.snapshot)&&(M[t]=tt.map(a=>{var e;return(e=a==null?void 0:a.snapshot)==null?void 0:e.capture()}))}function Wt(t){var a;(a=M[t])==null||a.forEach((e,r)=>{var n,o;(o=(n=tt[r])==null?void 0:n.snapshot)==null||o.restore(e)})}function jt(){Et(b),It(Kt,I),zt(R),It(qt,M)}async function Gt(t,a,e,r){let n;a.invalidateAll&&pt(),await D({type:"goto",url:gt(t),keepfocus:a.keepFocus,noscroll:a.noScroll,replace_state:a.replaceState,state:a.state,redirect_count:e,nav_token:r,accept:()=>{a.invalidateAll&&(St=!0,n=[...Ct.keys()]),a.invalidate&&a.invalidate.forEach(Te)}}),a.invalidateAll&&J().then(J).then(()=>{Ct.forEach(({resource:o},s)=>{var i;n!=null&&n.includes(s)&&((i=o.refresh)==null||i.call(o))})})}async function ke(t){if(t.id!==(v==null?void 0:v.id)){pt();const a={};at.add(a),v={id:t.id,token:a,promise:Xt({...t,preload:a}).then(e=>(at.delete(a),e.type==="loaded"&&e.state.error&&pt(),e)),fork:null}}return v.promise}async function lt(t){var e;const a=(e=await ot(t,!1))==null?void 0:e.route;a&&await Promise.all([...a.layouts,a.leaf].filter(Boolean).map(r=>r[1]()))}async function Jt(t,a,e){var n;g=t.state;const r=document.querySelector("style[data-sveltekit]");if(r&&r.remove(),Object.assign(x,t.props.page),Yt=new E.root({target:a,props:{...t.props,stores:P,components:tt},hydrate:e,sync:!1}),await Promise.resolve(),Wt(R),e){const o={from:null,to:{params:g.params,route:{id:((n=g.route)==null?void 0:n.id)??null},url:new URL(location.href),scroll:I[b]??C()},willUnload:!1,type:"enter",complete:Promise.resolve()};F.forEach(s=>s(o))}et=!0}function nt({url:t,params:a,branch:e,status:r,error:n,route:o,form:s}){let i="never";if(L&&(t.pathname===L||t.pathname===L+"/"))i="always";else for(const f of e)(f==null?void 0:f.slash)!==void 0&&(i=f.slash);t.pathname=se(t.pathname,i),t.search=t.search;const c={type:"loaded",state:{url:t,params:a,branch:e,error:n,route:o},props:{constructors:_e(e).map(f=>f.node.component),page:At(x)}};s!==void 0&&(c.props.form=s);let l={},h=!x,u=0;for(let f=0;fi(new URL(s))))return!0;return!1}function xt(t,a){return(t==null?void 0:t.type)==="data"?t:(t==null?void 0:t.type)==="skip"?a??null:null}function xe(t,a){if(!t)return new Set(a.searchParams.keys());const e=new Set([...t.searchParams.keys(),...a.searchParams.keys()]);for(const r of e){const n=t.searchParams.getAll(r),o=a.searchParams.getAll(r);n.every(s=>o.includes(s))&&o.every(s=>n.includes(s))&&e.delete(r)}return e}function Le({error:t,url:a,route:e,params:r}){return{type:"loaded",state:{error:t,url:a,route:e,params:r,branch:[]},props:{page:At(x),constructors:[]}}}async function Xt({id:t,invalidating:a,url:e,params:r,route:n,preload:o}){if((v==null?void 0:v.id)===t)return at.delete(v.token),v.promise;const{errors:s,layouts:i,leaf:c}=n,l=[...i,c];s.forEach(m=>m==null?void 0:m().catch(()=>{})),l.forEach(m=>m==null?void 0:m[1]().catch(()=>{}));const h=g.url?t!==rt(g.url):!1,u=g.route?n.id!==g.route.id:!1,w=xe(g.url,e);let f=!1;const d=l.map(async(m,p)=>{var A;if(!m)return;const y=g.branch[p];return m[1]===(y==null?void 0:y.loader)&&!Re(f,u,h,w,(A=y.universal)==null?void 0:A.uses,r)?y:(f=!0,Rt({loader:m[1],url:e,params:r,route:n,parent:async()=>{var z;const T={};for(let j=0;j{});const _=[];for(let m=0;mPromise.resolve({}),server_data_node:xt(o)}),i={node:await Q(),loader:Q,universal:null,server:null,data:null};return nt({url:e,params:n,branch:[s,i],status:t,error:a,route:null})}catch(s){if(s instanceof vt)return Gt(new URL(s.location,location.href),{},0);throw s}}async function Ae(t){const a=t.href;if(G.has(a))return G.get(a);let e;try{const r=(async()=>{let n=await E.hooks.reroute({url:new URL(t),fetch:async(o,s)=>Se(o,s,t).promise})??t;if(typeof n=="string"){const o=new URL(t);E.hash?o.hash=n:o.pathname=n,n=o}return n})();G.set(a,r),e=await r}catch{G.delete(a);return}return e}async function ot(t,a){if(t&&!_t(t,L,E.hash)){const e=await Ae(t);if(!e)return;const r=Pe(e);for(const n of kt){const o=n.exec(r);if(o)return{id:rt(t),invalidating:a,route:n,params:oe(o),url:t}}}}function Pe(t){return ie(E.hash?t.hash.replace(/^#/,"").replace(/[?#].+/,""):t.pathname.slice(L.length))||"/"}function rt(t){return(E.hash?t.hash.replace(/^#/,""):t.pathname)+t.search}function Qt({url:t,type:a,intent:e,delta:r,event:n,scroll:o}){let s=!1;const i=Ut(g,e,t,a,o??null);r!==void 0&&(i.navigation.delta=r),n!==void 0&&(i.navigation.event=n);const c={...i.navigation,cancel:()=>{s=!0,i.reject(new Error("navigation cancelled"))}};return H||Mt.forEach(l=>l(c)),s?null:i}async function D({type:t,url:a,popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s={},redirect_count:i=0,nav_token:c={},accept:l=Tt,block:h=Tt,event:u}){var j;const w=O;O=c;const f=await ot(a,!1),d=t==="enter"?Ut(g,f,a,t):Qt({url:a,type:t,delta:e==null?void 0:e.delta,intent:f,scroll:e==null?void 0:e.scroll,event:u});if(!d){h(),O===c&&(O=w);return}const _=b,m=R;l(),H=!0,et&&d.navigation.type!=="enter"&&P.navigating.set(ft.current=d.navigation);let p=f&&await Xt(f);if(!p){if(_t(a,L,E.hash))return await V(a,o);p=await Zt(a,{id:null},await Y(new yt(404,"Not Found",`Not found: ${a.pathname}`),{url:a,params:{},route:{id:null}}),404,o)}if(a=(f==null?void 0:f.url)||a,O!==c)return d.reject(new Error("navigation aborted")),!1;if(p.type==="redirect"){if(i<20){await D({type:t,url:new URL(p.location,a),popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s,redirect_count:i+1,nav_token:c}),d.fulfil(void 0);return}p=await Lt({status:500,error:await Y(new Error("Redirect loop"),{url:a,params:{},route:{id:null}}),url:a,route:{id:null}})}else p.props.page.status>=400&&await P.updated.check()&&(await Bt(),await V(a,o));if(Ee(),Et(_),zt(m),p.props.page.url.pathname!==a.pathname&&(a.pathname=p.props.page.url.pathname),s=e?e.state:s,!e){const k=o?0:1,W={[N]:b+=k,[B]:R+=k,[Nt]:s};(o?history.replaceState:history.pushState).call(history,W,"",a),o||ye(b,R)}const y=f&&(v==null?void 0:v.id)===f.id?v.fork:null;v=null,p.props.page.state=s;let S;if(et){const k=(await Promise.all(Array.from(be,$=>$(d.navigation)))).filter($=>typeof $=="function");if(k.length>0){let $=function(){k.forEach(st=>{F.delete(st)})};k.push($),k.forEach(st=>{F.add(st)})}g=p.state,p.props.page&&(p.props.page.url=a);const W=y&&await y;W?S=W.commit():(Yt.$set(p.props),fe(p.props.page),S=(j=ee)==null?void 0:j()),Ht=!0}else await Jt(p,dt,!1);const{activeElement:A}=document;await S,await J(),await J();let T=null;if(Ot){const k=e?e.scroll:n?C():null;k?scrollTo(k.x,k.y):(T=a.hash&&document.getElementById(te(a)))?T.scrollIntoView():scrollTo(0,0)}const z=document.activeElement!==A&&document.activeElement!==document.body;!r&&!z&&$e(a,!T),Ot=!0,p.props.page&&Object.assign(x,p.props.page),H=!1,t==="popstate"&&Wt(R),d.fulfil(void 0),d.navigation.to&&(d.navigation.to.scroll=C()),F.forEach(k=>k(d.navigation)),P.navigating.set(ft.current=null)}async function Zt(t,a,e,r,n){return t.origin===Dt&&t.pathname===location.pathname&&!Vt?await Lt({status:r,error:e,url:t,route:a}):await V(t,n)}function Ie(){let t,a={element:void 0,href:void 0},e;U.addEventListener("mousemove",i=>{const c=i.target;clearTimeout(t),t=setTimeout(()=>{o(c,q.hover)},20)});function r(i){i.defaultPrevented||o(i.composedPath()[0],q.tap)}U.addEventListener("mousedown",r),U.addEventListener("touchstart",r,{passive:!0});const n=new IntersectionObserver(i=>{for(const c of i)c.isIntersecting&&(lt(new URL(c.target.href)),n.unobserve(c.target))},{threshold:0});async function o(i,c){const l=$t(i,U),h=l===a.element&&(l==null?void 0:l.href)===a.href&&c>=e;if(!l||h)return;const{url:u,external:w,download:f}=ut(l,L,E.hash);if(w||f)return;const d=X(l),_=u&&rt(g.url)===rt(u);if(!(d.reload||_))if(c<=d.preload_data){a={element:l,href:l.href},e=q.tap;const m=await ot(u,!1);if(!m)return;ke(m)}else c<=d.preload_code&&(a={element:l,href:l.href},e=c,lt(u))}function s(){n.disconnect();for(const i of U.querySelectorAll("a")){const{url:c,external:l,download:h}=ut(i,L,E.hash);if(l||h)continue;const u=X(i);u.reload||(u.preload_code===q.viewport&&n.observe(i),u.preload_code===q.eager&<(c))}}F.add(s),s()}function Y(t,a){if(t instanceof wt)return t.body;const e=bt(t),r=we(t);return E.hooks.handleError({error:t,event:a,status:e,message:r})??{message:r}}function Be(t,a={}){return t=new URL(gt(t)),t.origin!==Dt?Promise.reject(new Error("goto: invalid URL")):Gt(t,a,0)}function Te(t){if(typeof t=="function")Z.push(t);else{const{href:a}=new URL(t,location.href);Z.push(e=>e.href===a)}}function Oe(){var a;history.scrollRestoration="manual",addEventListener("beforeunload",e=>{let r=!1;if(jt(),!H){const n=Ut(g,void 0,null,"leave"),o={...n.navigation,cancel:()=>{r=!0,n.reject(new Error("navigation cancelled"))}};Mt.forEach(s=>s(o))}r?(e.preventDefault(),e.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&jt()}),(a=navigator.connection)!=null&&a.saveData||Ie(),U.addEventListener("click",async e=>{if(e.button||e.which!==1||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.defaultPrevented)return;const r=$t(e.composedPath()[0],U);if(!r)return;const{url:n,external:o,target:s,download:i}=ut(r,L,E.hash);if(!n)return;if(s==="_parent"||s==="_top"){if(window.parent!==window)return}else if(s&&s!=="_self")return;const c=X(r);if(!(r instanceof SVGAElement)&&n.protocol!==location.protocol&&!(n.protocol==="https:"||n.protocol==="http:")||i)return;const[h,u]=(E.hash?n.hash.replace(/^#/,""):n.href).split("#"),w=h===it(location);if(o||c.reload&&(!w||!u)){Qt({url:n,type:"link",event:e})?H=!0:e.preventDefault();return}if(u!==void 0&&w){const[,f]=g.url.href.split("#");if(f===u){if(e.preventDefault(),u===""||u==="top"&&r.ownerDocument.getElementById("top")===null)scrollTo({top:0});else{const d=r.ownerDocument.getElementById(decodeURIComponent(u));d&&(d.scrollIntoView(),d.focus())}return}if(K=!0,Et(b),t(n),!c.replace_state)return;K=!1}e.preventDefault(),await new Promise(f=>{requestAnimationFrame(()=>{setTimeout(f,0)}),setTimeout(f,100)}),await D({type:"link",url:n,keepfocus:c.keepfocus,noscroll:c.noscroll,replace_state:c.replace_state??n.href===location.href,event:e})}),U.addEventListener("submit",e=>{if(e.defaultPrevented)return;const r=HTMLFormElement.prototype.cloneNode.call(e.target),n=e.submitter;if(((n==null?void 0:n.formTarget)||r.target)==="_blank"||((n==null?void 0:n.formMethod)||r.method)!=="get")return;const i=new URL((n==null?void 0:n.hasAttribute("formaction"))&&(n==null?void 0:n.formAction)||r.action);if(_t(i,L,!1))return;const c=e.target,l=X(c);if(l.reload)return;e.preventDefault(),e.stopPropagation();const h=new FormData(c,n);i.search=new URLSearchParams(h).toString(),D({type:"form",url:i,keepfocus:l.keepfocus,noscroll:l.noscroll,replace_state:l.replace_state??i.href===location.href,event:e})}),addEventListener("popstate",async e=>{var r;if(!mt){if((r=e.state)!=null&&r[N]){const n=e.state[N];if(O={},n===b)return;const o=I[n],s=e.state[Nt]??{},i=new URL(e.state[re]??location.href),c=e.state[B],l=g.url?it(location)===it(g.url):!1;if(c===R&&(Ht||l)){s!==x.state&&(x.state=s),t(i),I[b]=C(),o&&scrollTo(o.x,o.y),b=n;return}const u=n-b;await D({type:"popstate",url:i,popped:{state:s,scroll:o,delta:u},accept:()=>{b=n,R=c},block:()=>{history.go(-u)},nav_token:O,event:e})}else if(!K){const n=new URL(location.href);t(n),E.hash&&location.reload()}}}),addEventListener("hashchange",()=>{K&&(K=!1,history.replaceState({...history.state,[N]:++b,[B]:R},"",location.href))});for(const e of document.querySelectorAll("link"))ve.has(e.rel)&&(e.href=e.href);addEventListener("pageshow",e=>{e.persisted&&P.navigating.set(ft.current=null)});function t(e){g.url=x.url=e,P.page.set(At(x)),P.page.notify()}}async function Ce(t,{status:a=200,error:e,node_ids:r,params:n,route:o,server_route:s,data:i,form:c}){Vt=!0;const l=new URL(location.href);let h;({params:n={},route:o={id:null}}=await ot(l,!1)||{}),h=kt.find(({id:f})=>f===o.id);let u,w=!0;try{const f=r.map(async(_,m)=>{const p=i[m];return p!=null&&p.uses&&(p.uses=je(p.uses)),Rt({loader:E.nodes[_],url:l,params:n,route:o,parent:async()=>{const y={};for(let S=0;S{const i=history.state;mt=!0,location.replace(new URL(`#${r}`,location.href)),history.replaceState(i,"",t),a&&scrollTo(o,s),mt=!1})}else{const o=document.body,s=o.getAttribute("tabindex");o.tabIndex=-1,o.focus({preventScroll:!0,focusVisible:!1}),s!==null?o.setAttribute("tabindex",s):o.removeAttribute("tabindex")}const n=getSelection();if(n&&n.type!=="None"){const o=[];for(let s=0;s{if(n.rangeCount===o.length){for(let s=0;s{o=u,s=w});return i.catch(()=>{}),{navigation:{from:{params:t.params,route:{id:((l=t.route)==null?void 0:l.id)??null},url:t.url,scroll:C()},to:e&&{params:(a==null?void 0:a.params)??null,route:{id:((h=a==null?void 0:a.route)==null?void 0:h.id)??null},url:e,scroll:n},willUnload:!a,type:r,complete:i},fulfil:o,reject:s}}function At(t){return{data:t.data,error:t.error,form:t.form,params:t.params,route:t.route,state:t.state,status:t.status,url:t.url}}function Ne(t){const a=new URL(t);return a.hash=decodeURIComponent(t.hash),a}function te(t){let a;if(E.hash){const[,,e]=t.hash.split("#",3);a=e??""}else a=t.hash.slice(1);return decodeURIComponent(a)}export{Fe as a,Be as g,P as s}; +import{$ as J,bd as ee}from"./CpWkWWOo.js";import{w as ae}from"./BeMFXnHE.js";import{c as ne,H as N,N as B,r as mt,i as _t,b as L,s as j,p as x,n as ft,f as $t,g as ut,a as X,d as it,S as Nt,P as re,e as oe,h as se,o as qt,j as D,k as ie,l as Dt,m as ce,q as le,t as Kt,u as Pt,v as fe}from"./BdslOLCg.js";class wt{constructor(a,e){this.status=a,typeof e=="string"?this.body={message:e}:e?this.body=e:this.body={message:`Error: ${a}`}}toString(){return JSON.stringify(this.body)}}class vt{constructor(a,e){this.status=a,this.location=e}}class yt extends Error{constructor(a,e,r){super(r),this.status=a,this.text=e}}const ue=/^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/;function he(t){const a=[];return{pattern:t==="/"?/^\/$/:new RegExp(`^${pe(t).map(r=>{const n=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(r);if(n)return a.push({name:n[1],matcher:n[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const o=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(r);if(o)return a.push({name:o[1],matcher:o[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!r)return;const s=r.split(/\[(.+?)\](?!\])/);return"/"+s.map((c,l)=>{if(l%2){if(c.startsWith("x+"))return ct(String.fromCharCode(parseInt(c.slice(2),16)));if(c.startsWith("u+"))return ct(String.fromCharCode(...c.slice(2).split("-").map(_=>parseInt(_,16))));const h=ue.exec(c),[,u,w,f,d]=h;return a.push({name:f,matcher:d,optional:!!u,rest:!!w,chained:w?l===1&&s[0]==="":!1}),w?"([^]*?)":u?"([^/]*)?":"([^/]+?)"}return ct(c)}).join("")}).join("")}/?$`),params:a}}function de(t){return t!==""&&!/^\([^)]+\)$/.test(t)}function pe(t){return t.slice(1).split("/").filter(de)}function ge(t,a,e){const r={},n=t.slice(1),o=n.filter(i=>i!==void 0);let s=0;for(let i=0;ih).join("/"),s=0),l===void 0)if(c.rest)l="";else continue;if(!c.matcher||e[c.matcher](l)){r[c.name]=l;const h=a[i+1],u=n[i+1];h&&!h.rest&&h.optional&&u&&c.chained&&(s=0),!h&&!u&&Object.keys(r).length===o.length&&(s=0);continue}if(c.optional&&c.chained){s++;continue}return}if(!s)return r}function ct(t){return t.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}function me({nodes:t,server_loads:a,dictionary:e,matchers:r}){const n=new Set(a);return Object.entries(e).map(([i,[c,l,h]])=>{const{pattern:u,params:w}=he(i),f={id:i,exec:d=>{const _=u.exec(d);if(_)return ge(_,w,r)},errors:[1,...h||[]].map(d=>t[d]),layouts:[0,...l||[]].map(s),leaf:o(c)};return f.errors.length=f.layouts.length=Math.max(f.errors.length,f.layouts.length),f});function o(i){const c=i<0;return c&&(i=~i),[c,t[i]]}function s(i){return i===void 0?i:[n.has(i),t[i]]}}function Ft(t,a=JSON.parse){try{return a(sessionStorage[t])}catch{}}function It(t,a,e=JSON.stringify){const r=e(a);try{sessionStorage[t]=r}catch{}}function _e(t){return t.filter(a=>a!=null)}function Et(t){return t instanceof wt||t instanceof yt?t.status:500}function we(t){return t instanceof yt?t.text:"Internal Error"}const ve=new Set(["icon","shortcut icon","apple-touch-icon"]),I=Ft(Kt)??{},M=Ft(Dt)??{},P={url:Pt({}),page:Pt({}),navigating:ae(null),updated:ne()};function bt(t){I[t]=j()}function ye(t,a){let e=t+1;for(;I[e];)delete I[e],e+=1;for(e=a+1;M[e];)delete M[e],e+=1}function V(t,a=!1){return a?location.replace(t.href):location.href=t.href,new Promise(()=>{})}async function Bt(){if("serviceWorker"in navigator){const t=await navigator.serviceWorker.getRegistration(L||"/");t&&await t.update()}}function Tt(){}let kt,ht,Q,U,dt,b;const Z=[],tt=[];let v=null;function pt(){var t;(t=v==null?void 0:v.fork)==null||t.then(a=>a==null?void 0:a.discard()),v=null}const G=new Map,Mt=new Set,Ee=new Set,F=new Set;let m={branch:[],error:null,url:null},Vt=!1,et=!1,Ot=!0,H=!1,K=!1,Ht=!1,St=!1,Yt,E,R,O;const at=new Set,jt=new Map;async function Fe(t,a,e){var o,s,i,c,l;(o=globalThis.__sveltekit_1qjqcdh)!=null&&o.data&&globalThis.__sveltekit_1qjqcdh.data,document.URL!==location.href&&(location.href=location.href),b=t,await((i=(s=t.hooks).init)==null?void 0:i.call(s)),kt=me(t),U=document.documentElement,dt=a,ht=t.nodes[0],Q=t.nodes[1],ht(),Q(),E=(c=history.state)==null?void 0:c[N],R=(l=history.state)==null?void 0:l[B],E||(E=R=Date.now(),history.replaceState({...history.state,[N]:E,[B]:R},""));const r=I[E];function n(){r&&(history.scrollRestoration="manual",scrollTo(r.x,r.y))}e?(n(),await je(dt,e)):(await q({type:"enter",url:mt(b.hash?Ne(new URL(location.href)):location.href),replace_state:!0}),n()),Oe()}function be(){Z.length=0,St=!1}function zt(t){tt.some(a=>a==null?void 0:a.snapshot)&&(M[t]=tt.map(a=>{var e;return(e=a==null?void 0:a.snapshot)==null?void 0:e.capture()}))}function Wt(t){var a;(a=M[t])==null||a.forEach((e,r)=>{var n,o;(o=(n=tt[r])==null?void 0:n.snapshot)==null||o.restore(e)})}function Ct(){bt(E),It(Kt,I),zt(R),It(Dt,M)}async function Gt(t,a,e,r){let n;a.invalidateAll&&pt(),await q({type:"goto",url:mt(t),keepfocus:a.keepFocus,noscroll:a.noScroll,replace_state:a.replaceState,state:a.state,redirect_count:e,nav_token:r,accept:()=>{a.invalidateAll&&(St=!0,n=[...jt.keys()]),a.invalidate&&a.invalidate.forEach(Te)}}),a.invalidateAll&&J().then(J).then(()=>{jt.forEach(({resource:o},s)=>{var i;n!=null&&n.includes(s)&&((i=o.refresh)==null||i.call(o))})})}async function ke(t){if(t.id!==(v==null?void 0:v.id)){pt();const a={};at.add(a),v={id:t.id,token:a,promise:Xt({...t,preload:a}).then(e=>(at.delete(a),e.type==="loaded"&&e.state.error&&pt(),e)),fork:null}}return v.promise}async function lt(t){var e;const a=(e=await ot(t,!1))==null?void 0:e.route;a&&await Promise.all([...a.layouts,a.leaf].filter(Boolean).map(r=>r[1]()))}async function Jt(t,a,e){var n;m=t.state;const r=document.querySelector("style[data-sveltekit]");if(r&&r.remove(),Object.assign(x,t.props.page),Yt=new b.root({target:a,props:{...t.props,stores:P,components:tt},hydrate:e,sync:!1}),await Promise.resolve(),Wt(R),e){const o={from:null,to:{params:m.params,route:{id:((n=m.route)==null?void 0:n.id)??null},url:new URL(location.href),scroll:I[E]??j()},willUnload:!1,type:"enter",complete:Promise.resolve()};F.forEach(s=>s(o))}et=!0}function nt({url:t,params:a,branch:e,status:r,error:n,route:o,form:s}){let i="never";if(L&&(t.pathname===L||t.pathname===L+"/"))i="always";else for(const f of e)(f==null?void 0:f.slash)!==void 0&&(i=f.slash);t.pathname=se(t.pathname,i),t.search=t.search;const c={type:"loaded",state:{url:t,params:a,branch:e,error:n,route:o},props:{constructors:_e(e).map(f=>f.node.component),page:At(x)}};s!==void 0&&(c.props.form=s);let l={},h=!x,u=0;for(let f=0;fi(new URL(s))))return!0;return!1}function xt(t,a){return(t==null?void 0:t.type)==="data"?t:(t==null?void 0:t.type)==="skip"?a??null:null}function xe(t,a){if(!t)return new Set(a.searchParams.keys());const e=new Set([...t.searchParams.keys(),...a.searchParams.keys()]);for(const r of e){const n=t.searchParams.getAll(r),o=a.searchParams.getAll(r);n.every(s=>o.includes(s))&&o.every(s=>n.includes(s))&&e.delete(r)}return e}function Le({error:t,url:a,route:e,params:r}){return{type:"loaded",state:{error:t,url:a,route:e,params:r,branch:[]},props:{page:At(x),constructors:[]}}}async function Xt({id:t,invalidating:a,url:e,params:r,route:n,preload:o}){if((v==null?void 0:v.id)===t)return at.delete(v.token),v.promise;const{errors:s,layouts:i,leaf:c}=n,l=[...i,c];s.forEach(g=>g==null?void 0:g().catch(()=>{})),l.forEach(g=>g==null?void 0:g[1]().catch(()=>{}));const h=m.url?t!==rt(m.url):!1,u=m.route?n.id!==m.route.id:!1,w=xe(m.url,e);let f=!1;const d=l.map(async(g,p)=>{var A;if(!g)return;const y=m.branch[p];return g[1]===(y==null?void 0:y.loader)&&!Re(f,u,h,w,(A=y.universal)==null?void 0:A.uses,r)?y:(f=!0,Rt({loader:g[1],url:e,params:r,route:n,parent:async()=>{var z;const T={};for(let C=0;C{});const _=[];for(let g=0;gPromise.resolve({}),server_data_node:xt(o)}),i={node:await Q(),loader:Q,universal:null,server:null,data:null};return nt({url:e,params:n,branch:[s,i],status:t,error:a,route:null})}catch(s){if(s instanceof vt)return Gt(new URL(s.location,location.href),{},0);throw s}}async function Ae(t){const a=t.href;if(G.has(a))return G.get(a);let e;try{const r=(async()=>{let n=await b.hooks.reroute({url:new URL(t),fetch:async(o,s)=>Se(o,s,t).promise})??t;if(typeof n=="string"){const o=new URL(t);b.hash?o.hash=n:o.pathname=n,n=o}return n})();G.set(a,r),e=await r}catch{G.delete(a);return}return e}async function ot(t,a){if(t&&!_t(t,L,b.hash)){const e=await Ae(t);if(!e)return;const r=Pe(e);for(const n of kt){const o=n.exec(r);if(o)return{id:rt(t),invalidating:a,route:n,params:oe(o),url:t}}}}function Pe(t){return ie(b.hash?t.hash.replace(/^#/,"").replace(/[?#].+/,""):t.pathname.slice(L.length))||"/"}function rt(t){return(b.hash?t.hash.replace(/^#/,""):t.pathname)+t.search}function Qt({url:t,type:a,intent:e,delta:r,event:n,scroll:o}){let s=!1;const i=Ut(m,e,t,a,o??null);r!==void 0&&(i.navigation.delta=r),n!==void 0&&(i.navigation.event=n);const c={...i.navigation,cancel:()=>{s=!0,i.reject(new Error("navigation cancelled"))}};return H||Mt.forEach(l=>l(c)),s?null:i}async function q({type:t,url:a,popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s={},redirect_count:i=0,nav_token:c={},accept:l=Tt,block:h=Tt,event:u}){var C;const w=O;O=c;const f=await ot(a,!1),d=t==="enter"?Ut(m,f,a,t):Qt({url:a,type:t,delta:e==null?void 0:e.delta,intent:f,scroll:e==null?void 0:e.scroll,event:u});if(!d){h(),O===c&&(O=w);return}const _=E,g=R;l(),H=!0,et&&d.navigation.type!=="enter"&&P.navigating.set(ft.current=d.navigation);let p=f&&await Xt(f);if(!p){if(_t(a,L,b.hash))return await V(a,o);p=await Zt(a,{id:null},await Y(new yt(404,"Not Found",`Not found: ${a.pathname}`),{url:a,params:{},route:{id:null}}),404,o)}if(a=(f==null?void 0:f.url)||a,O!==c)return d.reject(new Error("navigation aborted")),!1;if(p.type==="redirect"){if(i<20){await q({type:t,url:new URL(p.location,a),popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s,redirect_count:i+1,nav_token:c}),d.fulfil(void 0);return}p=await Lt({status:500,error:await Y(new Error("Redirect loop"),{url:a,params:{},route:{id:null}}),url:a,route:{id:null}})}else p.props.page.status>=400&&await P.updated.check()&&(await Bt(),await V(a,o));if(be(),bt(_),zt(g),p.props.page.url.pathname!==a.pathname&&(a.pathname=p.props.page.url.pathname),s=e?e.state:s,!e){const k=o?0:1,W={[N]:E+=k,[B]:R+=k,[Nt]:s};(o?history.replaceState:history.pushState).call(history,W,"",a),o||ye(E,R)}const y=f&&(v==null?void 0:v.id)===f.id?v.fork:null;v=null,p.props.page.state=s;let S;if(et){const k=(await Promise.all(Array.from(Ee,$=>$(d.navigation)))).filter($=>typeof $=="function");if(k.length>0){let $=function(){k.forEach(st=>{F.delete(st)})};k.push($),k.forEach(st=>{F.add(st)})}m=p.state,p.props.page&&(p.props.page.url=a);const W=y&&await y;W?S=W.commit():(Yt.$set(p.props),fe(p.props.page),S=(C=ee)==null?void 0:C()),Ht=!0}else await Jt(p,dt,!1);const{activeElement:A}=document;await S,await J(),await J();let T=null;if(Ot){const k=e?e.scroll:n?j():null;k?scrollTo(k.x,k.y):(T=a.hash&&document.getElementById(te(a)))?T.scrollIntoView():scrollTo(0,0)}const z=document.activeElement!==A&&document.activeElement!==document.body;!r&&!z&&$e(a,!T),Ot=!0,p.props.page&&Object.assign(x,p.props.page),H=!1,t==="popstate"&&Wt(R),d.fulfil(void 0),d.navigation.to&&(d.navigation.to.scroll=j()),F.forEach(k=>k(d.navigation)),P.navigating.set(ft.current=null)}async function Zt(t,a,e,r,n){return t.origin===qt&&t.pathname===location.pathname&&!Vt?await Lt({status:r,error:e,url:t,route:a}):await V(t,n)}function Ie(){let t,a={element:void 0,href:void 0},e;U.addEventListener("mousemove",i=>{const c=i.target;clearTimeout(t),t=setTimeout(()=>{o(c,D.hover)},20)});function r(i){i.defaultPrevented||o(i.composedPath()[0],D.tap)}U.addEventListener("mousedown",r),U.addEventListener("touchstart",r,{passive:!0});const n=new IntersectionObserver(i=>{for(const c of i)c.isIntersecting&&(lt(new URL(c.target.href)),n.unobserve(c.target))},{threshold:0});async function o(i,c){const l=$t(i,U),h=l===a.element&&(l==null?void 0:l.href)===a.href&&c>=e;if(!l||h)return;const{url:u,external:w,download:f}=ut(l,L,b.hash);if(w||f)return;const d=X(l),_=u&&rt(m.url)===rt(u);if(!(d.reload||_))if(c<=d.preload_data){a={element:l,href:l.href},e=D.tap;const g=await ot(u,!1);if(!g)return;ke(g)}else c<=d.preload_code&&(a={element:l,href:l.href},e=c,lt(u))}function s(){n.disconnect();for(const i of U.querySelectorAll("a")){const{url:c,external:l,download:h}=ut(i,L,b.hash);if(l||h)continue;const u=X(i);u.reload||(u.preload_code===D.viewport&&n.observe(i),u.preload_code===D.eager&<(c))}}F.add(s),s()}function Y(t,a){if(t instanceof wt)return t.body;const e=Et(t),r=we(t);return b.hooks.handleError({error:t,event:a,status:e,message:r})??{message:r}}function Be(t,a={}){return t=new URL(mt(t)),t.origin!==qt?Promise.reject(new Error("goto: invalid URL")):Gt(t,a,0)}function Te(t){if(typeof t=="function")Z.push(t);else{const{href:a}=new URL(t,location.href);Z.push(e=>e.href===a)}}function Oe(){var a;history.scrollRestoration="manual",addEventListener("beforeunload",e=>{let r=!1;if(Ct(),!H){const n=Ut(m,void 0,null,"leave"),o={...n.navigation,cancel:()=>{r=!0,n.reject(new Error("navigation cancelled"))}};Mt.forEach(s=>s(o))}r?(e.preventDefault(),e.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&Ct()}),(a=navigator.connection)!=null&&a.saveData||Ie(),U.addEventListener("click",async e=>{if(e.button||e.which!==1||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.defaultPrevented)return;const r=$t(e.composedPath()[0],U);if(!r)return;const{url:n,external:o,target:s,download:i}=ut(r,L,b.hash);if(!n)return;if(s==="_parent"||s==="_top"){if(window.parent!==window)return}else if(s&&s!=="_self")return;const c=X(r);if(!(r instanceof SVGAElement)&&n.protocol!==location.protocol&&!(n.protocol==="https:"||n.protocol==="http:")||i)return;const[h,u]=(b.hash?n.hash.replace(/^#/,""):n.href).split("#"),w=h===it(location);if(o||c.reload&&(!w||!u)){Qt({url:n,type:"link",event:e})?H=!0:e.preventDefault();return}if(u!==void 0&&w){const[,f]=m.url.href.split("#");if(f===u){if(e.preventDefault(),u===""||u==="top"&&r.ownerDocument.getElementById("top")===null)scrollTo({top:0});else{const d=r.ownerDocument.getElementById(decodeURIComponent(u));d&&(d.scrollIntoView(),d.focus())}return}if(K=!0,bt(E),t(n),!c.replace_state)return;K=!1}e.preventDefault(),await new Promise(f=>{requestAnimationFrame(()=>{setTimeout(f,0)}),setTimeout(f,100)}),await q({type:"link",url:n,keepfocus:c.keepfocus,noscroll:c.noscroll,replace_state:c.replace_state??n.href===location.href,event:e})}),U.addEventListener("submit",e=>{if(e.defaultPrevented)return;const r=HTMLFormElement.prototype.cloneNode.call(e.target),n=e.submitter;if(((n==null?void 0:n.formTarget)||r.target)==="_blank"||((n==null?void 0:n.formMethod)||r.method)!=="get")return;const i=new URL((n==null?void 0:n.hasAttribute("formaction"))&&(n==null?void 0:n.formAction)||r.action);if(_t(i,L,!1))return;const c=e.target,l=X(c);if(l.reload)return;e.preventDefault(),e.stopPropagation();const h=new FormData(c,n);i.search=new URLSearchParams(h).toString(),q({type:"form",url:i,keepfocus:l.keepfocus,noscroll:l.noscroll,replace_state:l.replace_state??i.href===location.href,event:e})}),addEventListener("popstate",async e=>{var r;if(!gt){if((r=e.state)!=null&&r[N]){const n=e.state[N];if(O={},n===E)return;const o=I[n],s=e.state[Nt]??{},i=new URL(e.state[re]??location.href),c=e.state[B],l=m.url?it(location)===it(m.url):!1;if(c===R&&(Ht||l)){s!==x.state&&(x.state=s),t(i),I[E]=j(),o&&scrollTo(o.x,o.y),E=n;return}const u=n-E;await q({type:"popstate",url:i,popped:{state:s,scroll:o,delta:u},accept:()=>{E=n,R=c},block:()=>{history.go(-u)},nav_token:O,event:e})}else if(!K){const n=new URL(location.href);t(n),b.hash&&location.reload()}}}),addEventListener("hashchange",()=>{K&&(K=!1,history.replaceState({...history.state,[N]:++E,[B]:R},"",location.href))});for(const e of document.querySelectorAll("link"))ve.has(e.rel)&&(e.href=e.href);addEventListener("pageshow",e=>{e.persisted&&P.navigating.set(ft.current=null)});function t(e){m.url=x.url=e,P.page.set(At(x)),P.page.notify()}}async function je(t,{status:a=200,error:e,node_ids:r,params:n,route:o,server_route:s,data:i,form:c}){Vt=!0;const l=new URL(location.href);let h;({params:n={},route:o={id:null}}=await ot(l,!1)||{}),h=kt.find(({id:f})=>f===o.id);let u,w=!0;try{const f=r.map(async(_,g)=>{const p=i[g];return p!=null&&p.uses&&(p.uses=Ce(p.uses)),Rt({loader:b.nodes[_],url:l,params:n,route:o,parent:async()=>{const y={};for(let S=0;S{const i=history.state;gt=!0,location.replace(new URL(`#${r}`,location.href)),history.replaceState(i,"",t),a&&scrollTo(o,s),gt=!1})}else{const o=document.body,s=o.getAttribute("tabindex");o.tabIndex=-1,o.focus({preventScroll:!0,focusVisible:!1}),s!==null?o.setAttribute("tabindex",s):o.removeAttribute("tabindex")}const n=getSelection();if(n&&n.type!=="None"){const o=[];for(let s=0;s{if(n.rangeCount===o.length){for(let s=0;s{o=u,s=w});return i.catch(()=>{}),{navigation:{from:{params:t.params,route:{id:((l=t.route)==null?void 0:l.id)??null},url:t.url,scroll:j()},to:e&&{params:(a==null?void 0:a.params)??null,route:{id:((h=a==null?void 0:a.route)==null?void 0:h.id)??null},url:e,scroll:n},willUnload:!a,type:r,complete:i},fulfil:o,reject:s}}function At(t){return{data:t.data,error:t.error,form:t.form,params:t.params,route:t.route,state:t.state,status:t.status,url:t.url}}function Ne(t){const a=new URL(t);return a.hash=decodeURIComponent(t.hash),a}function te(t){let a;if(b.hash){const[,,e]=t.hash.split("#",3);a=e??""}else a=t.hash.slice(1);return decodeURIComponent(a)}export{Fe as a,Be as g,P as s}; diff --git a/apps/dashboard/build/_app/immutable/chunks/BTwePnbx.js.br b/apps/dashboard/build/_app/immutable/chunks/BTwePnbx.js.br new file mode 100644 index 0000000000000000000000000000000000000000..f8ab9e33f483ff214e332a9d2bdd71ffa24c6685 GIT binary patch literal 7668 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 z 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 TypeError(t)};var B=(t,e,n)=>e.has(t)||x("Cannot "+n);var a=(t,e,n)=>(B(t,e,"read from private field"),n?n.call(t):e.get(t)),c=(t,e,n)=>e.has(t)?x("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,n);import{o as I}from"./GG5zm9kr.js";import{s as u,g as f,h as d}from"./CpWkWWOo.js";import{w as V}from"./BeMFXnHE.js";new URL("sveltekit-internal://");function ae(t,e){return t==="/"||e==="ignore"?t:e==="never"?t.endsWith("/")?t.slice(0,-1):t:e==="always"&&!t.endsWith("/")?t+"/":t}function oe(t){return t.split("%25").map(decodeURI).join("%25")}function ie(t){for(const e in t)t[e]=decodeURIComponent(t[e]);return t}function le({href:t}){return t.split("#")[0]}function W(...t){let e=5381;for(const n of t)if(typeof n=="string"){let r=n.length;for(;r;)e=e*33^n.charCodeAt(--r)}else if(ArrayBuffer.isView(n)){const r=new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let s=r.length;for(;s;)e=e*33^r[--s]}else throw new TypeError("value must be a string or TypedArray");return(e>>>0).toString(36)}new TextEncoder;new TextDecoder;function X(t){const e=atob(t),n=new Uint8Array(e.length);for(let r=0;r((t instanceof Request?t.method:(e==null?void 0:e.method)||"GET")!=="GET"&&b.delete(U(t)),z(t,e));const b=new Map;function ce(t,e){const n=U(t,e),r=document.querySelector(n);if(r!=null&&r.textContent){r.remove();let{body:s,...l}=JSON.parse(r.textContent);const o=r.getAttribute("data-ttl");return o&&b.set(n,{body:s,init:l,ttl:1e3*Number(o)}),r.getAttribute("data-b64")!==null&&(s=X(s)),Promise.resolve(new Response(s,l))}return window.fetch(t,e)}function ue(t,e,n){if(b.size>0){const r=U(t,n),s=b.get(r);if(s){if(performance.now()o)}function s(o){n=!1,e.set(o)}function l(o){let i;return e.subscribe(h=>{(i===void 0||n&&h!==i)&&o(i=h)})}return{notify:r,set:s,subscribe:l}}const D={v:()=>{}};function Re(){const{set:t,subscribe:e}=V(!1);let n;async function r(){clearTimeout(n);try{const s=await fetch(`${M}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!s.ok)return!1;const o=(await s.json()).version!==F;return o&&(t(!0),D.v(),clearTimeout(n)),o}catch{return!1}}return{subscribe:e,check:r}}function Q(t,e,n){return t.origin!==G||!t.pathname.startsWith(e)?!0:n?t.pathname!==location.pathname:!1}function Se(t){}const H=new Set(["load","prerender","csr","ssr","trailingSlash","config"]);[...H];const Z=new Set([...H]);[...Z];let E,O,T;const ee=I.toString().includes("$$")||/function \w+\(\) \{\}/.test(I.toString());var _,w,m,p,v,y,A,R,j,S,C,k,P;ee?(E={data:{},form:null,error:null,params:{},route:{id:null},state:{},status:-1,url:new URL("https://example.com")},O={current:null},T={current:!1}):(E=new(j=class{constructor(){c(this,_,u({}));c(this,w,u(null));c(this,m,u(null));c(this,p,u({}));c(this,v,u({id:null}));c(this,y,u({}));c(this,A,u(-1));c(this,R,u(new URL("https://example.com")))}get data(){return f(a(this,_))}set data(e){d(a(this,_),e)}get form(){return f(a(this,w))}set form(e){d(a(this,w),e)}get error(){return f(a(this,m))}set error(e){d(a(this,m),e)}get params(){return f(a(this,p))}set params(e){d(a(this,p),e)}get route(){return f(a(this,v))}set route(e){d(a(this,v),e)}get state(){return f(a(this,y))}set state(e){d(a(this,y),e)}get status(){return f(a(this,A))}set status(e){d(a(this,A),e)}get url(){return f(a(this,R))}set url(e){d(a(this,R),e)}},_=new WeakMap,w=new WeakMap,m=new WeakMap,p=new WeakMap,v=new WeakMap,y=new WeakMap,A=new WeakMap,R=new WeakMap,j),O=new(C=class{constructor(){c(this,S,u(null))}get current(){return f(a(this,S))}set current(e){d(a(this,S),e)}},S=new WeakMap,C),T=new(P=class{constructor(){c(this,k,u(!1))}get current(){return f(a(this,k))}set current(e){d(a(this,k),e)}},k=new WeakMap,P),D.v=()=>T.current=!0);function Ue(t){Object.assign(E,t)}export{be as H,_e as N,ge as P,he as S,ye as a,J as b,Re as c,le as d,ie as e,pe as f,ve as g,ae as h,Q as i,N as j,oe as k,fe as l,ue as m,O as n,G as o,E as p,ce as q,we as r,me as s,de as t,Ae as u,Ue as v,Se as w}; diff --git a/apps/dashboard/build/_app/immutable/chunks/BdslOLCg.js.br b/apps/dashboard/build/_app/immutable/chunks/BdslOLCg.js.br new file mode 100644 index 0000000000000000000000000000000000000000..cf281467bb20f64d6a207afd9b4be7f77cb5130a GIT binary patch literal 2609 zcmV-13eNQ#h#4S^!nWD-abn!oOEM%$3cjzLdAiyTO~0OcNlR7o`7Z zYkl{*oFwf~$qbZ|3)QtMj36mcN}+7-Qn+&=Qt=x&ccjjkH$ z#)*SVP*D)R$F3;?D7jm6zOWQE)Srp$EtJyOAX6pOi5jVscK3p;s}wU^cM0(#va_i{z&#(F4nTe(cf|RqtlF8EWF?lWXGL60M&4-dIz9+gt)`ImS;U?}BFqX5N0PI!)gr8vnw?gnaMd;&Ed;p*bq&kxcRZS;#Rh`> zXdXo7511r66T8enD2WNa3W&X*foLl;vLGu6N4{cXWf!2&Z|s=Ds^R|kCm$-0 zex_zmXRw1b42_~nMM>W`$i|h>0uvPnfiaINsgKn$F7@Uwg?~_+ROR8d94trI2;b<% zp40bt*{mdHa%)qt%b2fWXuA|p?LA1<8Z3#nXM>HTCXl1|crr^$jSzc93bWblp{9YP z`TaSIFkAH#4^%<XE1KByBTCB$8Myv+yVhS%uCc z$U|QdJ}BHLaS0wJkL&mU)ZGnJtq?(m!{XWmO8TzW7duE4<-%ACfn3GAgtlsu5|ZDJ_0l(Y-TLn~JgvoAD@p|CN{y z4n&E{P_>%?(2G%6d_PASfjw&7^qlNM@r|Q0vd_e#Y9>Xd=5OuJ1*@36&xvfCFixtADzVI|DP7nC!Z*h^`h9}lPe0yG7o#j^rTn@@ z9xg1fwntjo!scJ1iWX0`8E*DsJT~2CWUHFz^6B;cBsetrmgD^G5n)^f38KaA|FpD4 zOHRg&Y`D_Nn3H+g$2b8)aQf2V8;8t7EFFz~<m;a4nfW7`Zu$X}1 zKhWRDJdCk^&E;9ak()JS5vPP>w!-SEawdLInyYkFdvy?&Kz}e0fKzw$q$)?*f+je4 zoJCYXk=s4h_CW)}^4)R&=A2QOMYbvFlbLf{!*QR4tUhUKxdv#@J8V4dVq&gsLR{`@ zP=S|gI*2(_Y7aWMi=yZfLiimCzQcxcjpt;{)Ns{quAWGZy&kqQm{8x0a)ag^X#Gbr z3lTr^eF}#4k2!$>>37R|L`!2`yzApw2q-0np#XWq2sfW+faykrAZL)B$x)!Wo>mM% z>jQ|&)kfzcO{@A!u%nDi3hviY`NoBz@vPRECDmi4A0m}qJ=~9pl ztP#FZ>tpNnqxJs4D61EoikONmxlY^-HEEGf80(6`R?`)6+d<;ZeDkZ0zT1e!Eln>q zy{t2by)KaU%usut9qOB8sBx*Grl?>OQzfxUJi=0VmDZb`wwOw)k*{*T4xvp=;a5!^ zgvV}<3W_%!EptFP&EOk?jkqMi9o&L`AlC(%T{GUqsNFyR({O;-tBrMWsEYvpG7J&xPGRIajT#A&YT(uFda4V9U zqzK?qq}w$%tWgRB(&dGpQ_+^2m!~uJt#Nn)-`DL-_yvbIN5v3&?E;QB-^U0jT&=qo z7yE_5xH(aExfgx|W+lUNUQf&V^~3$?o&aU0sCkuovbql$A*La?>MY^}pA=B%5$ z+tb2A@coAkwYux)V<8IN^>r$oD?}z`Xhf|wH(0)|6Hd%!)aM`Fw_7!ox!Z4KaC}>7 zE`{@4jLSp#A$f7WW$9*CugUdHV^t? z70=Yu_VxXsVou45H9OogC1H;l*9B^i9@y3Oz-<`vAIe?q2&8A!Hwzdz{K3!_Yqt_; zxILz{Y%i@{2P(nptx{Iio^=9aZ})NvuI&0BSy1&m7!*jNh91x=q*Hf&)?GKY)b#_W za&hE-uuN_v2Fg|tUF zTB!(YTJK%Rq>o^%x%0U(_#|=-1?W!a7JfJ%mGU zA>jzQ(=!SkDD^QbeL@=K+-!q_%Y8USJA^aFdtI^&=3MQDD~^V14#JX=d$^$5>4v#( T$#i5#UvfWmMZ(5b6-4<5Lp~z+ literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/BdslOLCg.js.gz b/apps/dashboard/build/_app/immutable/chunks/BdslOLCg.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..9f556516ba76163f340db32365fa71dda6c051ea GIT binary patch literal 2953 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 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js b/apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js deleted file mode 100644 index 26597bd..0000000 --- a/apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js +++ /dev/null @@ -1 +0,0 @@ -var x=t=>{throw TypeError(t)};var B=(t,e,n)=>e.has(t)||x("Cannot "+n);var a=(t,e,n)=>(B(t,e,"read from private field"),n?n.call(t):e.get(t)),c=(t,e,n)=>e.has(t)?x("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,n);import{o as I}from"./GG5zm9kr.js";import{s as u,g as f,h as d}from"./CpWkWWOo.js";import{w as G}from"./BeMFXnHE.js";new URL("sveltekit-internal://");function ae(t,e){return t==="/"||e==="ignore"?t:e==="never"?t.endsWith("/")?t.slice(0,-1):t:e==="always"&&!t.endsWith("/")?t+"/":t}function oe(t){return t.split("%25").map(decodeURI).join("%25")}function ie(t){for(const e in t)t[e]=decodeURIComponent(t[e]);return t}function le({href:t}){return t.split("#")[0]}function W(...t){let e=5381;for(const n of t)if(typeof n=="string"){let r=n.length;for(;r;)e=e*33^n.charCodeAt(--r)}else if(ArrayBuffer.isView(n)){const r=new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let s=r.length;for(;s;)e=e*33^r[--s]}else throw new TypeError("value must be a string or TypedArray");return(e>>>0).toString(36)}new TextEncoder;new TextDecoder;function X(t){const e=atob(t),n=new Uint8Array(e.length);for(let r=0;r((t instanceof Request?t.method:(e==null?void 0:e.method)||"GET")!=="GET"&&b.delete(U(t)),z(t,e));const b=new Map;function ce(t,e){const n=U(t,e),r=document.querySelector(n);if(r!=null&&r.textContent){r.remove();let{body:s,...l}=JSON.parse(r.textContent);const o=r.getAttribute("data-ttl");return o&&b.set(n,{body:s,init:l,ttl:1e3*Number(o)}),r.getAttribute("data-b64")!==null&&(s=X(s)),Promise.resolve(new Response(s,l))}return window.fetch(t,e)}function ue(t,e,n){if(b.size>0){const r=U(t,n),s=b.get(r);if(s){if(performance.now()o)}function s(o){n=!1,e.set(o)}function l(o){let i;return e.subscribe(h=>{(i===void 0||n&&h!==i)&&o(i=h)})}return{notify:r,set:s,subscribe:l}}const D={v:()=>{}};function Ae(){const{set:t,subscribe:e}=G(!1);let n;async function r(){clearTimeout(n);try{const s=await fetch(`${M}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!s.ok)return!1;const o=(await s.json()).version!==F;return o&&(t(!0),D.v(),clearTimeout(n)),o}catch{return!1}}return{subscribe:e,check:r}}function Q(t,e,n){return t.origin!==Y||!t.pathname.startsWith(e)?!0:n?t.pathname!==location.pathname:!1}function Re(t){}const H=new Set(["load","prerender","csr","ssr","trailingSlash","config"]);[...H];const Z=new Set([...H]);[...Z];let E,O,T;const ee=I.toString().includes("$$")||/function \w+\(\) \{\}/.test(I.toString());var _,m,w,p,v,y,k,A,P,R,V,S,j;ee?(E={data:{},form:null,error:null,params:{},route:{id:null},state:{},status:-1,url:new URL("https://example.com")},O={current:null},T={current:!1}):(E=new(P=class{constructor(){c(this,_,u({}));c(this,m,u(null));c(this,w,u(null));c(this,p,u({}));c(this,v,u({id:null}));c(this,y,u({}));c(this,k,u(-1));c(this,A,u(new URL("https://example.com")))}get data(){return f(a(this,_))}set data(e){d(a(this,_),e)}get form(){return f(a(this,m))}set form(e){d(a(this,m),e)}get error(){return f(a(this,w))}set error(e){d(a(this,w),e)}get params(){return f(a(this,p))}set params(e){d(a(this,p),e)}get route(){return f(a(this,v))}set route(e){d(a(this,v),e)}get state(){return f(a(this,y))}set state(e){d(a(this,y),e)}get status(){return f(a(this,k))}set status(e){d(a(this,k),e)}get url(){return f(a(this,A))}set url(e){d(a(this,A),e)}},_=new WeakMap,m=new WeakMap,w=new WeakMap,p=new WeakMap,v=new WeakMap,y=new WeakMap,k=new WeakMap,A=new WeakMap,P),O=new(V=class{constructor(){c(this,R,u(null))}get current(){return f(a(this,R))}set current(e){d(a(this,R),e)}},R=new WeakMap,V),T=new(j=class{constructor(){c(this,S,u(!1))}get current(){return f(a(this,S))}set current(e){d(a(this,S),e)}},S=new WeakMap,j),D.v=()=>T.current=!0);function Ue(t){Object.assign(E,t)}export{be as H,_e as N,ge as P,he as S,ye as a,J as b,Ae as c,le as d,ie as e,pe as f,ve as g,ae as h,Q as i,N as j,oe as k,fe as l,ue as m,O as n,Y as o,E as p,ce as q,me as r,we as s,de as t,ke as u,Ue as v,Re as w}; diff --git a/apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js.br b/apps/dashboard/build/_app/immutable/chunks/BskPcZf7.js.br deleted file mode 100644 index c787776ec69fae4e81b591e8f5c1b5ee138c48b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2617 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 bJ^W#^(=~J5km*RNPk9_Z8a{jye|^8W0 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 KYkT#O82|tx*1Pfm diff --git a/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.br b/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.br deleted file mode 100644 index 6e9072deefb0138be9ad099780892a82158ba53f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3562 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 diff --git a/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.gz b/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js.gz deleted file mode 100644 index 8b88be8df424986b174a5f333e7c3648c4122cb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4069 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 X4q4d3&)U(n`p3TjIYU&1Qz`%eKHch} diff --git a/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js b/apps/dashboard/build/_app/immutable/entry/app.DRELdRUq.js similarity index 90% rename from apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js rename to apps/dashboard/build/_app/immutable/entry/app.DRELdRUq.js index e396d4a..3db8b30 100644 --- a/apps/dashboard/build/_app/immutable/entry/app.CYIcgKkt.js +++ b/apps/dashboard/build/_app/immutable/entry/app.DRELdRUq.js @@ -1,2 +1,2 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../nodes/0.COz2esg5.js","../chunks/Bzak7iHL.js","../chunks/GG5zm9kr.js","../chunks/CpWkWWOo.js","../chunks/BlVfL1ME.js","../chunks/CHOnp4oo.js","../chunks/B4yTwGkE.js","../chunks/DdEqwvdI.js","../chunks/CGEBXrjl.js","../chunks/CJCPY1OL.js","../chunks/A7po6GxK.js","../chunks/aVbAZ-t7.js","../chunks/BKuqSeVd.js","../chunks/sZcqyNBA.js","../chunks/CJsMJEun.js","../chunks/C6HuKgyx.js","../chunks/BeMFXnHE.js","../chunks/BHGLDPij.js","../chunks/BskPcZf7.js","../chunks/MAY1QfFZ.js","../chunks/BUoSzNdg.js","../chunks/Cx-f-Pzo.js","../chunks/BjdL4Pm2.js","../chunks/DzfRjky4.js","../chunks/DNjM5a-l.js","../assets/0.IIz8MMYb.css","../nodes/1.DJo7hfwf.js","../nodes/2.D-vKwnTC.js","../nodes/3.Caati8mq.js","../nodes/4.DJCab_le.js","../chunks/V6gjw5Ec.js","../nodes/5.C0AYWqwr.js","../chunks/BnXDGOmJ.js","../assets/5.DQ_AfUnN.css","../nodes/6.DTUGCA1p.js","../chunks/C4h_mRt2.js","../assets/6.BSSBWVKL.css","../nodes/7.jHtvjgRi.js","../assets/7.CCrNEDd3.css","../nodes/8.CgPowUzz.js","../nodes/9.BWaJ-VBd.js","../assets/9.BBx09UGv.css","../nodes/10.Btb56kL1.js","../nodes/11.WP3QAgOF.js","../nodes/12.DaxyVsV4.js","../nodes/13.D52bbIQQ.js","../assets/13.Bjd0S47S.css","../nodes/14.DUh3SXOF.js","../nodes/15.C7Fk4d1G.js","../assets/15.ChjqzJHo.css","../nodes/16.DeYkCVEo.js","../assets/16.BnHgRQtR.css","../nodes/17.CLL0vjL4.js","../nodes/18.CXHHR36X.js","../nodes/19.D4UHDxxJ.js","../nodes/20.BwEdZXUF.js","../assets/20.DKhUrxcR.css"])))=>i.map(i=>d[i]); -var Q=r=>{throw TypeError(r)};var X=(r,t,e)=>t.has(r)||Q("Cannot "+e);var l=(r,t,e)=>(X(r,t,"read from private field"),e?e.call(r):t.get(r)),H=(r,t,e)=>t.has(r)?Q("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(r):t.set(r,e),W=(r,t,e,n)=>(X(r,t,"write to private field"),n?n.call(r,e):t.set(r,e),e);import{N as Z,ab as ut,b as _t,E as ct,ac as lt,ae as dt,T as ft,R as $,ax as vt,U as ht,h as U,L as pt,g as h,bc as Et,G as gt,I as Pt,p as Rt,aA as yt,aB as Ot,$ as At,f as L,e as Tt,a as bt,s as z,d as Lt,r as It,u as x,t as Dt}from"../chunks/CpWkWWOo.js";import{h as Vt,m as wt,u as kt,s as xt}from"../chunks/BlVfL1ME.js";import"../chunks/Bzak7iHL.js";import{o as St}from"../chunks/GG5zm9kr.js";import{i as B}from"../chunks/B4yTwGkE.js";import{a as g,c as V,f as et,t as jt}from"../chunks/CHOnp4oo.js";import{B as Ct}from"../chunks/DdEqwvdI.js";import{b as S}from"../chunks/CJsMJEun.js";import{p as N}from"../chunks/V6gjw5Ec.js";function j(r,t,e){var n;Z&&(n=ht,ut());var i=new Ct(r);_t(()=>{var c=t()??null;if(Z){var s=lt(n),a=s===vt,m=c!==null;if(a!==m){var R=dt();ft(R),i.anchor=R,$(!1),i.ensure(c,c&&(u=>e(u,c))),$(!0);return}}i.ensure(c,c&&(u=>e(u,c)))},ct)}function Bt(r){return class extends Nt{constructor(t){super({component:r,...t})}}}var P,d;class Nt{constructor(t){H(this,P);H(this,d);var c;var e=new Map,n=(s,a)=>{var m=Pt(a,!1,!1);return e.set(s,m),m};const i=new Proxy({...t.props||{},$$events:{}},{get(s,a){return h(e.get(a)??n(a,Reflect.get(s,a)))},has(s,a){return a===pt?!0:(h(e.get(a)??n(a,Reflect.get(s,a))),Reflect.has(s,a))},set(s,a,m){return U(e.get(a)??n(a,m),m),Reflect.set(s,a,m)}});W(this,d,(t.hydrate?Vt:wt)(t.component,{target:t.target,anchor:t.anchor,props:i,context:t.context,intro:t.intro??!1,recover:t.recover,transformError:t.transformError})),(!((c=t==null?void 0:t.props)!=null&&c.$$host)||t.sync===!1)&&Et(),W(this,P,i.$$events);for(const s of Object.keys(l(this,d)))s==="$set"||s==="$destroy"||s==="$on"||gt(this,s,{get(){return l(this,d)[s]},set(a){l(this,d)[s]=a},enumerable:!0});l(this,d).$set=s=>{Object.assign(i,s)},l(this,d).$destroy=()=>{kt(l(this,d))}}$set(t){l(this,d).$set(t)}$on(t,e){l(this,P)[t]=l(this,P)[t]||[];const n=(...i)=>e.call(this,...i);return l(this,P)[t].push(n),()=>{l(this,P)[t]=l(this,P)[t].filter(i=>i!==n)}}$destroy(){l(this,d).$destroy()}}P=new WeakMap,d=new WeakMap;const Ut="modulepreload",qt=function(r,t){return new URL(r,t).href},tt={},o=function(t,e,n){let i=Promise.resolve();if(e&&e.length>0){let s=function(u){return Promise.all(u.map(p=>Promise.resolve(p).then(y=>({status:"fulfilled",value:y}),y=>({status:"rejected",reason:y}))))};const a=document.getElementsByTagName("link"),m=document.querySelector("meta[property=csp-nonce]"),R=(m==null?void 0:m.nonce)||(m==null?void 0:m.getAttribute("nonce"));i=s(e.map(u=>{if(u=qt(u,n),u in tt)return;tt[u]=!0;const p=u.endsWith(".css"),y=p?'[rel="stylesheet"]':"";if(!!n)for(let O=a.length-1;O>=0;O--){const _=a[O];if(_.href===u&&(!p||_.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${u}"]${y}`))return;const E=document.createElement("link");if(E.rel=p?"stylesheet":Ut,p||(E.as="script"),E.crossOrigin="",E.href=u,R&&E.setAttribute("nonce",R),document.head.appendChild(E),p)return new Promise((O,_)=>{E.addEventListener("load",O),E.addEventListener("error",()=>_(new Error(`Unable to preload CSS for ${u}`)))})}))}function c(s){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=s,window.dispatchEvent(a),!a.defaultPrevented)throw s}return i.then(s=>{for(const a of s||[])a.status==="rejected"&&c(a.reason);return t().catch(c)})},ae={};var Ft=et('
'),Gt=et(" ",1);function Yt(r,t){Rt(t,!0);let e=N(t,"components",23,()=>[]),n=N(t,"data_0",3,null),i=N(t,"data_1",3,null),c=N(t,"data_2",3,null);yt(()=>t.stores.page.set(t.page)),Ot(()=>{t.stores,t.page,t.constructors,e(),t.form,n(),i(),c(),t.stores.page.notify()});let s=z(!1),a=z(!1),m=z(null);St(()=>{const _=t.stores.page.subscribe(()=>{h(s)&&(U(a,!0),At().then(()=>{U(m,document.title||"untitled page",!0)}))});return U(s,!0),_});const R=x(()=>t.constructors[2]);var u=Gt(),p=L(u);{var y=_=>{const A=x(()=>t.constructors[0]);var T=V(),w=L(T);j(w,()=>h(A),(b,I)=>{S(I(b,{get data(){return n()},get form(){return t.form},get params(){return t.page.params},children:(f,Wt)=>{var K=V(),at=L(K);{var st=D=>{const q=x(()=>t.constructors[1]);var k=V(),F=L(k);j(F,()=>h(q),(G,Y)=>{S(Y(G,{get data(){return i()},get form(){return t.form},get params(){return t.page.params},children:(v,zt)=>{var M=V(),nt=L(M);j(nt,()=>h(R),(it,mt)=>{S(mt(it,{get data(){return c()},get form(){return t.form},get params(){return t.page.params}}),C=>e()[2]=C,()=>{var C;return(C=e())==null?void 0:C[2]})}),g(v,M)},$$slots:{default:!0}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),g(D,k)},ot=D=>{const q=x(()=>t.constructors[1]);var k=V(),F=L(k);j(F,()=>h(q),(G,Y)=>{S(Y(G,{get data(){return i()},get form(){return t.form},get params(){return t.page.params}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),g(D,k)};B(at,D=>{t.constructors[2]?D(st):D(ot,!1)})}g(f,K)},$$slots:{default:!0}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),g(_,T)},J=_=>{const A=x(()=>t.constructors[0]);var T=V(),w=L(T);j(w,()=>h(A),(b,I)=>{S(I(b,{get data(){return n()},get form(){return t.form},get params(){return t.page.params}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),g(_,T)};B(p,_=>{t.constructors[1]?_(y):_(J,!1)})}var E=Tt(p,2);{var O=_=>{var A=Ft(),T=Lt(A);{var w=b=>{var I=jt();Dt(()=>xt(I,h(m))),g(b,I)};B(T,b=>{h(a)&&b(w)})}It(A),g(_,A)};B(E,_=>{h(s)&&_(O)})}g(r,u),bt()}const se=Bt(Yt),oe=[()=>o(()=>import("../nodes/0.COz2esg5.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]),import.meta.url),()=>o(()=>import("../nodes/1.DJo7hfwf.js"),__vite__mapDeps([26,1,20,3,4,5,18,2,16,17]),import.meta.url),()=>o(()=>import("../nodes/2.D-vKwnTC.js"),__vite__mapDeps([27,1,3,5,9,7]),import.meta.url),()=>o(()=>import("../nodes/3.Caati8mq.js"),__vite__mapDeps([28,1,20,3,2,17,16,18]),import.meta.url),()=>o(()=>import("../nodes/4.DJCab_le.js"),__vite__mapDeps([29,1,2,3,4,5,6,7,10,13,24,19,16,8,30,15,23]),import.meta.url),()=>o(()=>import("../nodes/5.C0AYWqwr.js"),__vite__mapDeps([31,1,3,4,5,6,7,8,11,12,21,32,10,30,15,16,33]),import.meta.url),()=>o(()=>import("../nodes/6.DTUGCA1p.js"),__vite__mapDeps([34,1,3,4,5,6,7,8,35,10,11,12,24,21,30,15,16,18,2,36]),import.meta.url),()=>o(()=>import("../nodes/7.jHtvjgRi.js"),__vite__mapDeps([37,1,2,3,4,5,6,7,8,10,13,11,12,21,23,38]),import.meta.url),()=>o(()=>import("../nodes/8.CgPowUzz.js"),__vite__mapDeps([39,1,3,4,5,6,7,8,10,11,12,21,13,24]),import.meta.url),()=>o(()=>import("../nodes/9.BWaJ-VBd.js"),__vite__mapDeps([40,1,20,3,4,5,6,7,8,21,12,15,16,19,23,10,11,30,41]),import.meta.url),()=>o(()=>import("../nodes/10.Btb56kL1.js"),__vite__mapDeps([42,1,2,3,4,5,6,7,8,10,11,12,21,13,32,15,16,18,14,30,23,20,24,19]),import.meta.url),()=>o(()=>import("../nodes/11.WP3QAgOF.js"),__vite__mapDeps([43,1,2,3,4,5,6,7,8,21,12,13,17,16,18,24,23,10,30,15]),import.meta.url),()=>o(()=>import("../nodes/12.DaxyVsV4.js"),__vite__mapDeps([44,1,2,3,4,5,6,7,8,11,12,24]),import.meta.url),()=>o(()=>import("../nodes/13.D52bbIQQ.js"),__vite__mapDeps([45,1,2,3,4,5,6,7,8,10,11,12,21,13,32,24,23,46]),import.meta.url),()=>o(()=>import("../nodes/14.DUh3SXOF.js"),__vite__mapDeps([47,1,2,3,4,5,6,7,8,10,11,12,21]),import.meta.url),()=>o(()=>import("../nodes/15.C7Fk4d1G.js"),__vite__mapDeps([48,1,2,3,4,5,6,7,8,35,10,21,12,13,14,24,11,30,15,16,23,49]),import.meta.url),()=>o(()=>import("../nodes/16.DeYkCVEo.js"),__vite__mapDeps([50,1,2,3,4,5,6,7,8,11,12,24,10,21,30,15,16,23,51]),import.meta.url),()=>o(()=>import("../nodes/17.CLL0vjL4.js"),__vite__mapDeps([52,1,2,3,4,5,6,7,8,11,12,21,15,16,24,19,22,23]),import.meta.url),()=>o(()=>import("../nodes/18.CXHHR36X.js"),__vite__mapDeps([53,1,2,3,4,5,6,7,8,21,12,24]),import.meta.url),()=>o(()=>import("../nodes/19.D4UHDxxJ.js"),__vite__mapDeps([54,1,2,3,4,5,6,7,8,21,12,32,24,23]),import.meta.url),()=>o(()=>import("../nodes/20.BwEdZXUF.js"),__vite__mapDeps([55,1,2,3,4,5,6,7,8,35,10,11,12,21,13,32,14,18,16,56]),import.meta.url)],ne=[],ie={"/":[3],"/(app)/activation":[4,[2]],"/(app)/contradictions":[5,[2]],"/(app)/dreams":[6,[2]],"/(app)/duplicates":[7,[2]],"/(app)/explore":[8,[2]],"/(app)/feed":[9,[2]],"/(app)/graph":[10,[2]],"/(app)/importance":[11,[2]],"/(app)/intentions":[12,[2]],"/(app)/memories":[13,[2]],"/(app)/patterns":[14,[2]],"/(app)/reasoning":[15,[2]],"/(app)/schedule":[16,[2]],"/(app)/settings":[17,[2]],"/(app)/stats":[18,[2]],"/(app)/timeline":[19,[2]],"/waitlist":[20]},rt={handleError:(({error:r})=>{console.error(r)}),reroute:(()=>{}),transport:{}},Ht=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.decode])),me=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.encode])),ue=!1,_e=(r,t)=>Ht[r](t);export{_e as decode,Ht as decoders,ie as dictionary,me as encoders,ue as hash,rt as hooks,ae as matchers,oe as nodes,se as root,ne as server_loads}; +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../nodes/0._nbDJIPC.js","../chunks/Bzak7iHL.js","../chunks/GG5zm9kr.js","../chunks/CpWkWWOo.js","../chunks/BlVfL1ME.js","../chunks/CHOnp4oo.js","../chunks/B4yTwGkE.js","../chunks/DdEqwvdI.js","../chunks/CGEBXrjl.js","../chunks/CJCPY1OL.js","../chunks/A7po6GxK.js","../chunks/aVbAZ-t7.js","../chunks/BKuqSeVd.js","../chunks/sZcqyNBA.js","../chunks/CJsMJEun.js","../chunks/C6HuKgyx.js","../chunks/BeMFXnHE.js","../chunks/BTwePnbx.js","../chunks/BdslOLCg.js","../chunks/MAY1QfFZ.js","../chunks/BUoSzNdg.js","../chunks/Cx-f-Pzo.js","../chunks/BjdL4Pm2.js","../chunks/DzfRjky4.js","../chunks/DNjM5a-l.js","../assets/0.IIz8MMYb.css","../nodes/1.Bnre2dw5.js","../nodes/2.D-vKwnTC.js","../nodes/3.De3LPrRR.js","../nodes/4.DJCab_le.js","../chunks/V6gjw5Ec.js","../nodes/5.C0AYWqwr.js","../chunks/BnXDGOmJ.js","../assets/5.DQ_AfUnN.css","../nodes/6.BN-BfASZ.js","../chunks/C4h_mRt2.js","../assets/6.BSSBWVKL.css","../nodes/7.jHtvjgRi.js","../assets/7.CCrNEDd3.css","../nodes/8.CgPowUzz.js","../nodes/9.BWaJ-VBd.js","../assets/9.BBx09UGv.css","../nodes/10.CecvzcnA.js","../nodes/11.BbfUOvv5.js","../nodes/12.DaxyVsV4.js","../nodes/13.D52bbIQQ.js","../assets/13.Bjd0S47S.css","../nodes/14.DUh3SXOF.js","../nodes/15.C7Fk4d1G.js","../assets/15.ChjqzJHo.css","../nodes/16.DeYkCVEo.js","../assets/16.BnHgRQtR.css","../nodes/17.CLL0vjL4.js","../nodes/18.CXHHR36X.js","../nodes/19.D4UHDxxJ.js","../nodes/20.BM_Hn1tR.js","../assets/20.DKhUrxcR.css"])))=>i.map(i=>d[i]); +var Q=r=>{throw TypeError(r)};var X=(r,t,e)=>t.has(r)||Q("Cannot "+e);var l=(r,t,e)=>(X(r,t,"read from private field"),e?e.call(r):t.get(r)),H=(r,t,e)=>t.has(r)?Q("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(r):t.set(r,e),W=(r,t,e,n)=>(X(r,t,"write to private field"),n?n.call(r,e):t.set(r,e),e);import{N as Z,ab as ut,b as _t,E as ct,ac as lt,ae as dt,T as ft,R as $,ax as vt,U as ht,h as U,L as pt,g as h,bc as Et,G as gt,I as Pt,p as Rt,aA as yt,aB as Ot,$ as At,f as L,e as Tt,a as bt,s as z,d as Lt,r as It,u as x,t as Dt}from"../chunks/CpWkWWOo.js";import{h as Vt,m as wt,u as kt,s as xt}from"../chunks/BlVfL1ME.js";import"../chunks/Bzak7iHL.js";import{o as St}from"../chunks/GG5zm9kr.js";import{i as B}from"../chunks/B4yTwGkE.js";import{a as g,c as V,f as et,t as jt}from"../chunks/CHOnp4oo.js";import{B as Ct}from"../chunks/DdEqwvdI.js";import{b as S}from"../chunks/CJsMJEun.js";import{p as N}from"../chunks/V6gjw5Ec.js";function j(r,t,e){var n;Z&&(n=ht,ut());var i=new Ct(r);_t(()=>{var c=t()??null;if(Z){var s=lt(n),a=s===vt,m=c!==null;if(a!==m){var R=dt();ft(R),i.anchor=R,$(!1),i.ensure(c,c&&(u=>e(u,c))),$(!0);return}}i.ensure(c,c&&(u=>e(u,c)))},ct)}function Bt(r){return class extends Nt{constructor(t){super({component:r,...t})}}}var P,d;class Nt{constructor(t){H(this,P);H(this,d);var c;var e=new Map,n=(s,a)=>{var m=Pt(a,!1,!1);return e.set(s,m),m};const i=new Proxy({...t.props||{},$$events:{}},{get(s,a){return h(e.get(a)??n(a,Reflect.get(s,a)))},has(s,a){return a===pt?!0:(h(e.get(a)??n(a,Reflect.get(s,a))),Reflect.has(s,a))},set(s,a,m){return U(e.get(a)??n(a,m),m),Reflect.set(s,a,m)}});W(this,d,(t.hydrate?Vt:wt)(t.component,{target:t.target,anchor:t.anchor,props:i,context:t.context,intro:t.intro??!1,recover:t.recover,transformError:t.transformError})),(!((c=t==null?void 0:t.props)!=null&&c.$$host)||t.sync===!1)&&Et(),W(this,P,i.$$events);for(const s of Object.keys(l(this,d)))s==="$set"||s==="$destroy"||s==="$on"||gt(this,s,{get(){return l(this,d)[s]},set(a){l(this,d)[s]=a},enumerable:!0});l(this,d).$set=s=>{Object.assign(i,s)},l(this,d).$destroy=()=>{kt(l(this,d))}}$set(t){l(this,d).$set(t)}$on(t,e){l(this,P)[t]=l(this,P)[t]||[];const n=(...i)=>e.call(this,...i);return l(this,P)[t].push(n),()=>{l(this,P)[t]=l(this,P)[t].filter(i=>i!==n)}}$destroy(){l(this,d).$destroy()}}P=new WeakMap,d=new WeakMap;const Ut="modulepreload",qt=function(r,t){return new URL(r,t).href},tt={},o=function(t,e,n){let i=Promise.resolve();if(e&&e.length>0){let s=function(u){return Promise.all(u.map(p=>Promise.resolve(p).then(y=>({status:"fulfilled",value:y}),y=>({status:"rejected",reason:y}))))};const a=document.getElementsByTagName("link"),m=document.querySelector("meta[property=csp-nonce]"),R=(m==null?void 0:m.nonce)||(m==null?void 0:m.getAttribute("nonce"));i=s(e.map(u=>{if(u=qt(u,n),u in tt)return;tt[u]=!0;const p=u.endsWith(".css"),y=p?'[rel="stylesheet"]':"";if(!!n)for(let O=a.length-1;O>=0;O--){const _=a[O];if(_.href===u&&(!p||_.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${u}"]${y}`))return;const E=document.createElement("link");if(E.rel=p?"stylesheet":Ut,p||(E.as="script"),E.crossOrigin="",E.href=u,R&&E.setAttribute("nonce",R),document.head.appendChild(E),p)return new Promise((O,_)=>{E.addEventListener("load",O),E.addEventListener("error",()=>_(new Error(`Unable to preload CSS for ${u}`)))})}))}function c(s){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=s,window.dispatchEvent(a),!a.defaultPrevented)throw s}return i.then(s=>{for(const a of s||[])a.status==="rejected"&&c(a.reason);return t().catch(c)})},ae={};var Ft=et('
'),Gt=et(" ",1);function Yt(r,t){Rt(t,!0);let e=N(t,"components",23,()=>[]),n=N(t,"data_0",3,null),i=N(t,"data_1",3,null),c=N(t,"data_2",3,null);yt(()=>t.stores.page.set(t.page)),Ot(()=>{t.stores,t.page,t.constructors,e(),t.form,n(),i(),c(),t.stores.page.notify()});let s=z(!1),a=z(!1),m=z(null);St(()=>{const _=t.stores.page.subscribe(()=>{h(s)&&(U(a,!0),At().then(()=>{U(m,document.title||"untitled page",!0)}))});return U(s,!0),_});const R=x(()=>t.constructors[2]);var u=Gt(),p=L(u);{var y=_=>{const A=x(()=>t.constructors[0]);var T=V(),w=L(T);j(w,()=>h(A),(b,I)=>{S(I(b,{get data(){return n()},get form(){return t.form},get params(){return t.page.params},children:(f,Wt)=>{var K=V(),at=L(K);{var st=D=>{const q=x(()=>t.constructors[1]);var k=V(),F=L(k);j(F,()=>h(q),(G,Y)=>{S(Y(G,{get data(){return i()},get form(){return t.form},get params(){return t.page.params},children:(v,zt)=>{var M=V(),nt=L(M);j(nt,()=>h(R),(it,mt)=>{S(mt(it,{get data(){return c()},get form(){return t.form},get params(){return t.page.params}}),C=>e()[2]=C,()=>{var C;return(C=e())==null?void 0:C[2]})}),g(v,M)},$$slots:{default:!0}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),g(D,k)},ot=D=>{const q=x(()=>t.constructors[1]);var k=V(),F=L(k);j(F,()=>h(q),(G,Y)=>{S(Y(G,{get data(){return i()},get form(){return t.form},get params(){return t.page.params}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),g(D,k)};B(at,D=>{t.constructors[2]?D(st):D(ot,!1)})}g(f,K)},$$slots:{default:!0}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),g(_,T)},J=_=>{const A=x(()=>t.constructors[0]);var T=V(),w=L(T);j(w,()=>h(A),(b,I)=>{S(I(b,{get data(){return n()},get form(){return t.form},get params(){return t.page.params}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),g(_,T)};B(p,_=>{t.constructors[1]?_(y):_(J,!1)})}var E=Tt(p,2);{var O=_=>{var A=Ft(),T=Lt(A);{var w=b=>{var I=jt();Dt(()=>xt(I,h(m))),g(b,I)};B(T,b=>{h(a)&&b(w)})}It(A),g(_,A)};B(E,_=>{h(s)&&_(O)})}g(r,u),bt()}const se=Bt(Yt),oe=[()=>o(()=>import("../nodes/0._nbDJIPC.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]),import.meta.url),()=>o(()=>import("../nodes/1.Bnre2dw5.js"),__vite__mapDeps([26,1,20,3,4,5,18,2,16,17]),import.meta.url),()=>o(()=>import("../nodes/2.D-vKwnTC.js"),__vite__mapDeps([27,1,3,5,9,7]),import.meta.url),()=>o(()=>import("../nodes/3.De3LPrRR.js"),__vite__mapDeps([28,1,20,3,2,17,16,18]),import.meta.url),()=>o(()=>import("../nodes/4.DJCab_le.js"),__vite__mapDeps([29,1,2,3,4,5,6,7,10,13,24,19,16,8,30,15,23]),import.meta.url),()=>o(()=>import("../nodes/5.C0AYWqwr.js"),__vite__mapDeps([31,1,3,4,5,6,7,8,11,12,21,32,10,30,15,16,33]),import.meta.url),()=>o(()=>import("../nodes/6.BN-BfASZ.js"),__vite__mapDeps([34,1,3,4,5,6,7,8,35,10,11,12,24,21,30,15,16,18,2,36]),import.meta.url),()=>o(()=>import("../nodes/7.jHtvjgRi.js"),__vite__mapDeps([37,1,2,3,4,5,6,7,8,10,13,11,12,21,23,38]),import.meta.url),()=>o(()=>import("../nodes/8.CgPowUzz.js"),__vite__mapDeps([39,1,3,4,5,6,7,8,10,11,12,21,13,24]),import.meta.url),()=>o(()=>import("../nodes/9.BWaJ-VBd.js"),__vite__mapDeps([40,1,20,3,4,5,6,7,8,21,12,15,16,19,23,10,11,30,41]),import.meta.url),()=>o(()=>import("../nodes/10.CecvzcnA.js"),__vite__mapDeps([42,1,2,3,4,5,6,7,8,10,11,12,21,13,32,15,16,18,14,30,23,20,24,19]),import.meta.url),()=>o(()=>import("../nodes/11.BbfUOvv5.js"),__vite__mapDeps([43,1,2,3,4,5,6,7,8,21,12,13,17,16,18,24,23,10,30,15]),import.meta.url),()=>o(()=>import("../nodes/12.DaxyVsV4.js"),__vite__mapDeps([44,1,2,3,4,5,6,7,8,11,12,24]),import.meta.url),()=>o(()=>import("../nodes/13.D52bbIQQ.js"),__vite__mapDeps([45,1,2,3,4,5,6,7,8,10,11,12,21,13,32,24,23,46]),import.meta.url),()=>o(()=>import("../nodes/14.DUh3SXOF.js"),__vite__mapDeps([47,1,2,3,4,5,6,7,8,10,11,12,21]),import.meta.url),()=>o(()=>import("../nodes/15.C7Fk4d1G.js"),__vite__mapDeps([48,1,2,3,4,5,6,7,8,35,10,21,12,13,14,24,11,30,15,16,23,49]),import.meta.url),()=>o(()=>import("../nodes/16.DeYkCVEo.js"),__vite__mapDeps([50,1,2,3,4,5,6,7,8,11,12,24,10,21,30,15,16,23,51]),import.meta.url),()=>o(()=>import("../nodes/17.CLL0vjL4.js"),__vite__mapDeps([52,1,2,3,4,5,6,7,8,11,12,21,15,16,24,19,22,23]),import.meta.url),()=>o(()=>import("../nodes/18.CXHHR36X.js"),__vite__mapDeps([53,1,2,3,4,5,6,7,8,21,12,24]),import.meta.url),()=>o(()=>import("../nodes/19.D4UHDxxJ.js"),__vite__mapDeps([54,1,2,3,4,5,6,7,8,21,12,32,24,23]),import.meta.url),()=>o(()=>import("../nodes/20.BM_Hn1tR.js"),__vite__mapDeps([55,1,2,3,4,5,6,7,8,35,10,11,12,21,13,32,14,18,16,56]),import.meta.url)],ne=[],ie={"/":[3],"/(app)/activation":[4,[2]],"/(app)/contradictions":[5,[2]],"/(app)/dreams":[6,[2]],"/(app)/duplicates":[7,[2]],"/(app)/explore":[8,[2]],"/(app)/feed":[9,[2]],"/(app)/graph":[10,[2]],"/(app)/importance":[11,[2]],"/(app)/intentions":[12,[2]],"/(app)/memories":[13,[2]],"/(app)/patterns":[14,[2]],"/(app)/reasoning":[15,[2]],"/(app)/schedule":[16,[2]],"/(app)/settings":[17,[2]],"/(app)/stats":[18,[2]],"/(app)/timeline":[19,[2]],"/waitlist":[20]},rt={handleError:(({error:r})=>{console.error(r)}),reroute:(()=>{}),transport:{}},Ht=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.decode])),me=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.encode])),ue=!1,_e=(r,t)=>Ht[r](t);export{_e as decode,Ht as decoders,ie as dictionary,me as encoders,ue as hash,rt as hooks,ae as matchers,oe as nodes,se as root,ne as server_loads}; diff --git a/apps/dashboard/build/_app/immutable/entry/app.DRELdRUq.js.br b/apps/dashboard/build/_app/immutable/entry/app.DRELdRUq.js.br new file mode 100644 index 0000000000000000000000000000000000000000..778cf10835aaf4606915bc33807c4aa3cfb2a9d5 GIT binary patch literal 3563 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 V(8kZ&;k5k6zW`vF>Y7t3006sCsAaf!{>1zZz2 UUNuHoEEk%+l?3c?pt2gB0R|v7SO5S3 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/entry/start.DfC8txIX.js.gz b/apps/dashboard/build/_app/immutable/entry/start.DfC8txIX.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..90eac39f00d7137925d31f6a1ce1111f0dfaa06a GIT binary patch literal 107 zcmb2|=3oE;CgIa(bWiAOt@I1=&StO;F_lU2W_e51WP4FiZ3ID9>>JbE8=J{7A+uB{OG`C3 zIh~wePk6B_egOp(a2N;&9~e&DZ(tiGGDrIe%K!iX diff --git a/apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js.gz b/apps/dashboard/build/_app/immutable/entry/start.gT92nAJC.js.gz deleted file mode 100644 index 0b2d810e0ccb6db40578d983afd868127e591dda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107 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

CDc)DQO<{5 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 H#oK%X%7_i7 diff --git a/apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js b/apps/dashboard/build/_app/immutable/nodes/0._nbDJIPC.js similarity index 99% rename from apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js rename to apps/dashboard/build/_app/immutable/nodes/0._nbDJIPC.js index f9dcc17..ba2f3b5 100644 --- a/apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js +++ b/apps/dashboard/build/_app/immutable/nodes/0._nbDJIPC.js @@ -1,4 +1,4 @@ -import"../chunks/Bzak7iHL.js";import{o as st}from"../chunks/GG5zm9kr.js";import{f as ce,e as o,d as s,r as t,t as N,p as We,n as se,g as e,a as Oe,s as ye,c as mt,h as A,u as j}from"../chunks/CpWkWWOo.js";import{s as _,d as Ye,a as re,e as Le}from"../chunks/BlVfL1ME.js";import{i as B}from"../chunks/B4yTwGkE.js";import{e as De,i as Ne}from"../chunks/CGEBXrjl.js";import{c as rt,a as u,f as m}from"../chunks/CHOnp4oo.js";import{s as Xe}from"../chunks/CJCPY1OL.js";import{s as be,r as ft}from"../chunks/A7po6GxK.js";import{s as G}from"../chunks/aVbAZ-t7.js";import{b as ht}from"../chunks/sZcqyNBA.js";import{b as gt}from"../chunks/CJsMJEun.js";import{a as H,s as Te}from"../chunks/C6HuKgyx.js";import{s as bt,g as Ze}from"../chunks/BHGLDPij.js";import{b as U}from"../chunks/BskPcZf7.js";import{s as nt,m as it,a as ot,e as xt,w as Je,u as kt,i as _t,f as yt}from"../chunks/MAY1QfFZ.js";import{i as wt}from"../chunks/BUoSzNdg.js";import{s as lt}from"../chunks/Cx-f-Pzo.js";import{t as ge}from"../chunks/BjdL4Pm2.js";import{a as Ue}from"../chunks/DNjM5a-l.js";import{d as $t,w as dt,g as ct}from"../chunks/BeMFXnHE.js";const Mt=()=>{const a=bt;return{page:{subscribe:a.page.subscribe},navigating:{subscribe:a.navigating.subscribe},updated:a.updated}},Ct={subscribe(a){return Mt().page.subscribe(a)}};var At=m('

');function Dt(a){const r=()=>H(nt,"$suppressedCount",i),[i,c]=Te();var f=rt(),M=ce(f);{var y=D=>{var x=At(),h=o(s(x),2),v=s(h);t(h),t(x),N(()=>_(v,`Actively forgetting ${r()??""} ${r()===1?"memory":"memories"}`)),u(D,x)};B(M,D=>{r()>0&&D(y)})}u(a,f),c()}var Tt=m(''),Et=m('
');function Ft(a,r){We(r,!1);const i=()=>H(ge,"$toasts",c),[c,f]=Te(),M={DreamCompleted:"✦",ConsolidationCompleted:"◉",ConnectionDiscovered:"⟷",MemoryPromoted:"↑",MemoryDemoted:"↓",MemorySuppressed:"◬",MemoryUnsuppressed:"◉",Rac1CascadeSwept:"✺",MemoryDeleted:"✕"};function y(v){return M[v]??"◆"}function D(v){ge.dismiss(v.id)}function x(v,l){(v.key==="Enter"||v.key===" ")&&(v.preventDefault(),ge.dismiss(l.id))}wt();var h=Et();De(h,5,i,v=>v.id,(v,l)=>{var b=Tt(),F=o(s(b),2),T=s(F),K=s(T),Q=s(K,!0);t(K);var V=o(K,2),X=s(V,!0);t(V),t(T);var Z=o(T,2),ne=s(Z,!0);t(Z),t(F),se(2),t(b),N(J=>{be(b,"aria-label",`${e(l).title??""}: ${e(l).body??""}. Click to dismiss.`),lt(b,`--toast-color: ${e(l).color??""}; --toast-dwell: ${e(l).dwellMs??""}ms;`),_(Q,J),_(X,e(l).title),_(ne,e(l).body)},[()=>y(e(l).type)]),re("click",b,()=>D(e(l))),re("keydown",b,J=>x(J,e(l))),Le("mouseenter",b,()=>ge.pauseDwell(e(l).id,e(l).dwellMs)),Le("mouseleave",b,()=>ge.resumeDwell(e(l).id)),Le("focus",b,()=>ge.pauseDwell(e(l).id,e(l).dwellMs)),Le("blur",b,()=>ge.resumeDwell(e(l).id)),u(v,b)}),t(h),u(a,h),Oe(),f()}Ye(["click","keydown"]);function we(a){const r=a.data;if(!r||typeof r!="object")return null;const i=r.timestamp??r.at??r.occurred_at;if(i==null)return null;if(typeof i=="number")return Number.isFinite(i)?i>1e12?i:i*1e3:null;if(typeof i!="string")return null;const c=Date.parse(i);return Number.isFinite(c)?c:null}const ze=10,vt=3e4,St=ze*vt;function It(a,r){const i=r-St,c=new Array(ze).fill(0);for(const M of a){if(M.type==="Heartbeat")continue;const y=we(M);if(y===null||yr)continue;const D=Math.min(ze-1,Math.floor((y-i)/vt));c[D]+=1}const f=Math.max(1,...c);return c.map(M=>({count:M,ratio:M/f}))}function Lt(a,r){const i=r-864e5;for(const c of a){if(c.type!=="DreamCompleted")continue;return(we(c)??r)>=i?c:null}return null}function Nt(a){if(!a||!a.data)return null;const r=a.data,i=typeof r.insights_generated=="number"?r.insights_generated:typeof r.insightsGenerated=="number"?r.insightsGenerated:null;return i!==null&&Number.isFinite(i)?i:null}function Rt(a,r){let i=null,c=null;for(const D of a)if(!i&&D.type==="DreamStarted"&&(i=D),!c&&D.type==="DreamCompleted"&&(c=D),i&&c)break;if(!i)return!1;const f=we(i)??r,M=r-300*1e3;return f=c}return!1}var Vt=m(' at risk',1),Bt=m('0 at risk',1),Gt=m(' at risk',1),Ht=m(' intentions',1),qt=m('— intentions'),zt=m('· insights',1),Pt=m(' Last dream: ',1),Wt=m('No recent dream'),Ot=m('
'),Yt=m('
DREAMING...
',1),Qt=m(''),Xt=m('
memories · avg retention
');function Zt(a,r){We(r,!0);const i=()=>H(ot,"$avgRetention",M),c=()=>H(xt,"$eventFeed",M),f=()=>H(it,"$memoryCount",M),[M,y]=Te(),D=j(()=>Math.round((i()??0)*100)),x=j(()=>(i()??0)>=.5);let h=ye(null);async function v(){try{const n=await Ue.retentionDistribution();if(Array.isArray(n.endangered)&&n.endangered.length>0){A(h,n.endangered.length,!0);return}const d=n.distribution??[];let $=0;for(const S of d){const W=/^(\d+)/.exec(S.range);if(!W)continue;const O=Number.parseInt(W[1],10);Number.isFinite(O)&&O<30&&($+=S.count??0)}A(h,$,!0)}catch{A(h,null)}}let l=ye(null);async function b(){var n;try{const d=await Ue.intentions("active");A(l,d.total??((n=d.intentions)==null?void 0:n.length)??0,!0)}catch{A(l,null)}}let F=ye(mt(Date.now()));const T=j(()=>{const n=c(),d=Lt(n,e(F)),$=d?we(d)??e(F):null,S=$!==null?e(F)-$:null;return{isDreaming:Rt(n,e(F)),recent:d,recentMsAgo:S,insights:Nt(d)}}),K=j(()=>It(c(),e(F))),Q=j(()=>Kt(c(),e(F)));st(()=>{v(),b();const n=setInterval(()=>{A(F,Date.now(),!0)},1e3),d=setInterval(()=>{v(),b()},6e4);return()=>{clearInterval(n),clearInterval(d)}});var V=Xt();let X;var Z=s(V),ne=s(Z),J=s(ne);let Ee;var Re=o(J,2);let Fe;t(ne);var Me=o(ne,2),w=s(Me,!0);t(Me);var k=o(Me,6);let p;var z=s(k);t(k),se(2),t(Z);var L=o(Z,4),I=s(L);{var ie=n=>{var d=Vt(),$=ce(d),S=s($,!0);t($),se(2),N(()=>_(S,e(h))),u(n,d)},Ce=n=>{var d=Bt();se(2),u(n,d)},xe=n=>{var d=Gt();se(2),u(n,d)};B(I,n=>{e(h)!==null&&e(h)>0?n(ie):e(h)===0?n(Ce,1):n(xe,!1)})}t(L);var g=o(L,4),q=s(g);{var P=n=>{var d=Ht(),$=ce(d);let S;var W=o($,2);let O;var Y=s(W,!0);t(W),se(2),N(()=>{S=G($,1,"inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,S,{"bg-node-pattern":e(l)>5,"animate-ping-slow":e(l)>5,"bg-muted":e(l)<=5}),O=G(W,1,"tabular-nums svelte-1kk3799",null,O,{"text-node-pattern":e(l)>5,"text-text":e(l)>0&&e(l)<=5,"text-muted":e(l)===0}),_(Y,e(l))}),u(n,d)},ve=n=>{var d=qt();u(n,d)};B(q,n=>{e(l)!==null?n(P):n(ve,!1)})}t(g);var oe=o(g,4),pe=s(oe);{var ue=n=>{var d=Pt(),$=o(ce(d),4),S=s($,!0);t($);var W=o($,2);{var O=Y=>{var Ae=zt(),Ie=o(ce(Ae),2),Be=s(Ie,!0);t(Ie),se(2),N(()=>_(Be,e(T).insights)),u(Y,Ae)};B(W,Y=>{e(T).insights!==null&&Y(O)})}N(Y=>_(S,Y),[()=>jt(e(T).recentMsAgo)]),u(n,d)},le=n=>{var d=Wt();u(n,d)};B(pe,n=>{e(T).recent&&e(T).recentMsAgo!==null?n(ue):n(le,!1)})}t(oe);var me=o(oe,4),ke=o(s(me),2);De(ke,21,()=>e(K),Ne,(n,d)=>{var $=Ot();N(S=>lt($,`height: ${S??""}%; opacity: ${e(d).count===0?.18:.5+e(d).ratio*.5};`),[()=>Math.max(10,e(d).ratio*100)]),u(n,$)}),t(ke),t(me);var Se=o(me,2);{var je=n=>{var d=Yt();se(2),u(n,d)};B(Se,n=>{e(T).isDreaming&&n(je)})}var Ke=o(Se,4);{var Ve=n=>{var d=Qt();u(n,d)};B(Ke,n=>{e(Q)&&n(Ve)})}t(V),N(()=>{X=G(V,1,"ambient-strip relative flex h-9 w-full items-center gap-0 overflow-hidden border-b border-synapse/15 bg-black/40 px-3 text-[11px] text-dim backdrop-blur-md svelte-1kk3799",null,X,{"ambient-flash":e(Q)}),Ee=G(J,1,"absolute inline-flex h-full w-full animate-ping rounded-full opacity-75 svelte-1kk3799",null,Ee,{"bg-recall":e(x),"bg-warning":!e(x)}),Fe=G(Re,1,"relative inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,Fe,{"bg-recall":e(x),"bg-warning":!e(x)}),_(w,f()),p=G(k,1,"svelte-1kk3799",null,p,{"text-recall":e(x),"text-warning":!e(x)}),_(z,`${e(D)??""}%`)}),u(a,V),Oe(),y()}const pt="vestige.theme",et="vestige-theme-light",$e=dt("dark"),Pe=dt(!0),tt=$t([$e,Pe],([a,r])=>a==="auto"?r?"dark":"light":a);function Jt(a){return a==="dark"||a==="light"||a==="auto"}function Ut(a){if(Jt(a)){$e.set(a);try{localStorage.setItem(pt,a)}catch{}}}function qe(){const a=ct($e);Ut(a==="dark"?"light":a==="light"?"auto":"dark")}function ea(){if(document.getElementById(et))return;const a=document.createElement("style");a.id=et,a.textContent=` +import"../chunks/Bzak7iHL.js";import{o as st}from"../chunks/GG5zm9kr.js";import{f as ce,e as o,d as s,r as t,t as N,p as We,n as se,g as e,a as Oe,s as ye,c as mt,h as A,u as j}from"../chunks/CpWkWWOo.js";import{s as _,d as Ye,a as re,e as Le}from"../chunks/BlVfL1ME.js";import{i as B}from"../chunks/B4yTwGkE.js";import{e as De,i as Ne}from"../chunks/CGEBXrjl.js";import{c as rt,a as u,f as m}from"../chunks/CHOnp4oo.js";import{s as Xe}from"../chunks/CJCPY1OL.js";import{s as be,r as ft}from"../chunks/A7po6GxK.js";import{s as G}from"../chunks/aVbAZ-t7.js";import{b as ht}from"../chunks/sZcqyNBA.js";import{b as gt}from"../chunks/CJsMJEun.js";import{a as H,s as Te}from"../chunks/C6HuKgyx.js";import{s as bt,g as Ze}from"../chunks/BTwePnbx.js";import{b as U}from"../chunks/BdslOLCg.js";import{s as nt,m as it,a as ot,e as xt,w as Je,u as kt,i as _t,f as yt}from"../chunks/MAY1QfFZ.js";import{i as wt}from"../chunks/BUoSzNdg.js";import{s as lt}from"../chunks/Cx-f-Pzo.js";import{t as ge}from"../chunks/BjdL4Pm2.js";import{a as Ue}from"../chunks/DNjM5a-l.js";import{d as $t,w as dt,g as ct}from"../chunks/BeMFXnHE.js";const Mt=()=>{const a=bt;return{page:{subscribe:a.page.subscribe},navigating:{subscribe:a.navigating.subscribe},updated:a.updated}},Ct={subscribe(a){return Mt().page.subscribe(a)}};var At=m('
');function Dt(a){const r=()=>H(nt,"$suppressedCount",i),[i,c]=Te();var f=rt(),M=ce(f);{var y=D=>{var x=At(),h=o(s(x),2),v=s(h);t(h),t(x),N(()=>_(v,`Actively forgetting ${r()??""} ${r()===1?"memory":"memories"}`)),u(D,x)};B(M,D=>{r()>0&&D(y)})}u(a,f),c()}var Tt=m(''),Et=m('
');function Ft(a,r){We(r,!1);const i=()=>H(ge,"$toasts",c),[c,f]=Te(),M={DreamCompleted:"✦",ConsolidationCompleted:"◉",ConnectionDiscovered:"⟷",MemoryPromoted:"↑",MemoryDemoted:"↓",MemorySuppressed:"◬",MemoryUnsuppressed:"◉",Rac1CascadeSwept:"✺",MemoryDeleted:"✕"};function y(v){return M[v]??"◆"}function D(v){ge.dismiss(v.id)}function x(v,l){(v.key==="Enter"||v.key===" ")&&(v.preventDefault(),ge.dismiss(l.id))}wt();var h=Et();De(h,5,i,v=>v.id,(v,l)=>{var b=Tt(),F=o(s(b),2),T=s(F),K=s(T),Q=s(K,!0);t(K);var V=o(K,2),X=s(V,!0);t(V),t(T);var Z=o(T,2),ne=s(Z,!0);t(Z),t(F),se(2),t(b),N(J=>{be(b,"aria-label",`${e(l).title??""}: ${e(l).body??""}. Click to dismiss.`),lt(b,`--toast-color: ${e(l).color??""}; --toast-dwell: ${e(l).dwellMs??""}ms;`),_(Q,J),_(X,e(l).title),_(ne,e(l).body)},[()=>y(e(l).type)]),re("click",b,()=>D(e(l))),re("keydown",b,J=>x(J,e(l))),Le("mouseenter",b,()=>ge.pauseDwell(e(l).id,e(l).dwellMs)),Le("mouseleave",b,()=>ge.resumeDwell(e(l).id)),Le("focus",b,()=>ge.pauseDwell(e(l).id,e(l).dwellMs)),Le("blur",b,()=>ge.resumeDwell(e(l).id)),u(v,b)}),t(h),u(a,h),Oe(),f()}Ye(["click","keydown"]);function we(a){const r=a.data;if(!r||typeof r!="object")return null;const i=r.timestamp??r.at??r.occurred_at;if(i==null)return null;if(typeof i=="number")return Number.isFinite(i)?i>1e12?i:i*1e3:null;if(typeof i!="string")return null;const c=Date.parse(i);return Number.isFinite(c)?c:null}const ze=10,vt=3e4,St=ze*vt;function It(a,r){const i=r-St,c=new Array(ze).fill(0);for(const M of a){if(M.type==="Heartbeat")continue;const y=we(M);if(y===null||yr)continue;const D=Math.min(ze-1,Math.floor((y-i)/vt));c[D]+=1}const f=Math.max(1,...c);return c.map(M=>({count:M,ratio:M/f}))}function Lt(a,r){const i=r-864e5;for(const c of a){if(c.type!=="DreamCompleted")continue;return(we(c)??r)>=i?c:null}return null}function Nt(a){if(!a||!a.data)return null;const r=a.data,i=typeof r.insights_generated=="number"?r.insights_generated:typeof r.insightsGenerated=="number"?r.insightsGenerated:null;return i!==null&&Number.isFinite(i)?i:null}function Rt(a,r){let i=null,c=null;for(const D of a)if(!i&&D.type==="DreamStarted"&&(i=D),!c&&D.type==="DreamCompleted"&&(c=D),i&&c)break;if(!i)return!1;const f=we(i)??r,M=r-300*1e3;return f=c}return!1}var Vt=m(' at risk',1),Bt=m('0 at risk',1),Gt=m(' at risk',1),Ht=m(' intentions',1),qt=m('— intentions'),zt=m('· insights',1),Pt=m(' Last dream: ',1),Wt=m('No recent dream'),Ot=m('
'),Yt=m('
DREAMING...
',1),Qt=m(''),Xt=m('
memories · avg retention
');function Zt(a,r){We(r,!0);const i=()=>H(ot,"$avgRetention",M),c=()=>H(xt,"$eventFeed",M),f=()=>H(it,"$memoryCount",M),[M,y]=Te(),D=j(()=>Math.round((i()??0)*100)),x=j(()=>(i()??0)>=.5);let h=ye(null);async function v(){try{const n=await Ue.retentionDistribution();if(Array.isArray(n.endangered)&&n.endangered.length>0){A(h,n.endangered.length,!0);return}const d=n.distribution??[];let $=0;for(const S of d){const W=/^(\d+)/.exec(S.range);if(!W)continue;const O=Number.parseInt(W[1],10);Number.isFinite(O)&&O<30&&($+=S.count??0)}A(h,$,!0)}catch{A(h,null)}}let l=ye(null);async function b(){var n;try{const d=await Ue.intentions("active");A(l,d.total??((n=d.intentions)==null?void 0:n.length)??0,!0)}catch{A(l,null)}}let F=ye(mt(Date.now()));const T=j(()=>{const n=c(),d=Lt(n,e(F)),$=d?we(d)??e(F):null,S=$!==null?e(F)-$:null;return{isDreaming:Rt(n,e(F)),recent:d,recentMsAgo:S,insights:Nt(d)}}),K=j(()=>It(c(),e(F))),Q=j(()=>Kt(c(),e(F)));st(()=>{v(),b();const n=setInterval(()=>{A(F,Date.now(),!0)},1e3),d=setInterval(()=>{v(),b()},6e4);return()=>{clearInterval(n),clearInterval(d)}});var V=Xt();let X;var Z=s(V),ne=s(Z),J=s(ne);let Ee;var Re=o(J,2);let Fe;t(ne);var Me=o(ne,2),w=s(Me,!0);t(Me);var k=o(Me,6);let p;var z=s(k);t(k),se(2),t(Z);var L=o(Z,4),I=s(L);{var ie=n=>{var d=Vt(),$=ce(d),S=s($,!0);t($),se(2),N(()=>_(S,e(h))),u(n,d)},Ce=n=>{var d=Bt();se(2),u(n,d)},xe=n=>{var d=Gt();se(2),u(n,d)};B(I,n=>{e(h)!==null&&e(h)>0?n(ie):e(h)===0?n(Ce,1):n(xe,!1)})}t(L);var g=o(L,4),q=s(g);{var P=n=>{var d=Ht(),$=ce(d);let S;var W=o($,2);let O;var Y=s(W,!0);t(W),se(2),N(()=>{S=G($,1,"inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,S,{"bg-node-pattern":e(l)>5,"animate-ping-slow":e(l)>5,"bg-muted":e(l)<=5}),O=G(W,1,"tabular-nums svelte-1kk3799",null,O,{"text-node-pattern":e(l)>5,"text-text":e(l)>0&&e(l)<=5,"text-muted":e(l)===0}),_(Y,e(l))}),u(n,d)},ve=n=>{var d=qt();u(n,d)};B(q,n=>{e(l)!==null?n(P):n(ve,!1)})}t(g);var oe=o(g,4),pe=s(oe);{var ue=n=>{var d=Pt(),$=o(ce(d),4),S=s($,!0);t($);var W=o($,2);{var O=Y=>{var Ae=zt(),Ie=o(ce(Ae),2),Be=s(Ie,!0);t(Ie),se(2),N(()=>_(Be,e(T).insights)),u(Y,Ae)};B(W,Y=>{e(T).insights!==null&&Y(O)})}N(Y=>_(S,Y),[()=>jt(e(T).recentMsAgo)]),u(n,d)},le=n=>{var d=Wt();u(n,d)};B(pe,n=>{e(T).recent&&e(T).recentMsAgo!==null?n(ue):n(le,!1)})}t(oe);var me=o(oe,4),ke=o(s(me),2);De(ke,21,()=>e(K),Ne,(n,d)=>{var $=Ot();N(S=>lt($,`height: ${S??""}%; opacity: ${e(d).count===0?.18:.5+e(d).ratio*.5};`),[()=>Math.max(10,e(d).ratio*100)]),u(n,$)}),t(ke),t(me);var Se=o(me,2);{var je=n=>{var d=Yt();se(2),u(n,d)};B(Se,n=>{e(T).isDreaming&&n(je)})}var Ke=o(Se,4);{var Ve=n=>{var d=Qt();u(n,d)};B(Ke,n=>{e(Q)&&n(Ve)})}t(V),N(()=>{X=G(V,1,"ambient-strip relative flex h-9 w-full items-center gap-0 overflow-hidden border-b border-synapse/15 bg-black/40 px-3 text-[11px] text-dim backdrop-blur-md svelte-1kk3799",null,X,{"ambient-flash":e(Q)}),Ee=G(J,1,"absolute inline-flex h-full w-full animate-ping rounded-full opacity-75 svelte-1kk3799",null,Ee,{"bg-recall":e(x),"bg-warning":!e(x)}),Fe=G(Re,1,"relative inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,Fe,{"bg-recall":e(x),"bg-warning":!e(x)}),_(w,f()),p=G(k,1,"svelte-1kk3799",null,p,{"text-recall":e(x),"text-warning":!e(x)}),_(z,`${e(D)??""}%`)}),u(a,V),Oe(),y()}const pt="vestige.theme",et="vestige-theme-light",$e=dt("dark"),Pe=dt(!0),tt=$t([$e,Pe],([a,r])=>a==="auto"?r?"dark":"light":a);function Jt(a){return a==="dark"||a==="light"||a==="auto"}function Ut(a){if(Jt(a)){$e.set(a);try{localStorage.setItem(pt,a)}catch{}}}function qe(){const a=ct($e);Ut(a==="dark"?"light":a==="light"?"auto":"dark")}function ea(){if(document.getElementById(et))return;const a=document.createElement("style");a.id=et,a.textContent=` /* Vestige light-mode overrides — injected by theme.ts. * Activated by [data-theme='light'] on . * Tokens mirror the real names used in app.css so the cascade stays clean. */ diff --git a/apps/dashboard/build/_app/immutable/nodes/0._nbDJIPC.js.br b/apps/dashboard/build/_app/immutable/nodes/0._nbDJIPC.js.br new file mode 100644 index 0000000000000000000000000000000000000000..33f9ab4d3d40b20b79eddffbdda89c7540fc6ac2 GIT binary patch literal 8174 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 UMmmYB!ESFGffZNYFHv-i2X$Wxk^lez literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js.gz b/apps/dashboard/build/_app/immutable/nodes/0._nbDJIPC.js.gz similarity index 88% rename from apps/dashboard/build/_app/immutable/nodes/0.COz2esg5.js.gz rename to apps/dashboard/build/_app/immutable/nodes/0._nbDJIPC.js.gz index aa16a20ab1affa9c032719c09f688c17a458c84a..6f80e95ad1f03cf92f410c48971a78a4c5692037 100644 GIT binary patch delta 94 zcmV-k0HOcpNaRScfdNRp81l2Ac{9V$s~Jc)@t>dUwr7Y3DeK|Wlhz7T;YBwo8{+dR z7jD^2g#)}#g*itv5})q8t-fd-yqoc|;SA{GSK;~RXYMSs%K?)j2%_zVI;3X+00=%X A1^@s6 delta 96 zcmV-m0H6QlNajeefdNW=a(J?L=6#&u=hX~k(miwDweHUl4^q~{rzfoyroxMEQZ~fr zQ!d=Hn+gYbp9*u1W+Xn{d0TzaI(RqZWy2ZJ$FIWk&(GZU4714rlOhNy*=xz9X8-_; CRWTL- diff --git a/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js b/apps/dashboard/build/_app/immutable/nodes/1.Bnre2dw5.js similarity index 80% rename from apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js rename to apps/dashboard/build/_app/immutable/nodes/1.Bnre2dw5.js index 748af3e..5e6aaef 100644 --- a/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js +++ b/apps/dashboard/build/_app/immutable/nodes/1.Bnre2dw5.js @@ -1 +1 @@ -import"../chunks/Bzak7iHL.js";import{i as h}from"../chunks/BUoSzNdg.js";import{p as g,f as d,t as l,a as v,d as s,r as o,e as _}from"../chunks/CpWkWWOo.js";import{s as p}from"../chunks/BlVfL1ME.js";import{a as x,f as $}from"../chunks/CHOnp4oo.js";import{p as m}from"../chunks/BskPcZf7.js";import{s as k}from"../chunks/BHGLDPij.js";const b={get error(){return m.error},get status(){return m.status}};k.updated.check;const i=b;var E=$("

",1);function C(f,n){g(n,!1),h();var t=E(),r=d(t),c=s(r,!0);o(r);var a=_(r,2),u=s(a,!0);o(a),l(()=>{var e;p(c,i.status),p(u,(e=i.error)==null?void 0:e.message)}),x(f,t),v()}export{C as component}; +import"../chunks/Bzak7iHL.js";import{i as h}from"../chunks/BUoSzNdg.js";import{p as g,f as d,t as l,a as v,d as s,r as o,e as _}from"../chunks/CpWkWWOo.js";import{s as p}from"../chunks/BlVfL1ME.js";import{a as x,f as $}from"../chunks/CHOnp4oo.js";import{p as m}from"../chunks/BdslOLCg.js";import{s as k}from"../chunks/BTwePnbx.js";const b={get error(){return m.error},get status(){return m.status}};k.updated.check;const i=b;var E=$("

",1);function C(f,n){g(n,!1),h();var t=E(),r=d(t),c=s(r,!0);o(r);var a=_(r,2),u=s(a,!0);o(a),l(()=>{var e;p(c,i.status),p(u,(e=i.error)==null?void 0:e.message)}),x(f,t),v()}export{C as component}; diff --git a/apps/dashboard/build/_app/immutable/nodes/1.Bnre2dw5.js.br b/apps/dashboard/build/_app/immutable/nodes/1.Bnre2dw5.js.br new file mode 100644 index 0000000000000000000000000000000000000000..bf2a3410dc66b7e61c97ab2990bbb74a92b56595 GIT binary patch literal 334 zcmV-U0kQrYi2@*ulrC=+nP$uWo9e^1G$Gt<0I)nDj+FoZ=6eI=iYAuX!)z@p>RDq< zOP^vVEByFvos-3y`uj@?lYtt;pBFbaHVwCmgJScl*MdXu;bp@w76srmcyq0oyA$&T zjQUN!`!~~}QtZH%z(fflG^k-hfgBQ8M1@x1I{gp+|KAg;Ag2zX!aw_E`}LO6n3lZE zj(m8J)4haB`6HBBgzqoc4poo?F!!giK4QJq-*}(SbvZaz`S;5DndC(qI(LFu4gIC5 z%4V8Gu#r#BMhy>(tUVJCp`Rlr` z?1IkM^vS?_vy=KksX^UxU>)0Hw_T-!68S*+`ODws@!TmRC9Ok8TBqD0Zj3UR)P}pt zNK^*hpaIWW$6RIm>9y_|m1PqO_BM?!G4UA?aRM=d3Mi1@io=_cfH@V{&k;&xRTR%BC1Nyt;z7x+Who~OfpgobjXhz~@N>7& Ym0xJ2+U-g%T@&8@0cL>hz={F@07?S5#sB~S literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.br b/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.br deleted file mode 100644 index fc2f8d46c262921e8fb9a8b7b0812a8cc4d09664..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 331 zcmV-R0kr-bi2@+RDqG7xiNI&78q;MF^%JxI|K@uG@o3X_2v!=ESS=NB})2)%6KuvNSb=lpu!%_aok)H!2HHf9gZ7clB2dTMWV zi;A%YQvw}1_)wsP4jEF2U=aUk1&-o3@9pg_qB3&q0Lp(gua|C4D21uXQ|!p|yD(mj zsF*)MW!}B^X>L#%*#mRW&#sT}9an$jeLAMf&NA}9SJuxYFPPW41I%jZFHKc8!yvr* zd~)VD8=|9i-=N)ugE`bu*@jTta76;d?J>+9cpQam^3&ZKQLk{K!$YYhgr(q!`?fq dlf`XgKF{8HVANzHXOzT)QOA@zGKvomVg&skp_>2z diff --git a/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.gz b/apps/dashboard/build/_app/immutable/nodes/1.DJo7hfwf.js.gz deleted file mode 100644 index 91c8b8218941e556e833d82a6d649b98aa9bd10c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 379 zcmV->0fhb^iwFP!000026J=0AOT#c2z56TT@Q}bq=R^?fGQm0AVd_A1;AO-#ZDZRc zB)*OS3C>yEi@bbU|rG>E&m-nZ2xr z%0B3LO1~Oeuiuop)p}I78d%QlUQSW;u+m{qZY_r!Mw@Nh^;1 ZLYHBoTzA`5Liskn_yg?{{U3?~000jivxWcw diff --git a/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.br b/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.br deleted file mode 100644 index 0115d29ca0b5455a0ddcd79a5bd6a51c72d358b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 124124 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ŎIh6hdUVhuVs_ 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 XSJrYfB9A)l>#~PiGL6L1Q2ajv#b^Yz diff --git a/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.gz b/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js.gz deleted file mode 100644 index b707b9187153a201b2b39fc3f789bd761d1eb36e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148777 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

T~BR;VS0!&8)c?wEV`b=17Oyk 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�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 H&+Z5S!PnkG diff --git a/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js b/apps/dashboard/build/_app/immutable/nodes/10.CecvzcnA.js similarity index 99% rename from apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js rename to apps/dashboard/build/_app/immutable/nodes/10.CecvzcnA.js index cb871ff..5190a66 100644 --- a/apps/dashboard/build/_app/immutable/nodes/10.Btb56kL1.js +++ b/apps/dashboard/build/_app/immutable/nodes/10.CecvzcnA.js @@ -1,4 +1,4 @@ -var Bc=Object.defineProperty;var zc=(i,t,e)=>t in i?Bc(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var kt=(i,t,e)=>zc(i,typeof t!="symbol"?t+"":t,e);import"../chunks/Bzak7iHL.js";import{o as jl,a as Zl}from"../chunks/GG5zm9kr.js";import{s as me,c as va,h as zt,g as B,p as ys,aB as kc,a as Es,d as yt,e as bt,n as Hc,r as xt,t as Ke,u as Gn,f as Kl,j as Vc}from"../chunks/CpWkWWOo.js";import{s as fe,d as $l,a as Fe}from"../chunks/BlVfL1ME.js";import{i as kn}from"../chunks/B4yTwGkE.js";import{e as _s,i as hr}from"../chunks/CGEBXrjl.js";import{a as _e,f as Se,c as Gc}from"../chunks/CHOnp4oo.js";import{s as ve,r as xa}from"../chunks/A7po6GxK.js";import{s as Us}from"../chunks/aVbAZ-t7.js";import{s as Sr}from"../chunks/Cx-f-Pzo.js";import{b as Ma}from"../chunks/sZcqyNBA.js";import{b as Jl}from"../chunks/BnXDGOmJ.js";import{s as Wc,a as Xc}from"../chunks/C6HuKgyx.js";import{b as Do}from"../chunks/BskPcZf7.js";import{b as Yc}from"../chunks/CJsMJEun.js";import{p as vs}from"../chunks/V6gjw5Ec.js";import{N as Sa}from"../chunks/DzfRjky4.js";import{i as qc}from"../chunks/BUoSzNdg.js";import{a as gi}from"../chunks/DNjM5a-l.js";import{e as jc}from"../chunks/MAY1QfFZ.js";/** +var Bc=Object.defineProperty;var zc=(i,t,e)=>t in i?Bc(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var kt=(i,t,e)=>zc(i,typeof t!="symbol"?t+"":t,e);import"../chunks/Bzak7iHL.js";import{o as jl,a as Zl}from"../chunks/GG5zm9kr.js";import{s as me,c as va,h as zt,g as B,p as ys,aB as kc,a as Es,d as yt,e as bt,n as Hc,r as xt,t as Ke,u as Gn,f as Kl,j as Vc}from"../chunks/CpWkWWOo.js";import{s as fe,d as $l,a as Fe}from"../chunks/BlVfL1ME.js";import{i as kn}from"../chunks/B4yTwGkE.js";import{e as _s,i as hr}from"../chunks/CGEBXrjl.js";import{a as _e,f as Se,c as Gc}from"../chunks/CHOnp4oo.js";import{s as ve,r as xa}from"../chunks/A7po6GxK.js";import{s as Us}from"../chunks/aVbAZ-t7.js";import{s as Sr}from"../chunks/Cx-f-Pzo.js";import{b as Ma}from"../chunks/sZcqyNBA.js";import{b as Jl}from"../chunks/BnXDGOmJ.js";import{s as Wc,a as Xc}from"../chunks/C6HuKgyx.js";import{b as Do}from"../chunks/BdslOLCg.js";import{b as Yc}from"../chunks/CJsMJEun.js";import{p as vs}from"../chunks/V6gjw5Ec.js";import{N as Sa}from"../chunks/DzfRjky4.js";import{i as qc}from"../chunks/BUoSzNdg.js";import{a as gi}from"../chunks/DNjM5a-l.js";import{e as jc}from"../chunks/MAY1QfFZ.js";/** * @license * Copyright 2010-2024 Three.js Authors * SPDX-License-Identifier: MIT diff --git a/apps/dashboard/build/_app/immutable/nodes/10.CecvzcnA.js.br b/apps/dashboard/build/_app/immutable/nodes/10.CecvzcnA.js.br new file mode 100644 index 0000000000000000000000000000000000000000..4a5a4f15f279aa54acf8eeb171fbcbd1b5ea401c GIT binary patch literal 124143 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 w=C();w!==w&&(w=re),T&&w!==null&&typeof w=="object"&&(w={}),v.ensure(w,m)})}function Mt(a){return a==null||!Number.isFinite(a)||a<0?0:a>1?1:a}function ne(a){return{novelty:Mt(a==null?void 0:a.novelty),arousal:Mt(a==null?void 0:a.arousal),reward:Mt(a==null?void 0:a.reward),attention:Mt(a==null?void 0:a.attention)}}const It={sm:80,md:180,lg:320};function $t(a){return a&&(a==="sm"||a==="md"||a==="lg")?It[a]:It.md}const gt=[{key:"novelty",angle:-Math.PI/2},{key:"arousal",angle:0},{key:"reward",angle:Math.PI/2},{key:"attention",angle:Math.PI}];function oe(a){const C=$t(a);let m;switch(a){case"lg":m=44;break;case"sm":m=4;break;default:m=28}return Math.max(0,C/2-m)}var ie=yt(''),le=yt(''),de=yt(''),ce=yt(' ',1),ve=yt('');function Et(a,C){Rt(C,!0);let m=ae(C,"size",3,"md"),v=y(()=>$t(m())),T=y(()=>m()!=="sm"),w=y(()=>oe(m())),Y=y(()=>t(v)/2),J=y(()=>t(v)/2);const St={novelty:"Novelty",arousal:"Arousal",reward:"Reward",attention:"Attention"};let N=y(()=>ne({novelty:C.novelty,arousal:C.arousal,reward:C.reward,attention:C.attention}));function H(d,l){const r=d*t(w);return[t(Y)+Math.cos(l)*r,t(J)+Math.sin(l)*r]}const st=[.25,.5,.75,1];function nt(d){return gt.map(({angle:r})=>H(d,r)).map((r,c)=>`${c===0?"M":"L"}${r[0].toFixed(2)},${r[1].toFixed(2)}`).join(" ")+" Z"}let $=q(0);Pt(()=>{const l=performance.now();let r=0;const c=b=>{const g=Math.min(1,(b-l)/600);F($,1-Math.pow(1-g,3)),g<1&&(r=requestAnimationFrame(c))};return r=requestAnimationFrame(c),()=>cancelAnimationFrame(r)});let ot=y(()=>{const d=t($);return gt.map(({key:r,angle:c})=>H(t(N)[r]*d,c)).map((r,c)=>`${c===0?"M":"L"}${r[0].toFixed(2)},${r[1].toFixed(2)}`).join(" ")+" Z"});function _t(d){const l=t(w)+(m()==="lg"?18:12),r=t(Y)+Math.cos(d)*l,c=t(J)+Math.sin(d)*l;let b="middle";return Math.abs(Math.cos(d))>.5&&(b=Math.cos(d)>0?"start":"end"),{x:r,y:c,anchor:b}}var P=ve(),it=i(P);V(it,17,()=>st,rt,(d,l)=>{var r=ie();S(c=>{p(r,"d",c),p(r,"stroke-opacity",t(l)===1?.45:.18),p(r,"stroke-width",t(l)===1?1:.75)},[()=>nt(t(l))]),x(d,r)});var ht=o(it);V(ht,17,()=>gt,rt,(d,l)=>{const r=y(()=>{const[b,g]=H(1,t(l).angle);return{x:b,y:g}});var c=le();S(()=>{p(c,"x1",t(Y)),p(c,"y1",t(J)),p(c,"x2",t(r).x),p(c,"y2",t(r).y)}),x(d,c)});var W=o(ht),Q=o(W);{var wt=d=>{var l=Nt(),r=U(l);V(r,17,()=>gt,rt,(c,b)=>{const g=y(()=>{const[I,dt]=H(t(N)[t(b).key]*t($),t(b).angle);return{px:I,py:dt}});var j=de();S(()=>{p(j,"cx",t(g).px),p(j,"cy",t(g).py),p(j,"r",m()==="lg"?3:2.25)}),x(c,j)}),x(d,l)};R(Q,d=>{m()!=="sm"&&d(wt)})}var lt=o(Q);{var tt=d=>{var l=Nt(),r=U(l);V(r,17,()=>gt,rt,(c,b)=>{const g=y(()=>_t(t(b).angle));var j=ce(),I=U(j),dt=i(I);n(I);var L=o(I),ct=i(L,!0);n(L),S(At=>{p(I,"x",t(g).x),p(I,"y",t(g).y),p(I,"text-anchor",t(g).anchor),p(I,"font-size",m()==="lg"?12:10),_(dt,`${At??""}%`),p(L,"x",t(g).x),p(L,"y",t(g).y+(m()==="lg"?14:11)),p(L,"text-anchor",t(g).anchor),p(L,"font-size",m()==="lg"?10:8.5),_(ct,St[t(b).key])},[()=>(t(N)[t(b).key]*100).toFixed(0)]),x(c,j)}),x(d,l)};R(lt,d=>{t(T)&&d(tt)})}n(P),S((d,l,r,c)=>{p(P,"width",t(v)),p(P,"height",t(v)),p(P,"viewBox",`0 0 ${t(v)??""} ${t(v)??""}`),p(P,"aria-label",`Importance radar: novelty ${d??""}%, arousal ${l??""}%, reward ${r??""}%, attention ${c??""}%`),p(W,"d",t(ot)),p(W,"stroke-width",m()==="sm"?1:1.5)},[()=>(t(N).novelty*100).toFixed(0),()=>(t(N).arousal*100).toFixed(0),()=>(t(N).reward*100).toFixed(0),()=>(t(N).attention*100).toFixed(0)]),x(a,P),Tt()}var pe=h(' '),xe=h('Driven by ',1),me=h('

'),ue=h('Weakest channel: ',1),fe=h('
⨯ Skip

'),ge=h('
Composite
%
',1),ye=h(`

Type some content above to score its importance.

Composite = 0.25·novelty + 0.30·arousal + 0.25·reward + 0.20·attention. +import"../chunks/Bzak7iHL.js";import{o as Pt}from"../chunks/GG5zm9kr.js";import{N as Kt,ab as qt,aP as Ht,b as Wt,p as Rt,h as F,d as i,t as S,g as t,e as o,r as n,a as Tt,u as y,s as q,f as U,c as Ft,C as Xt,i as Zt,n as Gt}from"../chunks/CpWkWWOo.js";import{s as _,d as Ut,a as kt}from"../chunks/BlVfL1ME.js";import{i as R}from"../chunks/B4yTwGkE.js";import{B as Vt}from"../chunks/DdEqwvdI.js";import{e as V,i as rt}from"../chunks/CGEBXrjl.js";import{a as x,c as Nt,b as yt,f as h}from"../chunks/CHOnp4oo.js";import{s as Yt}from"../chunks/Cx-f-Pzo.js";import{b as Jt}from"../chunks/sZcqyNBA.js";import{g as Qt}from"../chunks/BTwePnbx.js";import{b as te}from"../chunks/BdslOLCg.js";import{a as Ct}from"../chunks/DNjM5a-l.js";import{N as ee}from"../chunks/DzfRjky4.js";import{s as p}from"../chunks/A7po6GxK.js";import{p as ae}from"../chunks/V6gjw5Ec.js";const re=Symbol("NaN");function se(a,C,m){Kt&&qt();var v=new Vt(a),T=!Ht();Wt(()=>{var w=C();w!==w&&(w=re),T&&w!==null&&typeof w=="object"&&(w={}),v.ensure(w,m)})}function Mt(a){return a==null||!Number.isFinite(a)||a<0?0:a>1?1:a}function ne(a){return{novelty:Mt(a==null?void 0:a.novelty),arousal:Mt(a==null?void 0:a.arousal),reward:Mt(a==null?void 0:a.reward),attention:Mt(a==null?void 0:a.attention)}}const It={sm:80,md:180,lg:320};function $t(a){return a&&(a==="sm"||a==="md"||a==="lg")?It[a]:It.md}const gt=[{key:"novelty",angle:-Math.PI/2},{key:"arousal",angle:0},{key:"reward",angle:Math.PI/2},{key:"attention",angle:Math.PI}];function oe(a){const C=$t(a);let m;switch(a){case"lg":m=44;break;case"sm":m=4;break;default:m=28}return Math.max(0,C/2-m)}var ie=yt(''),le=yt(''),de=yt(''),ce=yt(' ',1),ve=yt('');function Et(a,C){Rt(C,!0);let m=ae(C,"size",3,"md"),v=y(()=>$t(m())),T=y(()=>m()!=="sm"),w=y(()=>oe(m())),Y=y(()=>t(v)/2),J=y(()=>t(v)/2);const St={novelty:"Novelty",arousal:"Arousal",reward:"Reward",attention:"Attention"};let N=y(()=>ne({novelty:C.novelty,arousal:C.arousal,reward:C.reward,attention:C.attention}));function H(d,l){const r=d*t(w);return[t(Y)+Math.cos(l)*r,t(J)+Math.sin(l)*r]}const st=[.25,.5,.75,1];function nt(d){return gt.map(({angle:r})=>H(d,r)).map((r,c)=>`${c===0?"M":"L"}${r[0].toFixed(2)},${r[1].toFixed(2)}`).join(" ")+" Z"}let $=q(0);Pt(()=>{const l=performance.now();let r=0;const c=b=>{const g=Math.min(1,(b-l)/600);F($,1-Math.pow(1-g,3)),g<1&&(r=requestAnimationFrame(c))};return r=requestAnimationFrame(c),()=>cancelAnimationFrame(r)});let ot=y(()=>{const d=t($);return gt.map(({key:r,angle:c})=>H(t(N)[r]*d,c)).map((r,c)=>`${c===0?"M":"L"}${r[0].toFixed(2)},${r[1].toFixed(2)}`).join(" ")+" Z"});function _t(d){const l=t(w)+(m()==="lg"?18:12),r=t(Y)+Math.cos(d)*l,c=t(J)+Math.sin(d)*l;let b="middle";return Math.abs(Math.cos(d))>.5&&(b=Math.cos(d)>0?"start":"end"),{x:r,y:c,anchor:b}}var P=ve(),it=i(P);V(it,17,()=>st,rt,(d,l)=>{var r=ie();S(c=>{p(r,"d",c),p(r,"stroke-opacity",t(l)===1?.45:.18),p(r,"stroke-width",t(l)===1?1:.75)},[()=>nt(t(l))]),x(d,r)});var ht=o(it);V(ht,17,()=>gt,rt,(d,l)=>{const r=y(()=>{const[b,g]=H(1,t(l).angle);return{x:b,y:g}});var c=le();S(()=>{p(c,"x1",t(Y)),p(c,"y1",t(J)),p(c,"x2",t(r).x),p(c,"y2",t(r).y)}),x(d,c)});var W=o(ht),Q=o(W);{var wt=d=>{var l=Nt(),r=U(l);V(r,17,()=>gt,rt,(c,b)=>{const g=y(()=>{const[I,dt]=H(t(N)[t(b).key]*t($),t(b).angle);return{px:I,py:dt}});var j=de();S(()=>{p(j,"cx",t(g).px),p(j,"cy",t(g).py),p(j,"r",m()==="lg"?3:2.25)}),x(c,j)}),x(d,l)};R(Q,d=>{m()!=="sm"&&d(wt)})}var lt=o(Q);{var tt=d=>{var l=Nt(),r=U(l);V(r,17,()=>gt,rt,(c,b)=>{const g=y(()=>_t(t(b).angle));var j=ce(),I=U(j),dt=i(I);n(I);var L=o(I),ct=i(L,!0);n(L),S(At=>{p(I,"x",t(g).x),p(I,"y",t(g).y),p(I,"text-anchor",t(g).anchor),p(I,"font-size",m()==="lg"?12:10),_(dt,`${At??""}%`),p(L,"x",t(g).x),p(L,"y",t(g).y+(m()==="lg"?14:11)),p(L,"text-anchor",t(g).anchor),p(L,"font-size",m()==="lg"?10:8.5),_(ct,St[t(b).key])},[()=>(t(N)[t(b).key]*100).toFixed(0)]),x(c,j)}),x(d,l)};R(lt,d=>{t(T)&&d(tt)})}n(P),S((d,l,r,c)=>{p(P,"width",t(v)),p(P,"height",t(v)),p(P,"viewBox",`0 0 ${t(v)??""} ${t(v)??""}`),p(P,"aria-label",`Importance radar: novelty ${d??""}%, arousal ${l??""}%, reward ${r??""}%, attention ${c??""}%`),p(W,"d",t(ot)),p(W,"stroke-width",m()==="sm"?1:1.5)},[()=>(t(N).novelty*100).toFixed(0),()=>(t(N).arousal*100).toFixed(0),()=>(t(N).reward*100).toFixed(0),()=>(t(N).attention*100).toFixed(0)]),x(a,P),Tt()}var pe=h(' '),xe=h('Driven by ',1),me=h('

✓ Save

'),ue=h('Weakest channel: ',1),fe=h('
⨯ Skip

'),ge=h('
Composite
%
',1),ye=h(`

Type some content above to score its importance.

Composite = 0.25·novelty + 0.30·arousal + 0.25·reward + 0.20·attention. Threshold for save: 60%.

`),_e=h('
'),he=h('
'),we=h('

No memories yet.

'),be=h('· ',1),ke=h(' '),Me=h('
'),Se=h(``),Ae=h('
'),Ce=h(`

Importance Radar

4-channel importance model: Novelty · Arousal · Reward · Attention

Test Importance

Paste any content below. Vestige scores it across 4 channels and decides whether it is worth saving.

Why Pro exists

Two plans. One promise: agent memory you can depend on.

Always-on answers

The support bot handles the first wave.

This is the first support layer: instant onboarding answers before anyone has to write an email. It can run locally from the FAQ now and call a hosted support endpoint later.

Onboarding bot

May to June

The plan is simple.

  1. May Get Vestige into every MCP, Claude Code, Cursor, local AI, Rust, and self-hosted channel that cares about agent memory.
  2. June Invite the first Solo Pro and Team Pro users into sync, backups, shared memory, PostgreSQL-backed deployments, and bot-assisted support.
  3. After Use paid feedback to turn Vestige from a beloved local tool into durable agent-memory infrastructure.
`);function Ft(Be,Ee){ct(Ee,!0);let q,G=p(""),j=p(""),I=p("solo"),J=p("sync"),x=p(""),H=p(""),y=p("idle"),_=p(""),S=p(""),T=p(!1),C=p(mt([{role:"bot",content:"Ask me about installing Vestige, whether heavy models are required, Solo vs Team Pro, sync, pricing, or what happens after you join the June list."}]));const Fe=[{value:"Local",label:"SQLite memory, no hosted memory service"},{value:"MCP",label:"Claude Code, Cursor, Cline, Codex, Goose"},{value:"June",label:"Pro sync, backup, team memory early access"}],De=[{name:"Solo Pro",accent:"#22c55e",copy:"Multi-device sync, encrypted backups, managed updates, and a cleaner memory dashboard for developers living inside AI coding agents."},{name:"Team Pro",accent:"#06b6d4",copy:"Shared project memory, admin review, audit trails, PostgreSQL-backed deployments, and async support for engineering teams."}],Oe=["Private by default","Sync without lock-in","Team memory controls","Bot-assisted support"],ze=[{label:"Install",prompt:"How do I install Vestige and connect it to Claude Code?"},{label:"No 20GB?",prompt:"Do I need the Sanhedrin model or 20GB of RAM?"},{label:"Solo vs Team",prompt:"Should I choose Solo Pro or Team Pro?"},{label:"Sync",prompt:"How will Pro sync and backups work?"},{label:"Pricing",prompt:"How much will Vestige Pro cost?"},{label:"Human help",prompt:"When does a human get involved?"}];it(()=>{const t=q.getContext("2d");if(!t)return;const e=t;let r=0,i=0,m=0;const d=Array.from({length:62},(b,w)=>({x:Math.random(),y:Math.random(),vx:(Math.random()-.5)*16e-5,vy:(Math.random()-.5)*16e-5,phase:Math.random()*Math.PI*2,kind:w%5}));function M(){const b=Math.min(window.devicePixelRatio||1,2);i=window.innerWidth,m=window.innerHeight,q.width=Math.floor(i*b),q.height=Math.floor(m*b),q.style.width=`${i}px`,q.style.height=`${m}px`,e.setTransform(b,0,0,b,0,0)}function Me(b){e.clearRect(0,0,i,m);const w=e.createLinearGradient(0,0,i,m);w.addColorStop(0,"#07100f"),w.addColorStop(.45,"#0b1221"),w.addColorStop(1,"#15100a"),e.fillStyle=w,e.fillRect(0,0,i,m),e.strokeStyle="rgba(148, 163, 184, 0.08)",e.lineWidth=1;for(let n=0;n.96)&&(n.vx*=-1),(n.y<.06||n.y>.94)&&(n.vy*=-1);for(let n=0;n{cancelAnimationFrame(r),window.removeEventListener("resize",M)}});function Ne(){const t=["## Vestige Pro waitlist","",`Plan: ${a(I)}`,`Priority: ${a(J)}`,a(x).trim()?`Use case: ${a(x).trim()}`:"Use case:","","Please do not include private email addresses in this public issue."].join(` `);return`https://github.com/samvallad33/vestige/issues/new?title=${encodeURIComponent("Vestige Pro waitlist")}&body=${encodeURIComponent(t)}`}async function Ye(t){if(t.preventDefault(),c(y,"submitting"),c(_,""),a(H).trim()){c(y,"success"),c(_,"You are on the list.");return}if(!a(j).includes("@")){c(y,"error"),c(_,"Enter an email so the early-access invite can reach you.");return}a(G).trim(),a(j).trim(),a(I),a(J),a(x).trim(),new Date().toISOString();{c(y,"success"),c(_,"Email capture is ready for an endpoint. Opening the GitHub waitlist fallback with your email omitted."),window.open(Ne(),"_blank","noopener,noreferrer");return}}function Ke(t){const e=t.toLowerCase();return/(install|setup|onboard|claude|cursor|cline|codex|connect)/.test(e)?["Start with the open-source install:","1. `npm install -g vestige-mcp-server@latest`","2. Claude Code: `claude mcp add vestige vestige-mcp -s user`","3. Codex: `codex mcp add vestige -- vestige-mcp`","Then test it by asking your agent to remember a preference, opening a fresh session, and asking for that preference back."].join(` diff --git a/apps/dashboard/build/_app/immutable/nodes/20.BM_Hn1tR.js.br b/apps/dashboard/build/_app/immutable/nodes/20.BM_Hn1tR.js.br new file mode 100644 index 0000000000000000000000000000000000000000..a992989d3dded33bd1fd56957634665d952cc49e GIT binary patch literal 5511 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 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/20.BwEdZXUF.js.br b/apps/dashboard/build/_app/immutable/nodes/20.BwEdZXUF.js.br deleted file mode 100644 index 469e075272fe10d9f51682959a8dde927f8cc373..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5519 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 RH+dg%YU!WTo?xsI`vMeM$2tH2 diff --git a/apps/dashboard/build/_app/immutable/nodes/20.BwEdZXUF.js.gz b/apps/dashboard/build/_app/immutable/nodes/20.BwEdZXUF.js.gz deleted file mode 100644 index 2d1f99e32a9f7f37554a5fd067b87e343ee248ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6452 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 OfBYZUVLp-IK>z@rv8`(W diff --git a/apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js.br b/apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js.br deleted file mode 100644 index 1830c35e524a1d040bb43fcfa5b7d1667bbd81eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 164 zcmV;V09*eXBmrP#aZZ1uwyNYrs0ReM+4-3!mRT6r7I<4ESsLIg{~r0>#-`&cRuQep zJ9tg1)fy)Ursma_DWmn2{kf`oWJI@2p%{;{|Gq;ieXLh{B%- S#Ig-oW&r;}951FK|DytehErky diff --git a/apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js.gz b/apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js.gz deleted file mode 100644 index 9de279d0996a3ed11215f6a663aa931102921d49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 196 zcmV;#06YI5iwFP!000026J^ao3xY5hfZ=<;!aQv-v@K>&9a0a>mwF$m$q yQ6ksR4b_E9I>YsgGM-p!`F^?TF(w*eLJ{uy`?q88eJiePA1pqYtP{~C0RR9RO;z#$ diff --git a/apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js b/apps/dashboard/build/_app/immutable/nodes/3.De3LPrRR.js similarity index 56% rename from apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js rename to apps/dashboard/build/_app/immutable/nodes/3.De3LPrRR.js index 1814225..1e3af41 100644 --- a/apps/dashboard/build/_app/immutable/nodes/3.Caati8mq.js +++ b/apps/dashboard/build/_app/immutable/nodes/3.De3LPrRR.js @@ -1 +1 @@ -import"../chunks/Bzak7iHL.js";import{i as p}from"../chunks/BUoSzNdg.js";import{o as r}from"../chunks/GG5zm9kr.js";import{p as t,a}from"../chunks/CpWkWWOo.js";import{g as m}from"../chunks/BHGLDPij.js";function g(i,o){t(o,!1),r(()=>m("/graph",{replaceState:!0})),p(),a()}export{g as component}; +import"../chunks/Bzak7iHL.js";import{i as p}from"../chunks/BUoSzNdg.js";import{o as r}from"../chunks/GG5zm9kr.js";import{p as t,a}from"../chunks/CpWkWWOo.js";import{g as m}from"../chunks/BTwePnbx.js";function g(i,o){t(o,!1),r(()=>m("/graph",{replaceState:!0})),p(),a()}export{g as component}; diff --git a/apps/dashboard/build/_app/immutable/nodes/3.De3LPrRR.js.br b/apps/dashboard/build/_app/immutable/nodes/3.De3LPrRR.js.br new file mode 100644 index 0000000000000000000000000000000000000000..f0979e6d6bc3f02a96d13d6ad0ff83aea89b6263 GIT binary patch literal 164 zcmV;V09*eXBmrP#aZZ1uwyNYrs0ReM+4-3!mRT6r7I<4ESsLIg{~r0>#-`&cRuQep zJ9tg1)fy)Ursma_DWmn2{kf`oWJI@2p%{;{|Gq;ieXLh{_F6#sAjk3wadW(9V+p-9 zzcPyEja(LHEOjp}p}%&glOjn@Ft%B5<=_AE;%9ZM2boriSpmw)kRX6ti-5Q@ObkMJ zy^+WZGDCIlk=Ahiq>RUwTE23p9mYf>Oen$~ufID6pSR-5cH!g=OO?~cm#bKj literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/6.DTUGCA1p.js b/apps/dashboard/build/_app/immutable/nodes/6.BN-BfASZ.js similarity index 99% rename from apps/dashboard/build/_app/immutable/nodes/6.DTUGCA1p.js rename to apps/dashboard/build/_app/immutable/nodes/6.BN-BfASZ.js index 5f3fc6c..dcfb793 100644 --- a/apps/dashboard/build/_app/immutable/nodes/6.DTUGCA1p.js +++ b/apps/dashboard/build/_app/immutable/nodes/6.BN-BfASZ.js @@ -1,4 +1,4 @@ -import"../chunks/Bzak7iHL.js";import{p as qe,d as a,r as t,e as i,g as e,f as he,u as b,t as R,a as Se,n as X,h as de,s as be,W as Ge,aG as Ae}from"../chunks/CpWkWWOo.js";import{s as x,d as Ye,a as pe}from"../chunks/BlVfL1ME.js";import{c as Fe,a as m,f as _,b as Ve,t as Ie}from"../chunks/CHOnp4oo.js";import{i as j}from"../chunks/B4yTwGkE.js";import{e as ge}from"../chunks/CGEBXrjl.js";import{h as We}from"../chunks/C4h_mRt2.js";import{s as A,r as Be,a as Xe}from"../chunks/A7po6GxK.js";import{s as _e}from"../chunks/aVbAZ-t7.js";import{a as ze}from"../chunks/DNjM5a-l.js";import{s as ae}from"../chunks/Cx-f-Pzo.js";import{p as Ue}from"../chunks/V6gjw5Ec.js";import{b as Je}from"../chunks/BskPcZf7.js";const Te=5,je=["Replay","Cross-reference","Strengthen","Prune","Transfer"];function Oe(v){if(!Number.isFinite(v))return 1;const n=Math.floor(v);return n<1?1:n>Te?Te:n}const Ke=.3,Qe=.7;function Ze(v){const n=ye(v);return n>Qe?"high":n1?1:v}function $e(v){return v==null||!Number.isFinite(v)||v<0?"0ms":v<1e3?`${Math.round(v)}ms`:`${(v/1e3).toFixed(2)}s`}function et(v){const n=ye(v);return`${Math.round(n*100)}%`}function tt(v,n=""){return`${n}/memories/${v}`}function st(v,n=2){return!v||v.length===0?[]:v.slice(0,Math.max(0,n))}function at(v,n=2){return v?Math.max(0,v.length-n):0}function rt(v){return v?v.length>8?v.slice(0,8):v:""}var nt=_('
Episodic hippocampus
Semantic cortex
',1),it=Ve(''),vt=_('
'),lt=_(''),ot=_('Replaying memories'),ct=_('New connections found: '),dt=_('Strengthened: '),ut=_('Compressed: '),ft=_('Connections persisted: Insights: ',1),mt=_('
');function pt(v,n){qe(n,!0);const N=[{num:1,name:"Replay",color:"#818cf8",desc:"Hippocampal replay: tagged memories surface for consolidation."},{num:2,name:"Cross-reference",color:"#a855f7",desc:"Semantic proximity check — new edges discovered across memories."},{num:3,name:"Strengthen",color:"#c084fc",desc:"Co-activated memories strengthen; FSRS stability grows."},{num:4,name:"Prune",color:"#ef4444",desc:"Low-retention redundant memories compressed or released."},{num:5,name:"Transfer",color:"#10b981",desc:"Episodic → semantic consolidation (hippocampus → cortex)."}];let l=b(()=>Oe(n.stage)),f=b(()=>N[e(l)-1]),q=b(()=>{if(!n.dreamResult)return 8;const s=n.dreamResult.memoriesReplayed??8;return Math.max(6,Math.min(12,s))}),re=b(()=>{var r;if(!n.dreamResult)return 5;const s=((r=n.dreamResult.stats)==null?void 0:r.newConnectionsFound)??5;return Math.max(3,Math.min(e(q),s))}),z=b(()=>{var r;if(!n.dreamResult)return Math.ceil(e(q)*.5);const s=((r=n.dreamResult.stats)==null?void 0:r.memoriesStrengthened)??Math.ceil(e(q)*.5);return Math.max(1,Math.min(e(q),s))}),ne=b(()=>{var r;if(!n.dreamResult)return Math.ceil(e(q)*.25);const s=((r=n.dreamResult.stats)==null?void 0:r.memoriesCompressed)??Math.ceil(e(q)*.25);return Math.max(1,Math.min(Math.floor(e(q)/2),s))});function C(s,r=0){const d=Math.sin((s+1)*9301+49297+r*233)*233280;return d-Math.floor(d)}let U=b(()=>{const s=[],r=Math.ceil(Math.sqrt(e(q))),d=Math.ceil(e(q)/r);for(let c=0;c{const s=[],r=e(U).length;for(let d=0;d{var r=nt();X(4),m(s,r)};j(le,s=>{e(l)===5&&s(oe)})}var ee=i(le,2);ge(ee,23,()=>e(L),(s,r)=>s.a+"-"+s.b+"-"+r,(s,r,d)=>{const c=b(()=>e(U)[e(r).a]),p=b(()=>e(U)[e(r).b]);var u=Fe(),k=he(u);{var w=g=>{const M=b(()=>I(e(c))),h=b(()=>F(e(c))),V=b(()=>I(e(p))),ke=b(()=>F(e(p)));var E=it();R(()=>{A(E,"x1",e(M)),A(E,"y1",e(h)),A(E,"x2",e(V)),A(E,"y2",e(ke)),A(E,"stroke",e(f).color),A(E,"stroke-width",e(l)===2?.25:e(l)===3?.35:.2),A(E,"stroke-opacity",e(l)<2?0:e(l)===4?.25:e(l)===5?.15:.6),A(E,"stroke-dasharray",e(l)===2?"1.2 0.8":"none"),ae(E,`--edge-delay: ${e(d)*80}ms`)}),m(g,E)};j(k,g=>{e(c)&&e(p)&&g(w)})}m(s,u)}),t(ee);var S=i(ee,2);ge(S,17,()=>e(U),s=>s.id,(s,r)=>{var d=vt();let c;R((p,u,k,w,g)=>{c=_e(d,1,"memory-card svelte-1cq1ntk",null,c,{"is-pulsing":e(l)===3&&e(r).strengthened,"is-pruning":e(l)===4&&e(r).pruned,"is-transferring":e(l)===5,"semantic-side":e(l)===5&&e(r).transferIsSemantic}),ae(d,` +import"../chunks/Bzak7iHL.js";import{p as qe,d as a,r as t,e as i,g as e,f as he,u as b,t as R,a as Se,n as X,h as de,s as be,W as Ge,aG as Ae}from"../chunks/CpWkWWOo.js";import{s as x,d as Ye,a as pe}from"../chunks/BlVfL1ME.js";import{c as Fe,a as m,f as _,b as Ve,t as Ie}from"../chunks/CHOnp4oo.js";import{i as j}from"../chunks/B4yTwGkE.js";import{e as ge}from"../chunks/CGEBXrjl.js";import{h as We}from"../chunks/C4h_mRt2.js";import{s as A,r as Be,a as Xe}from"../chunks/A7po6GxK.js";import{s as _e}from"../chunks/aVbAZ-t7.js";import{a as ze}from"../chunks/DNjM5a-l.js";import{s as ae}from"../chunks/Cx-f-Pzo.js";import{p as Ue}from"../chunks/V6gjw5Ec.js";import{b as Je}from"../chunks/BdslOLCg.js";const Te=5,je=["Replay","Cross-reference","Strengthen","Prune","Transfer"];function Oe(v){if(!Number.isFinite(v))return 1;const n=Math.floor(v);return n<1?1:n>Te?Te:n}const Ke=.3,Qe=.7;function Ze(v){const n=ye(v);return n>Qe?"high":n1?1:v}function $e(v){return v==null||!Number.isFinite(v)||v<0?"0ms":v<1e3?`${Math.round(v)}ms`:`${(v/1e3).toFixed(2)}s`}function et(v){const n=ye(v);return`${Math.round(n*100)}%`}function tt(v,n=""){return`${n}/memories/${v}`}function st(v,n=2){return!v||v.length===0?[]:v.slice(0,Math.max(0,n))}function at(v,n=2){return v?Math.max(0,v.length-n):0}function rt(v){return v?v.length>8?v.slice(0,8):v:""}var nt=_('
Episodic hippocampus
Semantic cortex
',1),it=Ve(''),vt=_('
'),lt=_(''),ot=_('Replaying memories'),ct=_('New connections found: '),dt=_('Strengthened: '),ut=_('Compressed: '),ft=_('Connections persisted: Insights: ',1),mt=_('
');function pt(v,n){qe(n,!0);const N=[{num:1,name:"Replay",color:"#818cf8",desc:"Hippocampal replay: tagged memories surface for consolidation."},{num:2,name:"Cross-reference",color:"#a855f7",desc:"Semantic proximity check — new edges discovered across memories."},{num:3,name:"Strengthen",color:"#c084fc",desc:"Co-activated memories strengthen; FSRS stability grows."},{num:4,name:"Prune",color:"#ef4444",desc:"Low-retention redundant memories compressed or released."},{num:5,name:"Transfer",color:"#10b981",desc:"Episodic → semantic consolidation (hippocampus → cortex)."}];let l=b(()=>Oe(n.stage)),f=b(()=>N[e(l)-1]),q=b(()=>{if(!n.dreamResult)return 8;const s=n.dreamResult.memoriesReplayed??8;return Math.max(6,Math.min(12,s))}),re=b(()=>{var r;if(!n.dreamResult)return 5;const s=((r=n.dreamResult.stats)==null?void 0:r.newConnectionsFound)??5;return Math.max(3,Math.min(e(q),s))}),z=b(()=>{var r;if(!n.dreamResult)return Math.ceil(e(q)*.5);const s=((r=n.dreamResult.stats)==null?void 0:r.memoriesStrengthened)??Math.ceil(e(q)*.5);return Math.max(1,Math.min(e(q),s))}),ne=b(()=>{var r;if(!n.dreamResult)return Math.ceil(e(q)*.25);const s=((r=n.dreamResult.stats)==null?void 0:r.memoriesCompressed)??Math.ceil(e(q)*.25);return Math.max(1,Math.min(Math.floor(e(q)/2),s))});function C(s,r=0){const d=Math.sin((s+1)*9301+49297+r*233)*233280;return d-Math.floor(d)}let U=b(()=>{const s=[],r=Math.ceil(Math.sqrt(e(q))),d=Math.ceil(e(q)/r);for(let c=0;c{const s=[],r=e(U).length;for(let d=0;d{var r=nt();X(4),m(s,r)};j(le,s=>{e(l)===5&&s(oe)})}var ee=i(le,2);ge(ee,23,()=>e(L),(s,r)=>s.a+"-"+s.b+"-"+r,(s,r,d)=>{const c=b(()=>e(U)[e(r).a]),p=b(()=>e(U)[e(r).b]);var u=Fe(),k=he(u);{var w=g=>{const M=b(()=>I(e(c))),h=b(()=>F(e(c))),V=b(()=>I(e(p))),ke=b(()=>F(e(p)));var E=it();R(()=>{A(E,"x1",e(M)),A(E,"y1",e(h)),A(E,"x2",e(V)),A(E,"y2",e(ke)),A(E,"stroke",e(f).color),A(E,"stroke-width",e(l)===2?.25:e(l)===3?.35:.2),A(E,"stroke-opacity",e(l)<2?0:e(l)===4?.25:e(l)===5?.15:.6),A(E,"stroke-dasharray",e(l)===2?"1.2 0.8":"none"),ae(E,`--edge-delay: ${e(d)*80}ms`)}),m(g,E)};j(k,g=>{e(c)&&e(p)&&g(w)})}m(s,u)}),t(ee);var S=i(ee,2);ge(S,17,()=>e(U),s=>s.id,(s,r)=>{var d=vt();let c;R((p,u,k,w,g)=>{c=_e(d,1,"memory-card svelte-1cq1ntk",null,c,{"is-pulsing":e(l)===3&&e(r).strengthened,"is-pruning":e(l)===4&&e(r).pruned,"is-transferring":e(l)===5,"semantic-side":e(l)===5&&e(r).transferIsSemantic}),ae(d,` left: ${p??""}%; top: ${u??""}%; opacity: ${k??""}; diff --git a/apps/dashboard/build/_app/immutable/nodes/6.BN-BfASZ.js.br b/apps/dashboard/build/_app/immutable/nodes/6.BN-BfASZ.js.br new file mode 100644 index 0000000000000000000000000000000000000000..51c72649f25c2709e7db09e2649ab1abc4ed3ddd GIT binary patch literal 5620 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 ON_^^_+(A+L-`)YC>J>Hs literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/6.BN-BfASZ.js.gz b/apps/dashboard/build/_app/immutable/nodes/6.BN-BfASZ.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..64972c861b39f32e2b2fdfbc5b9e8aa309464024 GIT binary patch literal 6334 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 NiBHYR9TcVi?H#l_0k!}D diff --git a/apps/dashboard/build/_app/immutable/nodes/6.DTUGCA1p.js.gz b/apps/dashboard/build/_app/immutable/nodes/6.DTUGCA1p.js.gz deleted file mode 100644 index 50ce680fd2b3626b2a33d60bd985a79a60aea25b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6332 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 delta 29 kcmdPUpCB$_V!qwLz;ug&nVFGcz$#XTHL5ap(hLj?0CHId#sB~S diff --git a/apps/dashboard/build/index.html b/apps/dashboard/build/index.html index 31b0831..e3ef7f4 100644 --- a/apps/dashboard/build/index.html +++ b/apps/dashboard/build/index.html @@ -11,13 +11,13 @@ - - + + - + - + @@ -33,7 +33,7 @@
+ +{#if visible} +
+ + + {#if expanded && receipt} +
+
+
+
Claim
+

{displayClaim?.text ?? receipt.draftPreview}

+
+
+
Verdict
+

{displayClaim?.decision ?? receipt.overall} · {displayClaim?.evidence_state ?? verdict}

+
+
+
Precedent
+
    + {#each precedentText(displayClaim) as item} +
  • {item}
  • + {/each} +
+
+
+
Fix
+

{displayClaim?.fix || 'No change required.'}

+
+
+ +
+ Appeal + {#if appealClaim && receipt.verdictBar === 'VETO'} + + + + {:else if receipt.verdictBar === 'APPEALED'} +

Appeal recorded.

+ {:else} +

No appealable veto in this receipt.

+ {/if} +
+
+ {/if} +
+{/if} + + diff --git a/apps/dashboard/src/lib/stores/api.ts b/apps/dashboard/src/lib/stores/api.ts index f4b77e0..536eaea 100644 --- a/apps/dashboard/src/lib/stores/api.ts +++ b/apps/dashboard/src/lib/stores/api.ts @@ -12,7 +12,10 @@ import type { ConsolidationResult, IntentionItem, SuppressResult, - UnsuppressResult + UnsuppressResult, + SanhedrinAppealReason, + SanhedrinAppealResponse, + SanhedrinLatestResponse } from '$types'; const BASE = '/api'; @@ -119,5 +122,14 @@ export const api = { fetcher>('/deep_reference', { method: 'POST', body: JSON.stringify({ query, depth }) - }) + }), + + sanhedrin: { + latest: () => fetcher('/sanhedrin/latest'), + appeal: (reason: SanhedrinAppealReason, note?: string, claimId?: string, receiptId?: string) => + fetcher('/sanhedrin/appeal', { + method: 'POST', + body: JSON.stringify({ reason, note, claimId, receiptId }) + }) + } }; diff --git a/apps/dashboard/src/lib/stores/toast.ts b/apps/dashboard/src/lib/stores/toast.ts index 6daef38..6bc195c 100644 --- a/apps/dashboard/src/lib/stores/toast.ts +++ b/apps/dashboard/src/lib/stores/toast.ts @@ -61,6 +61,13 @@ function createToastStore() { update(list => { const next = [entry, ...list]; if (next.length > MAX_VISIBLE) { + for (const dropped of next.slice(MAX_VISIBLE)) { + const handle = dwellTimers.get(dropped.id); + if (handle) clearTimeout(handle); + dwellTimers.delete(dropped.id); + dwellPaused.delete(dropped.id); + dwellStart.delete(dropped.id); + } return next.slice(0, MAX_VISIBLE); } return next; @@ -229,6 +236,18 @@ function createToastStore() { }; } + case 'HookVerdictRecorded': { + const verdict = String(d.verdict ?? 'NOTE'); + const reason = String(d.reason ?? 'Sanhedrin receipt updated'); + return { + type: event.type, + title: `Sanhedrin ${verdict}`, + body: reason, + color, + dwellMs: verdict === 'VETO' ? 8000 : DEFAULT_DWELL_MS, + }; + } + // Noise — never toast case 'Heartbeat': case 'SearchPerformed': diff --git a/apps/dashboard/src/lib/types/index.ts b/apps/dashboard/src/lib/types/index.ts index a76b092..b2b3bac 100644 --- a/apps/dashboard/src/lib/types/index.ts +++ b/apps/dashboard/src/lib/types/index.ts @@ -167,6 +167,7 @@ export type VestigeEventType = | 'ActivationSpread' | 'ImportanceScored' | 'DeepReferenceCompleted' + | 'HookVerdictRecorded' | 'Heartbeat'; export interface VestigeEvent { @@ -202,6 +203,64 @@ export interface UnsuppressResult { stability: number; } +export type VerdictLevel = 'PASS' | 'NOTE' | 'CAUTION' | 'VETO' | 'APPEALED'; +export type SanhedrinAppealReason = 'stale' | 'wrong' | 'too_strict'; + +export interface SanhedrinAppealState { + status: 'open' | 'appealed'; + actions?: SanhedrinAppealReason[]; + lastReason?: SanhedrinAppealReason; + note?: string; +} + +export interface SanhedrinPrecedent { + type?: string; + summary?: string; + command?: string; + exitCode?: number | null; + evidence?: string; +} + +export interface SanhedrinClaim { + id: string; + text: string; + fingerprint: string; + class: string; + subject: string; + risk: string; + evidence_state: string; + decision: string; + precedent: SanhedrinPrecedent[]; + fix: string; + appeal: SanhedrinAppealState; +} + +export interface SanhedrinReceipt { + schema: string; + id: string; + draftId: string; + createdAt: string; + overall: string; + verdictBar: VerdictLevel; + summary: string; + draftPreview: string; + claims: SanhedrinClaim[]; + receipts: Array>; + source?: Record; +} + +export interface SanhedrinLatestResponse { + receipt: SanhedrinReceipt | null; + stateDir: string; + receiptPath?: string; + htmlPath?: string; +} + +export interface SanhedrinAppealResponse { + appeal: Record; + receipt: SanhedrinReceipt; +} + // Intentions (prospective memory) export interface IntentionItem { id: string; @@ -238,6 +297,7 @@ export const EVENT_TYPE_COLORS: Record = { Rac1CascadeSwept: '#6E3FFF', SearchPerformed: '#818CF8', DeepReferenceCompleted: '#C4B5FD', + HookVerdictRecorded: '#F59E0B', DreamStarted: '#9D00FF', DreamProgress: '#B44AFF', DreamCompleted: '#C084FC', diff --git a/apps/dashboard/src/routes/+layout.svelte b/apps/dashboard/src/routes/+layout.svelte index c00c098..ca19491 100644 --- a/apps/dashboard/src/routes/+layout.svelte +++ b/apps/dashboard/src/routes/+layout.svelte @@ -16,6 +16,7 @@ import ForgettingIndicator from '$lib/components/ForgettingIndicator.svelte'; import InsightToast from '$lib/components/InsightToast.svelte'; import AmbientAwarenessStrip from '$lib/components/AmbientAwarenessStrip.svelte'; + import VerdictBar from '$lib/components/VerdictBar.svelte'; import ThemeToggle from '$lib/components/ThemeToggle.svelte'; import { initTheme } from '$stores/theme'; @@ -199,6 +200,7 @@
+
{@render children()}
diff --git a/crates/vestige-core/Cargo.toml b/crates/vestige-core/Cargo.toml index 1e159ea..e84625e 100644 --- a/crates/vestige-core/Cargo.toml +++ b/crates/vestige-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vestige-core" -version = "2.1.21" +version = "2.1.22" edition = "2024" rust-version = "1.91" authors = ["Vestige Team"] diff --git a/crates/vestige-mcp/Cargo.toml b/crates/vestige-mcp/Cargo.toml index 8dafa5e..b0a5490 100644 --- a/crates/vestige-mcp/Cargo.toml +++ b/crates/vestige-mcp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vestige-mcp" -version = "2.1.21" +version = "2.1.22" edition = "2024" description = "Cognitive memory MCP server for AI agents - FSRS-6, spreading activation, synaptic tagging, 3D dashboard, and 130 years of memory research" authors = ["samvallad33"] @@ -47,7 +47,7 @@ path = "src/bin/cli.rs" # Only `bundled-sqlite` is always on. `embeddings` and `vector-search` are # toggled via vestige-mcp's own feature flags below so `--no-default-features` # actually works (previously hardcoded here, which silently defeated the flag). -vestige-core = { version = "2.1.21", path = "../vestige-core", default-features = false, features = ["bundled-sqlite"] } +vestige-core = { version = "2.1.22", path = "../vestige-core", default-features = false, features = ["bundled-sqlite"] } # ============================================================================ # MCP Server Dependencies diff --git a/crates/vestige-mcp/src/autopilot.rs b/crates/vestige-mcp/src/autopilot.rs index 4b4c260..2db04a8 100644 --- a/crates/vestige-mcp/src/autopilot.rs +++ b/crates/vestige-mcp/src/autopilot.rs @@ -435,6 +435,7 @@ async fn handle_event( | VestigeEvent::MemoryUnsuppressed { .. } | VestigeEvent::Rac1CascadeSwept { .. } | VestigeEvent::DeepReferenceCompleted { .. } + | VestigeEvent::HookVerdictRecorded { .. } | VestigeEvent::DreamStarted { .. } | VestigeEvent::DreamProgress { .. } | VestigeEvent::DreamCompleted { .. } diff --git a/crates/vestige-mcp/src/dashboard/events.rs b/crates/vestige-mcp/src/dashboard/events.rs index a6807e2..8edb238 100644 --- a/crates/vestige-mcp/src/dashboard/events.rs +++ b/crates/vestige-mcp/src/dashboard/events.rs @@ -85,6 +85,16 @@ pub enum VestigeEvent { timestamp: DateTime, }, + // -- Hook verdicts -- + HookVerdictRecorded { + hook: String, + verdict: String, + phase: String, + reason: String, + receipt_id: Option, + timestamp: DateTime, + }, + // -- Dream -- DreamStarted { memory_count: usize, diff --git a/crates/vestige-mcp/src/dashboard/handlers.rs b/crates/vestige-mcp/src/dashboard/handlers.rs index 78e3b87..df3fc35 100644 --- a/crates/vestige-mcp/src/dashboard/handlers.rs +++ b/crates/vestige-mcp/src/dashboard/handlers.rs @@ -3,6 +3,9 @@ //! v2.0: Adds cognitive operation endpoints (dream, explore, predict, importance, consolidation) use std::cmp::Reverse; +use std::fs::{self, OpenOptions}; +use std::io::Write; +use std::path::{Path as FsPath, PathBuf}; use axum::extract::{Path, Query, State}; use axum::http::StatusCode; @@ -342,6 +345,328 @@ pub async fn unsuppress_memory( }))) } +#[derive(Debug, Deserialize)] +pub struct SanhedrinAppealRequest { + pub reason: String, + pub note: Option, + #[serde(rename = "receiptId")] + pub receipt_id: Option, + #[serde(rename = "claimId")] + pub claim_id: Option, +} + +/// Return the latest Sanhedrin receipt written by the Stop-hook bridge. +pub async fn get_sanhedrin_latest() -> Result, StatusCode> { + let state_dir = sanhedrin_state_dir(); + let latest_path = state_dir.join("latest.json"); + if !latest_path.exists() { + return Ok(Json(serde_json::json!({ + "receipt": null, + "stateDir": state_dir, + }))); + } + + let raw = fs::read_to_string(&latest_path).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + let receipt: Value = + serde_json::from_str(&raw).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + Ok(Json(serde_json::json!({ + "receipt": receipt, + "stateDir": state_dir, + "receiptPath": latest_path, + "htmlPath": state_dir.join("latest.html"), + }))) +} + +/// Record feedback that a Sanhedrin veto was stale, wrong, or too strict. +/// +/// This intentionally does not promote, demote, suppress, edit, or delete any +/// memory. The hook reads this ledger and suppresses future same-fingerprint +/// vetoes, which keeps appeal training scoped to Sanhedrin behavior. +pub async fn appeal_sanhedrin( + State(state): State, + Json(req): Json, +) -> Result, StatusCode> { + let reason = req.reason.trim().to_ascii_lowercase(); + if !matches!(reason.as_str(), "stale" | "wrong" | "too_strict") { + return Err(StatusCode::BAD_REQUEST); + } + + let state_dir = sanhedrin_state_dir(); + let latest_path = state_dir.join("latest.json"); + let raw = match fs::read_to_string(&latest_path) { + Ok(raw) => raw, + Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + return Err(StatusCode::NOT_FOUND); + } + Err(_) => return Err(StatusCode::INTERNAL_SERVER_ERROR), + }; + let mut receipt: Value = serde_json::from_str(&raw).map_err(|_| StatusCode::BAD_REQUEST)?; + let original_receipt = receipt.clone(); + let note = req.note.unwrap_or_default(); + let receipt_id = receipt + .get("id") + .and_then(Value::as_str) + .map(ToOwned::to_owned); + let receipt_id_ref = receipt_id.as_deref().ok_or(StatusCode::BAD_REQUEST)?; + let _ = sanitize_receipt_id(receipt_id_ref)?; + let expected_receipt_id = req.receipt_id.as_deref().ok_or(StatusCode::BAD_REQUEST)?; + if expected_receipt_id != receipt_id_ref { + return Err(StatusCode::CONFLICT); + } + if receipt + .get("verdictBar") + .and_then(Value::as_str) + .map(|v| v != "VETO") + .unwrap_or(true) + { + return Err(StatusCode::CONFLICT); + } + let claim = mark_sanhedrin_claim(&mut receipt, &reason, ¬e, req.claim_id.as_deref())?; + + let appeal = serde_json::json!({ + "timestamp": Utc::now().to_rfc3339(), + "receiptId": receipt_id.as_deref(), + "claimId": claim.get("id").and_then(Value::as_str), + "claimFingerprint": claim.get("fingerprint").and_then(Value::as_str), + "claim": claim.get("text").and_then(Value::as_str), + "reason": &reason, + "note": ¬e, + "status": "active", + }); + + set_json_field(&mut receipt, "overall", "appealed"); + set_json_field(&mut receipt, "verdictBar", "APPEALED"); + set_json_field(&mut receipt, "summary", &format!("Appealed as {}.", reason)); + save_sanhedrin_receipt(&state_dir, &receipt)?; + if let Err(err) = append_sanhedrin_appeal(&state_dir, &appeal) { + let _ = save_sanhedrin_receipt(&state_dir, &original_receipt); + return Err(err); + } + + state.emit(VestigeEvent::HookVerdictRecorded { + hook: "sanhedrin".to_string(), + verdict: "APPEALED".to_string(), + phase: "appeal".to_string(), + reason: reason.clone(), + receipt_id: receipt_id.clone(), + timestamp: Utc::now(), + }); + + Ok(Json(serde_json::json!({ + "appeal": appeal, + "receipt": receipt, + }))) +} + +fn sanhedrin_state_dir() -> PathBuf { + std::env::var_os("VESTIGE_SANHEDRIN_STATE_DIR") + .map(PathBuf::from) + .or_else(|| { + std::env::var_os("HOME").map(|home| PathBuf::from(home).join(".vestige/sanhedrin")) + }) + .unwrap_or_else(|| PathBuf::from(".vestige/sanhedrin")) +} + +fn ensure_sanhedrin_dirs(state_dir: &FsPath) -> Result<(), StatusCode> { + fs::create_dir_all(state_dir.join("receipts")).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR) +} + +fn mark_sanhedrin_claim( + receipt: &mut Value, + reason: &str, + note: &str, + claim_id: Option<&str>, +) -> Result { + let claim_id = claim_id.ok_or(StatusCode::BAD_REQUEST)?; + let claims = receipt + .get_mut("claims") + .and_then(Value::as_array_mut) + .ok_or(StatusCode::BAD_REQUEST)?; + + if claims.is_empty() { + return Err(StatusCode::BAD_REQUEST); + } + + let selected = claims + .iter() + .position(|claim| claim.get("id").and_then(Value::as_str) == Some(claim_id)) + .ok_or(StatusCode::NOT_FOUND)?; + + if claims + .get(selected) + .and_then(|claim| claim.get("decision")) + .and_then(Value::as_str) + != Some("veto") + { + return Err(StatusCode::CONFLICT); + } + + let claim = claims + .get_mut(selected) + .and_then(Value::as_object_mut) + .ok_or(StatusCode::BAD_REQUEST)?; + + claim.insert( + "decision".to_string(), + Value::String("appealed".to_string()), + ); + claim.insert( + "evidence_state".to_string(), + Value::String("appealed".to_string()), + ); + claim.insert( + "appeal".to_string(), + serde_json::json!({ + "status": "appealed", + "lastReason": reason, + "note": note, + "actions": ["stale", "wrong", "too_strict"], + }), + ); + + Ok(Value::Object(claim.clone())) +} + +fn set_json_field(receipt: &mut Value, key: &str, value: &str) { + if let Some(obj) = receipt.as_object_mut() { + obj.insert(key.to_string(), Value::String(value.to_string())); + } +} + +fn save_sanhedrin_receipt(state_dir: &FsPath, receipt: &Value) -> Result<(), StatusCode> { + ensure_sanhedrin_dirs(state_dir)?; + let rendered = render_sanhedrin_receipt_html(receipt); + let pretty = serde_json::to_string_pretty(receipt).map_err(|_| StatusCode::BAD_REQUEST)?; + let safe_id = receipt + .get("id") + .and_then(Value::as_str) + .map(sanitize_receipt_id) + .transpose()?; + + if let Some(safe_id) = safe_id { + write_atomic( + &state_dir.join("receipts").join(format!("{}.json", safe_id)), + pretty.as_bytes(), + )?; + write_atomic( + &state_dir.join("receipts").join(format!("{}.html", safe_id)), + rendered.as_bytes(), + )?; + } + + write_atomic(&state_dir.join("latest.json"), pretty.as_bytes())?; + write_atomic(&state_dir.join("latest.html"), rendered.as_bytes())?; + Ok(()) +} + +fn append_sanhedrin_appeal(state_dir: &FsPath, appeal: &Value) -> Result<(), StatusCode> { + ensure_sanhedrin_dirs(state_dir)?; + let mut appeals = OpenOptions::new() + .create(true) + .append(true) + .open(state_dir.join("appeals.jsonl")) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + writeln!(appeals, "{}", appeal).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR) +} + +fn sanitize_receipt_id(id: &str) -> Result<&str, StatusCode> { + if !id.is_empty() + && id + .bytes() + .all(|b| b.is_ascii_alphanumeric() || matches!(b, b'_' | b'-')) + { + Ok(id) + } else { + Err(StatusCode::BAD_REQUEST) + } +} + +fn write_atomic(path: &FsPath, bytes: &[u8]) -> Result<(), StatusCode> { + let parent = path.parent().ok_or(StatusCode::INTERNAL_SERVER_ERROR)?; + fs::create_dir_all(parent).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + let tmp = path.with_extension(format!( + "{}.tmp", + Utc::now().timestamp_nanos_opt().unwrap_or_default() + )); + fs::write(&tmp, bytes).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + fs::rename(&tmp, path).map_err(|_| { + let _ = fs::remove_file(&tmp); + StatusCode::INTERNAL_SERVER_ERROR + }) +} + +fn render_sanhedrin_receipt_html(receipt: &Value) -> String { + let verdict = escape_html( + receipt + .get("verdictBar") + .and_then(Value::as_str) + .unwrap_or("PASS"), + ); + let summary = escape_html(receipt.get("summary").and_then(Value::as_str).unwrap_or("")); + let mut claims_html = String::new(); + + if let Some(claims) = receipt.get("claims").and_then(Value::as_array) { + for claim in claims { + let text = escape_html(claim.get("text").and_then(Value::as_str).unwrap_or("")); + let decision = escape_html(claim.get("decision").and_then(Value::as_str).unwrap_or("")); + let evidence_state = escape_html( + claim + .get("evidence_state") + .and_then(Value::as_str) + .unwrap_or(""), + ); + let fix = escape_html( + claim + .get("fix") + .and_then(Value::as_str) + .filter(|s| !s.is_empty()) + .unwrap_or("No change required."), + ); + let mut precedents = String::new(); + if let Some(items) = claim.get("precedent").and_then(Value::as_array) { + for item in items { + let summary = item + .get("summary") + .and_then(Value::as_str) + .unwrap_or("Precedent recorded."); + precedents.push_str(&format!("
  • {}
  • ", escape_html(summary))); + } + } + claims_html.push_str(&format!( + "
    {} / {}

    {}

    Fix: {}

    Appeal: stale | wrong | too_strict

      {}
    ", + decision, evidence_state, text, fix, precedents + )); + } + } + + format!( + r#" +Vestige Veto Receipt + +
    Verdict{}
    +

    Veto Receipt

    {}

    {} +"#, + verdict, summary, claims_html + ) +} + +fn escape_html(value: &str) -> String { + value + .replace('&', "&") + .replace('<', "<") + .replace('>', ">") + .replace('"', """) + .replace('\'', "'") +} + /// Get system stats pub async fn get_stats(State(state): State) -> Result, StatusCode> { let stats = state diff --git a/crates/vestige-mcp/src/dashboard/mod.rs b/crates/vestige-mcp/src/dashboard/mod.rs index 6bf9bc1..2a3b5c9 100644 --- a/crates/vestige-mcp/src/dashboard/mod.rs +++ b/crates/vestige-mcp/src/dashboard/mod.rs @@ -176,6 +176,9 @@ fn build_router_inner(state: AppState, port: u16) -> (Router, AppState) { // Wraps crate::tools::cross_reference::execute. Emits // DeepReferenceCompleted so Graph3D can glide, pulse, and arc. .route("/api/deep_reference", post(handlers::deep_reference_query)) + // Sanhedrin receipts (v2.1.22): latest local hook verdict + appeal training. + .route("/api/sanhedrin/latest", get(handlers::get_sanhedrin_latest)) + .route("/api/sanhedrin/appeal", post(handlers::appeal_sanhedrin)) .layer( ServiceBuilder::new() .concurrency_limit(50) diff --git a/hooks/sanhedrin-local.py b/hooks/sanhedrin-local.py index aec10ff..45064af 100755 --- a/hooks/sanhedrin-local.py +++ b/hooks/sanhedrin-local.py @@ -25,8 +25,15 @@ import unicodedata import urllib.error import urllib.request from dataclasses import asdict, dataclass, field, replace +from pathlib import Path from typing import Any +sys.path.insert(0, str(Path(__file__).resolve().parent)) +try: + import sanhedrin_core +except Exception: + sanhedrin_core = None + def env_int(name: str, default: int) -> int: try: @@ -1059,6 +1066,139 @@ def render_legacy_from_verdicts(verdicts: list[ClaimVerdict]) -> str: return f"no - [Sanhedrin Veto] [{chosen.claim.claim_class}]: {reason}" +def recompute_legacy_from_result(result: dict[str, Any]) -> str: + vetoes = [] + for raw in result.get("verdicts", []): + claim = raw.get("claim", {}) if isinstance(raw, dict) else {} + status = str(raw.get("status", "")) + if status not in {"REFUTED", "REFUTED_BY_ABSENCE"}: + continue + vetoes.append( + ( + SEVERITY_ORDER.get(str(claim.get("claim_class", "")), 99), + int(claim.get("source_index", 0) or 0), + str(claim.get("claim_class", "TECHNICAL")), + truncate_chars(str(raw.get("reason") or claim.get("text") or ""), 140), + ) + ) + if not vetoes: + return "yes" + _, _, claim_class, reason = sorted(vetoes)[0] + return f"no - [Sanhedrin Veto] [{claim_class}]: {reason}" + + +def apply_appeals_to_claim_mode_result(result: dict[str, Any]) -> dict[str, Any]: + if sanhedrin_core is None: + return result + appeals = sanhedrin_core.load_appeals() + changed = False + for raw in result.get("verdicts", []): + if not isinstance(raw, dict) or raw.get("status") not in {"REFUTED", "REFUTED_BY_ABSENCE"}: + continue + claim = raw.get("claim", {}) if isinstance(raw.get("claim"), dict) else {} + text = str(claim.get("text") or "") + if sanhedrin_core.is_appealed({"fingerprint": sanhedrin_core.claim_fingerprint(text)}, appeals): + raw["status"] = "APPEALED" + raw["reason"] = "Prior appeal suppresses this Sanhedrin veto." + changed = True + + if changed: + legacy = recompute_legacy_from_result(result) + result["legacy_verdict"] = legacy + result["decision"] = "yes" if legacy == "yes" else "no" + result["verdict"] = result["decision"] + result["passed"] = legacy == "yes" + result["reason"] = "" if result["passed"] else legacy.split(" - ", 1)[-1] + return result + + +def save_claim_mode_receipt( + draft: str, + result: dict[str, Any], + manifest: dict[str, Any] | None = None, +) -> None: + if sanhedrin_core is None: + return + manifest = manifest or sanhedrin_core.new_manifest(draft) + claims = [] + for idx, raw in enumerate(result.get("verdicts", []), start=1): + if not isinstance(raw, dict): + continue + claim = raw.get("claim", {}) if isinstance(raw.get("claim"), dict) else {} + text = str(claim.get("text") or "") + claim_class = str(claim.get("claim_class") or "TECHNICAL") + status = str(raw.get("status") or "NEI") + evidence_ids = raw.get("evidence_ids") if isinstance(raw.get("evidence_ids"), list) else [] + if status == "SUPPORTED": + decision = "pass" + evidence_state = "supported" + fix = "No change required." + elif status == "APPEALED": + decision = "appealed" + evidence_state = "appealed" + fix = "Prior appeal suppresses this veto fingerprint." + elif status == "REFUTED_BY_ABSENCE": + decision = "veto" + evidence_state = "missing_precedent" + fix = "Remove the unsupported user-specific claim or cite durable Vestige evidence first." + elif status == "REFUTED": + decision = "veto" + evidence_state = "contradicted" + fix = "Remove or qualify the contradicted claim using the cited Vestige precedent." + else: + decision = "pass_unverified" + evidence_state = "not_enough_information" + fix = "No blocking change required." + claims.append( + { + "id": f"c{idx:03d}", + "text": text, + "fingerprint": sanhedrin_core.claim_fingerprint(text), + "class": claim_class, + "subject": "Sam" if bool(claim.get("sam_critical")) else "draft", + "risk": "hard" if bool(claim.get("sam_critical")) else "normal", + "evidence_state": evidence_state, + "decision": decision, + "precedent": [ + { + "type": "vestige", + "summary": str(raw.get("reason") or status), + "evidence": ", ".join(str(eid) for eid in evidence_ids[:5]), + "durableCount": raw.get("durable_evidence_count"), + "highTrustCount": raw.get("high_trust_evidence_count"), + } + ], + "fix": fix, + "appeal": { + "status": "appealed" if decision == "appealed" else "open", + "actions": ["stale", "wrong", "too_strict"], + }, + } + ) + + manifest["claims"] = claims + manifest["overall"] = "pass" if result.get("passed") else "veto" + if any(claim["decision"] == "appealed" for claim in claims): + manifest["overall"] = "pass_with_warnings" if result.get("passed") else manifest["overall"] + manifest["verdictBar"] = "APPEALED" + manifest["summary"] = "Prior appeal suppressed a Sanhedrin veto." + elif result.get("passed"): + manifest["verdictBar"] = "PASS" if not claims else "NOTE" + manifest["summary"] = "Sanhedrin found no blocking claim issues." + else: + manifest["verdictBar"] = "VETO" + manifest["summary"] = str(result.get("reason") or "Sanhedrin blocked a claim.") + sanhedrin_core.save_manifest(manifest) + + +def save_legacy_receipt(manifest: dict[str, Any] | None, verdict: str, evidence: str = "") -> str: + if sanhedrin_core is None or manifest is None: + return verdict + updated = sanhedrin_core.apply_model_verdict(manifest, verdict, evidence) + sanhedrin_core.save_manifest(manifest) + return updated + + def claim_mode_result(draft: str) -> dict[str, Any]: claims = extract_check_worthy_claims(draft) staged = load_staged_evidence(os.environ.get(STAGE_FILE_ENV)) @@ -1105,8 +1245,18 @@ def main() -> None: print("yes") return + manifest = sanhedrin_core.new_manifest(draft) if sanhedrin_core is not None else None + if sanhedrin_core is not None and manifest is not None: + receipt_veto = sanhedrin_core.apply_receipt_lock(manifest) + if receipt_veto: + sanhedrin_core.save_manifest(manifest) + print(f"no - [Sanhedrin Veto] [TECHNICAL]: {receipt_veto}") + return + if env_flag(CLAIM_MODE_ENV): - print_claim_mode_result(claim_mode_result(draft)) + result = apply_appeals_to_claim_mode_result(claim_mode_result(draft)) + save_claim_mode_receipt(draft, result, manifest) + print_claim_mode_result(result) return evidence, high_trust_count = fetch_evidence(draft) @@ -1115,6 +1265,7 @@ def main() -> None: # without something concrete to cite. Eliminates the common false-positive # mode where the model invents a contradiction from low-trust noise. if high_trust_count == 0: + save_legacy_receipt(manifest, "yes", evidence) print("yes") return @@ -1122,9 +1273,11 @@ def main() -> None: if not verdict: # Fail-open: server unreachable, malformed response, etc. + save_legacy_receipt(manifest, "yes", evidence) print("yes") return + verdict = save_legacy_receipt(manifest, verdict, evidence) print(verdict) diff --git a/hooks/sanhedrin.sh b/hooks/sanhedrin.sh index 49c5798..2802e08 100755 --- a/hooks/sanhedrin.sh +++ b/hooks/sanhedrin.sh @@ -30,7 +30,7 @@ load_vestige_sanhedrin_env() { command -v python3 >/dev/null 2>&1 || return 0 while IFS="$(printf '\t')" read -r key value; do case "$key" in - VESTIGE_SANHEDRIN_ENABLED|VESTIGE_SANHEDRIN_MODEL|VESTIGE_SANHEDRIN_ENDPOINT|VESTIGE_SANHEDRIN_CLAIM_MODE|VESTIGE_SANHEDRIN_OUTPUT|VESTIGE_SANHEDRIN_PYTHON|VESTIGE_DASHBOARD_PORT) + VESTIGE_SANHEDRIN_ENABLED|VESTIGE_SANHEDRIN_MODEL|VESTIGE_SANHEDRIN_ENDPOINT|VESTIGE_SANHEDRIN_CLAIM_MODE|VESTIGE_SANHEDRIN_OUTPUT|VESTIGE_SANHEDRIN_PYTHON|VESTIGE_SANHEDRIN_STATE_DIR|VESTIGE_SANHEDRIN_ALLOW_COMMAND_LEDGER|VESTIGE_DASHBOARD_PORT) export "$key=$value" ;; esac @@ -45,6 +45,8 @@ allowed = { "VESTIGE_SANHEDRIN_CLAIM_MODE", "VESTIGE_SANHEDRIN_OUTPUT", "VESTIGE_SANHEDRIN_PYTHON", + "VESTIGE_SANHEDRIN_STATE_DIR", + "VESTIGE_SANHEDRIN_ALLOW_COMMAND_LEDGER", "VESTIGE_DASHBOARD_PORT", } @@ -117,7 +119,7 @@ DRAFT_SCRIPT="$(mktemp -t vestige-sanhedrin-draft.XXXXXX)" trap 'rm -f "$DRAFT_SCRIPT"' EXIT cat > "$DRAFT_SCRIPT" <<'DRAFT_PYEOF' -import json, os, sys +import json, os, re, sys transcript = os.environ.get("TRANSCRIPT_PATH", "") last_assistant = "" @@ -146,21 +148,31 @@ try: except Exception: sys.exit(0) -# Print nothing if no draft or draft too short to contain a technical claim +# Print nothing if no draft. Short verification claims still need Receipt Lock. stripped = last_assistant.strip() -if not stripped or len(stripped) < 100: +if not stripped: sys.exit(0) # Legacy gate: only check drafts that contain technical indicators. Claim mode # deliberately broadens this to any substantive assistant draft while keeping # Sanhedrin opt-in through VESTIGE_SANHEDRIN_ENABLED. claim_mode = os.environ.get("VESTIGE_SANHEDRIN_CLAIM_MODE", "") == "1" +receipt_gate = bool( + re.search( + r"\b((all\s+)?(tests?|test suite|build|lint|typecheck|checks?|cargo test|npm test|pnpm test|pytest|vitest|jest|playwright|tsc|clippy)\s+(passed|passes|passing|green|succeeded|succeeds|clean)|(verified|validated|confirmed)\s+(with|by|via))\b", + stripped, + re.I, + ) +) +if len(stripped) < 100 and not receipt_gate: + sys.exit(0) + if not claim_mode: has_code = "`" in stripped or "```" in stripped has_cmd = any(kw in stripped.lower() for kw in ["install", "run ", "use ", "call ", "invoke", "execute"]) has_path = "/" in stripped and any(ext in stripped for ext in [".rs", ".ts", ".py", ".sh", ".md", ".json"]) - if not (has_code or has_cmd or has_path): + if not (has_code or has_cmd or has_path or receipt_gate): sys.exit(0) # Truncate to 4000 chars to keep Haiku prompt bounded @@ -190,6 +202,7 @@ fi # === SPAWN LOCAL EXECUTIONER (background with timeout) === OUTPUT_FILE="$(mktemp -t vestige-sanhedrin-out.XXXXXX)" trap 'rm -f "$DRAFT_SCRIPT" "$OUTPUT_FILE"' EXIT +export VESTIGE_SANHEDRIN_TRANSCRIPT="$TRANSCRIPT_PATH" ( printf '%s\n' "$DRAFT" | "$PYTHON_BIN" "$BRIDGE" > "$OUTPUT_FILE" 2>/dev/null @@ -225,6 +238,22 @@ sanhedrin_veto() { REASON="$1" REASON="$(printf '%s' "$REASON" | "$PYTHON_BIN" -c 'import sys; print(sys.stdin.read().strip())' 2>/dev/null || printf '%s' "$REASON")" + if printf '%s' "$REASON" | /usr/bin/grep -qi 'Receipt Lock'; then + cat >&2 <&2 < str: + return dt.datetime.now(dt.timezone.utc).isoformat(timespec="seconds") + + +def ensure_dirs() -> None: + RECEIPTS_DIR.mkdir(parents=True, exist_ok=True) + + +def stable_id(text: str, prefix: str = "sr") -> str: + digest = hashlib.sha256(text.encode("utf-8")).hexdigest()[:16] + return f"{prefix}_{digest}" + + +def claim_fingerprint(text: str) -> str: + normalized = re.sub(r"\s+", " ", text.lower()).strip() + normalized = re.sub(r"[`'\"$]", "", normalized) + return hashlib.sha256(normalized.encode("utf-8")).hexdigest()[:16] + + +def split_claims(draft: str) -> list[str]: + chunks = re.split(r"(?<=[.!?])\s+|\n+", draft) + claims: list[str] = [] + for chunk in chunks: + text = chunk.strip(" -\t") + if len(text) >= 18 or VERIFICATION_RE.search(text) or is_hard_user_claim(text): + claims.append(text) + return claims[:24] + + +def detect_claim_type(text: str) -> str: + low = text.lower() + if VERIFICATION_RE.search(text): + return "receipt_lock" + if is_hard_user_claim(text): + return "hard_user_claim" + if any(word in low for word in ("won", "prize", "ranked", "placed", "score", "graduated", "worked at")): + return "hard_user_claim" + if any(word in low for word in ("should", "could", "recommend", "plan", "target", "estimate")): + return "advice" + if "`" in text or "/" in text or re.search(r"\bv?\d+\.\d+", text): + return "technical" + return "general" + + +def is_hard_user_claim(text: str) -> bool: + if not re.search(r"\b(Sam|you|your|I|my)\b", text, re.I): + return False + hard_patterns = ( + r"\b(attended|graduated|studied|enrolled|accepted|worked|works|employed|hired)\b", + r"\b(was\s+born|born\s+in|born\s+on|birthdate|birthday)\b", + r"\b(won|placed|ranked|scored|earned|raised|sold|founded|launched)\b", + r"\b(prize|award|payout|grant|scholarship|degree|gpa|employer|school|university|college|birth\s+date)\b", + r"\$[0-9]", + ) + return any(re.search(pattern, text, re.I) for pattern in hard_patterns) + + +def new_manifest(draft: str) -> dict[str, Any]: + draft_id = stable_id(draft, "draft") + claims = [] + for i, text in enumerate(split_claims(draft), start=1): + claim_type = detect_claim_type(text) + claims.append( + { + "id": f"c{i:03d}", + "text": text, + "fingerprint": claim_fingerprint(text), + "class": claim_type, + "subject": infer_subject(text), + "risk": "hard" if claim_type == "receipt_lock" else "normal", + "evidence_state": "unchecked", + "decision": "pending", + "precedent": [], + "fix": "", + "appeal": { + "status": "open", + "actions": ["stale", "wrong", "too_strict"], + }, + } + ) + return { + "schema": "vestige.sanhedrin.receipt.v1", + "id": stable_id(f"{draft_id}:{now_iso()}", "receipt"), + "draftId": draft_id, + "createdAt": now_iso(), + "overall": "pass", + "verdictBar": "PASS", + "summary": "No blocking claim issues found.", + "draftPreview": draft[:1000], + "claims": claims, + "receipts": [], + "source": { + "stateDir": str(STATE_DIR), + "transcript": os.environ.get("VESTIGE_SANHEDRIN_TRANSCRIPT"), + }, + } + + +def infer_subject(text: str) -> str: + if re.search(r"\b(Sam|you|your)\b", text, re.I): + return "Sam" + if re.search(r"\b(test|pytest|cargo test|npm test|pnpm test|vitest|jest)\b", text, re.I): + return "test receipt" + if re.search(r"\b(build|lint|typecheck|clippy|tsc)\b", text, re.I): + return "command receipt" + return "draft" + + +def command_families_for_claim(text: str) -> list[str]: + low = text.lower() + if re.search(r"\b(all\s+checks?|checks)\s+(passed|passes|passing|green|succeeded|succeeds|clean)\b", low) and "cargo check" not in low: + return ["test", "build", "lint", "typecheck"] + families: list[str] = [] + if any(word in low for word in ("test", "pytest", "vitest", "jest", "playwright")): + families.append("test") + if any(word in low for word in ("build", "compiled", "compile")): + families.append("build") + if any(word in low for word in ("lint", "clippy", "eslint", "ruff")): + families.append("lint") + if any(word in low for word in ("typecheck", "tsc", "mypy", "pyright", "cargo check")): + families.append("typecheck") + if "check" in low and "cargo check" not in low and "checks" not in low: + families.append("typecheck") + return families or ["test"] + + +def load_command_receipts() -> list[dict[str, Any]]: + transcript = os.environ.get("VESTIGE_SANHEDRIN_TRANSCRIPT") + if transcript: + return extract_transcript_receipts(Path(transcript)) + if os.environ.get("VESTIGE_SANHEDRIN_ALLOW_COMMAND_LEDGER") != "1": + return [] + return load_jsonl(COMMAND_RECEIPTS_JSONL) + + +def load_jsonl(path: Path) -> list[dict[str, Any]]: + if not path.exists(): + return [] + items: list[dict[str, Any]] = [] + try: + for line in path.read_text(encoding="utf-8").splitlines(): + line = line.strip() + if not line: + continue + obj = json.loads(line) + if isinstance(obj, dict): + items.append(obj) + except (OSError, json.JSONDecodeError): + return items + return items + + +def extract_transcript_receipts(path: Path) -> list[dict[str, Any]]: + if not path.exists(): + return [] + receipts: list[dict[str, Any]] = [] + pending_commands: dict[str, dict[str, Any]] = {} + try: + lines = path.read_text(encoding="utf-8", errors="ignore").splitlines() + except OSError: + return receipts + for line in lines: + try: + obj = json.loads(line) + except json.JSONDecodeError: + continue + receipts.extend(extract_structured_receipts(obj, pending_commands)) + blob = json.dumps(obj, ensure_ascii=False) + command = extract_command(blob) + if not command: + continue + exit_code = extract_exit_code(blob) + receipts.append( + { + "source": "transcript", + "command": command, + "exitCode": exit_code, + "success": exit_code == 0 if exit_code is not None else None, + "timestamp": obj.get("timestamp") or obj.get("created_at") or now_iso(), + } + ) + return receipts + + +def extract_structured_receipts( + obj: dict[str, Any], + pending_commands: dict[str, dict[str, Any]], +) -> list[dict[str, Any]]: + """Extract Claude Code Bash receipts from assistant tool_use/user tool_result pairs.""" + receipts: list[dict[str, Any]] = [] + timestamp = obj.get("timestamp") or obj.get("created_at") or now_iso() + receipts.extend(extract_codex_receipts(obj, pending_commands, timestamp)) + content = obj.get("message", {}).get("content", obj.get("content", "")) + + blocks = content if isinstance(content, list) else [] + for block in blocks: + if not isinstance(block, dict): + continue + if block.get("type") == "tool_use" and str(block.get("name", "")).lower() in {"bash", "shell", "exec_command"}: + tool_id = str(block.get("id") or "") + tool_input = block.get("input") if isinstance(block.get("input"), dict) else {} + command = str(tool_input.get("command") or tool_input.get("cmd") or "") + if tool_id and command: + pending_commands[tool_id] = { + "source": "transcript", + "toolUseId": tool_id, + "command": command, + "timestamp": timestamp, + } + if block.get("type") == "tool_result": + tool_id = str(block.get("tool_use_id") or "") + if not tool_id or tool_id not in pending_commands: + continue + receipt = dict(pending_commands[tool_id]) + text = stringify_tool_result(block) + explicit_exit = extract_exit_code(text) + is_error = bool(block.get("is_error")) + receipt["exitCode"] = explicit_exit if explicit_exit is not None else (1 if is_error else 0) + receipt["success"] = receipt["exitCode"] == 0 and not is_error + receipt["timestamp"] = timestamp + receipts.append(receipt) + + tool_result = obj.get("toolUseResult") + if isinstance(tool_result, dict): + command = str(obj.get("command") or tool_result.get("command") or "") + if command: + exit_code = tool_result.get("exitCode") + if exit_code is None: + exit_code = tool_result.get("exit_code") + try: + parsed_exit = int(exit_code) if exit_code is not None else None + except (TypeError, ValueError): + parsed_exit = extract_exit_code(json.dumps(tool_result, ensure_ascii=False)) + is_error = bool(tool_result.get("is_error") or tool_result.get("interrupted")) + receipts.append( + { + "source": "transcript", + "command": command, + "exitCode": parsed_exit if parsed_exit is not None else (1 if is_error else 0), + "success": (parsed_exit == 0 if parsed_exit is not None else not is_error), + "timestamp": timestamp, + } + ) + + return receipts + + +def extract_codex_receipts( + obj: dict[str, Any], + pending_commands: dict[str, dict[str, Any]], + timestamp: str, +) -> list[dict[str, Any]]: + receipts: list[dict[str, Any]] = [] + payload = obj.get("payload") + if not isinstance(payload, dict): + return receipts + + payload_type = payload.get("type") + name = str(payload.get("name") or "").lower() + call_id = str(payload.get("call_id") or "") + if payload_type == "function_call" and name in {"exec_command", "bash", "shell"} and call_id: + args = payload.get("arguments") + if isinstance(args, str): + try: + args = json.loads(args) + except json.JSONDecodeError: + args = {} + if isinstance(args, dict): + command = str(args.get("cmd") or args.get("command") or "") + if command: + pending_commands[call_id] = { + "source": "codex-transcript", + "toolUseId": call_id, + "command": command, + "timestamp": timestamp, + } + elif payload_type == "function_call" and name == "write_stdin" and call_id: + args = payload.get("arguments") + if isinstance(args, str): + try: + args = json.loads(args) + except json.JSONDecodeError: + args = {} + if isinstance(args, dict): + session_id = args.get("session_id") + session_receipt = pending_commands.get(f"session:{session_id}") + if session_receipt: + pending_commands[call_id] = dict(session_receipt) + + if payload_type == "function_call_output" and call_id in pending_commands: + receipt = dict(pending_commands[call_id]) + output = str(payload.get("output") or "") + running = re.search(r"Process running with session ID\s+(\d+)", output) + if running: + pending_commands[f"session:{running.group(1)}"] = receipt + return receipts + exit_code = extract_exit_code(output) + receipt["exitCode"] = exit_code + receipt["success"] = exit_code == 0 if exit_code is not None else None + receipt["timestamp"] = timestamp + receipts.append(receipt) + + return receipts + + +def stringify_tool_result(block: dict[str, Any]) -> str: + content = block.get("content", "") + if isinstance(content, str): + return content + return json.dumps(content, ensure_ascii=False) + + +def extract_command(blob: str) -> str | None: + for key in ("cmd", "command"): + match = re.search(rf'"{key}"\s*:\s*"([^"]+)"', blob) + if match: + return bytes(match.group(1), "utf-8").decode("unicode_escape") + match = CLAUDE_TOOL_NAME_RE.search(blob) + if match and match.group(1).lower() in {"bash", "shell", "exec_command"}: + return match.group(1) + return None + + +def extract_exit_code(blob: str) -> int | None: + match = COMMAND_EXIT_RE.search(blob) + if not match: + return None + try: + return int(match.group(2) or match.group(3) or match.group(4)) + except ValueError: + return None + + +def receipt_matches_family(receipt: dict[str, Any], family: str) -> bool: + command = str(receipt.get("command") or "") + pattern = COMMAND_FAMILY_PATTERNS.get(family) + return bool(pattern and pattern.search(command)) + + +def apply_receipt_lock(manifest: dict[str, Any]) -> str | None: + receipts = load_command_receipts() + manifest["receipts"] = receipts[-20:] + appeals = load_appeals() + + for claim in manifest["claims"]: + if claim["class"] != "receipt_lock": + continue + missing_families: list[str] = [] + failed_family: tuple[str, dict[str, Any]] | None = None + supported_families: list[tuple[str, dict[str, Any]]] = [] + + for family in command_families_for_claim(claim["text"]): + matching = [r for r in receipts if receipt_matches_family(r, family)] + latest = matching[-1] if matching else None + if latest is None: + missing_families.append(family) + elif latest.get("success") is not True: + failed_family = (family, latest) + break + else: + supported_families.append((family, latest)) + + if failed_family is not None: + family, latest = failed_family + claim["evidence_state"] = "failed_receipt" if latest.get("success") is False else "unknown_receipt" + claim["decision"] = "veto" + claim["precedent"].append( + { + "type": "command", + "summary": f"Latest {family} command did not produce a successful receipt.", + "command": latest.get("command"), + "exitCode": latest.get("exitCode"), + } + ) + claim["fix"] = f"Replace the claim with: I do not have a successful {family} receipt for this session." + manifest["overall"] = "veto" + manifest["verdictBar"] = "VETO" + manifest["summary"] = "Receipt Lock blocked a contradicted verification claim." + return f"Receipt Lock: Draft claims {family} passed, but latest {family} receipt is not successful." + + if missing_families and is_appealed(claim, appeals): + claim["evidence_state"] = "appealed" + claim["decision"] = "appealed" + claim["precedent"].append({"type": "appeal", "summary": "Prior appeal suppresses this missing-receipt veto."}) + manifest["overall"] = "pass_with_warnings" + manifest["verdictBar"] = "APPEALED" + manifest["summary"] = "Prior appeal suppressed a Receipt Lock veto." + continue + + if missing_families: + family_list = ", ".join(missing_families) + claim["evidence_state"] = "missing_receipt" + claim["decision"] = "veto" + claim["precedent"].append( + { + "type": "receipt_lock", + "summary": f"No {family_list} command receipt found in this session.", + "source": "transcript/command ledger", + } + ) + claim["fix"] = f"Replace the claim with: I do not have recorded {family_list} receipt(s) for this session." + manifest["overall"] = "veto" + manifest["verdictBar"] = "VETO" + manifest["summary"] = "Receipt Lock blocked an unsupported verification claim." + return f"Receipt Lock: Draft claims {family_list} passed, but no {family_list} command receipt exists." + + claim["evidence_state"] = "supported" + claim["decision"] = "pass" + for family, latest in supported_families: + claim["precedent"].append( + { + "type": "command", + "summary": f"{family} receipt found.", + "command": latest.get("command"), + "exitCode": latest.get("exitCode"), + } + ) + + return None + + +def apply_model_verdict(manifest: dict[str, Any], verdict: str, evidence: str = "") -> str: + low = verdict.strip().lower() + if low == "yes" or low.startswith("yes "): + if manifest["overall"] != "veto": + has_appealed = any(c["decision"] == "appealed" for c in manifest["claims"]) + has_unchecked = any(c["decision"] == "pending" for c in manifest["claims"]) + manifest["overall"] = "pass_with_warnings" if has_unchecked or has_appealed else "pass" + manifest["verdictBar"] = "APPEALED" if has_appealed else ("NOTE" if has_unchecked else "PASS") + manifest["summary"] = ( + "Prior appeal suppressed a Sanhedrin veto." + if has_appealed + else "Sanhedrin found no blocking contradiction." + ) + for claim in manifest["claims"]: + if claim["decision"] == "pending": + claim["decision"] = "pass_unverified" + claim["evidence_state"] = "out_of_scope" + return "yes" + + reason = verdict.split(" - ", 1)[1] if " - " in verdict else verdict + appeals = load_appeals() + candidate = first_relevant_claim(manifest) + if candidate and is_appealed(candidate, appeals): + candidate["decision"] = "appealed" + candidate["evidence_state"] = "appealed" + candidate["precedent"].append({"type": "appeal", "summary": "Prior appeal suppresses this model veto."}) + manifest["overall"] = "pass_with_warnings" + manifest["verdictBar"] = "APPEALED" + manifest["summary"] = "Prior appeal suppressed the Sanhedrin veto." + return "yes" + + if candidate: + candidate["decision"] = "veto" + candidate["evidence_state"] = "contradicted" + candidate["precedent"].append({"type": "vestige", "summary": reason[:500], "evidence": evidence[:1000]}) + candidate["fix"] = "Remove or qualify the contradicted claim using the cited Vestige precedent." + manifest["overall"] = "veto" + manifest["verdictBar"] = "VETO" + manifest["summary"] = reason[:500] + return verdict + + +def first_relevant_claim(manifest: dict[str, Any]) -> dict[str, Any] | None: + for claim in manifest["claims"]: + if claim["decision"] in {"pending", "pass_unverified"}: + return claim + return manifest["claims"][0] if manifest["claims"] else None + + +def load_appeals() -> list[dict[str, Any]]: + return load_jsonl(APPEALS_JSONL) + + +def is_appealed(claim: dict[str, Any], appeals: list[dict[str, Any]]) -> bool: + fp = claim.get("fingerprint") + if not fp: + return False + for appeal in appeals: + if ( + appeal.get("claimFingerprint") == fp + and appeal.get("reason") in {"stale", "wrong", "too_strict"} + and appeal.get("status", "active") == "active" + ): + return True + return False + + +def save_manifest(manifest: dict[str, Any]) -> None: + ensure_dirs() + receipt_path = RECEIPTS_DIR / f"{manifest['id']}.json" + html_path = RECEIPTS_DIR / f"{manifest['id']}.html" + json_blob = json.dumps(manifest, indent=2) + write_text_atomic(receipt_path, json_blob) + write_text_atomic(LATEST_JSON, json_blob) + rendered = render_receipt_html(manifest) + write_text_atomic(html_path, rendered) + write_text_atomic(LATEST_HTML, rendered) + + +def write_text_atomic(path: Path, content: str) -> None: + ensure_dirs() + tmp = path.with_name(f".{path.name}.{os.getpid()}.tmp") + tmp.write_text(content, encoding="utf-8") + tmp.replace(path) + + +def render_receipt_html(manifest: dict[str, Any]) -> str: + status = html.escape(str(manifest.get("verdictBar", "PASS"))) + summary = html.escape(str(manifest.get("summary", ""))) + claims = [] + for claim in manifest.get("claims", []): + precedents = "".join( + f"
  • {html.escape(str(p.get('summary', p)))}
  • " + for p in claim.get("precedent", []) + ) + claims.append( + "
    " + f"
    {html.escape(str(claim.get('decision')))} / {html.escape(str(claim.get('evidence_state')))}
    " + f"

    {html.escape(str(claim.get('text')))}

    " + f"

    Fix: {html.escape(str(claim.get('fix') or 'No change required.'))}

    " + f"

    Appeal: stale | wrong | too_strict

    " + f"
      {precedents}
    " + "
    " + ) + return f""" +Vestige Veto Receipt + +
    Verdict{status}
    +

    Veto Receipt

    {summary}

    {''.join(claims)} +""" + + +def appeal_latest(reason: str, note: str = "", claim_id: str | None = None) -> dict[str, Any]: + if not LATEST_JSON.exists(): + raise FileNotFoundError(str(LATEST_JSON)) + manifest = json.loads(LATEST_JSON.read_text(encoding="utf-8")) + claims = manifest.get("claims", []) + claim = next((c for c in claims if c.get("id") == claim_id), None) if claim_id else None + if claim is None: + claim = next((c for c in claims if c.get("decision") == "veto"), claims[0] if claims else None) + if claim is None: + raise ValueError("latest receipt has no claims") + appeal = { + "timestamp": now_iso(), + "receiptId": manifest.get("id"), + "claimId": claim.get("id"), + "claimFingerprint": claim.get("fingerprint"), + "claim": claim.get("text"), + "reason": reason, + "note": note, + "status": "active", + } + ensure_dirs() + with APPEALS_JSONL.open("a", encoding="utf-8") as f: + f.write(json.dumps(appeal) + "\n") + claim["appeal"]["status"] = "appealed" + claim["appeal"]["lastReason"] = reason + manifest["overall"] = "appealed" + manifest["verdictBar"] = "APPEALED" + manifest["summary"] = f"Appealed as {reason}." + save_manifest(manifest) + return appeal diff --git a/package.json b/package.json index dc84552..d72a5ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vestige", - "version": "2.1.21", + "version": "2.1.22", "private": true, "description": "Cognitive memory for AI - MCP server with FSRS-6 spaced repetition", "author": "Sam Valladares", diff --git a/packages/vestige-init/package.json b/packages/vestige-init/package.json index 5325c4a..1c6ac04 100644 --- a/packages/vestige-init/package.json +++ b/packages/vestige-init/package.json @@ -1,6 +1,6 @@ { "name": "@vestige/init", - "version": "2.1.21", + "version": "2.1.22", "description": "Configure Vestige local memory for MCP-compatible AI agents", "bin": { "vestige-init": "bin/init.js" diff --git a/packages/vestige-mcp-npm/package.json b/packages/vestige-mcp-npm/package.json index 39bcb68..f51b5e1 100644 --- a/packages/vestige-mcp-npm/package.json +++ b/packages/vestige-mcp-npm/package.json @@ -1,6 +1,6 @@ { "name": "vestige-mcp-server", - "version": "2.1.21", + "version": "2.1.22", "mcpName": "io.github.samvallad33/vestige", "description": "Vestige MCP Server — local cognitive memory for MCP-compatible AI agents", "bin": { diff --git a/packages/vestige-mcpb/README.md b/packages/vestige-mcpb/README.md index 582c113..595dd58 100644 --- a/packages/vestige-mcpb/README.md +++ b/packages/vestige-mcpb/README.md @@ -4,7 +4,7 @@ One-click installation bundle for Claude Desktop. ## For Users -1. Download `vestige-2.1.21.mcpb` from [GitHub Releases](https://github.com/samvallad33/vestige/releases) +1. Download `vestige-2.1.22.mcpb` from [GitHub Releases](https://github.com/samvallad33/vestige/releases) 2. Double-click to install 3. Restart Claude Desktop @@ -34,5 +34,5 @@ vestige-mcpb/ │ ├── vestige-mcp-darwin-arm64 │ ├── vestige-mcp-linux-x64 │ └── vestige-mcp-win32-x64.exe -└── vestige-2.1.21.mcpb # Final bundle (generated) +└── vestige-2.1.22.mcpb # Final bundle (generated) ``` diff --git a/packages/vestige-mcpb/build.sh b/packages/vestige-mcpb/build.sh index eae32a7..cf48da8 100755 --- a/packages/vestige-mcpb/build.sh +++ b/packages/vestige-mcpb/build.sh @@ -1,7 +1,7 @@ #!/bin/bash set -euo pipefail -VERSION="${1:-2.1.21}" +VERSION="${1:-2.1.22}" REPO="samvallad33/vestige" TMPDIR="$(mktemp -d)" trap 'rm -rf "$TMPDIR"' EXIT diff --git a/packages/vestige-mcpb/manifest.json b/packages/vestige-mcpb/manifest.json index a1e2e67..690302d 100644 --- a/packages/vestige-mcpb/manifest.json +++ b/packages/vestige-mcpb/manifest.json @@ -2,7 +2,7 @@ "manifest_version": "0.2", "name": "vestige", "display_name": "Vestige", - "version": "2.1.21", + "version": "2.1.22", "description": "AI memory system built on 130 years of cognitive science. FSRS-6 spaced repetition, synaptic tagging, and local-first storage.", "author": { "name": "Sam Valladares", diff --git a/server.json b/server.json index 9bf97fb..d92c067 100644 --- a/server.json +++ b/server.json @@ -7,12 +7,12 @@ "url": "https://github.com/samvallad33/vestige", "source": "github" }, - "version": "2.1.21", + "version": "2.1.22", "packages": [ { "registryType": "npm", "identifier": "vestige-mcp-server", - "version": "2.1.21", + "version": "2.1.22", "transport": { "type": "stdio" } diff --git a/tests/hooks/test_sanhedrin_claim_mode.py b/tests/hooks/test_sanhedrin_claim_mode.py index 1996bc1..48efb22 100644 --- a/tests/hooks/test_sanhedrin_claim_mode.py +++ b/tests/hooks/test_sanhedrin_claim_mode.py @@ -41,6 +41,22 @@ class SanhedrinClaimModeTests(unittest.TestCase): def setUp(self): self.sanhedrin = load_sanhedrin() + @contextlib.contextmanager + def isolated_receipt_state(self): + with tempfile.TemporaryDirectory() as tmp: + state_dir = Path(tmp) + core = self.sanhedrin.sanhedrin_core + with patched_attr(core, "STATE_DIR", state_dir), patched_attr( + core, "RECEIPTS_DIR", state_dir / "receipts" + ), patched_attr(core, "LATEST_JSON", state_dir / "latest.json"), patched_attr( + core, "LATEST_HTML", state_dir / "latest.html" + ), patched_attr( + core, "APPEALS_JSONL", state_dir / "appeals.jsonl" + ), patched_attr( + core, "COMMAND_RECEIPTS_JSONL", state_dir / "command-receipts.jsonl" + ): + yield state_dir + def run_main(self, draft): stdin = io.StringIO(draft) stdout = io.StringIO() @@ -48,6 +64,54 @@ class SanhedrinClaimModeTests(unittest.TestCase): self.sanhedrin.main() return stdout.getvalue().strip() + def test_receipt_lock_blocks_unbacked_test_claim(self): + with self.isolated_receipt_state() as state_dir: + out = self.run_main("All tests passed.") + + self.assertIn("Receipt Lock", out) + receipt = json.loads((state_dir / "latest.json").read_text(encoding="utf-8")) + + self.assertEqual(receipt["verdictBar"], "VETO") + self.assertEqual(receipt["claims"][0]["decision"], "veto") + self.assertEqual(receipt["claims"][0]["evidence_state"], "missing_receipt") + + def test_receipt_lock_allows_matching_success_receipt(self): + with self.isolated_receipt_state() as state_dir, mock.patch.dict( + os.environ, {"VESTIGE_SANHEDRIN_ALLOW_COMMAND_LEDGER": "1"}, clear=False + ): + (state_dir / "command-receipts.jsonl").write_text( + json.dumps({ + "command": "cargo test --workspace --release", + "exitCode": 0, + "success": True, + }) + "\n", + encoding="utf-8", + ) + out = self.run_main("All tests passed.") + receipt = json.loads((state_dir / "latest.json").read_text(encoding="utf-8")) + + self.assertEqual(out, "yes") + self.assertNotEqual(receipt["verdictBar"], "VETO") + self.assertEqual(receipt["claims"][0]["decision"], "pass") + + def test_receipt_lock_appeal_suppresses_same_fingerprint(self): + with self.isolated_receipt_state() as state_dir: + fingerprint = self.sanhedrin.sanhedrin_core.claim_fingerprint("All tests passed.") + (state_dir / "appeals.jsonl").write_text( + json.dumps({ + "claimFingerprint": fingerprint, + "reason": "too_strict", + "status": "active", + }) + "\n", + encoding="utf-8", + ) + out = self.run_main("All tests passed.") + receipt = json.loads((state_dir / "latest.json").read_text(encoding="utf-8")) + + self.assertEqual(out, "yes") + self.assertEqual(receipt["verdictBar"], "APPEALED") + self.assertEqual(receipt["claims"][0]["decision"], "appealed") + def test_plain_sam_biographical_achievement_claim_is_check_worthy(self): claims = self.sanhedrin.extract_check_worthy_claims( "Sam graduated from Example University and won the Example AI Challenge." From a8550410b0a506aefd8eae7a321e68adc99e7e92 Mon Sep 17 00:00:00 2001 From: Luc Lauzon <128917870+randomnimbus@users.noreply.github.com> Date: Mon, 25 May 2026 12:49:51 -0600 Subject: [PATCH 12/31] feat(mcp): add per-tool _meta["anthropic/maxResultSizeChars"] annotation (#56) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude Code v2.1.91+ honors the per-tool annotation `_meta["anthropic/maxResultSizeChars"]` (up to 500_000) to override its 50K default truncation of `CallToolResult`. Without it, large Vestige payloads are silently truncated and spilled to disk, forcing the parent agent to chunk-read them. Empirically observed truncation under realistic default parameters (measured on v1.3.0 against ~3,300 memories; v2.x tool surface preserves the same names + payload shapes): search(detail_level="full", limit=20) -> 134,824 chars -> truncated search(detail_level="summary", limit=10) -> 71,318 chars -> truncated memory_timeline(limit=30) -> 83,626 chars -> truncated This patch: 1. Adds `meta: Option` to `ToolDescription` with `#[serde(rename = "_meta")]` so the wire shape matches the MCP spec. Backwards-compatible (the field is optional + `skip_serializing_if`; older MCP clients ignore unknown JSON keys per the spec). 2. Derives `Default` on `ToolDescription` so existing call sites can adopt the new field via struct-update syntax (`..Default::default()`) without restating it. 3. Annotates the four high-payload tools per measurement-driven discipline; the other 21 tools deliberately do NOT carry the annotation (cargo-cult prevention — a generous cap on every tool dilutes the signal and trains future maintainers that the value is arbitrary): - search -> 300_000 (2.2x headroom over observed peak) - memory_timeline -> 200_000 (2.4x headroom over observed peak) - memory -> 100_000 (single-record bounded) - codebase -> 100_000 (future-growth bounded) Tools that COULD plausibly grow into the annotated set with future workload (`deep_reference`, `cross_reference`, `memory_graph`, `explore_connections`, `session_context`) are left unannotated until empirical measurement shows truncation under realistic use. 4. Adds three regression tests in `server::tests`: - test_high_payload_tools_have_max_result_size_annotation: pins each cap value + asserts <= 500K Anthropic ceiling - test_other_tools_do_not_carry_max_result_size_annotation: cargo-cult prevention; dynamically iterates `tools/list` and asserts every tool NOT in the discipline-prescribed set lacks the annotation (robust to new tools being added by future PRs) - test_meta_wire_shape_uses_underscore_meta_field: pins the serde rename to `_meta` (the spec'd wire name) so a refactor of `ToolDescription` cannot silently drop the rename All 22 `server::tests` pass on v2.1.22 base (19 pre-existing + 3 new). Full lib test suite: 379/380 pass; the 1 unrelated failure (`tools::maintenance::tests::test_portable_export_writes_archive_to_storage_exports_dir`) is a pre-existing Windows path-separator assertion bug in `tools/maintenance.rs:823` (`path.ends_with("exports/portable-test.json")` fails on Windows where the path uses `\`) — unaffected by this PR. References: - Anthropic CC v2.1.91 release notes (April 2026): "Added MCP tool result persistence override via _meta['anthropic/maxResultSizeChars'] annotation (up to 500K), allowing larger results like DB schemas to pass through without truncation" - claude-agent-sdk-python v0.1.55 #756: forward bookkeeping establishing the on-Tool-definition (not on-CallToolResult) semantics for this annotation Co-authored-by: Peter Lauzon --- crates/vestige-mcp/src/protocol/messages.rs | 14 +- crates/vestige-mcp/src/server.rs | 202 +++++++++++++++++++- 2 files changed, 214 insertions(+), 2 deletions(-) diff --git a/crates/vestige-mcp/src/protocol/messages.rs b/crates/vestige-mcp/src/protocol/messages.rs index c58fa0a..8f7e459 100644 --- a/crates/vestige-mcp/src/protocol/messages.rs +++ b/crates/vestige-mcp/src/protocol/messages.rs @@ -82,13 +82,25 @@ pub struct ServerCapabilities { // ============================================================================ /// Tool description for tools/list -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ToolDescription { pub name: String, #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, pub input_schema: Value, + /// Per-tool `_meta` annotations from the MCP wire spec. + /// + /// Notable keys recognized by Claude Code (v2.1.91+): + /// - `anthropic/maxResultSizeChars` (integer, up to 500_000): + /// per-tool override of the 50K default `CallToolResult` truncation + /// ceiling. Pinned on the Tool definition; applies to every invocation. + /// + /// Free-form `serde_json::Value` (typically an object) so additional + /// vendor-specific `_meta` keys can be added without further schema + /// changes. + #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")] + pub meta: Option, } /// Result of tools/list diff --git a/crates/vestige-mcp/src/server.rs b/crates/vestige-mcp/src/server.rs index 2f0b457..a409ff5 100644 --- a/crates/vestige-mcp/src/server.rs +++ b/crates/vestige-mcp/src/server.rs @@ -227,7 +227,7 @@ impl McpServer { // v2.1.21: 25 tools (verified by the `tools.len() == 25` assertion in the // handle_tools_list test below — the `suppress` tool landed in v2.0.5). // Deprecated tools still work via redirects in handle_tools_call. - let tools = vec![ + let mut tools = vec![ // ================================================================ // UNIFIED TOOLS (v1.1+) // ================================================================ @@ -235,21 +235,25 @@ impl McpServer { name: "search".to_string(), description: Some("Unified search tool. Uses hybrid search (keyword + semantic + convex combination fusion) internally. Auto-strengthens memories on access (Testing Effect).".to_string()), input_schema: tools::search_unified::schema(), + ..Default::default() }, ToolDescription { name: "memory".to_string(), description: Some("Unified memory management tool. Actions: 'get' (retrieve full node), 'purge' (irreversibly remove content/embeddings with confirm=true), 'delete' (legacy alias for purge), 'state' (get accessibility state), 'promote' (thumbs up — increases retrieval strength), 'demote' (thumbs down — decreases retrieval strength, does NOT delete), 'edit' (update content in-place, preserves FSRS state).".to_string()), input_schema: tools::memory_unified::schema(), + ..Default::default() }, ToolDescription { name: "codebase".to_string(), description: Some("Unified codebase tool. Actions: 'remember_pattern' (store code pattern), 'remember_decision' (store architectural decision), 'get_context' (retrieve patterns and decisions).".to_string()), input_schema: tools::codebase_unified::schema(), + ..Default::default() }, ToolDescription { name: "intention".to_string(), description: Some("Unified intention management tool. Actions: 'set' (create), 'check' (find triggered), 'update' (complete/snooze/cancel), 'list' (show intentions).".to_string()), input_schema: tools::intention_unified::schema(), + ..Default::default() }, // ================================================================ // CORE MEMORY (v1.7: smart_ingest absorbs ingest + checkpoint) @@ -258,6 +262,7 @@ impl McpServer { name: "smart_ingest".to_string(), description: Some("INTELLIGENT memory ingestion with Prediction Error Gating. Single mode: provide 'content' to auto-decide CREATE/UPDATE/SUPERSEDE. Batch mode: provide 'items' array (max 20) for session-end saves — each item runs the full cognitive pipeline (importance scoring, intent detection, synaptic tagging).".to_string()), input_schema: tools::smart_ingest::schema(), + ..Default::default() }, // ================================================================ // TEMPORAL TOOLS (v1.2+) @@ -266,11 +271,13 @@ impl McpServer { name: "memory_timeline".to_string(), description: Some("Browse memories chronologically. Returns memories in a time range, grouped by day. Defaults to last 7 days.".to_string()), input_schema: tools::timeline::schema(), + ..Default::default() }, ToolDescription { name: "memory_changelog".to_string(), description: Some("View audit trail of memory changes. Per-memory: state transitions. System-wide: consolidations + recent state changes.".to_string()), input_schema: tools::changelog::schema(), + ..Default::default() }, // ================================================================ // MAINTENANCE TOOLS (v1.7: system_status replaces health_check + stats) @@ -279,26 +286,31 @@ impl McpServer { name: "system_status".to_string(), description: Some("Combined system health and statistics. Returns status (healthy/degraded/critical/empty), full stats, FSRS preview, cognitive module health, state distribution, warnings, and recommendations.".to_string()), input_schema: tools::maintenance::system_status_schema(), + ..Default::default() }, ToolDescription { name: "consolidate".to_string(), description: Some("Run FSRS-6 memory consolidation cycle. Applies decay, generates embeddings, and performs maintenance. Use when memories seem stale.".to_string()), input_schema: tools::maintenance::consolidate_schema(), + ..Default::default() }, ToolDescription { name: "backup".to_string(), description: Some("Create a SQLite database backup. Returns the backup file path.".to_string()), input_schema: tools::maintenance::backup_schema(), + ..Default::default() }, ToolDescription { name: "export".to_string(), description: Some("Export memories as JSON or JSONL. Supports tag and date filters.".to_string()), input_schema: tools::maintenance::export_schema(), + ..Default::default() }, ToolDescription { name: "gc".to_string(), description: Some("Garbage collect stale memories below retention threshold. Defaults to dry_run=true for safety.".to_string()), input_schema: tools::maintenance::gc_schema(), + ..Default::default() }, // ================================================================ // AUTO-SAVE & DEDUP TOOLS (v1.3+) @@ -307,11 +319,13 @@ impl McpServer { name: "importance_score".to_string(), description: Some("Score content importance using 4-channel neuroscience model (novelty/arousal/reward/attention). Returns composite score, channel breakdown, encoding boost, and explanations.".to_string()), input_schema: tools::importance::schema(), + ..Default::default() }, ToolDescription { name: "find_duplicates".to_string(), description: Some("Find duplicate and near-duplicate memory clusters using cosine similarity on embeddings. Returns clusters with suggested actions (merge/review). Use to clean up redundant memories.".to_string()), input_schema: tools::dedup::schema(), + ..Default::default() }, // ================================================================ // COGNITIVE TOOLS (v1.5+) @@ -320,16 +334,19 @@ impl McpServer { name: "dream".to_string(), description: Some("Trigger memory dreaming — replays recent memories to discover hidden connections, synthesize insights, and strengthen important patterns. Returns insights, connections, and dream stats.".to_string()), input_schema: tools::dream::schema(), + ..Default::default() }, ToolDescription { name: "explore_connections".to_string(), description: Some("Graph exploration tool for memory connections. Actions: 'chain' (build reasoning path between memories), 'associations' (find related memories via spreading activation + hippocampal index), 'bridges' (find connecting memories between two nodes).".to_string()), input_schema: tools::explore::schema(), + ..Default::default() }, ToolDescription { name: "predict".to_string(), description: Some("Proactive memory prediction — predicts what memories you'll need next based on context, recent activity, and learned patterns. Returns predictions, suggestions, and speculative retrievals.".to_string()), input_schema: tools::predict::schema(), + ..Default::default() }, // ================================================================ // RESTORE TOOL (v1.5+) @@ -338,6 +355,7 @@ impl McpServer { name: "restore".to_string(), description: Some("Restore memories from a JSON backup file. Supports MCP wrapper format, RecallResult format, and direct memory array format.".to_string()), input_schema: tools::restore::schema(), + ..Default::default() }, // ================================================================ // CONTEXT PACKETS (v1.8+) @@ -346,6 +364,7 @@ impl McpServer { name: "session_context".to_string(), description: Some("One-call session initialization. Combines search, intentions, status, predictions, and codebase context into a single token-budgeted response. Replaces 5 separate calls at session start.".to_string()), input_schema: tools::session_context::schema(), + ..Default::default() }, // ================================================================ // AUTONOMIC TOOLS (v1.9+) @@ -354,11 +373,13 @@ impl McpServer { name: "memory_health".to_string(), description: Some("Retention dashboard. Returns avg retention, retention distribution (buckets: 0-20%, 20-40%, etc.), trend (improving/declining/stable), and recommendation. Lightweight alternative to full system_status focused on memory quality.".to_string()), input_schema: tools::health::schema(), + ..Default::default() }, ToolDescription { name: "memory_graph".to_string(), description: Some("Subgraph export for visualization. Input: center_id or query, depth (1-3), max_nodes. Returns nodes with force-directed layout positions and edges with weights. Powers memory graph visualization.".to_string()), input_schema: tools::graph::schema(), + ..Default::default() }, // ================================================================ // DEEP REFERENCE (v2.0.4+) — replaces cross_reference @@ -367,16 +388,19 @@ impl McpServer { name: "deep_reference".to_string(), description: Some("Deep cognitive reasoning across memories. Combines FSRS-6 trust scoring, spreading activation, temporal supersession, dream insights, and contradiction analysis to build a complete understanding of a topic. Returns trust-scored evidence, fact evolution timeline, and a recommended answer. Use this when accuracy matters.".to_string()), input_schema: tools::cross_reference::schema(), + ..Default::default() }, ToolDescription { name: "cross_reference".to_string(), description: Some("Alias for deep_reference. Connect the dots across memories with cognitive reasoning.".to_string()), input_schema: tools::cross_reference::schema(), + ..Default::default() }, ToolDescription { name: "contradictions".to_string(), description: Some("Inspect memory disagreements directly. Scans a topic or recent memories for trust-weighted contradiction pairs using the same local logic as deep_reference.".to_string()), input_schema: tools::contradictions::schema(), + ..Default::default() }, // ================================================================ // ACTIVE FORGETTING (v2.0.5) — top-down suppression @@ -386,9 +410,47 @@ impl McpServer { name: "suppress".to_string(), description: Some("Actively suppress a memory via top-down inhibitory control (Anderson 2025 SIF + Davis Rac1). Distinct from delete: the memory persists but is inhibited from retrieval and actively decays. Each call compounds. A background Rac1 worker cascades decay to co-activated neighbors. Reversible within 24 hours via reverse=true.".to_string()), input_schema: tools::suppress::schema(), + ..Default::default() }, ]; + // Per-tool result-size annotation `_meta["anthropic/maxResultSizeChars"]`. + // + // Claude Code v2.1.91+ honors this annotation to override its 50K default + // `CallToolResult` truncation. Without it, large Vestige payloads + // (`search` with `detail_level="full"` at `limit=20` has been observed + // at ~135K chars; `memory_timeline` at `limit=30` at ~84K chars) are + // silently truncated and spilled to disk, forcing the parent agent to + // chunk-read them. + // + // Per-tool caps below are sized at ~2× observed peak with growth + // headroom; max permitted by Anthropic is 500_000. Only the four + // empirically-measured high-payload tools carry the annotation today; + // the remaining 21 tools deliberately do NOT (cargo-cult prevention — + // annotating a small-payload tool dilutes the signal). + // + // Other tools that COULD plausibly grow into the annotated set with + // future workload (`deep_reference`, `cross_reference`, `memory_graph`, + // `explore_connections`, `session_context`) are left unannotated until + // empirical measurement shows truncation under realistic use. + for tool in tools.iter_mut() { + let max_chars: Option = match tool.name.as_str() { + "search" => Some(300_000), + "memory_timeline" => Some(200_000), + "memory" => Some(100_000), + "codebase" => Some(100_000), + _ => None, + }; + if let Some(n) = max_chars { + let mut meta = serde_json::Map::new(); + meta.insert( + "anthropic/maxResultSizeChars".to_string(), + serde_json::Value::from(n), + ); + tool.meta = Some(serde_json::Value::Object(meta)); + } + } + let result = ListToolsResult { tools }; serde_json::to_value(result).map_err(|e| JsonRpcError::internal_error(&e.to_string())) } @@ -1899,4 +1961,142 @@ mod tests { assert!(response.error.is_some()); assert_eq!(response.error.unwrap().code, -32602); } + + // ======================================================================== + // Per-tool result-size annotation tests + // (`_meta["anthropic/maxResultSizeChars"]`, CC v2.1.91+) + // + // The annotation lives on the Tool definition in `tools/list`, so CC reads + // it once when the MCP session opens and applies the override to every + // invocation of that tool. These tests pin the wire-form so a future + // refactor of `ToolDescription` cannot silently drop the annotation. + // ======================================================================== + + /// Expected per-tool caps. Returns `Some(cap)` for tools the discipline + /// annotates, `None` for tools that MUST NOT carry the annotation + /// (cargo-cult prevention). + fn expected_max_result_size(name: &str) -> Option { + match name { + "search" => Some(300_000), + "memory_timeline" => Some(200_000), + "memory" => Some(100_000), + "codebase" => Some(100_000), + _ => None, + } + } + + #[tokio::test] + async fn test_high_payload_tools_have_max_result_size_annotation() { + let (mut server, _dir) = test_server().await; + let init_request = make_request("initialize", Some(init_params())); + server.handle_request(init_request).await; + + let request = make_request("tools/list", None); + let response = server.handle_request(request).await.unwrap(); + let result = response.result.unwrap(); + let tools = result["tools"].as_array().unwrap(); + + for name in ["search", "memory_timeline", "memory", "codebase"] { + let tool = tools + .iter() + .find(|t| t["name"].as_str() == Some(name)) + .unwrap_or_else(|| panic!("Tool '{}' missing from tools/list", name)); + + let expected = expected_max_result_size(name).unwrap(); + let meta = tool.get("_meta").unwrap_or_else(|| { + panic!("Tool '{}' is missing the `_meta` field on the wire", name) + }); + let actual = meta + .get("anthropic/maxResultSizeChars") + .and_then(|v| v.as_u64()) + .unwrap_or_else(|| { + panic!( + "Tool '{}' _meta lacks integer 'anthropic/maxResultSizeChars'", + name + ) + }); + assert_eq!( + actual, expected, + "Tool '{}' cap drift: expected {} got {}", + name, expected, actual + ); + assert!( + actual <= 500_000, + "Tool '{}' cap {} exceeds Anthropic 500K ceiling", + name, + actual + ); + } + } + + #[tokio::test] + async fn test_other_tools_do_not_carry_max_result_size_annotation() { + // Cargo-cult prevention. Dynamically derived from tools/list so this + // test is robust to new tools being added: any tool that is NOT in + // the discipline-prescribed set MUST NOT carry the annotation. + // Adding the annotation to a small-payload tool dilutes the signal + // and trains future maintainers that the value is arbitrary. + let (mut server, _dir) = test_server().await; + let init_request = make_request("initialize", Some(init_params())); + server.handle_request(init_request).await; + + let request = make_request("tools/list", None); + let response = server.handle_request(request).await.unwrap(); + let result = response.result.unwrap(); + let tools = result["tools"].as_array().unwrap(); + + for tool in tools { + let name = tool["name"].as_str().unwrap(); + if expected_max_result_size(name).is_some() { + continue; // covered by the annotated-tools test + } + + // Either the `_meta` key is absent OR it is an object without the + // anthropic key — both are acceptable. The forbidden case is the + // anthropic key present on this tool. + let has_max_size = tool + .get("_meta") + .and_then(|m| m.get("anthropic/maxResultSizeChars")) + .is_some(); + assert!( + !has_max_size, + "Tool '{}' should NOT carry maxResultSizeChars annotation \ + (not in the discipline-prescribed set: search, memory_timeline, \ + memory, codebase). If this tool's realistic max-payload now \ + routinely exceeds 50K, update expected_max_result_size() + the \ + annotation loop in handle_tools_list together.", + name + ); + } + } + + #[tokio::test] + async fn test_meta_wire_shape_uses_underscore_meta_field() { + // Anthropic's MCP spec is explicit: the field on the wire is `_meta`, + // NOT `meta`. The Rust struct uses `meta: Option` with + // `#[serde(rename = "_meta")]` — assert the rename actually fired. + let (mut server, _dir) = test_server().await; + let init_request = make_request("initialize", Some(init_params())); + server.handle_request(init_request).await; + + let request = make_request("tools/list", None); + let response = server.handle_request(request).await.unwrap(); + let result = response.result.unwrap(); + let tools = result["tools"].as_array().unwrap(); + + let search_tool = tools + .iter() + .find(|t| t["name"].as_str() == Some("search")) + .expect("'search' tool present"); + + // Wire-form: `_meta` must exist; `meta` (un-renamed) must NOT exist. + assert!( + search_tool.get("_meta").is_some(), + "search tool missing `_meta` key (serde rename to _meta did not apply)" + ); + assert!( + search_tool.get("meta").is_none(), + "search tool has un-renamed `meta` key (regression — serde rename broke)" + ); + } } From c584ec8afeb8a82b9659b2c1fc36fc900f997c4b Mon Sep 17 00:00:00 2001 From: Jan De Landtsheer Date: Wed, 27 May 2026 09:35:23 +0200 Subject: [PATCH 13/31] docs(adr): add ADR 0002 -- Phase 2 execution Binding ADR for Phase 2 Postgres backend integration plus the Phase 1 amendment that removes async_trait from the storage and embedder traits. Decisions D1-D8: - D1: sunset async_trait across MemoryStore + Embedder via trait_variant - D2: PgMemoryStore::connect(url, max_connections) mirrors SqliteMemoryStore; no Embedder in constructor; register_model handles pgvector typmod - D3: split sqlite.rs into a sqlite/ directory as Phase 1 amendment - D4: postgres/ as a directory from day one - D5: sub-plan layout -- 3 Phase 1 amendment + 9 Phase 2 sub-plans - D6: no separate ADR for the SQLite split (pure code motion) - D7: reserve multi-tenancy schema (users/groups/group_memberships + owner_user_id/visibility/shared_with_groups) in Phase 2 so Phase 3 auth is additive, not an online migration over an HNSW-indexed table - D8: codebase promoted to a first-class indexed column on knowledge_nodes; mcp_client_id and session_id stay in metadata JSONB PR cadence: PR A = Phase 1 amendment (code on feat/storage-trait-phase1); PR B = this ADR + Phase 2 sub-plans (docs only); PR C = Phase 2 implementation. Phase 4 sharing_rules table sketched in Follow-ups. --- docs/adr/0002-phase-2-execution.md | 545 +++++++++++++++++++++++++++++ 1 file changed, 545 insertions(+) create mode 100644 docs/adr/0002-phase-2-execution.md diff --git a/docs/adr/0002-phase-2-execution.md b/docs/adr/0002-phase-2-execution.md new file mode 100644 index 0000000..6b6949f --- /dev/null +++ b/docs/adr/0002-phase-2-execution.md @@ -0,0 +1,545 @@ +# ADR 0002: Phase 2 Execution -- Postgres Backend Integration, Phase 1 Amendment + +**Status**: Accepted +**Date**: 2026-05-26 +**Related**: [docs/adr/0001-pluggable-storage-and-network-access.md](0001-pluggable-storage-and-network-access.md), [docs/plans/0002-phase-2-postgres-backend.md](../plans/0002-phase-2-postgres-backend.md) + +--- + +## Context + +ADR 0001 set the architectural direction: introduce `MemoryStore` and `Embedder` +traits, ship a Postgres backend behind a feature flag, and reach a single shared +memory brain across machines. Phase 1 (storage trait extraction) shipped on +`feat/storage-trait-phase1` (790c0c8). The Phase 2 master plan at +`docs/plans/0002-phase-2-postgres-backend.md` was drafted before Phase 1 was +frozen. + +Starting Phase 2 surfaces a small set of execution-level decisions that ADR 0001 +did not cover and that the master plan now disagrees with the live code on. +These decisions are too big to silently absorb into a per-step plan and too +small to amend ADR 0001. They live here. + +Three concrete realities driving this ADR: + +1. **Trait shape mismatch.** Master plan 0002 assumed `trait_variant::make` + produced distinct `MemoryStore` (Send-bound) and `LocalMemoryStore` + (non-Send) variants, and that errors were `StoreError`. Phase 1 froze on + `#[async_trait::async_trait]` with `pub use MemoryStore as LocalMemoryStore` + and an error type called `MemoryStoreError`. The Postgres backend has to + follow Phase 1, not the master plan -- but we should record that explicitly. +2. **`SqliteMemoryStore` is monolithic.** + `crates/vestige-core/src/storage/sqlite.rs` is ~8200 lines. Phase 1 appended + the trait impl block at the bottom of the same file. Adding a similarly + large `postgres.rs` perpetuates the pattern; this is the natural moment to + decide whether the SQLite file gets split. +3. **Constructor surface drift.** Master plan 0002 specifies + `PgMemoryStore::connect(url, max_connections, &dyn Embedder)`. The Phase 1 + `SqliteMemoryStore` constructor takes no embedder -- registry consistency + runs through `registered_model()` / `register_model()` on the trait, + invoked by the caller. The two backends should look the same to a caller; + right now they would not. +4. **Multi-tenancy is a one-way door.** The Postgres schema is the place to + reserve user/group/visibility columns *now*, even though Phase 3 is the + phase that wires the auth filter using them. Adding `owner_user_id` and + GIN indexes to a populated, HNSW-indexed `knowledge_nodes` table later is an + expensive online migration; reserving NULL-defaulted columns at schema + creation is ~10 lines of SQL. The same logic applies to per-memory + context capture (codebase, MCP caller, session) -- promoting `codebase` + to a first-class column now keeps the door open for context-aware + sharing rules in Phase 4 without touching `knowledge_nodes`. See D7 and D8. + +This ADR is also the umbrella under which Phase 2 sub-plans (`0002a-...`, +`0002b-...`, etc.) sit. The intent is: ADR + sub-plans land as one PR for +review; the implementation lands as a second PR with many commits inside. + +--- + +## Already Decided (carried in by reference) + +These are settled by ADR 0001 or by explicit agreement during this session. +Listed here so the discussion frame is clear; not re-litigated below. + +- Postgres backend ships behind a `postgres-backend` Cargo feature, default + OFF. Mutually compilable with SQLite. (ADR 0001.) +- Single big `MemoryStore` trait. `PgMemoryStore` implements the same surface + as `SqliteMemoryStore`. (ADR 0001.) +- pgvector HNSW + tsvector + GIN + RRF hybrid search in one SQL statement. + (Master plan 0002, D4-D5.) +- sqlx 0.8 + pgvector 0.4 + compile-time-checked queries + offline `.sqlx/` + cache committed. (Master plan 0002.) +- Two sqlx migration files: `0001_init` (extensions, tables, non-vector + indexes) and `0002_hnsw` (HNSW separated for re-embed drop/recreate). + (Master plan 0002, D4.) +- `vestige migrate --from sqlite --to postgres` and + `vestige migrate --reembed --model=` CLI subcommands. (ADR 0001 + + master plan 0002, D8-D10.) +- PR cadence: PR #1 carries this ADR plus all sub-plans; PR #2 carries the + implementation as many commits. +- Sub-plans use `0002a-`, `0002b-`, ... suffixes off `0002-`. +- `PgMemoryStore::connect` lands as `todo!()` in the skeleton; real body + comes later. + +--- + +## Decisions + +### D1. Sunset async_trait across the Phase 1 traits + +Phase 1 froze with `#[async_trait::async_trait]` on both the `MemoryStore` +trait (`storage/memory_store.rs:194`) and the `Embedder` trait +(`embedder/mod.rs:27`), plus their SQLite and Fastembed impl blocks. async_trait +boxes every async fn into `Pin>` -- one heap allocation +per call inside the hottest code path. We are amending Phase 1 to remove +async_trait entirely and replace it with `trait_variant::make`, so each trait +becomes two real generated variants (`MemoryStore` / `LocalMemoryStore`, +`Embedder` / `LocalEmbedder`) with `Send` bounds on the outer variant. + +Scope split across three Phase 1 amendment sub-plans: + +- **`0001a-trait-rewrite.md`** -- Rewrite `MemoryStore` only. Touches + `storage/memory_store.rs` (trait declaration) and `storage/sqlite.rs` + (impl block attribute). Leaves async_trait in place on the embedder side + so the diff stays focused. +- **`0001b-sqlite-split.md`** -- Pure code motion. Splits the + ~8200-line `sqlite.rs` into a `sqlite/` directory. Independent of D1; can + land in either order relative to `0001a`. +- **`0001c-async-trait-sunset.md`** -- Rewrite `Embedder` the same way, then + remove `async-trait = "0.1"` from `crates/vestige-core/Cargo.toml`. Final + amendment commit removes the dependency entirely. After this lands, the + workspace contains zero references to `async_trait`. + +All three sub-plans land on the existing `feat/storage-trait-phase1` branch +(790c0c8 has not been opened upstream yet; amend in place, no force-push to a +public PR). + +### D2. PgMemoryStore::connect mirrors SqliteMemoryStore::new + +```rust +impl PgMemoryStore { + pub async fn connect(url: &str, max_connections: u32) -> MemoryStoreResult; + pub async fn from_pool(pool: PgPool) -> MemoryStoreResult; +} +``` + +No `Embedder` in the constructor. The pgvector-specific +`ALTER TABLE knowledge_nodes ALTER COLUMN embedding TYPE vector($N)` DDL lives +inside the trait method `register_model(&ModelSignature)`. That method is +called by the caller (cognitive engine bootstrap, migrate CLI, tests) after +construction, exactly as it is for `SqliteMemoryStore`. + +`MemoryStoreError` gains two variants behind the feature flag (added during +the Postgres impl, not during the Phase 1 amendment): +```rust +#[cfg(feature = "postgres-backend")] +#[error("postgres error: {0}")] +Postgres(#[from] sqlx::Error), + +#[cfg(feature = "postgres-backend")] +#[error("postgres migration error: {0}")] +Migrate(#[from] sqlx::migrate::MigrateError), +``` + +### D3. Split sqlite.rs into a sqlite/ directory as Phase 1 amendment + +Pure code motion, no behavioural change. Target layout: +``` +crates/vestige-core/src/storage/sqlite/ + mod.rs -- SqliteMemoryStore struct, new(), reader/writer locks + crud.rs -- insert/get/update/delete + search.rs -- fts_search, vector_search, hybrid search + scheduling.rs -- FSRS state methods + graph.rs -- edges, neighbors + domain.rs -- domain CRUD, classify stub + registry.rs -- embedding_model table + register_model + portable_sync.rs -- portable archive backend bridge + trait_impl.rs -- impl LocalMemoryStore for SqliteMemoryStore +``` + +Cognitive-module imports stay on `crate::storage::SqliteMemoryStore` and +related re-exports from `storage/mod.rs`; the split is private to the +module. Each motion commit must keep `cargo test -p vestige-core` green for +bisectability. + +This lands in the Phase 1 amendment PR alongside D1 (separate commit, same +branch). + +### D4. Postgres backend as a directory from day one + +``` +crates/vestige-core/src/storage/postgres/ + mod.rs -- PgMemoryStore struct, connect, from_pool, trait impl + pool.rs -- PgPool construction from PostgresConfig + migrations.rs -- sqlx::migrate! wrapper + registry.rs -- ensure_registry, ALTER COLUMN TYPE vector(N) + search.rs -- RRF query + row mapping + migrate_cli.rs -- SQLite -> Postgres streaming copy + reembed.rs -- O(n) re-encode + HNSW rebuild +``` + +D1+D2 of the master plan land first as a skeleton in `mod.rs` with `todo!()` +bodies; later sub-plans fill in the other files. + +### D5. Sub-plan layout: two phases worth of sub-plans + +Phase 1 amendment sub-plans (under `docs/plans/`): +- `0001a-trait-rewrite.md` -- MemoryStore async_trait -> trait_variant, call-site audit +- `0001b-sqlite-split.md` -- sqlite.rs -> sqlite/ directory, commit-by-commit +- `0001c-async-trait-sunset.md` -- Embedder rewrite + drop async-trait dep from Cargo.toml + +Phase 2 sub-plans (under `docs/plans/`): +- `0002a-skeleton-and-feature-gate.md` -- master plan D1 + D2 (todo!() bodies) +- `0002b-pool-and-config.md` -- master plan D3 + D7 +- `0002c-migrations.md` -- master plan D4 +- `0002d-store-impl-bodies.md` -- master plan D2 real bodies + D6 registry +- `0002e-hybrid-search.md` -- master plan D5 +- `0002f-migrate-cli.md` -- master plan D8 + D10 +- `0002g-reembed.md` -- master plan D9 +- `0002h-testing-and-benches.md` -- master plan D14 + D15 +- `0002i-runbook.md` -- master plan D16 + +Each sub-plan is a self-contained brief sized to fit one focused +implementation session (handed to Claude Code as a `/goal` instruction +without requiring the agent to load the master plan). + +### D6. SQLite split does not get its own ADR + +The split is pure code motion; no public types, behaviour, or paths change. +`0001b-sqlite-split.md` is enough. + +### D7. Multi-tenancy schema reservation (L1-L3) + +Phase 2 reserves the columns and tables needed for future per-user / per-group +visibility, so Phase 3 (auth) does not require a column-add migration over a +populated, HNSW-indexed `knowledge_nodes` table. Single-user behaviour is unchanged +in both backends. + +New tables in `0001_init.up.sql`: + +```sql +CREATE TABLE users ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + handle TEXT NOT NULL UNIQUE, + display_name TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + metadata JSONB NOT NULL DEFAULT '{}'::jsonb +); + +CREATE TABLE groups ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + handle TEXT NOT NULL UNIQUE, + display_name TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + metadata JSONB NOT NULL DEFAULT '{}'::jsonb +); + +CREATE TABLE group_memberships ( + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + group_id UUID NOT NULL REFERENCES groups(id) ON DELETE CASCADE, + role TEXT NOT NULL DEFAULT 'member', -- 'member' | 'admin' + joined_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (user_id, group_id) +); + +INSERT INTO users (id, handle, display_name) + VALUES ('00000000-0000-0000-0000-000000000001', 'local', 'Local User'); +``` + +New columns on `knowledge_nodes`: + +```sql +owner_user_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000001' + REFERENCES users(id), +visibility TEXT NOT NULL DEFAULT 'private', -- 'private' | 'group' | 'public' +shared_with_groups UUID[] NOT NULL DEFAULT '{}' + +CREATE INDEX idx_knowledge_nodes_owner ON knowledge_nodes (owner_user_id); +CREATE INDEX idx_knowledge_nodes_shared_groups ON knowledge_nodes USING GIN (shared_with_groups); +``` + +Phase 3 visibility filter (declared here for reference; implemented in Phase 3): + +```sql +WHERE + (visibility = 'private' AND owner_user_id = $me) + OR (visibility = 'group' + AND (owner_user_id = $me OR shared_with_groups && $my_group_ids)) + OR visibility = 'public' +``` + +Why tri-state enum and not just `shared_with_groups[] + is_public`: the +explicit `visibility` field documents intent at the row level. A `'private'` +row with a non-empty `shared_with_groups` is detectable inconsistency +(a CHECK constraint can enforce it later) rather than silent data. + +SQLite parity: same tables and columns with identical defaults. +`shared_with_groups` is a JSON `'[]'` text encoding (no array type). +Single-user mode never changes any of these values; the trait surface ignores +the visibility filter for SQLite because there is exactly one user. + +Sharing automation (matching by domain, tag, repo, MCP caller, ...) is +explicitly **not** in Phase 2. See D8 for context capture, and the Follow-ups +section for the Phase 4 `sharing_rules` design sketch. + +RLS policies are not declared in Phase 2. Phase 3 decides whether to add +RLS as defense-in-depth on top of the app-layer filter. + +### D8. Context-aware ingest + +Every memory carries its ingest context, so future automation (sharing rules, +domain scoping, audit) can match on it without a schema migration. Most of +this is already happening in the Phase 1 ingest pipeline; D8 promotes it to +ADR-level commitment so Phase 2 cannot drop it on the way to Postgres. + +Context dimensions and where they live: + +- **`codebase`** -- promoted to a first-class indexed column on `knowledge_nodes`. + High-frequency query path (`SELECT ... WHERE codebase = 'vestige'`) for + both human exploration and Phase 4 HDBSCAN scoping. Direct B-tree index + beats JSONB extraction. + ```sql + codebase TEXT, -- nullable; populated from ingest context + CREATE INDEX idx_knowledge_nodes_codebase ON knowledge_nodes (codebase) WHERE codebase IS NOT NULL; + ``` + `MemoryRecord` gains `pub codebase: Option`. + +- **`mcp_client_id`** -- which MCP caller created this. Persistent identity + once Phase 3 API keys exist. Lives in `metadata.mcp_client_id` (JSONB). + Not query-hot enough to deserve a column. + +- **`session_id`** -- ephemeral; identifies the calling session for runtime + override scoping. Lives in `metadata.session_id` (JSONB). Sessions die + fast; storing them as rows or indexed columns is waste. + +- **`file` / `topics`** -- existing optional context already accepted by the + ingest pipeline. Stay in metadata JSONB. + +Phase 2's job for D8 is operational, not architectural: audit the ingest +path from MCP request to row write to ensure none of these fields gets +dropped when crossing the SQLite -> Postgres backend boundary. + +--- + +## PR Cadence + +Two work streams, three PRs total: + +1. **PR A: Phase 1 amendment** + - Branch: `feat/storage-trait-phase1` (existing, amended in place) + - Commits: MemoryStore trait rewrite (0001a) + sqlite split (0001b, multiple + motion commits) + Embedder rewrite & async-trait dep removal (0001c). + - Sub-plans `0001a-`, `0001b-`, `0001c-` are committed on this branch. + +2. **PR B: ADR 0002 + Phase 2 sub-plans (this document + the 9 sub-plans)** + - New branch off PR A's tip once that is reviewed. + - No code; docs only. + +3. **PR C: Phase 2 implementation** + - New branch off PR B's tip. + - One PR with many commits clustered by sub-plan. + +PR B is the "let's discuss execution before writing code" gate. PR C is the +"now we write code" gate. If PR A is itself sizable enough that it needs the +amendments reviewed in stages, the three sub-plans (`0001a`, `0001b`, `0001c`) +can split into separate PRs; that's a tactical call at PR time. + +--- + +## Architecture Overview + +Final layout after the Phase 1 amendment (PR A) and Phase 2 implementation +(PR C): + +``` +crates/vestige-core/src/storage/ + mod.rs -- re-exports, Storage alias for BC + memory_store.rs -- trait_variant-generated MemoryStore + LocalMemoryStore, types, error + migrations.rs -- SQLite migration registry (Phase 1, unchanged) + portable.rs -- portable archive format (Phase 1, unchanged) + sqlite/ -- was sqlite.rs (D3, Phase 1 amendment) + mod.rs -- SqliteMemoryStore struct, new(), reader/writer locks + crud.rs -- insert/get/update/delete + search.rs -- fts/vector/hybrid + scheduling.rs -- FSRS state + graph.rs -- edges, neighbors + domain.rs -- domain CRUD, classify stub + registry.rs -- embedding_model table + register_model + portable_sync.rs -- portable backend bridge + trait_impl.rs -- impl LocalMemoryStore for SqliteMemoryStore + postgres/ -- D4, Phase 2 + mod.rs -- PgMemoryStore struct, connect, from_pool, trait impl + pool.rs -- PgPool construction from config + migrations.rs -- sqlx::migrate! wrapper + registry.rs -- register_model body, ALTER COLUMN TYPE vector(N) + search.rs -- RRF query + row mapping + migrate_cli.rs -- SQLite -> Postgres streaming copy + reembed.rs -- O(n) re-encode + HNSW rebuild + +crates/vestige-core/migrations/ + sqlite/ -- Phase 1, with V15 migration for D7+D8 columns/tables + postgres/ -- Phase 2 + 0001_init.up.sql -- includes D7 tables + columns, D8 codebase column + 0001_init.down.sql + 0002_hnsw.up.sql + 0002_hnsw.down.sql +``` + +Tables in the Postgres schema after migration 0001: + +| Table | Purpose | Phase that populates | +|-------|---------|----------------------| +| `embedding_model` | One-row registry of name/dim/hash | Phase 2 (first connect) | +| `knowledge_nodes` | Core records + owner/visibility/codebase | Phase 2 ingest; Phase 4 fills `domains` | +| `scheduling` | FSRS state | Phase 2 | +| `edges` | Spreading activation graph | Phase 2 | +| `review_events` | Append-only FSRS review log | Phase 2; Phase 5 federation reads | +| `domains` | Phase 4 cluster centroids | Phase 4 | +| `users` | L1 identities (D7) | Phase 3 | +| `groups` | L3 groups (D7) | Phase 3 | +| `group_memberships` | L3 user-group links (D7) | Phase 3 | + +`sharing_rules` (Phase 4) and `api_keys` (Phase 3) are added later by their +own migrations. + +--- + +## Alternatives Considered + +| Alternative | Why not | +|-------------|---------| +| Keep async_trait on the Phase 1 trait | One heap allocation per trait call inside the hottest code path in Vestige. Boxing every future also obscures the actual return type, which makes lifetimes and Send-ness harder to reason about. The Phase 1 PR is not opened upstream yet, so amending is free. | +| Take `&dyn Embedder` into `connect` | Couples constructor to embedder; breaks ADR 0001's separation; can't be used by callers that don't have an embedder yet (tests, migrate CLI). | +| Defer SQLite split | Postgres lands alongside an 8K-line peer; the pattern compounds; future readers see "backends are huge here". | +| Single `postgres.rs` | Master plan calls out 7 sub-files; we know it's getting split; doing it twice is waste. | +| Per-deliverable sub-plans (16 docs) | Review fatigue; many sub-plans would be 3-5 lines of Cargo or one migration each. Logical groups cluster naturally with PR commits. | +| One rolling sub-plan with checkboxes | Moving target; doesn't serve as a `/goal` brief for a fresh Claude Code session. | +| Separate ADR for the SQLite split | Pure code motion with no public-surface change; doesn't constrain future decisions. ADRs are for decisions that bind. | +| Punt multi-tenancy schema entirely to Phase 3 | Adding `owner_user_id` and indexes to a populated, HNSW-indexed `knowledge_nodes` table later is an expensive online migration. Reserving NULL-defaulted columns now is ~10 lines of SQL. | +| `shared_with_groups[] + is_public` instead of tri-state visibility enum | More compact but `visibility = 'private'` documents intent at the row level; a CHECK constraint can later enforce array/enum consistency. Two columns conveying one fact is fine when both are referenced often. | +| Add `shared_with_users[]` for direct user-to-user sharing | A "group of one" subsumes it without an extra column and GIN index. Phase 3 CLI can auto-create singleton groups if a user requests direct shares. | +| Bake per-domain or per-tag sharing defaults into Phase 2 schema | Sharing automation needs real usage data before committing to fuzzy (domain centroids) vs crisp (tags) vs context (codebase / MCP caller). Phase 4 designs a generic `sharing_rules` table that matches on any context dimension; deferring costs nothing because rules live in a new table, not new columns. | +| `codebase` stays in JSONB metadata | High-frequency query path (HDBSCAN scoping, codebase-wide searches, future `sharing_rules` match). B-tree on a real column beats GIN on a JSONB key for this access pattern. Cost is one nullable TEXT column. | + +--- + +## Consequences + +### Positive +- Phase 1 trait stops boxing futures on every call. Lifetimes and Send-ness + become inspectable instead of hidden inside an `async_trait` macro expansion. +- `connect` stays backend-agnostic; tests and CLI tools stand up either backend + without an `Embedder` in scope. +- Cognitive module imports never change paths -- the SQLite split is private + to `storage/sqlite/`, public re-exports through `storage/mod.rs` unchanged. +- Postgres backend lands already-modular; future SQL changes touch one of + seven small files, not one of eight thousand lines. +- Phase 2 master plan stays archival; ADR 0002 + sub-plans are the live source + of truth for execution. +- Multi-tenancy columns reserved now means Phase 3 auth is purely additive -- + no online migration over a populated, HNSW-indexed `knowledge_nodes` table. +- Context-aware ingest (D8) keeps the door open for repo / session / + MCP-caller-scoped sharing rules in Phase 4 without changing `knowledge_nodes`. + +### Negative +- The Phase 1 amendment expands a "finished" branch. It is a real cost: the + trait rewrite touches every cognitive module that holds a store handle. +- SQLite split is a pure-motion diff. Annoying to review even when safe. +- Three PRs (amendment, ADR+plans, implementation) instead of one or two. + Discipline tax in exchange for reviewability. +- Multi-tenancy reservation adds three never-queried tables and three + always-default columns to the SQLite schema. Real but small storage cost in + single-user mode (a single bootstrap row + empty tables + NULL/empty + defaults per memory). + +### Risks +- **Trait rewrite breaks a cognitive module's Send-ness expectation.** + Mitigation: `cargo test --workspace` runs after each call-site edit; + trait_variant-generated `MemoryStore` is the Send variant and matches the + current `Arc` usage everywhere except thread-local impls (none + exist today). +- **SQLite motion commit introduces a silent semantic change.** Mitigation: + each commit keeps `cargo test -p vestige-core` green; reviewer can bisect. +- **Sub-plan boundaries don't match how implementation wants to commit.** + Mitigation: sub-plans are advisory; the implementation PR clusters commits + however it ends up needing to. +- **Reserved columns get used in Phase 3 in a way that mismatches Phase 2 + defaults.** Mitigation: Phase 3 owns the auth filter; Phase 2 defaults + (`owner_user_id = local`, `visibility = 'private'`) are intentionally the + "no access for anyone but the owner" worst-case; widening at Phase 3 is + safe, narrowing would be the dangerous direction. +- **Memory: PR A amendment invalidates the locally-deployed Phase 1 binary's + ABI.** Not a real risk -- the trait change is purely source-level Rust; the + on-disk DB schema is unchanged. The rebuilt binary slots in over the + current one without DB migration. + +--- + +## Resolved Decisions + +| # | Question | Resolution | +|---|----------|------------| +| Q1 | Phase 1 trait shape | Rewrite with trait_variant::make. Amend Phase 1 PR. | +| Q2 | PgMemoryStore::connect signature | Mirror SqliteMemoryStore::new; no Embedder. register_model does the pgvector typmod stamp. | +| Q3 | Split sqlite.rs | Yes, as Phase 1 amendment. sqlite.rs -> sqlite/ directory; pure code motion. | +| Q4 | Postgres module layout | Directory from day one. | +| Q5 | Sub-plan granularity | Logical groups, ~9 docs for Phase 2 plus 2 for the Phase 1 amendment. | +| Q6 | ADR for SQLite split | No. Sub-plan `0001b-sqlite-split.md` is sufficient. | +| Q7 | Multi-tenancy schema | Reserve users / groups / group_memberships tables and owner_user_id / visibility / shared_with_groups columns on knowledge_nodes in Phase 2. Single-user defaults; Phase 3 fills in real values. | +| Q8 | Visibility encoding | Tri-state enum `'private' \| 'group' \| 'public'` plus `shared_with_groups[]`. No `shared_with_users[]`; no RLS in Phase 2. | +| Q9 | Sharing automation grain | Per-memory only in Phase 2. Phase 4 ships a generic `sharing_rules` table matching on codebase / tag / node_type / mcp_client_id. | +| Q10 | Context capture on ingest | `codebase` promoted to a first-class indexed column; `mcp_client_id` and `session_id` stay in metadata JSONB. | + +--- + +## Follow-ups + +- Phase 1 amendment sub-plans drafted: `0001a-trait-rewrite.md`, + `0001b-sqlite-split.md`, `0001c-async-trait-sunset.md`. Ready to execute on + `feat/storage-trait-phase1`. +- Phase 2 sub-plans drafted: `0002a-` through `0002i-` against the accepted + decisions above. Ready to execute on a new branch off PR A's tip. +- Decide branch placement for this ADR before it gets committed -- it cannot + live on `feat/storage-trait-phase1` (that branch is now PR A's code-only + amendment branch). Likely a new branch off PR A's tip for PR B (docs only). +- Validate local Postgres dev cluster before PR C work begins. Recipe at + `docs/plans/local-dev-postgres-setup.md` is correct but needs to be applied + on this machine (delandtj-home): cluster is not initdb'd, pgvector is not + installed. Containerized `pgvector/pgvector:pg16` is a viable alternative + if pgvector packaging is friction. See open discussion thread. + +### Phase 4 sketch: `sharing_rules` and the precedence chain + +Recorded here so the Phase 4 author does not have to rediscover the design. +Phase 2 does **not** implement any of this; it only ensures the schema and +ingest context capture make this possible without a `knowledge_nodes` migration. + +```sql +-- Phase 4 migration (not Phase 2) +CREATE TABLE sharing_rules ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + owner_user_id UUID NOT NULL REFERENCES users(id), + -- Match: any subset; all set fields must match conjunctively + match_codebase TEXT, + match_tag TEXT, + match_node_type TEXT, + match_api_key_id UUID REFERENCES api_keys(id), -- MCP caller identity + -- Policy + visibility TEXT NOT NULL, + shared_with_groups UUID[] NOT NULL DEFAULT '{}', + -- Conflict resolution + priority INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); +``` + +Precedence on ingest, first match wins: + +1. Caller-explicit visibility in the MCP request +2. Active session override held by the MCP server (per-session, in-memory, + not persisted; matched by `session_id`) +3. Highest-priority `sharing_rules` row whose match fields all hold +4. User's `default_visibility` (typically `'private'`) + +Per-session overrides do not persist; storing ephemeral session IDs as DB +rows is waste. Per-codebase / per-MCP-caller rules do persist as +`sharing_rules` rows. From 697ade5b02decdfaf1165958f945f0f92b905497 Mon Sep 17 00:00:00 2001 From: Jan De Landtsheer Date: Wed, 27 May 2026 09:35:37 +0200 Subject: [PATCH 14/31] docs(plans): add Phase 1 amendment sub-plans 0001a/b/c Three sub-plans operationalising ADR 0002 D1 + D3 on the existing feat/storage-trait-phase1 branch (790c0c8, not yet pushed upstream): - 0001a-trait-rewrite.md -- rewrite MemoryStore with #[trait_variant::make(MemoryStore: Send)] generating a non-Send LocalMemoryStore companion. Production callers use Arc and are unaffected; only the trait declaration and SQLite impl block change. - 0001b-sqlite-split.md -- pure code motion. Split sqlite.rs (8713 lines) into a sqlite/ directory (mod, crud, search, scheduling, graph, domain, registry, portable_sync, trait_impl). Public re-exports unchanged; tests green commit-by-commit. Depends on 0001a so trait_impl.rs picks up the trait_variant attribute once. - 0001c-async-trait-sunset.md -- rewrite Embedder the same way, then remove async-trait = "0.1" from crates/vestige-core/Cargo.toml. End state: zero async_trait references in the workspace. Together these three lands as PR A. --- docs/plans/0001a-trait-rewrite.md | 689 ++++++++++++++++++++ docs/plans/0001b-sqlite-split.md | 732 +++++++++++++++++++++ docs/plans/0001c-async-trait-sunset.md | 847 +++++++++++++++++++++++++ 3 files changed, 2268 insertions(+) create mode 100644 docs/plans/0001a-trait-rewrite.md create mode 100644 docs/plans/0001b-sqlite-split.md create mode 100644 docs/plans/0001c-async-trait-sunset.md diff --git a/docs/plans/0001a-trait-rewrite.md b/docs/plans/0001a-trait-rewrite.md new file mode 100644 index 0000000..354e138 --- /dev/null +++ b/docs/plans/0001a-trait-rewrite.md @@ -0,0 +1,689 @@ +# Phase 1 Amendment Sub-Plan: async_trait -> trait_variant + +**Status**: Draft +**Depends on**: Phase 1 (already on `feat/storage-trait-phase1`, tip 790c0c8) +**Followed by**: `docs/plans/0001c-async-trait-sunset.md` (Embedder rewrite + async-trait crate removal) +**Related**: docs/adr/0002-phase-2-execution.md (decision D1), docs/plans/0001-phase-1-storage-trait-extraction.md + +--- + +## Context + +Phase 1 froze with the storage trait declared as +`#[async_trait::async_trait] pub trait MemoryStore: Send + Sync + 'static` +and a `pub use MemoryStore as LocalMemoryStore;` alias. `async_trait` boxes +every `async fn` in the trait into `Pin>`. That is one +heap allocation per call inside the hottest code path in Vestige (insert, +search, update_scheduling are all on this surface). It also collapses the +two intended trait shapes -- a Send-bound `MemoryStore` for tokio/axum and a +non-Send `LocalMemoryStore` for thread-local backends -- into a single trait +behind an alias, removing the type-system signal we will want for Phase 2's +Postgres backend. + +ADR 0002 decision D1 supersedes this. The amendment lands on the existing +`feat/storage-trait-phase1` branch before Phase 2 starts, before the PR is +opened upstream. The end state: + +- `LocalMemoryStore` is the source-of-truth trait, declared with native + async-fn-in-trait (stable on MSRV 1.91), no `Sync` bound on the trait + itself, and `Sync + 'static` on the trait object. +- `MemoryStore` is auto-generated by `#[trait_variant::make(MemoryStore: Send)]` + with `Send` bounds on every returned future, so `Arc` is + movable across `tokio::spawn`. +- `trait-variant` 0.1 is already present in `crates/vestige-core/Cargo.toml`. + The `async-trait` crate dependency stays in place through this sub-plan + (it is still in use by the embedder impl); removing it is the job of + `0001c-async-trait-sunset.md`. +- No production caller changes. Every production call site holds + `Arc` (the concrete `SqliteMemoryStore` alias), which the trait + rewrite does not touch. Only the trait declaration and impl blocks change. + +--- + +## Scope + +### In scope + +- Rewrite `MemoryStore` / `LocalMemoryStore` declaration in + `crates/vestige-core/src/storage/memory_store.rs` to use + `#[trait_variant::make(MemoryStore: Send)] pub trait LocalMemoryStore`. +- Remove the `pub use MemoryStore as LocalMemoryStore;` alias from the same + file. `LocalMemoryStore` becomes the real trait; `MemoryStore` is the + generated Send variant. +- Drop the `#[async_trait::async_trait]` attribute on the SQLite impl block + in `crates/vestige-core/src/storage/sqlite.rs` (line 6274). The impl block + switches from `impl MemoryStore for SqliteMemoryStore` (currently spelled + through the `LocalMemoryStore` alias) to `impl LocalMemoryStore for + SqliteMemoryStore`. `trait_variant` provides a blanket `impl MemoryStore for T` so `&dyn MemoryStore` and + `Arc` keep working unchanged. +- Update doc comments in `memory_store.rs` to drop + references to `#[async_trait::async_trait]` and instead describe the + `trait_variant` mechanism. +- Keep the existing Phase 1 test suite (`tests/phase_1/*.rs`) green. The + tests already use `Arc` and `Box`, which is + exactly the surface the rewrite is meant to preserve. + +### Out of scope -- moved to 0001c + +- Rewriting the `Embedder` / `LocalEmbedder` trait declaration -- handled by + `0001c-async-trait-sunset.md`. +- Dropping `#[async_trait::async_trait]` from + `crates/vestige-core/src/embedder/fastembed.rs`. +- Removing `async-trait = "0.1"` from `crates/vestige-core/Cargo.toml`. +- The hard `grep -rn 'async_trait' crates/` zero-match gate (async_trait is + still present in the embedder module after 0001a alone). + +### Out of scope + +- The SQLite file split (`sqlite.rs` -> `sqlite/` directory). That is the + sibling sub-plan `0001b-sqlite-split.md`. +- Any production-side refactor that switches `Arc` to + `Arc`. Production code keeps using the concrete alias. +- Adding `register_model` / `from_pool` / Postgres-specific variants of + `MemoryStoreError`. Those land with the Postgres backend in Phase 2. +- Removing the `pub type Storage = SqliteMemoryStore;` alias. + +--- + +## Prerequisites + +### Current state (verified) + +- `crates/vestige-core/Cargo.toml` already declares + `trait-variant = "0.1"` (line 117). `async-trait = "0.1"` (line 119) + remains in place for the duration of this sub-plan; `0001c` removes it. +- `crates/vestige-core/src/storage/memory_store.rs:194` declares the trait + with `#[async_trait::async_trait] pub trait MemoryStore: Send + Sync + + 'static`. +- `crates/vestige-core/src/storage/memory_store.rs:262` has + `pub use MemoryStore as LocalMemoryStore;`. +- `crates/vestige-core/src/storage/sqlite.rs:6274` declares + `#[async_trait::async_trait] impl + crate::storage::memory_store::LocalMemoryStore for SqliteMemoryStore`. +- Production call sites use `Arc` (the concrete + `SqliteMemoryStore` alias). Confirmed by grep: + `grep -rn "dyn MemoryStore\|dyn LocalMemoryStore" --include="*.rs"` + returns hits only in `tests/phase_1/*.rs`, in two comments inside + `memory_store.rs` and `sqlite.rs`, and in one test-only `&dyn MemoryStore` + cast inside `sqlite.rs::tests` (line 8669). +- Workspace-wide `async_trait` usages: only the trait declarations and + impl blocks in `memory_store.rs`, `sqlite.rs`, `embedder/mod.rs`, and + `embedder/fastembed.rs` (verified by + `grep -rn async_trait --include="*.rs"`). This sub-plan touches only the + first two; the embedder files are addressed by `0001c`. + +### Required crates + +| Crate | Version | Action | +|-------|---------|--------| +| `trait-variant` | `0.1` | Already declared. Verify present after edit. | +| `async-trait` | `0.1` | Unchanged for this sub-plan (still used by embedder impl). Removed by `0001c`. | +| `blake3`, `thiserror`, `chrono`, `uuid`, `serde`, `serde_json` | unchanged | unchanged | + +--- + +## Files Touched + +Grouped by category. Every change is listed; nothing else gets touched. + +### Trait declarations (vestige-core) + +| File | Lines (approx) | Change | +|------|----------------|--------| +| `crates/vestige-core/src/storage/memory_store.rs` | 183-262 | Replace `#[async_trait::async_trait]` block with `#[trait_variant::make(MemoryStore: Send)] pub trait LocalMemoryStore`. Drop the `pub use MemoryStore as LocalMemoryStore;` alias. Update doc comments. | + +### Impl blocks (vestige-core) + +| File | Lines (approx) | Change | +|------|----------------|--------| +| `crates/vestige-core/src/storage/sqlite.rs` | 6274 (impl block header only) | Delete the `#[async_trait::async_trait]` attribute. Keep the `impl crate::storage::memory_store::LocalMemoryStore for SqliteMemoryStore { ... }` body verbatim. | + +### Cargo dependency cleanup + +None in this sub-plan. The `async-trait` crate stays declared in +`crates/vestige-core/Cargo.toml` because the embedder impl still uses it. +`0001c-async-trait-sunset.md` removes the dependency after the embedder +side is rewritten. + +### Cognitive module call sites + +No changes. The 29 cognitive modules under `crates/vestige-core/src/neuroscience/` +and `crates/vestige-core/src/advanced/` already operate on concrete +`SqliteMemoryStore` (via the `Storage` alias) or on plain data types +(`KnowledgeNode`, `Vec`, `ConnectionRecord`). Grep verified zero +production references to `dyn MemoryStore` or `dyn LocalMemoryStore`. + +### MCP call sites + +No changes. All ~30 `vestige-mcp/src/**.rs` files holding `Arc` +keep working because: +- `Storage` is still `pub type Storage = SqliteMemoryStore;` (unchanged). +- They call inherent methods on the concrete type, never via a trait object. +- `SqliteMemoryStore` implements `LocalMemoryStore`; `trait_variant` auto- + generates a blanket `impl MemoryStore for T`, + so the concrete type also satisfies `MemoryStore` for any future caller + that wants the trait-object form. + +### Test files (vestige-core integration tests) + +| File | Lines | Change | +|------|-------|--------| +| `tests/phase_1/trait_round_trip.rs` | 7-18, 134 | No change. Already uses `Arc` and `use vestige_core::storage::MemoryStore`. trait_variant emits a `MemoryStore` trait at the same path, so the imports resolve. | +| `tests/phase_1/send_bound_variant.rs` | 10-12, 36, 57 | No change. Already asserts the trait_variant Send invariant; the rewrite is what makes the doc comment on lines 3-4 actually true. | +| `tests/phase_1/cognitive_module_isolation.rs` | 11, 37, 76, 102, 115 | No change. | +| `tests/phase_1/embedding_model_registry.rs` | 10 | No change. | +| `tests/phase_1/domain_column_migration.rs` | 98 | No change. | +| `crates/vestige-core/src/storage/sqlite.rs::tests` | 8666-8675 | No change. The existing test casts `&s` to `&dyn MemoryStore` and calls trait methods through that vtable; trait_variant preserves this exact dyn-compatible surface. | + +### Documentation + +| File | Change | +|------|--------| +| `crates/vestige-core/src/storage/memory_store.rs` | Rewrite the trait-level doc comment (lines 185-193) to describe trait_variant rather than async_trait. | +| `CLAUDE.md` | No change. The repo-level architecture notes do not name the trait attribute. | + +--- + +## Trait Declaration Rewrite + +### Before (current state on `feat/storage-trait-phase1`) + +`crates/vestige-core/src/storage/memory_store.rs:183-262`: + +```rust +// ---------------------------------------------------------------------------- +// TRAIT +// ---------------------------------------------------------------------------- + +/// The single storage abstraction. +/// +/// `#[async_trait::async_trait]` makes every `async fn` return a +/// `Pin>`, which is required for `Arc` +/// to be movable across `tokio::spawn` boundaries. +/// +/// `LocalMemoryStore` is a type alias kept for source compatibility with code +/// that refers to the non-send variant. In Phase 1 both names refer to the same +/// (dyn-compatible, Send-safe) trait. +#[async_trait::async_trait] +pub trait MemoryStore: Send + Sync + 'static { + // --- Lifecycle --- + async fn init(&self) -> MemoryStoreResult<()>; + async fn health_check(&self) -> MemoryStoreResult; + + // ... 25 more async fn ... + + async fn vacuum(&self) -> MemoryStoreResult<()>; +} + +/// Type alias kept for source compatibility. Both names refer to the same +/// `async_trait`-annotated trait that is dyn-compatible and `Send + Sync`. +pub use MemoryStore as LocalMemoryStore; +``` + +### After + +`crates/vestige-core/src/storage/memory_store.rs:183-262`: + +```rust +// ---------------------------------------------------------------------------- +// TRAIT +// ---------------------------------------------------------------------------- + +/// The single storage abstraction. +/// +/// `LocalMemoryStore` is the source-of-truth trait. The +/// `#[trait_variant::make(MemoryStore: Send)]` attribute auto-generates a +/// `MemoryStore` trait whose returned futures are `Send`, so +/// `Arc` is movable across `tokio::spawn` boundaries while +/// `Arc` remains usable on single-threaded executors +/// and thread-local backends. +/// +/// Every method is native async-fn-in-trait (stable on MSRV 1.91); no +/// per-call heap allocation, no boxed futures. +#[trait_variant::make(MemoryStore: Send)] +pub trait LocalMemoryStore: Sync + 'static { + // --- Lifecycle --- + async fn init(&self) -> MemoryStoreResult<()>; + async fn health_check(&self) -> MemoryStoreResult; + + // --- Embedding model registry --- + async fn registered_model(&self) -> MemoryStoreResult>; + async fn register_model(&self, sig: &ModelSignature) -> MemoryStoreResult<()>; + + // --- CRUD --- + async fn insert(&self, record: &MemoryRecord) -> MemoryStoreResult; + async fn get(&self, id: Uuid) -> MemoryStoreResult>; + async fn update(&self, record: &MemoryRecord) -> MemoryStoreResult<()>; + async fn delete(&self, id: Uuid) -> MemoryStoreResult<()>; + + // --- Search --- + async fn search(&self, query: &SearchQuery) -> MemoryStoreResult>; + async fn fts_search(&self, text: &str, limit: usize) -> MemoryStoreResult>; + async fn vector_search( + &self, + embedding: &[f32], + limit: usize, + ) -> MemoryStoreResult>; + + // --- FSRS Scheduling --- + async fn get_scheduling( + &self, + memory_id: Uuid, + ) -> MemoryStoreResult>; + async fn update_scheduling(&self, state: &SchedulingState) -> MemoryStoreResult<()>; + async fn get_due_memories( + &self, + before: DateTime, + limit: usize, + ) -> MemoryStoreResult>; + + // --- Graph (spreading activation) --- + async fn add_edge(&self, edge: &MemoryEdge) -> MemoryStoreResult<()>; + async fn get_edges( + &self, + node_id: Uuid, + edge_type: Option<&str>, + ) -> MemoryStoreResult>; + async fn remove_edge(&self, source: Uuid, target: Uuid) -> MemoryStoreResult<()>; + async fn get_neighbors( + &self, + node_id: Uuid, + depth: usize, + ) -> MemoryStoreResult>; + + // --- Domains --- + async fn list_domains(&self) -> MemoryStoreResult>; + async fn get_domain(&self, id: &str) -> MemoryStoreResult>; + async fn upsert_domain(&self, domain: &Domain) -> MemoryStoreResult<()>; + async fn delete_domain(&self, id: &str) -> MemoryStoreResult<()>; + async fn classify(&self, embedding: &[f32]) -> MemoryStoreResult>; + + // --- Bulk / Maintenance --- + async fn count(&self) -> MemoryStoreResult; + async fn get_stats(&self) -> MemoryStoreResult; + async fn vacuum(&self) -> MemoryStoreResult<()>; +} +``` + +Notes: + +- The `pub use MemoryStore as LocalMemoryStore;` line on the current + `memory_store.rs:262` is **deleted** entirely. `MemoryStore` is now the + generated trait that `trait_variant::make` emits at the same module path; + `LocalMemoryStore` is the source-of-truth declaration. Both names export + from `storage/mod.rs` already (see lines 10-14 of that file). +- `Sync + 'static` on `LocalMemoryStore` (and no `Send` bound on the trait + itself) is correct: `Send` on the trait is what `trait_variant::make` + inserts when it emits the `MemoryStore` variant. The current trait carries + `Send + Sync + 'static`; the rewrite drops the `Send` bound from the + local variant. `Arc` is `Sync` but not `Send`; + `Arc` (the generated variant) is `Send + Sync`. +- `trait_variant` 0.1 does **not** require any attribute on the impl block. + The attribute lives only on the trait declaration. See the next section. + +The Embedder trait rewrite uses the identical `trait_variant::make` pattern +and is fully specified in `0001c-async-trait-sunset.md`. + +--- + +## Impl Block Migration + +`trait_variant` 0.1 attaches the attribute only to the trait declaration. +The impl side is plain `impl LocalMemoryStore for SqliteMemoryStore`; no +attribute on the impl, no `#[trait_variant::make(MemoryStore: Send)]` on the +impl block. The crate auto-generates the blanket +`impl MemoryStore for T`, so any concrete type +that implements `LocalMemoryStore` automatically also implements +`MemoryStore` provided it is `Send`. + +`SqliteMemoryStore` already is `Send + Sync` (it holds `Mutex` +fields whose `Mutex` is `std::sync::Mutex`, which is `Send + Sync` when its +guarded type is `Send`; `rusqlite::Connection` is `Send`). No new bound is +needed. + +### Before + +`crates/vestige-core/src/storage/sqlite.rs:6274`: + +```rust +#[async_trait::async_trait] +impl crate::storage::memory_store::LocalMemoryStore for SqliteMemoryStore { + async fn init(&self) -> crate::storage::memory_store::MemoryStoreResult<()> { + // Migrations run in `new`; this is a no-op for the SQLite backend. + Ok(()) + } + + // ... ~2400 lines of method bodies, unchanged ... +} +``` + +### After + +`crates/vestige-core/src/storage/sqlite.rs:6274`: + +```rust +impl crate::storage::memory_store::LocalMemoryStore for SqliteMemoryStore { + async fn init(&self) -> crate::storage::memory_store::MemoryStoreResult<()> { + // Migrations run in `new`; this is a no-op for the SQLite backend. + Ok(()) + } + + // ... ~2400 lines of method bodies, unchanged ... +} +``` + +Diff is exactly one removed line (the `#[async_trait::async_trait]` attribute). +Every method body, every `async fn` signature, every `use` statement inside +the impl block stays verbatim. No `Box::pin(async move { ... })`, no manual +`Pin>`, no `'async_trait` lifetime markers; native +async-fn-in-trait does this directly. + +The Embedder impl block rewrite follows the identical "remove one +`#[async_trait::async_trait]` attribute" pattern and is fully specified in +`0001c-async-trait-sunset.md`. + +### Why the impl block does not need an attribute + +`trait_variant::make` generates two things from the source trait: + +1. The source trait itself (`LocalMemoryStore`), with native async fns. +2. A second trait (`MemoryStore`) whose method signatures return + `impl Future + Send` instead of `impl Future`, + plus a blanket impl wiring concrete types through. + +Both are emitted at the macro-call site. `SqliteMemoryStore` only writes one +impl block (against `LocalMemoryStore`); the macro-generated blanket +guarantees `SqliteMemoryStore: MemoryStore` for free. The current `&dyn +MemoryStore` casts (sqlite.rs:8669; tests under tests/phase_1/) keep +type-checking unchanged. + +--- + +## Call Site Audit + +Verified via: + +```bash +grep -rn "dyn MemoryStore\|dyn LocalMemoryStore" --include="*.rs" \ + /home/delandtj/prppl/vestige-phase2/ +grep -rn "Arc\|Arc" --include="*.rs" \ + /home/delandtj/prppl/vestige-phase2/ +grep -rn "use.*MemoryStore;\|use.*LocalMemoryStore;" --include="*.rs" \ + /home/delandtj/prppl/vestige-phase2/ +``` + +### Files that reference the trait object form (`dyn MemoryStore` / `dyn LocalMemoryStore`) + +All test-only or doc-comment-only: + +| File | Line | Use | Required change | +|------|------|-----|-----------------| +| `tests/phase_1/trait_round_trip.rs` | 7-18 | `Arc` in `make_store()` and test bodies | None. `MemoryStore` is the generated Send variant; signature stays. | +| `tests/phase_1/trait_round_trip.rs` | 134 | `Arc` upcast inside a test body | None. | +| `tests/phase_1/send_bound_variant.rs` | 10-97 | `Arc` moved across `tokio::spawn` | None. This test becomes meaningfully correct only after the rewrite (currently it relies on async_trait boxing; after the rewrite it relies on trait_variant's Send variant -- same observable outcome). | +| `tests/phase_1/cognitive_module_isolation.rs` | 11, 33-115 | `Arc` passed into cognitive module-style closures | None. | +| `tests/phase_1/embedding_model_registry.rs` | 10 | `Arc` in `make_store()` | None. | +| `tests/phase_1/domain_column_migration.rs` | 98 | `Arc` cast inside a migration assertion | None. | +| `crates/vestige-core/src/storage/sqlite.rs` | 8666-8675 | `let dyn_s: &dyn MemoryStore = &s;` inside `mod tests` | None. The cast is testing that the dyn-vtable still resolves the trait methods correctly; after the rewrite it resolves through the `MemoryStore` trait that `trait_variant::make` emits at the same path. | +| `crates/vestige-core/src/storage/memory_store.rs` | 188 (doc) | Doc comment mentioning `Arc` | Replaced as part of the doc rewrite (see Trait Declaration section). | + +### Files that hold the concrete type (`Arc` / `Arc`) + +35 files, 116 hits. Every one of them keeps working unchanged because the +concrete `SqliteMemoryStore` type stays exactly as it is. Listed here for +completeness so a reviewer can confirm none of them needs an edit: + +``` +crates/vestige-core/src/storage/mod.rs (alias declaration) +crates/vestige-core/src/storage/sqlite.rs (impl block) +crates/vestige-mcp/src/server.rs (Arc in McpServer) +crates/vestige-mcp/src/cognitive.rs (hydrate(&Storage)) +crates/vestige-mcp/src/autopilot.rs +crates/vestige-mcp/src/protocol/http.rs +crates/vestige-mcp/src/dashboard/mod.rs +crates/vestige-mcp/src/dashboard/state.rs +crates/vestige-mcp/src/dashboard/handlers.rs +crates/vestige-mcp/src/resources/codebase.rs +crates/vestige-mcp/src/resources/memory.rs +crates/vestige-mcp/src/tools/changelog.rs +crates/vestige-mcp/src/tools/codebase_unified.rs +crates/vestige-mcp/src/tools/context.rs +crates/vestige-mcp/src/tools/contradictions.rs +crates/vestige-mcp/src/tools/cross_reference.rs +crates/vestige-mcp/src/tools/dedup.rs +crates/vestige-mcp/src/tools/dream.rs +crates/vestige-mcp/src/tools/explore.rs +crates/vestige-mcp/src/tools/feedback.rs +crates/vestige-mcp/src/tools/graph.rs +crates/vestige-mcp/src/tools/health.rs +crates/vestige-mcp/src/tools/importance.rs +crates/vestige-mcp/src/tools/intention_unified.rs +crates/vestige-mcp/src/tools/maintenance.rs +crates/vestige-mcp/src/tools/memory_states.rs +crates/vestige-mcp/src/tools/memory_unified.rs +crates/vestige-mcp/src/tools/predict.rs +crates/vestige-mcp/src/tools/restore.rs +crates/vestige-mcp/src/tools/review.rs +crates/vestige-mcp/src/tools/search_unified.rs +crates/vestige-mcp/src/tools/session_context.rs +crates/vestige-mcp/src/tools/smart_ingest.rs +crates/vestige-mcp/src/tools/suppress.rs +crates/vestige-mcp/src/tools/tagging.rs +crates/vestige-mcp/src/tools/timeline.rs +``` + +Each holds `Arc` and dispatches to inherent methods on +`SqliteMemoryStore`. None of them goes through a trait vtable. Required +change for every one of them: **none**. + +### Files that `use ...MemoryStore` from production code + +``` +grep -rn "use.*MemoryStore;\|use.*LocalMemoryStore;" --include="*.rs" \ + | grep -v "memory_store.rs\|sqlite.rs\|tests/phase_1" +``` + +returns nothing. Production code does not import the trait by name. + +### Conclusion + +The rewrite is a strictly local change to two source files +(`storage/memory_store.rs` and `storage/sqlite.rs`). Zero production call +sites need edits. The integration tests that consume `Arc` +keep their current form; the rewrite is what gives that signature its +no-box semantics on the storage side. The `Box` surface is +addressed by `0001c-async-trait-sunset.md`. + +--- + +## Commit Sequence + +Two commits, each green on `cargo test -p vestige-core --no-default-features` +and `cargo test -p vestige-core --features embeddings,vector-search`. + +### Commit 1: rewrite MemoryStore / LocalMemoryStore trait declaration + +- Touches: `crates/vestige-core/src/storage/memory_store.rs` only. +- Action: replace lines 183-262 per the "Trait Declaration Rewrite" section + above. Delete the `pub use MemoryStore as LocalMemoryStore;` line. +- Green after: `cargo check -p vestige-core` (the impl block in `sqlite.rs` + still has `#[async_trait::async_trait]` on it, but it still resolves + through the `LocalMemoryStore` trait which is now native-async; the + `async_trait` macro is harmless when applied to a trait that the impl + block targets by path, because the macro rewrites the impl's async fns + into boxed-future fns whose signatures still match the native-async + declarations after trait_variant lowering). If `cargo check` complains + here, fold commit 2 into commit 1. + + **Mitigation if check fails between commits 1 and 2:** combine the two + into a single commit. The split is offered for review convenience; the + build must be green after every commit lands. + +### Commit 2: drop `#[async_trait::async_trait]` from SqliteMemoryStore impl + +- Touches: `crates/vestige-core/src/storage/sqlite.rs` only. +- Action: delete line 6274 (`#[async_trait::async_trait]`). +- Green after: `cargo test -p vestige-core --features embeddings,vector-search`, + including all `trait_*` tests inside `sqlite.rs::tests` (lines 8643-8712) + and the trait-object cast on line 8669. + +### Combined alternative + +If the per-step split feels artificial, commits 1 and 2 can collapse into +a single commit covering both the trait rewrite and the impl-attribute +drop for `MemoryStore`. That is acceptable; the two-commit form is +preferred only because it lets a reviewer bisect trait-rewrite failures +separately from impl-rewrite failures. + +The Embedder / fastembed commits and the `async-trait` Cargo dependency +removal live in `0001c-async-trait-sunset.md`. + +--- + +## Verification + +Every command runs from the repo root unless noted otherwise. + +```bash +# 1. Vestige-core, default features (embeddings + vector-search). +cargo test -p vestige-core --features embeddings,vector-search + +# 2. Vestige-core, minimal features (no embeddings, no vector-search). +cargo test -p vestige-core --no-default-features + +# 3. Workspace build, release mode (catches any feature-gated regression +# in the vestige-mcp tools tree). +cargo build --workspace --release + +# 4. Whole-workspace test (vestige-mcp 406 tests + vestige-core 352 tests +# per the CLAUDE.md baseline). +cargo test --workspace + +# 5. Phase 1 integration tests (these are the trait-shape contract). +cargo test --test trait_round_trip --features embeddings,vector-search +cargo test --test send_bound_variant --features embeddings,vector-search +cargo test --test cognitive_module_isolation --features embeddings,vector-search +cargo test --test embedding_model_registry --features embeddings,vector-search +cargo test --test domain_column_migration --features embeddings,vector-search + +# 6. Clippy gate, deny warnings (matches Phase 1 PR policy of zero warnings). +cargo clippy --workspace --all-targets --features embeddings,vector-search -- -D warnings + +# 7. Storage-side dependency hygiene check (must return zero hits). +# Scoped to the storage module only -- the embedder module still uses +# async_trait until 0001c lands. +grep -rn "async_trait\|async-trait" crates/vestige-core/src/storage/ + +# 8. Confirm trait_variant attribute is in place on the storage trait +# (must return exactly one hit in memory_store.rs). +grep -rn "trait_variant::make" crates/vestige-core/src/storage/ +``` + +Expected outcomes: + +- Command 1: 352 tests pass (matches baseline). +- Command 2: smaller test count, all pass. +- Command 3: workspace compiles in release mode. +- Command 4: 758 total tests pass (matches CLAUDE.md baseline). +- Command 5: each phase_1 integration test binary runs green. The + `send_bound_variant::arc_dyn_memory_store_moves_across_tokio_tasks` test + is the canary; if `MemoryStore` lost its Send-bound future variant, this + fails to compile with "future cannot be sent between threads safely". +- Command 6: zero clippy warnings. The rewrite must not introduce a new + `clippy::needless_lifetimes` or `clippy::async_yields_async`. +- Command 7: empty output. async_trait is gone from the storage module. + The embedder module still contains async_trait; that is removed by + `0001c-async-trait-sunset.md`. +- Command 8: one hit, in `memory_store.rs`. + +--- + +## Acceptance Criteria + +A reviewer should be able to check every box: + +- [ ] `crates/vestige-core/src/storage/memory_store.rs` declares the trait + with `#[trait_variant::make(MemoryStore: Send)] pub trait + LocalMemoryStore: Sync + 'static`, no `async_trait` attribute, no + `Send` bound on `LocalMemoryStore` itself. +- [ ] `crates/vestige-core/src/storage/memory_store.rs` no longer contains + `pub use MemoryStore as LocalMemoryStore;`. +- [ ] `crates/vestige-core/src/storage/sqlite.rs:6274` is plain + `impl crate::storage::memory_store::LocalMemoryStore for + SqliteMemoryStore` -- no attribute on the impl block. +- [ ] `grep -rn "async_trait\|async-trait" crates/vestige-core/src/storage/` + returns zero hits. +- [ ] `grep -rn "trait_variant::make" crates/vestige-core/src/storage/` + returns exactly one hit (the storage trait in `memory_store.rs`). +- [ ] All 758 workspace tests pass (`cargo test --workspace`). +- [ ] Phase 1 integration tests pass with the trait-object surface + (`Arc`) intact. +- [ ] `cargo clippy --workspace --all-targets --features + embeddings,vector-search -- -D warnings` is clean. +- [ ] No production source file under `crates/vestige-mcp/` or + `crates/vestige-core/src/{neuroscience,advanced,consolidation,codebase, + memory,embeddings,embedder}/` was modified by this sub-plan. +- [ ] `Arc` still type-checks at every existing call site (verified + by the workspace test pass). +- [ ] Doc comments on the storage trait declaration describe + `trait_variant`, not `async_trait`. + +--- + +## Risks and Mitigations + +- **`trait_variant` 0.1 macro emits unexpected diagnostics on MSRV 1.91.** + Mitigation: the master Phase 1 plan already prescribed this exact pattern + (`#[trait_variant::make(MemoryStore: Send)] pub trait LocalMemoryStore: + Sync + 'static`, see plan `0001-...` line 274-275); the crate has been in + `vestige-core/Cargo.toml` since Phase 1 landed. If a diagnostic appears, + pin to the exact known-good version with `trait-variant = "=0.1.2"` and + open an upstream issue. +- **Native async-fn-in-trait makes the trait no longer dyn-compatible.** + Mitigation: `trait_variant::make` is specifically the workaround for this + -- it emits both the source trait (for static dispatch) and a Send-bound + variant whose returned futures use `Pin>` only at + the dyn boundary. `Arc` keeps working because the + generated `MemoryStore` trait is dyn-compatible by construction. Verified + by the existing `send_bound_variant::*` tests, which intentionally move + `Arc` across `tokio::spawn` from inside a + `multi_thread` runtime. +- **A cognitive module silently relied on the boxed-future return type.** + Mitigation: grep verified no cognitive module imports `MemoryStore` / + `LocalMemoryStore` or holds an `Arc` form; all of them use the + concrete `Storage` alias. There is no Send-ness expectation downstream to + break. +- **Future bodies inside the SQLite impl capture non-Send locals.** + Mitigation: every method body in `sqlite.rs:6274..` runs synchronous + rusqlite calls inside the same `async fn` frame; no `.await` points + exist inside the bodies that we ship today. The `Send` bound on the + generated `MemoryStore` variant is therefore satisfied automatically. + If a future change adds `.await` inside an impl method, the new + trait_variant surface will surface that as a compile error at the call + site, which is the correct outcome. +- **`async-trait` crate is left declared after this sub-plan.** + This is intentional: the embedder impl still depends on it. The + `0001c-async-trait-sunset.md` sub-plan removes the crate after the + embedder side is rewritten. Grep on the whole workspace returns only + the storage and embedder files; no downstream crate pulls `async-trait`. + +--- + +## Out-of-Band Notes + +- This sub-plan amends `feat/storage-trait-phase1` (tip 790c0c8). The + branch has not been opened upstream yet, so amending in place is safe; + no force-push to a public PR. +- The companion sub-plan `0001b-sqlite-split.md` lands after this one on + the same branch. The trait-rewrite landing first is intentional: the + SQLite split moves the impl block into `storage/sqlite/trait_impl.rs`, + and it is cleaner to move a small attribute-free impl than a + macro-decorated one. +- The companion sub-plan `0001c-async-trait-sunset.md` lands after this + one (order with `0001b` is independent) and finishes the + async_trait -> trait_variant transition for the Embedder trait, then + removes the `async-trait` crate dependency. +- After the Phase 1 amendment sub-plans (`0001a`, `0001b`, `0001c`) land, + the branch is reviewed and merged before Phase 2 sub-plans (`0002a-` + through `0002i-`) begin implementation. diff --git a/docs/plans/0001b-sqlite-split.md b/docs/plans/0001b-sqlite-split.md new file mode 100644 index 0000000..ce2590d --- /dev/null +++ b/docs/plans/0001b-sqlite-split.md @@ -0,0 +1,732 @@ +# Sub-Plan 0001b: Split sqlite.rs into a sqlite/ directory + +**Status**: Draft +**Branch**: `feat/storage-trait-phase1` (Phase 1 amendment, PR A) +**Depends on**: `0001a-trait-rewrite.md` (must land first; it carries the +`trait_variant`-generated trait declaration that `trait_impl.rs` matches) +**Related**: `docs/adr/0002-phase-2-execution.md` (D3, D6) + +--- + +## Context + +`crates/vestige-core/src/storage/sqlite.rs` is the single SQLite backend file +that Phase 1 inherited from pre-trait Vestige and then appended the +`LocalMemoryStore` trait impl block to. The file is 8713 lines as of +commit 790c0c8 on `feat/storage-trait-phase1`. ADR 0002 D3 decides to split +it into a `sqlite/` directory before Phase 2 lands `postgres/` as a peer. +Reasoning, in one paragraph: + +The Postgres backend is going in as a directory of seven small files +(`postgres/{mod,pool,migrations,registry,search,migrate_cli,reembed}.rs`). +If SQLite stays as one 8K-line file alongside that, the repo says "backends +look like one big file or seven small ones, pick a side", which forces +every future maintainer to re-litigate the layout. Splitting now -- as +**pure code motion**, no public-API change, no behavioural change, no +migration -- lets both backends look the same, keeps each surface mappable +in a single editor tab, and shrinks the diffs Phase 2 has to review. +This sub-plan is sized as one focused implementation session. + +The split is **private** to `storage/sqlite/`. Cognitive modules continue +to `use crate::storage::SqliteMemoryStore`; the existing re-exports in +`crates/vestige-core/src/storage/mod.rs` keep working without touching +any caller. Tests stay green commit-by-commit. + +This sub-plan depends on `0001a-trait-rewrite.md` landing first because +`sqlite/trait_impl.rs` is the file that picks up the new trait_variant +attribute. Doing the split first would force a second rewrite of +`trait_impl.rs` when the trait rewrite arrives. Order matters; this is +the cheap-to-respect ordering. + +--- + +## Target Layout + +Final directory after this sub-plan: + +``` +crates/vestige-core/src/storage/sqlite/ + mod.rs -- module root: SqliteMemoryStore struct, new(), + reader/writer locks, error types, shared helpers, + portable-sync-related types, record types + crud.rs -- ingest/smart_ingest/get/update/delete/purge/search-by-id + search.rs -- fts, semantic, hybrid, time-based queries + scheduling.rs -- FSRS state, decay, consolidation, review, promote/demote, + suppression, gc, retention, waking tags + graph.rs -- memory_connections (edges), subgraph, neighbors + domain.rs -- domains/domain_scores column readers, classify stub + (Phase 4 will expand this file) + registry.rs -- embedding_model table, enforce_model, register_model body + portable_sync.rs -- portable export/import/sync + merge helpers + trait_impl.rs -- impl LocalMemoryStore for SqliteMemoryStore +``` + +`storage/mod.rs` is unchanged in spirit: it still does `mod sqlite;` and +`pub use sqlite::{...};` -- the only difference is that `sqlite` is now a +directory module instead of a leaf file. The re-export list does not +change. + +--- + +## Current File Map (line numbers from commit 790c0c8) + +The current `sqlite.rs` is structurally: + +| Region | Lines | Contents | +|--------|-------|----------| +| Header | 1-43 | Imports, feature-gated imports | +| Error types | 45-89 | `StorageError`, `Result`, `SmartIngestResult`, `MergeWrite` | +| Portable sync types | 97-211 | `PortableSyncBackend` trait, `FilePortableSyncBackend` struct, `PortableSyncReport`, `PurgeReport` | +| Constants | 233-273 | `PORTABLE_TABLES`, `PORTABLE_USER_DATA_TABLES`, `PortableMergeState`, env constants | +| Struct decl | 287-301 | `SqliteMemoryStore` struct fields | +| Impl block 1 | 303-3740 | Constructor + bulk of native API | +| Record structs | 3747-3866 | `IntentionRecord`, `InsightRecord`, `ConnectionRecord`, `MemoryStateRecord`, `StateTransitionRecord`, `ConsolidationHistoryRecord`, `DreamHistoryRecord`, `Default for InsightRecord` | +| Impl block 2 | 3868-6133 | Intentions / Insights / Connections / States / History / Backup / Portable / GC / Subgraph | +| Impl block 3 | 6139-6272 | Trait-helper methods (`node_to_record`, `read_domain_columns`, `enforce_model`) | +| Trait impl | 6274-7110 | `impl LocalMemoryStore for SqliteMemoryStore` | +| Tests | 7112-8713 | `#[cfg(test)] mod tests`: native API tests + trait round-trip tests | + +--- + +## Mapping Table + +Every public method, every private helper, every struct, every test module +in the current file -- with the destination file in the new layout. Line +ranges cite the current `sqlite.rs` (commit 790c0c8 on +`feat/storage-trait-phase1`, viewed through the +`/home/delandtj/prppl/vestige-phase2` worktree). + +### Header and shared types (-> `sqlite/mod.rs`) + +| Item | Lines | Destination | Notes | +|------|-------|-------------|-------| +| Module-level `use` imports | 1-43 | `sqlite/mod.rs` | Trimmed per-file in destination; what does not fit in `mod.rs` moves with its consumers | +| `StorageError` enum + `Result` alias | 49-71 | `sqlite/mod.rs` | Re-exported through `pub use` chain; called from every sub-module | +| `SmartIngestResult` struct | 73-89 | `sqlite/mod.rs` | Returned by `crud::smart_ingest`; defined here because other code depends on the type | +| `MergeWrite` enum | 91-95 | `sqlite/portable_sync.rs` | Only used by merge helpers | +| `PortableSyncBackend` trait | 97-109 | `sqlite/portable_sync.rs` | Public trait; re-exported through `mod.rs` | +| `FilePortableSyncBackend` struct + `impl` | 111-194 | `sqlite/portable_sync.rs` | | +| `PortableSyncReport` struct | 196-211 | `sqlite/portable_sync.rs` | | +| `PurgeReport` struct | 213-231 | `sqlite/crud.rs` | Returned by `purge_node` | +| `PORTABLE_TABLES` constant | 237-254 | `sqlite/portable_sync.rs` | | +| `PORTABLE_USER_DATA_TABLES` constant | 256-272 | `sqlite/portable_sync.rs` | | +| `PortableMergeState` struct | 274-277 | `sqlite/portable_sync.rs` | | +| `DATA_DIR_ENV` constant | 279 | `sqlite/mod.rs` | Read by constructor | +| `DATABASE_FILE` constant | 280 | `sqlite/mod.rs` | Read by constructor | +| `SqliteMemoryStore` struct decl | 282-301 | `sqlite/mod.rs` | All fields stay public-to-crate within the directory | + +### Constructor and config (-> `sqlite/mod.rs`) + +These are foundational; they live in `mod.rs` because every sub-module +calls them or operates on the struct they build. + +| Item | Lines | Destination | Notes | +|------|-------|-------------|-------| +| `fn data_dir_from_env` | 304-313 | `sqlite/mod.rs` | private helper | +| `fn expand_tilde` | 314-332 | `sqlite/mod.rs` | private helper | +| `fn prepare_data_dir` | 333-346 | `sqlite/mod.rs` | private helper | +| `pub fn db_path_for_data_dir` | 347-355 | `sqlite/mod.rs` | | +| `pub fn default_db_path` | 356-368 | `sqlite/mod.rs` | | +| `fn configure_connection` | 369-396 | `sqlite/mod.rs` | | +| `pub fn new` | 397-457 | `sqlite/mod.rs` | The constructor | +| `pub fn db_path` | 458-462 | `sqlite/mod.rs` | | +| `pub fn data_dir` | 463-467 | `sqlite/mod.rs` | | +| `pub fn sidecar_dir` | 468-473 | `sqlite/mod.rs` | | +| `fn load_embeddings_into_index` | 474-552 | `sqlite/mod.rs` | Called by `new`; touches vector index | + +### CRUD: ingest, get, update, delete, purge (-> `sqlite/crud.rs`) + +| Item | Lines | Destination | Notes | +|------|-------|-------------|-------| +| `pub fn ingest` | 553-643 | `sqlite/crud.rs` | | +| `pub fn smart_ingest` | 644-864 | `sqlite/crud.rs` | Calls vector search via `self.semantic_search`; cross-module call resolved by impl block being on the same struct | +| `pub fn get_node_embedding` (vector-search) | 865-887 | `sqlite/crud.rs` | embedding read for one node | +| `pub fn get_all_embeddings` (vector-search) | 888-914 | `sqlite/crud.rs` | | +| `pub fn get_node_embedding` (no vector-search stub) | 915-919 | `sqlite/crud.rs` | feature-gated alternative | +| `pub fn update_node_content` | 920-951 | `sqlite/crud.rs` | | +| `fn generate_embedding_for_node` | 952-999 | `sqlite/crud.rs` | private helper; only called by ingest and update_node_content | +| `pub fn get_node` | 1000-1011 | `sqlite/crud.rs` | | +| `fn parse_timestamp` | 1012-1027 | `sqlite/mod.rs` | **Shared helper**: row_to_node uses it, intention/insight rows also parse timestamps. Bump to `pub(super) fn` | +| `fn row_to_node` | 1028-1119 | `sqlite/mod.rs` | **Shared helper**: crud reads single nodes; search.rs builds node lists from rows; scheduling.rs returns nodes for review queue. Bump to `pub(super) fn`. Static method (no `&self`) so a free function in `mod.rs` is fine | +| `pub fn delete_node` | 1842-1869 | `sqlite/crud.rs` | | +| `pub fn purge_node` | 1870-1987 | `sqlite/crud.rs` | | +| `fn node_exists` | 1988-1996 | `sqlite/crud.rs` | static helper, called only by purge | +| `fn record_sync_tombstone` | 1997-2014 | `sqlite/crud.rs` | static helper, called by delete and purge | +| `pub fn get_all_nodes` | 2268-2291 | `sqlite/crud.rs` | bulk read | +| `pub fn get_nodes_by_type_and_tag` | 2292-2342 | `sqlite/crud.rs` | bulk read | + +### Search: fts, semantic, hybrid, temporal (-> `sqlite/search.rs`) + +| Item | Lines | Destination | Notes | +|------|-------|-------------|-------| +| `pub fn recall` | 1120-1147 | `sqlite/search.rs` | top-level recall path | +| `fn keyword_search` | 1148-1180 | `sqlite/search.rs` | private | +| `pub fn search` | 2015-2043 | `sqlite/search.rs` | | +| `pub fn search_terms` | 2044-2075 | `sqlite/search.rs` | | +| `pub fn concrete_search_filtered` | 2076-2172 | `sqlite/search.rs` | | +| `fn upsert_concrete_result` | 2173-2197 | `sqlite/search.rs` | static helper | +| `fn normalize_literal_query` | 2198-2210 | `sqlite/search.rs` | static helper | +| `fn escape_like` | 2211-2224 | `sqlite/search.rs` | static helper | +| `fn literal_match_score` | 2225-2248 | `sqlite/search.rs` | static helper | +| `fn node_matches_type_filters` | 2249-2267 | `sqlite/search.rs` | static helper | +| `pub fn is_embedding_ready` (both feature variants) | 2343-2354 | `sqlite/search.rs` | both versions move together | +| `pub fn init_embeddings` (both feature variants) | 2355-2367 | `sqlite/search.rs` | both versions move together | +| `fn get_query_embedding` | 2368-2400 | `sqlite/search.rs` | private; uses `query_cache` field | +| `pub fn semantic_search` | 2401-2434 | `sqlite/search.rs` | | +| `pub fn hybrid_search` (feature on) | 2435-2452 | `sqlite/search.rs` | | +| `pub fn hybrid_search_filtered` (feature on) | 2453-2581 | `sqlite/search.rs` | | +| `pub fn hybrid_search` (feature off) | 2582-2593 | `sqlite/search.rs` | feature-gated stub | +| `pub fn hybrid_search_filtered` (feature off) | 2594-2635 | `sqlite/search.rs` | feature-gated stub | +| `fn keyword_search_with_scores` | 2636-2726 | `sqlite/search.rs` | | +| `fn semantic_search_raw` | 2727-2765 | `sqlite/search.rs` | | +| `pub fn generate_embeddings` | 2766-2819 | `sqlite/search.rs` | populates embeddings post hoc | +| `fn embedding_regeneration_candidates` | 2820-2891 | `sqlite/search.rs` | called by generate_embeddings | +| `pub fn query_at_time` | 2892-2933 | `sqlite/search.rs` | temporal query | +| `pub fn query_time_range` | 2934-3005 | `sqlite/search.rs` | temporal query | +| `fn embedding_model_matches_active` (associated fn) | 5652-5671 | `sqlite/search.rs` | static helper for hybrid_search; promoted to `pub(super)` (test references it) | +| `fn embedding_model_supports_matryoshka` | 5672-5677 | `sqlite/search.rs` | static helper | +| `fn embedding_vector_for_active_model` | 5678-5697 | `sqlite/search.rs` | static helper | +| `fn active_embedding_model_like_pattern` | 5698-5713 | `sqlite/search.rs` | static helper | + +### Scheduling: FSRS, decay, consolidation, review, promote/demote, suppression, gc, retention (-> `sqlite/scheduling.rs`) + +This is the busiest destination file. The grouping rule is: anything that +touches FSRS scheduling fields (`stability`, `difficulty`, `retrievability`, +`reps`, `lapses`, `retention_strength`, `retrieval_strength`) or the +review/decay/consolidation/gc lifecycle lives here. + +| Item | Lines | Destination | Notes | +|------|-------|-------------|-------| +| `pub fn mark_reviewed` | 1181-1275 | `sqlite/scheduling.rs` | FSRS state mutation | +| `pub fn strengthen_on_access` | 1276-1344 | `sqlite/scheduling.rs` | | +| `pub fn strengthen_batch_on_access` | 1345-1357 | `sqlite/scheduling.rs` | | +| `pub fn mark_memory_useful` | 1358-1377 | `sqlite/scheduling.rs` | | +| `fn log_access` | 1378-1393 | `sqlite/scheduling.rs` | private | +| `pub fn promote_memory` | 1394-1425 | `sqlite/scheduling.rs` | | +| `pub fn demote_memory` | 1426-1472 | `sqlite/scheduling.rs` | | +| `pub fn suppress_memory` | 1473-1504 | `sqlite/scheduling.rs` | active forgetting | +| `pub fn reverse_suppression` | 1505-1552 | `sqlite/scheduling.rs` | | +| `pub fn count_suppressed` | 1553-1567 | `sqlite/scheduling.rs` | | +| `pub fn get_recently_suppressed` | 1568-1594 | `sqlite/scheduling.rs` | | +| `pub fn apply_rac1_cascade` | 1595-1641 | `sqlite/scheduling.rs` | active forgetting cascade | +| `pub fn run_rac1_cascade_sweep` | 1642-1657 | `sqlite/scheduling.rs` | | +| `pub fn get_review_queue` | 1658-1681 | `sqlite/scheduling.rs` | | +| `pub fn preview_review` | 1682-1712 | `sqlite/scheduling.rs` | | +| `pub fn get_stats` | 1713-1841 | `sqlite/scheduling.rs` | reports retention/lapses/review counts; lives here for symmetry with the FSRS reporters next door | +| `pub fn apply_decay` | 3006-3095 | `sqlite/scheduling.rs` | core decay loop | +| `fn get_fsrs_w20` | 3096-3119 | `sqlite/scheduling.rs` | | +| `pub fn run_consolidation` | 3120-3407 | `sqlite/scheduling.rs` | | +| `fn auto_dedup_consolidation` | 3408-3538 | `sqlite/scheduling.rs` | called by run_consolidation | +| `fn compute_act_r_activations` | 3539-3605 | `sqlite/scheduling.rs` | called by run_consolidation | +| `fn prune_access_log` | 3606-3620 | `sqlite/scheduling.rs` | called by run_consolidation | +| `fn optimize_w20_if_ready` | 3621-3720 | `sqlite/scheduling.rs` | called by run_consolidation | +| `fn generate_missing_embeddings` | 3721-3740 | `sqlite/scheduling.rs` | called by run_consolidation | +| `pub fn get_state_transitions` | 5714-5748 | `sqlite/scheduling.rs` | audit trail tied to scheduling state | +| `pub fn get_avg_retention` | 5780-5792 | `sqlite/scheduling.rs` | | +| `pub fn get_retention_distribution` | 5794-5825 | `sqlite/scheduling.rs` | | +| `pub fn get_retention_trend` | 5826-5858 | `sqlite/scheduling.rs` | | +| `pub fn save_retention_snapshot` | 5859-5878 | `sqlite/scheduling.rs` | | +| `pub fn count_memories_below_retention` | 5879-5892 | `sqlite/scheduling.rs` | | +| `pub fn gc_below_retention` | 5893-5936 | `sqlite/scheduling.rs` | | +| `pub fn auto_promote_frequent_access` | 5937-5985 | `sqlite/scheduling.rs` | | +| `pub fn set_waking_tag` | 5986-5998 | `sqlite/scheduling.rs` | waking SWR tagging | +| `pub fn clear_waking_tags` | 5999-6011 | `sqlite/scheduling.rs` | | +| `pub fn get_waking_tagged_memories` | 6012-6028 | `sqlite/scheduling.rs` | | +| `pub fn get_recent_state_transitions` | 6105-6132 | `sqlite/scheduling.rs` | | + +### Graph: edges (memory_connections), neighbors, subgraph (-> `sqlite/graph.rs`) + +| Item | Lines | Destination | Notes | +|------|-------|-------------|-------| +| `pub fn save_connection` | 4180-4202 | `sqlite/graph.rs` | | +| `pub fn get_connections_for_memory` | 4203-4220 | `sqlite/graph.rs` | | +| `pub fn get_all_connections` | 4221-4236 | `sqlite/graph.rs` | | +| `pub fn strengthen_connection` | 4237-4259 | `sqlite/graph.rs` | | +| `pub fn apply_connection_decay` | 4260-4272 | `sqlite/graph.rs` | | +| `pub fn prune_weak_connections` | 4273-4284 | `sqlite/graph.rs` | | +| `fn row_to_connection` | 4285-4305 | `sqlite/graph.rs` | private | +| `pub fn get_most_connected_memory` | 6029-6046 | `sqlite/graph.rs` | | +| `pub fn get_memory_subgraph` | 6048-6103 | `sqlite/graph.rs` | calls `get_connections_for_memory`, `get_node`, `get_all_connections` -- all resolvable through `self` | + +### Domain (-> `sqlite/domain.rs`) + +Phase 1 keeps domain logic to JSON-column reads + classify stub. Phase 4 +expands this file. Keeping the file in the split so Phase 4 has an +obvious place to add to. + +| Item | Lines | Destination | Notes | +|------|-------|-------------|-------| +| `fn read_domain_columns` | 6167-6196 | `sqlite/domain.rs` | private helper used by trait `get`. Bump to `pub(super)` | + +The trait methods `list_domains` / `get_domain` / `upsert_domain` / +`delete_domain` / `classify` live in `sqlite/trait_impl.rs`; they +delegate to thin helpers that, in Phase 1, are essentially noops or +JSON reads. Phase 4 will move the substance of those methods into +`sqlite/domain.rs` as real functions. + +### Registry: embedding_model table (-> `sqlite/registry.rs`) + +| Item | Lines | Destination | Notes | +|------|-------|-------------|-------| +| `fn enforce_model` | 6203-6272 | `sqlite/registry.rs` | private helper used by trait `insert` and `update`. Bump to `pub(super)` | + +The trait methods `registered_model` and `register_model` themselves +live in `sqlite/trait_impl.rs`. Phase 2's `postgres/registry.rs` will +mirror this layout. + +### Intentions, Insights, Memory States, Consolidation History, Dream History, Backup (-> `sqlite/mod.rs`) + +These were tacked onto `SqliteMemoryStore` over time as the cognitive +modules needed somewhere to persist their state. They are not part of the +trait surface, they are not naturally grouped with crud/search/scheduling, +and they are each fairly small and self-contained. They live in `mod.rs` +under labelled sections (one big impl block can carry them) rather than +inventing extra files like `intentions.rs` and `insights.rs`. Postgres +will mirror this once Phase 5 picks up the work; for now they have no +peer. + +Rationale: every one of these methods writes to a single table, the +bodies are short, and grouping them next to the constructor preserves +"open `mod.rs` to see the whole struct" as the navigation default. + +| Item | Lines | Destination | Notes | +|------|-------|-------------|-------| +| `IntentionRecord` struct | 3747-3766 | `sqlite/mod.rs` | re-exported through `storage/mod.rs` | +| `InsightRecord` struct + `Default` | 3767-3797 | `sqlite/mod.rs` | re-exported | +| `ConnectionRecord` struct | 3799-3809 | `sqlite/mod.rs` | re-exported; consumed by `graph.rs` | +| `MemoryStateRecord` struct | 3811-3821 | `sqlite/mod.rs` | | +| `StateTransitionRecord` struct | 3823-3833 | `sqlite/mod.rs` | re-exported | +| `ConsolidationHistoryRecord` struct | 3835-3846 | `sqlite/mod.rs` | | +| `DreamHistoryRecord` struct | 3848-3866 | `sqlite/mod.rs` | re-exported | +| `pub fn save_intention` etc. (intention block) | 3874-4058 | `sqlite/mod.rs` | one impl block, in-section labelled | +| `fn row_to_intention` | 4023-4058 | `sqlite/mod.rs` | private | +| insights block (`save_insight`, `get_insights`, etc.) | 4065-4174 | `sqlite/mod.rs` | | +| `fn row_to_insight` | 4153-4173 | `sqlite/mod.rs` | private | +| memory-state block | 4306-4459 | `sqlite/mod.rs` | | +| `fn row_to_memory_state` | 4431-4459 | `sqlite/mod.rs` | private | +| consolidation-history block | 4465-4540 | `sqlite/mod.rs` | | +| dream-history block | 4546-4638 | `sqlite/mod.rs` | | +| `pub fn count_memories_since` | 4639-4651 | `sqlite/mod.rs` | | +| `fn scan_last_backup_timestamp` | 4652-4682 | `sqlite/mod.rs` | | +| `pub fn last_backup_timestamp` | 4683-4688 | `sqlite/mod.rs` | | +| `pub fn get_last_backup_timestamp` (associated) | 4689-4696 | `sqlite/mod.rs` | | +| `pub fn backup_to` | 5749-5774 | `sqlite/mod.rs` | sqlite VACUUM INTO; called by backup tool | + +### Portable export/import/sync (-> `sqlite/portable_sync.rs`) + +This is the second-largest destination after `scheduling.rs` and the most +self-contained. + +| Item | Lines | Destination | Notes | +|------|-------|-------------|-------| +| `pub fn export_portable_archive` | 4699-4755 | `sqlite/portable_sync.rs` | | +| `pub fn export_portable_archive_to_path` | 4756-4806 | `sqlite/portable_sync.rs` | | +| `pub fn import_portable_archive` | 4807-4978 | `sqlite/portable_sync.rs` | | +| `pub fn import_portable_archive_from_path` | 4979-4996 | `sqlite/portable_sync.rs` | | +| `pub fn sync_portable_archive` (generic over backend) | 4997-5025 | `sqlite/portable_sync.rs` | | +| `pub fn sync_portable_archive_file` | 5026-5030 | `sqlite/portable_sync.rs` | | +| `fn merge_portable_table` | 5031-5073 | `sqlite/portable_sync.rs` | | +| `fn merge_knowledge_nodes` | 5074-5126 | `sqlite/portable_sync.rs` | | +| `fn merge_sync_tombstones` | 5127-5204 | `sqlite/portable_sync.rs` | | +| `fn merge_deletion_tombstones` | 5205-5245 | `sqlite/portable_sync.rs` | | +| `fn merge_keyed_table` | 5246-5281 | `sqlite/portable_sync.rs` | | +| `fn row_references_locally_newer_node` | 5282-5302 | `sqlite/portable_sync.rs` | | +| `fn merge_append_only_table` | 5303-5338 | `sqlite/portable_sync.rs` | | +| `fn parent_rows_exist` | 5339-5370 | `sqlite/portable_sync.rs` | | +| `fn insert_or_replace_row` | 5371-5386 | `sqlite/portable_sync.rs` | | +| `fn merge_key_columns` | 5387-5398 | `sqlite/portable_sync.rs` | | +| `fn upsert_row_with_columns` | 5399-5446 | `sqlite/portable_sync.rs` | | +| `fn insert_row_with_columns` | 5447-5469 | `sqlite/portable_sync.rs` | | +| `fn merge_row_exists` | 5470-5487 | `sqlite/portable_sync.rs` | | +| `fn row_exists_by_values` | 5488-5507 | `sqlite/portable_sync.rs` | | +| `fn row_values_for_columns` | 5508-5528 | `sqlite/portable_sync.rs` | | +| `fn portable_value` | 5529-5540 | `sqlite/portable_sync.rs` | | +| `fn portable_text` | 5541-5551 | `sqlite/portable_sync.rs` | | +| `fn portable_timestamp` | 5552-5559 | `sqlite/portable_sync.rs` | | +| `fn parse_rfc3339_opt` | 5560-5565 | `sqlite/portable_sync.rs` | | +| `fn tombstone_timestamp` | 5566-5580 | `sqlite/portable_sync.rs` | | +| `fn current_schema_version` | 5581-5589 | `sqlite/portable_sync.rs` | static helper | +| `fn ensure_portable_import_target_empty` | 5590-5604 | `sqlite/portable_sync.rs` | static helper | +| `fn table_exists` | 5605-5613 | `sqlite/portable_sync.rs` | static helper | +| `fn table_row_count` | 5614-5618 | `sqlite/portable_sync.rs` | static helper | +| `fn table_columns` | 5619-5630 | `sqlite/portable_sync.rs` | static helper | +| `fn portable_value_from_ref` | 5631-5646 | `sqlite/portable_sync.rs` | static helper | +| `fn quote_ident` | 5647-5651 | `sqlite/portable_sync.rs` | static helper | + +### Trait helpers and trait impl (-> `sqlite/trait_impl.rs`) + +| Item | Lines | Destination | Notes | +|------|-------|-------------|-------| +| `fn node_to_record` | 6142-6164 | `sqlite/trait_impl.rs` | associated fn used only by trait body; co-locate | +| `impl LocalMemoryStore for SqliteMemoryStore` block | 6274-7110 | `sqlite/trait_impl.rs` | full trait impl; attribute changes from `#[async_trait::async_trait]` to whatever 0001a settles on (`#[trait_variant::make(...)]` is on the trait declaration; the impl block carries no attribute under trait_variant) | + +### Tests + +The current `#[cfg(test)] mod tests` block at lines 7112-8713 contains +**two** distinct test families: + +1. **Native API tests** (7120-8198): unit tests against the legacy + `pub fn` surface (`test_ingest_and_get`, `test_search`, `test_review`, + `test_delete`, `test_dream_history_save_and_get_last`, + `test_portable_archive_exact_round_trip`, `test_keyword_search_*`, + `test_concrete_search_*`, `test_purge_*`, etc.). +2. **Trait round-trip tests** (8200-8712, after the + `// ===== Phase 1: LocalMemoryStore trait round-trip tests =====` + banner): `trait_init_is_idempotent`, `trait_register_model_*`, + `trait_insert_*`, `trait_get_*`, `trait_update_*`, `trait_delete_*`, + `trait_fts_search_*`, `trait_hybrid_search_*`, + `trait_scheduling_*`, `trait_add_edge_*`, `trait_get_edges_*`, + `trait_remove_edge_*`, `trait_get_neighbors_*`, `trait_list_domains_*`, + `trait_upsert_*`, `trait_classify_*`, `trait_count_*`, + `trait_get_stats_*`, `trait_vacuum_*`, + `trait_insert_refuses_dimension_mismatch`. + +See the Test Relocation section below for the resolution. + +--- + +## Visibility Changes + +The split moves items into sibling files inside one module. Helpers that +were `fn ...` (i.e. crate-private but file-private under the current +layout, since the file *is* the module) need their visibility lifted +just enough that sibling files can call them. The principle is: smallest +bump that makes the call site compile. + +`pub(super)` is sufficient for everything below; nothing needs +`pub(crate)`. The trait `LocalMemoryStore` exposure does not change -- +sub-modules call `self.method(...)` on `SqliteMemoryStore`, which +resolves through the impl blocks defined in their own files; visibility +is automatic at impl-block scope. + +Items that need a visibility bump (currently private fn, become +`pub(super) fn`): + +- `parse_timestamp` (1012): called by `row_to_node` and by intention / + insight row mappers. +- `row_to_node` (1028): called by `crud.rs`, `search.rs`, + `scheduling.rs`. Static associated fn. +- `read_domain_columns` (6167): called by `trait_impl.rs`. +- `enforce_model` (6203): called by `trait_impl.rs`. +- `embedding_model_matches_active` (5652): currently called by + `hybrid_search_filtered`; tests also reference it. Has to remain + `pub(super) fn` and be `pub` only if the existing test names reach it + through a re-export. (See Test Relocation.) +- `embedding_model_supports_matryoshka` (5672): private; only callers in + `search.rs` after the move; stays `fn` (no bump needed). +- `embedding_vector_for_active_model` (5678): same as the matches + function -- a test references it. Bump to `pub(super)`. +- `active_embedding_model_like_pattern` (5698): private; only used by + search; stays `fn`. +- `generate_embedding_for_node` (952): currently called by `ingest` and + `update_node_content`. Both move to `crud.rs`; stays `fn`. +- `get_query_embedding` (2368): only used inside `search.rs`; stays `fn`. +- `keyword_search_with_scores` (2636): only used inside `search.rs`; + stays `fn`. +- `semantic_search_raw` (2727): only used inside `search.rs`; stays `fn`. +- `embedding_regeneration_candidates` (2820): used by + `generate_embeddings`; both move to `search.rs`; stays `fn`. The + existing test (line 7167) references it through `storage.method()`, + which will continue to work because the test file can move with it. +- `log_access` (1378): private to `scheduling.rs`; stays `fn`. +- All the `auto_dedup_consolidation` / `compute_act_r_activations` / + `prune_access_log` / `optimize_w20_if_ready` / + `generate_missing_embeddings` helpers (3408-3740): private to + `scheduling.rs`; stays `fn`. +- `row_to_intention` / `row_to_insight` / `row_to_memory_state` / + `row_to_connection`: all stay private in their destination file (only + one caller each). +- All `merge_*` / `portable_*` / `parse_rfc3339_opt` / `quote_ident`: + private to `portable_sync.rs`; stays `fn`. +- `node_exists` (1988): private to `crud.rs`; stays `fn`. +- `record_sync_tombstone` (1997): private to `crud.rs`; stays `fn`. +- `get_fsrs_w20` (3096): private to `scheduling.rs`; stays `fn`. + +Items already `pub fn` (or `pub(crate) fn`) stay as they are -- no +visibility regression. + +Field visibility on `SqliteMemoryStore` itself: currently all fields are +private. The sub-modules access them via `self.field`. Because impl +blocks for `SqliteMemoryStore` are written in sibling files of the same +module, `self.field` reaches private fields without a visibility bump. +**No field visibility changes are required.** Confirm this during the +first motion commit; if Rust disagrees, mark the relevant fields +`pub(super)` and document in the commit message. + +--- + +## Public Re-exports + +`crates/vestige-core/src/storage/mod.rs` currently exports: + +```rust +mod memory_store; +mod migrations; +mod portable; +mod sqlite; + +pub use memory_store::{...}; +pub use migrations::MIGRATIONS; +pub use portable::{...}; +pub use sqlite::{ + ConnectionRecord, ConsolidationHistoryRecord, DreamHistoryRecord, FilePortableSyncBackend, + InsightRecord, IntentionRecord, PortableSyncBackend, PortableSyncReport, Result, + SmartIngestResult, SqliteMemoryStore, StateTransitionRecord, StorageError, +}; + +pub type Storage = SqliteMemoryStore; +``` + +After the split, `mod sqlite;` resolves to the new directory module +(`storage/sqlite/mod.rs`). The `pub use sqlite::{...}` block resolves +against the items re-exported by `storage/sqlite/mod.rs`. + +`storage/sqlite/mod.rs` therefore needs the same names visible at its +top level. Add at the end of `mod.rs`: + +```rust +mod crud; +mod search; +mod scheduling; +mod graph; +mod domain; +mod registry; +mod portable_sync; +mod trait_impl; + +pub use portable_sync::{FilePortableSyncBackend, PortableSyncBackend, PortableSyncReport}; +// SqliteMemoryStore, StorageError, Result, SmartIngestResult, IntentionRecord, +// InsightRecord, ConnectionRecord, StateTransitionRecord, +// ConsolidationHistoryRecord, DreamHistoryRecord are defined in mod.rs itself, +// so they are already in scope and do not need a re-export. +``` + +The `crates/vestige-core/src/storage/mod.rs` file does not change. The +`pub type Storage = SqliteMemoryStore;` alias keeps working. + +If `cargo build` complains that `storage/mod.rs` cannot resolve a name +in its `pub use sqlite::{...}` block, the fix is to add the missing name +to `sqlite/mod.rs`'s re-export tail; no change to `storage/mod.rs`. + +--- + +## Test Relocation + +Two test families, two destinations. + +**Native API tests** (current lines 7120-8198) cover the legacy `pub fn` +surface. They live close to their subject: + +- Tests that touch the constructor, common helpers, and shared setup + (`create_test_storage`, `create_test_storage_at`, + `test_storage_creation`, `test_get_last_backup_timestamp_no_panic`) + move to `sqlite/mod.rs` in a `#[cfg(test)] mod tests` block. +- `test_ingest_and_get`, `test_delete`, + `test_purge_scrubs_insight_json_orphans_children_and_writes_tombstone` + go to `sqlite/crud.rs` as a `#[cfg(test)] mod tests` block. +- `test_search`, `test_keyword_search_with_include_types`, + `test_keyword_search_with_exclude_types`, + `test_include_types_takes_precedence_over_exclude`, + `test_type_filter_with_no_matches_returns_empty`, + `test_hybrid_search_backward_compat`, + `test_concrete_search_literal_identifier_lands_first`, + `test_embedding_model_family_matching`, + `test_embedding_regeneration_candidates_include_entire_mismatched_corpus` + go to `sqlite/search.rs`. +- `test_review` goes to `sqlite/scheduling.rs`. +- `test_dream_history_save_and_get_last`, `test_dream_history_empty`, + `test_count_memories_since` go to `sqlite/mod.rs` (history tables live + there). +- All `test_portable_*` go to `sqlite/portable_sync.rs`. +- `test_file_portable_sync_round_trips_between_devices` goes to + `sqlite/portable_sync.rs`. + +**Trait round-trip tests** (current lines 8200-8712) test the +`LocalMemoryStore` trait impl. Two viable layouts: + +A. Co-locate with the impl in `sqlite/trait_impl.rs` (one big + `#[cfg(test)] mod trait_tests`). +B. Keep them as a single `tests.rs` file in the sqlite directory. + +**Decision: A.** Co-locate. The trait round-trip tests are explicitly +testing the `impl LocalMemoryStore for SqliteMemoryStore` block; +co-location means a reader who edits the trait impl sees its tests in +the same file. Option B would mean two places to look every time a +trait method changes shape. For an 8K-line collapse the tradeoff +favours co-location. + +Concretely: `sqlite/trait_impl.rs` ends with a +`#[cfg(test)] mod trait_tests { ... }` block that contains all 30+ +`trait_*` tests, plus the shared `make_record`, `rt`, and small helpers +defined inside the current test mod for trait tests (lines 8208-8226). + +--- + +## Commit Sequence + +Each commit moves one logical group. After each commit: + +``` +cargo build -p vestige-core +cargo test -p vestige-core +cargo clippy -p vestige-core -- -D warnings +``` + +must pass. Order is chosen so that each move is small, the next move +does not depend on the previous having grown surprising visibility, and +the largest / riskiest move (the trait impl, with the new +trait_variant attribute) lands last. + +| # | Commit | What moves | Tests touched | +|---|--------|-----------|----------------| +| 1 | `refactor(sqlite): scaffold sqlite/ directory` | Convert `sqlite.rs` -> `sqlite/mod.rs` verbatim (rename + create empty sibling files `crud.rs`, `search.rs`, `scheduling.rs`, `graph.rs`, `domain.rs`, `registry.rs`, `portable_sync.rs`, `trait_impl.rs` each with `use super::*;`). At this point `mod.rs` declares the new modules but they are empty. | None move. Build proves the rename works. | +| 2 | `refactor(sqlite): split out portable sync` | Move all `merge_*`, `portable_*`, `export_*`, `import_*`, `sync_*` items + `MergeWrite`, `PortableSyncBackend`, `FilePortableSyncBackend`, `PortableSyncReport`, `PortableMergeState`, `PORTABLE_TABLES`, `PORTABLE_USER_DATA_TABLES`, helper statics into `sqlite/portable_sync.rs`. Add `pub use portable_sync::{...}` in `mod.rs` for the public types. | `test_portable_*` and `test_file_portable_sync_round_trips_between_devices` move too. | +| 3 | `refactor(sqlite): split out graph / connections` | Move `save_connection`, `get_connections_for_memory`, `get_all_connections`, `strengthen_connection`, `apply_connection_decay`, `prune_weak_connections`, `row_to_connection`, `get_most_connected_memory`, `get_memory_subgraph` to `sqlite/graph.rs`. | None move (no native graph tests; trait edge tests still in trait_tests). | +| 4 | `refactor(sqlite): split out scheduling / fsrs / consolidation` | Move all items listed in the Scheduling row to `sqlite/scheduling.rs`. | `test_review` moves. | +| 5 | `refactor(sqlite): split out search / fts / semantic / hybrid` | Move all items listed in the Search row to `sqlite/search.rs`. Add `pub(super)` to the four `embedding_model_*` helpers that tests reference. | `test_search`, `test_keyword_search_*`, `test_include_types_*`, `test_type_filter_*`, `test_hybrid_search_*`, `test_concrete_search_*`, `test_embedding_model_family_matching`, `test_embedding_regeneration_candidates_include_entire_mismatched_corpus` move. | +| 6 | `refactor(sqlite): split out crud / ingest / get / update / delete / purge` | Move `ingest`, `smart_ingest`, `get_node`, `update_node_content`, `delete_node`, `purge_node`, `get_all_nodes`, `get_nodes_by_type_and_tag`, `node_exists`, `record_sync_tombstone`, `generate_embedding_for_node`, `get_node_embedding`, `get_all_embeddings`, `PurgeReport` to `sqlite/crud.rs`. Bump `row_to_node` and `parse_timestamp` to `pub(super) fn` in `mod.rs`. | `test_ingest_and_get`, `test_delete`, `test_purge_scrubs_insight_json_orphans_children_and_writes_tombstone` move. | +| 7 | `refactor(sqlite): split out registry helper` | Move `enforce_model` to `sqlite/registry.rs`, bumped to `pub(super)`. | None move. | +| 8 | `refactor(sqlite): split out domain helper` | Move `read_domain_columns` to `sqlite/domain.rs`, bumped to `pub(super)`. | None move. | +| 9 | `refactor(sqlite): split out trait impl + tests` | Move `node_to_record` and the full `impl LocalMemoryStore for SqliteMemoryStore` block to `sqlite/trait_impl.rs`. Move the entire trait round-trip test module (lines 8200-8712, including `make_record` and `rt` helpers) to a `#[cfg(test)] mod trait_tests` block at the bottom of `trait_impl.rs`. This is the commit where the trait_variant attribute (from sub-plan 0001a) is observed: the impl block on `SqliteMemoryStore` uses whatever syntax the rewritten trait expects (no `#[async_trait::async_trait]`). | All `trait_*` tests move. | + +Commit 1 is the only commit that creates new files; the rest move +existing code into them. Reviewers can bisect through this list to +find any silent-semantic change. + +--- + +## Verification + +Run after every commit. All three must pass before pushing: + +``` +cargo build -p vestige-core +cargo test -p vestige-core +cargo clippy -p vestige-core -- -D warnings +``` + +The Phase 1 amendment branch must also build with the no-default-features +configuration that the release binary uses for the alternative feature +set: + +``` +cargo build -p vestige-core --no-default-features +cargo test -p vestige-core --no-default-features +``` + +Some of the methods being moved (`get_node_embedding`, `is_embedding_ready`, +`init_embeddings`, the feature-on/feature-off `hybrid_search` pair) have +two definitions guarded by feature flags. The split must preserve both +copies in the same destination file with their existing `#[cfg(...)]` +attributes; the no-default-features build confirms. + +After the last commit, run the workspace-wide check that Phase 1 promised: + +``` +cargo build --workspace +cargo test --workspace +``` + +This catches downstream consumers (`vestige-mcp`, `vestige`, +`vestige-restore`) that might depend on a specific module path (they +should not -- they import from `crate::storage::SqliteMemoryStore` and +the re-exports in `storage/mod.rs` -- but the workspace build is the +authoritative confirmation). + +--- + +## Acceptance Criteria + +1. `crates/vestige-core/src/storage/sqlite.rs` no longer exists. In its + place is `crates/vestige-core/src/storage/sqlite/` with the eight + files listed in the Target Layout section, each below 2000 lines. +2. `crates/vestige-core/src/storage/mod.rs` is unchanged (or + functionally unchanged -- the `pub use sqlite::{...}` block contains + the same identifiers in the same order). +3. Every cognitive module and binary in the workspace + (`vestige-core`, `vestige-mcp`, `vestige`, `vestige-restore`) + compiles with no source edits other than the ones in + `crates/vestige-core/src/storage/sqlite/`. +4. `cargo build -p vestige-core`, + `cargo test -p vestige-core`, + `cargo clippy -p vestige-core -- -D warnings`, + `cargo build -p vestige-core --no-default-features`, and + `cargo test -p vestige-core --no-default-features` all pass at the + end of every commit in the sequence (bisectability). +5. `cargo test --workspace` matches the Phase 1 baseline test count + (758 tests, of which 352 are in `vestige-core`). No new tests are + added by this sub-plan; no existing test is renamed or deleted. +6. The on-disk SQLite schema is unchanged. A live database created on + the pre-split build opens cleanly on the post-split build and round + trips a memory. +7. `git log --follow` works for at least one method in each destination + file (i.e. `git mv` was used where the line range constitutes most + of the file content of the destination, otherwise a `git log -p` + on the new file shows the history before the rename through the + block-move detection that recent `git log` versions support). +8. No public symbol disappears from `crate::storage::*`. A reviewer can + verify with: + ``` + cargo doc -p vestige-core --no-deps + ``` + before and after the split, and `diff` the generated + `target/doc/vestige_core/storage/index.html` lists. + +--- + +## Non-Goals (explicit) + +- No public API change. The trait surface (`LocalMemoryStore`, + `MemoryStore`), the legacy `pub fn` surface on `SqliteMemoryStore`, + the re-exports through `storage/mod.rs`, and the `pub type Storage = + SqliteMemoryStore;` alias are all preserved. +- No behavioural change. No SQL is rewritten, no FSRS parameter is + retuned, no embedding model is touched, no migration is added. +- No new tests. Tests move with their subject; no new tests are + written. +- No clippy fix-ups that pre-date this sub-plan. If `cargo clippy + -- -D warnings` was passing before the split, it must continue to + pass; if it was not passing, the failures stay where they are and + are addressed in a separate commit (out of scope here). +- No removal of the `pub type Storage = SqliteMemoryStore;` BC alias. + That happens at the end of Phase 4 per ADR 0001. +- No reorganisation of `storage/memory_store.rs`, + `storage/migrations.rs`, or `storage/portable.rs`. Those files are + out of scope; the split is private to `storage/sqlite/`. + +--- + +## Risks and Mitigations + +| Risk | Mitigation | +|------|------------| +| Silent semantic change introduced by a motion commit | Per-commit `cargo test -p vestige-core` keeps the bisect window to a single commit. Reviewer bisects with `cargo test -p vestige-core` as the witness. | +| Sibling-file `self.field` accesses fail because Rust enforces module visibility on tuple-struct or named fields | Confirmed: associated impl blocks in sibling files of the same `mod sqlite` reach private fields. If the compiler disagrees, bump the affected fields to `pub(super)` in `mod.rs` and note the bump in the commit message. | +| Test-only helpers (`create_test_storage`, `make_record`, `rt`) get duplicated across test modules | Lift them once into a `#[cfg(test)] mod test_support { ... }` sub-module in `sqlite/mod.rs` and re-export with `pub(super) use`. Do this in commit 1 (scaffold), not later. | +| `#[cfg(all(feature = "embeddings", feature = "vector-search"))]` items end up in `mod.rs` where they pollute the shared layer | Audit during commit 5 (search split); items behind both feature flags belong in `search.rs`. The `query_cache` field stays in `mod.rs` because the struct definition is there; the field declaration is feature-gated and that gate moves with the struct as-is. | +| `git log --follow` blame chains break on the moved methods | Use `git mv sqlite.rs sqlite/mod.rs` in commit 1 so commit 1 looks like a rename (`git log --follow` keeps working). Subsequent commits are content moves inside the module; modern `git log --follow -M -C` heuristics still trace the lines. Reviewers who need pristine blame should bisect to before commit 1. | +| Sub-plan 0001a (trait rewrite) has not landed when this work starts | Block: do not start commits 1-9 until 0001a is on the same branch (`feat/storage-trait-phase1`) and tests pass. `trait_impl.rs` lands the new attribute in commit 9; if 0001a is not in, commit 9 fails. | + +--- + +## Self-Contained Brief (for /goal) + +A fresh Claude Code session can execute this sub-plan by: + +1. Reading this file end to end. +2. Reading `crates/vestige-core/src/storage/sqlite.rs` (the file to be + split) in full, using line ranges from the Mapping Table to confirm + the current shape matches the brief. +3. Reading `crates/vestige-core/src/storage/mod.rs` (the re-export + surface that must continue to work). +4. Reading `crates/vestige-core/src/storage/memory_store.rs` (the + trait surface that `trait_impl.rs` implements). +5. Confirming sub-plan 0001a has landed on the current branch by + checking that `memory_store.rs` no longer carries + `#[async_trait::async_trait]` on the trait declaration. +6. Working through the Commit Sequence in order, running the + Verification commands after each commit. + +The session does not need to read ADR 0002 or the master Phase 2 plan +to do this work. The split is purely mechanical relative to the +mapping table above. diff --git a/docs/plans/0001c-async-trait-sunset.md b/docs/plans/0001c-async-trait-sunset.md new file mode 100644 index 0000000..f9d8938 --- /dev/null +++ b/docs/plans/0001c-async-trait-sunset.md @@ -0,0 +1,847 @@ +# Sub-Plan 0001c: Sunset the `async-trait` crate dependency + +**Status**: Draft +**Branch**: `feat/storage-trait-phase1` (Phase 1 amendment, PR A) +**Depends on**: +- `0001a-trait-rewrite.md` (rewrites `MemoryStore` / `LocalMemoryStore` and + the SQLite impl; lands first) +- `0001b-sqlite-split.md` (moves `sqlite.rs` into `sqlite/`; lands second) + +**Related**: `docs/adr/0002-phase-2-execution.md` (decision D1 closing line: +"async-trait dependency stays in Cargo.toml only if other code uses it; +otherwise removed"). This sub-plan operationalises the removal. + +--- + +## Context + +This is the third and final Phase 1 amendment sub-plan. Sub-plan `0001a` +rewrote `MemoryStore` / `LocalMemoryStore` using +`#[trait_variant::make(MemoryStore: Send)]` and dropped the +`#[async_trait::async_trait]` attribute from the SQLite impl block. +Sub-plan `0001b` then split `sqlite.rs` into a `sqlite/` directory; the +trait impl now lives in `sqlite/trait_impl.rs`. After `0001a` lands, the +only remaining `async_trait` usage in the workspace is the embedder pair +(`embedder/mod.rs` declares the trait; `embedder/fastembed.rs` implements +it). This sub-plan rewrites those two files following the exact pattern +from `0001a`, then removes `async-trait = "0.1"` from +`crates/vestige-core/Cargo.toml`. End state: zero `async_trait` references +anywhere under `crates/`, zero direct dependency on the `async-trait` +crate, workspace tests and clippy green. + +The rewrite is mechanically tiny -- one trait declaration, one impl block, +one Cargo.toml line -- but it is gated behind `0001a` and `0001b` so the +trait-rewrite pattern is already settled and so the SQLite trait impl +attribute has already been dropped. Doing the embedder rewrite without +that pre-work would leave the `async-trait` dep behind for the SQLite +side and force the Cargo.toml deletion into a separate commit later. + +--- + +## Scope + +### In scope + +- Rewrite `LocalEmbedder` declaration in + `crates/vestige-core/src/embedder/mod.rs` to use + `#[trait_variant::make(Embedder: Send)] pub trait LocalEmbedder`. +- Delete the `pub use LocalEmbedder as Embedder;` alias from the same file. + The `Embedder` symbol becomes the trait that `trait_variant::make` emits + at the same module path, so the existing + `pub use embedder::{Embedder, ..., LocalEmbedder};` line in + `crates/vestige-core/src/lib.rs:167` keeps working untouched. +- Drop the `#[async_trait::async_trait]` attribute from the + `FastembedEmbedder` impl block in + `crates/vestige-core/src/embedder/fastembed.rs`. +- Update doc comments on the trait declaration to describe + `trait_variant` rather than `async_trait`. +- Remove `async-trait = "0.1"` from + `crates/vestige-core/Cargo.toml` (line 119 area). Use + `cargo rm async-trait` from inside the crate directory. +- Verify with `grep -rn "async_trait" crates/` returning zero hits. + +### Out of scope + +- Any change to the `MemoryStore` trait or `SqliteMemoryStore` impl; + those were handled by `0001a`. +- Any file moves in `embedder/` (no parallel of `0001b` is required; + `embedder/` already has the `mod.rs` + `fastembed.rs` shape). +- Touching `crates/vestige-mcp/` or any cognitive module. None of them + hold `Arc` or `Box` in production. +- Renaming the `Embedder` / `LocalEmbedder` symbols or changing the + re-exports in `crates/vestige-core/src/lib.rs`. + +--- + +## Prerequisites + +### State assumed at start + +- `0001a` is merged onto the branch. After `0001a`: + - `crates/vestige-core/src/storage/memory_store.rs` declares + `#[trait_variant::make(MemoryStore: Send)] pub trait LocalMemoryStore`. + - The SQLite impl block has no `#[async_trait::async_trait]` attribute. + - `grep -rn async_trait crates/` returns exactly three hits, all in + `crates/vestige-core/src/embedder/` (two in `mod.rs`, one in + `fastembed.rs`), and one Cargo.toml hit. +- `0001b` is merged onto the branch. After `0001b`: + - `crates/vestige-core/src/storage/sqlite.rs` no longer exists as a + single file; the impl lives in `crates/vestige-core/src/storage/sqlite/trait_impl.rs`. + - The embedder files are untouched. + +### Required crates + +| Crate | Version | Action | +|----------------|---------|-----------------------------------------------------------------| +| `trait-variant`| `0.1` | Already declared (line 117 of Cargo.toml). Verify present. | +| `async-trait` | `0.1` | Remove. Only the two embedder files still use it after `0001a`. | + +### Workspace-wide audit before starting + +Run from `/home/delandtj/prppl/vestige-phase2/` (or the equivalent +worktree where this sub-plan executes): + +```bash +grep -rn "async_trait\|async-trait" crates/ tests/ +``` + +Expected hits before this sub-plan starts (after `0001a` + `0001b`): + +``` +crates/vestige-core/Cargo.toml:119:async-trait = "0.1" +crates/vestige-core/src/embedder/mod.rs:24:/// `#[async_trait::async_trait]` makes every `async fn` return a +crates/vestige-core/src/embedder/mod.rs:27:#[async_trait::async_trait] +crates/vestige-core/src/embedder/mod.rs:56:/// Both names refer to the same `async_trait`-annotated trait. +crates/vestige-core/src/embedder/fastembed.rs:44:#[async_trait::async_trait] +``` + +Five hits across two source files and one Cargo.toml. After this sub-plan, +the same grep must return zero hits. + +```bash +grep -rn "async-trait\|async_trait" --include="Cargo.toml" crates/ +``` + +Expected: exactly one hit (`crates/vestige-core/Cargo.toml:119`). No other +workspace crate declares `async-trait` as a direct dependency. This is +the precondition that lets us delete the line cleanly. + +--- + +## Files Touched + +### Trait declaration (vestige-core) + +| File | Lines (approx) | Change | +|-------------------------------------------------|----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `crates/vestige-core/src/embedder/mod.rs` | 21-57 | Replace `#[async_trait::async_trait] pub trait LocalEmbedder: Send + Sync + 'static` with `#[trait_variant::make(Embedder: Send)] pub trait LocalEmbedder: Sync + 'static`. Delete the `pub use LocalEmbedder as Embedder;` alias on line 57. Update doc comments (lines 21-26, 55-56). | + +### Impl block (vestige-core) + +| File | Lines (approx) | Change | +|-------------------------------------------------|----------------|--------------------------------------------------------------------------------------------------------------| +| `crates/vestige-core/src/embedder/fastembed.rs` | 44 | Delete the `#[async_trait::async_trait]` attribute. Keep the `impl LocalEmbedder for FastembedEmbedder { ... }` body verbatim. No `Box::pin`, no `'async_trait` lifetimes, no manual `Pin>`. | + +### Other Embedder impls + +None. `grep -rn "impl.*LocalEmbedder\|impl.*Embedder for" crates/ tests/` +returns exactly one production hit: +`crates/vestige-core/src/embedder/fastembed.rs:45: impl LocalEmbedder for FastembedEmbedder`. +There is no test mock implementing `Embedder` in the test tree (the only +test that touches the trait, `tests/phase_1/embedder_trait.rs`, uses the +concrete `FastembedEmbedder` boxed as `Box`). + +### Call sites (production) + +Verified by: + +```bash +grep -rn "dyn Embedder\|dyn LocalEmbedder" crates/ tests/ --include="*.rs" +grep -rn "Box\|Arc" crates/ tests/ --include="*.rs" +grep -rn "use.*Embedder" crates/ tests/ --include="*.rs" +``` + +Production call sites that may need verification (and the expected change +for each, even though we have already verified that none need an edit): + +| File | Use | Required change | +|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|-----------------| +| `crates/vestige-core/src/lib.rs:167` | `pub use embedder::{Embedder, EmbedderError, EmbedderResult, FastembedEmbedder, LocalEmbedder};` | None. Both names still exist at `crate::embedder::*` after the rewrite; `Embedder` is now the `trait_variant`-generated trait, `LocalEmbedder` is the source-of-truth trait. The re-export keeps resolving. | +| `crates/vestige-core/src/embedder/fastembed.rs:7` | `use super::{EmbedderError, EmbedderResult, LocalEmbedder};` | None. `LocalEmbedder` is still the source-of-truth trait name. | +| `crates/vestige-core/src/embedder/mod.rs:5` | `pub use fastembed::FastembedEmbedder;` | None. Concrete type, untouched. | +| `crates/vestige-mcp/src/**` | No file imports `Embedder` or `LocalEmbedder` by name; none hold `Arc` or `Box`. | None. Verified by grep returning empty for `dyn Embedder` and `dyn LocalEmbedder` under `crates/vestige-mcp/`. | +| Cognitive modules under `crates/vestige-core/src/advanced/` and `crates/vestige-core/src/neuroscience/` | No file imports `Embedder` or `LocalEmbedder` by name. `advanced/adaptive_embedding.rs` defines its own unrelated `AdaptiveEmbedder` struct. | None. The name collision is purely surface-level; the two types live in different modules and never resolve to each other. | +| `crates/vestige-core/src/embeddings/**` | No file imports `Embedder` or `LocalEmbedder`. The `EmbeddingService` struct is what `FastembedEmbedder` wraps internally. | None. | + +The production audit returns zero files that need editing. + +### Call sites (tests) + +| File | Lines | Use | Required change | +|------------------------------------------------------------|-------|--------------------------------------------------------------------|-----------------| +| `tests/phase_1/embedder_trait.rs` | 3, 19 | `use vestige_core::embedder::{Embedder, FastembedEmbedder};`
    `let e: Box = Box::new(FastembedEmbedder::new());` | None. `Embedder` is the `trait_variant`-generated Send variant; `Box` keeps compiling. `FastembedEmbedder` implements `LocalEmbedder`; the blanket `impl Embedder for T` that `trait_variant::make` emits gives the boxing for free. | + +The test audit returns zero files that need editing. + +### Cargo dependency cleanup + +| File | Lines | Change | +|-------------------------------------|-----------|-----------------------------------------------------------------------------------------------------| +| `crates/vestige-core/Cargo.toml` | 119 | Remove `async-trait = "0.1"`. Run `cargo rm async-trait` from inside `crates/vestige-core/` so `Cargo.lock` updates atomically with the manifest. | + +### Documentation + +| File | Change | +|---------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------| +| `crates/vestige-core/src/embedder/mod.rs` | Rewrite the trait-level doc comment (lines 21-26) and the `pub use` doc comment (lines 55-56) to describe `trait_variant`, not `async_trait`. See "Trait declaration rewrite" below for the exact new text. | +| `CLAUDE.md` | No change. The repo-level architecture notes do not name the trait attribute. | + +--- + +## Trait Declaration Rewrite + +### Before (state after `0001a` and `0001b` land) + +`crates/vestige-core/src/embedder/mod.rs:1-58`: + +```rust +//! Text-to-vector encoding trait. Pluggable per-install. + +mod fastembed; + +pub use fastembed::FastembedEmbedder; + +/// Error returned by every `Embedder` method. +#[non_exhaustive] +#[derive(Debug, thiserror::Error)] +pub enum EmbedderError { + #[error("embedder initialization failed: {0}")] + Init(String), + #[error("embedding generation failed: {0}")] + EmbedFailed(String), + #[error("invalid input: {0}")] + InvalidInput(String), +} + +pub type EmbedderResult = std::result::Result; + +/// Pluggable embedder. The storage layer NEVER calls fastembed directly; +/// callers compute vectors via this trait and pass them into `MemoryStore`. +/// +/// `#[async_trait::async_trait]` makes every `async fn` return a +/// `Pin>`, which is required for `Box` +/// and `Arc` to be dyn-compatible. +#[async_trait::async_trait] +pub trait LocalEmbedder: Send + Sync + 'static { + async fn embed(&self, text: &str) -> EmbedderResult>; + + fn model_name(&self) -> &str; + + fn dimension(&self) -> usize; + + /// Stable blake3 hash of (model_name || dimension || vestige-core crate version). + /// Lowercase hex, 64 chars. + /// + /// Used by `MemoryStore::register_model` to detect silent model drift + /// (e.g. a fastembed minor upgrade that changes vector output). + fn model_hash(&self) -> String; + + async fn embed_batch(&self, texts: &[&str]) -> EmbedderResult>>; + + /// Returns the `ModelSignature` describing this embedder. Convenience + /// wrapper over the three accessors above. + fn signature(&self) -> crate::storage::ModelSignature { + crate::storage::ModelSignature { + name: self.model_name().to_string(), + dimension: self.dimension(), + hash: self.model_hash(), + } + } +} + +/// Type alias: `Embedder` is the dyn-compatible, Send+Sync variant. +/// Both names refer to the same `async_trait`-annotated trait. +pub use LocalEmbedder as Embedder; +``` + +### After + +`crates/vestige-core/src/embedder/mod.rs:1-55` (approximately): + +```rust +//! Text-to-vector encoding trait. Pluggable per-install. + +mod fastembed; + +pub use fastembed::FastembedEmbedder; + +/// Error returned by every `Embedder` method. +#[non_exhaustive] +#[derive(Debug, thiserror::Error)] +pub enum EmbedderError { + #[error("embedder initialization failed: {0}")] + Init(String), + #[error("embedding generation failed: {0}")] + EmbedFailed(String), + #[error("invalid input: {0}")] + InvalidInput(String), +} + +pub type EmbedderResult = std::result::Result; + +/// Pluggable embedder. The storage layer NEVER calls fastembed directly; +/// callers compute vectors via this trait and pass them into `MemoryStore`. +/// +/// `LocalEmbedder` is the source-of-truth trait. The +/// `#[trait_variant::make(Embedder: Send)]` attribute auto-generates an +/// `Embedder` variant whose returned futures are `Send`, so +/// `Box` and `Arc` are usable on tokio/axum +/// runtimes, while `Box` remains usable on single- +/// threaded executors and thread-local backends. +/// +/// Every method is native async-fn-in-trait (stable on MSRV 1.91); no +/// per-call heap allocation, no boxed futures at the static-dispatch +/// boundary. +#[trait_variant::make(Embedder: Send)] +pub trait LocalEmbedder: Sync + 'static { + async fn embed(&self, text: &str) -> EmbedderResult>; + + fn model_name(&self) -> &str; + + fn dimension(&self) -> usize; + + /// Stable blake3 hash of (model_name || dimension || vestige-core crate version). + /// Lowercase hex, 64 chars. + /// + /// Used by `MemoryStore::register_model` to detect silent model drift + /// (e.g. a fastembed minor upgrade that changes vector output). + fn model_hash(&self) -> String; + + async fn embed_batch(&self, texts: &[&str]) -> EmbedderResult>>; + + /// Returns the `ModelSignature` describing this embedder. Convenience + /// wrapper over the three accessors above. + fn signature(&self) -> crate::storage::ModelSignature { + crate::storage::ModelSignature { + name: self.model_name().to_string(), + dimension: self.dimension(), + hash: self.model_hash(), + } + } +} +``` + +### Both halves of the macro-generated output (for reviewer clarity) + +`trait_variant::make(Embedder: Send)` expands the source-of-truth +`LocalEmbedder` declaration above into the equivalent of: + +```rust +// 1. The source-of-truth trait, exactly as written. +pub trait LocalEmbedder: Sync + 'static { + fn embed(&self, text: &str) -> impl Future>>; + fn model_name(&self) -> &str; + fn dimension(&self) -> usize; + fn model_hash(&self) -> String; + fn embed_batch(&self, texts: &[&str]) -> impl Future>>>; + fn signature(&self) -> crate::storage::ModelSignature { /* default impl unchanged */ } +} + +// 2. The generated Send variant. +pub trait Embedder: Sync + 'static { + fn embed(&self, text: &str) -> impl Future>> + Send; + fn model_name(&self) -> &str; + fn dimension(&self) -> usize; + fn model_hash(&self) -> String; + fn embed_batch(&self, texts: &[&str]) -> impl Future>>> + Send; + fn signature(&self) -> crate::storage::ModelSignature { /* default impl unchanged */ } +} + +// 3. The blanket impl that wires any LocalEmbedder + Send through to Embedder. +impl Embedder for T +where + T: LocalEmbedder + Send, + // (all returned futures of LocalEmbedder's async fns are required to be Send, + // which is satisfied for FastembedEmbedder -- see "Risks" below) +{ /* forwarders */ } +``` + +Notes: + +- The `pub use LocalEmbedder as Embedder;` line on the current + `embedder/mod.rs:57` is **deleted** entirely. `Embedder` is now the + trait that `trait_variant::make` emits at the same module path; the + re-export in `crates/vestige-core/src/lib.rs:167` + (`pub use embedder::{Embedder, ..., LocalEmbedder};`) keeps resolving + unchanged. +- `Sync + 'static` on `LocalEmbedder` (and no `Send` bound on the trait + itself) mirrors the `0001a` pattern for `LocalMemoryStore`. The current + trait carries `Send + Sync + 'static`; the rewrite drops the `Send` + bound from the local variant. `Box` is `Sync` but + not `Send`; `Box` (the generated variant) is `Send + Sync`. +- `trait_variant` 0.1 does **not** require any attribute on the impl + block. The attribute lives only on the trait declaration. See next + section. + +--- + +## Impl Block Migration + +`trait_variant` 0.1 attaches the attribute only to the trait declaration. +The impl side is plain `impl LocalEmbedder for FastembedEmbedder`; no +attribute on the impl, no `#[trait_variant::make(Embedder: Send)]` on the +impl block. The macro auto-generates the blanket +`impl Embedder for T`, so any concrete type that +implements `LocalEmbedder` automatically also implements `Embedder` +provided it is `Send`. + +`FastembedEmbedder` is `Send + Sync` because: + +- `inner: EmbeddingService` is `Send + Sync` (it wraps fastembed's + `TextEmbedding` which is `Send + Sync` after fastembed 4.x; verified + in `crates/vestige-core/src/embeddings/mod.rs`). +- `cached_hash: std::sync::OnceLock` is `Send + Sync` for `T: Send + Sync`. +- The `#[cfg(not(feature = "embeddings"))]` branch carries only + `cached_hash`, which is unconditionally `Send + Sync`. + +No new bound is needed. + +### Before + +`crates/vestige-core/src/embedder/fastembed.rs:38-100` (relevant header): + +```rust +impl Default for FastembedEmbedder { + fn default() -> Self { + Self::new() + } +} + +#[async_trait::async_trait] +impl LocalEmbedder for FastembedEmbedder { + async fn embed(&self, text: &str) -> EmbedderResult> { + // ... body unchanged ... + } + + fn model_name(&self) -> &str { /* ... */ } + fn dimension(&self) -> usize { /* ... */ } + fn model_hash(&self) -> String { /* ... */ } + + async fn embed_batch(&self, texts: &[&str]) -> EmbedderResult>> { + // ... body unchanged ... + } +} +``` + +### After + +`crates/vestige-core/src/embedder/fastembed.rs:38-99` (one fewer line): + +```rust +impl Default for FastembedEmbedder { + fn default() -> Self { + Self::new() + } +} + +impl LocalEmbedder for FastembedEmbedder { + async fn embed(&self, text: &str) -> EmbedderResult> { + // ... body unchanged ... + } + + fn model_name(&self) -> &str { /* ... */ } + fn dimension(&self) -> usize { /* ... */ } + fn model_hash(&self) -> String { /* ... */ } + + async fn embed_batch(&self, texts: &[&str]) -> EmbedderResult>> { + // ... body unchanged ... + } +} +``` + +Diff is exactly one removed line (the `#[async_trait::async_trait]` +attribute on line 44). Every method body, every `async fn` signature, +every `use` statement inside the impl block stays verbatim. No +`Box::pin(async move { ... })`, no manual `Pin>`, no +`'async_trait` lifetime markers; native async-fn-in-trait does this +directly. + +### Why the impl block does not need an attribute + +`trait_variant::make` generates two things from the source trait +(see the "macro-generated output" subsection above): + +1. The source trait itself (`LocalEmbedder`), with native async fns. +2. A second trait (`Embedder`) whose method signatures return + `impl Future + Send` instead of `impl Future`, + plus a blanket impl wiring concrete types through. + +Both are emitted at the macro-call site. `FastembedEmbedder` writes one +impl block (against `LocalEmbedder`); the macro-generated blanket +guarantees `FastembedEmbedder: Embedder` for free. The +`Box` cast on `tests/phase_1/embedder_trait.rs:19` keeps +type-checking unchanged. + +--- + +## Call Site Audit + +Verified via, from the phase2 worktree root: + +```bash +grep -rn "async_trait\|LocalEmbedder\|dyn Embedder" crates/ +grep -rn "use.*Embedder" crates/ tests/ --include="*.rs" +grep -rn "Box\|Arc\|&dyn Embedder" crates/ tests/ --include="*.rs" +grep -rn "Box\|Arc\|&dyn LocalEmbedder" crates/ tests/ --include="*.rs" +grep -rn "impl LocalEmbedder for\|impl Embedder for" crates/ tests/ --include="*.rs" +``` + +### Files that reference the trait object form + +Exactly one, test-only: + +| File | Line | Use | Required change | +|--------------------------------------|------|------------------------------------------------------------------------------------------|-----------------| +| `tests/phase_1/embedder_trait.rs` | 3 | `use vestige_core::embedder::{Embedder, FastembedEmbedder};` | None. `Embedder` is the generated Send variant at the same path. | +| `tests/phase_1/embedder_trait.rs` | 19 | `let e: Box = Box::new(FastembedEmbedder::new());` | None. `FastembedEmbedder: LocalEmbedder + Send` -> blanket gives `: Embedder` -> `Box` is well-formed. | + +### Files that import `Embedder` or `LocalEmbedder` by name + +| File | Line | Use | Required change | +|-----------------------------------------------------|------|----------------------------------------------------------------------------------------------------------------|-----------------| +| `crates/vestige-core/src/lib.rs` | 167 | `pub use embedder::{Embedder, EmbedderError, EmbedderResult, FastembedEmbedder, LocalEmbedder};` | None. Both names still resolve. | +| `crates/vestige-core/src/embedder/mod.rs` | 5 | `pub use fastembed::FastembedEmbedder;` | None. | +| `crates/vestige-core/src/embedder/fastembed.rs` | 7 | `use super::{EmbedderError, EmbedderResult, LocalEmbedder};` | None. | +| `tests/phase_1/embedder_trait.rs` | 3 | `use vestige_core::embedder::{Embedder, FastembedEmbedder};` | None. | + +### Files that implement the trait + +| File | Line | Impl | Required change | +|-----------------------------------------------------|------|-----------------------------------------------------------------------|----------------------------------------------| +| `crates/vestige-core/src/embedder/fastembed.rs` | 45 | `impl LocalEmbedder for FastembedEmbedder` (currently `#[async_trait]`) | Drop the `#[async_trait::async_trait]` attr. | + +No other impls exist. There is no test mock implementing `Embedder` or +`LocalEmbedder` anywhere in the workspace. + +### Files that import `async_trait` directly + +After `0001a` lands, only the embedder pair: + +``` +crates/vestige-core/src/embedder/mod.rs:24 (doc comment) +crates/vestige-core/src/embedder/mod.rs:27 (attribute) +crates/vestige-core/src/embedder/mod.rs:56 (doc comment) +crates/vestige-core/src/embedder/fastembed.rs:44 (attribute) +``` + +Plus the Cargo manifest: + +``` +crates/vestige-core/Cargo.toml:119:async-trait = "0.1" +``` + +### Production files that hold a concrete embedder + +`FastembedEmbedder` is constructed and used by concrete name (not via +trait object) in: the dashboard / MCP layer if it needs to embed query +strings ad-hoc. None of those call sites need an edit because the +concrete type is what they hold, and the concrete type is untouched by +this sub-plan. + +### Conclusion + +| Category | Count | +|--------------------------------------------------|-------| +| Production source files modified | 2 | +| Test source files modified | 0 | +| Cargo manifests modified | 1 | +| Production source files importing `Embedder` / `LocalEmbedder` (verified unchanged) | 3 | +| Test source files importing `Embedder` (verified unchanged) | 1 | +| Direct `async_trait` uses outside the embedder module after `0001a` | 0 | + +--- + +## Cargo.toml Change + +From inside `crates/vestige-core/`: + +```bash +cargo rm async-trait +``` + +This removes line 119 of `Cargo.toml` and updates `Cargo.lock` in one +step. Manual editing is acceptable as a fallback if `cargo rm` is +unavailable in the agent environment; in that case, follow up with +`cargo check -p vestige-core` to refresh the lockfile. + +### Verification + +```bash +# Direct dependency must be gone. +grep -rn "async-trait\|async_trait" --include="Cargo.toml" crates/ +# Expected: empty. + +# Transitive presence is permitted (e.g. via a third-party crate). +cargo tree -p vestige-core --depth 2 | grep async-trait +# Expected: empty for the direct edges; if a sub-dependency still pulls +# async-trait transitively, the output may contain it deeper than depth 2, +# which is fine. We only care about removing the DIRECT edge. +``` + +If `cargo tree --depth 2` returns any `async-trait` line, inspect with +`cargo tree -p vestige-core -i async-trait` to see what is pulling it. +Acceptable parents: any third-party crate. Unacceptable parent: anything +under `vestige-*`, which would mean a missed file. + +--- + +## Commit Sequence + +Three commits, each green on +`cargo test -p vestige-core --features embeddings,vector-search` and +`cargo test -p vestige-core --no-default-features`. + +### Commit 1: rewrite LocalEmbedder trait declaration + +- Touches: `crates/vestige-core/src/embedder/mod.rs` only. +- Action: replace lines 21-57 per the "Trait Declaration Rewrite" + section above. Delete the `pub use LocalEmbedder as Embedder;` line. +- Green after: `cargo check -p vestige-core` (the impl block in + `fastembed.rs` still has its `#[async_trait::async_trait]` attribute; + the macro is harmless when applied to a trait that the impl block + targets by path, because async_trait rewrites the impl's async fns + into boxed-future fns whose signatures still match the native-async + declarations after trait_variant lowering, just as it did for the + SQLite intermediate state in `0001a`'s commit 1). + + **Mitigation if check fails between commits 1 and 2:** combine the + two into a single commit. The split is offered for review convenience; + the build must be green after every commit lands. + +### Commit 2: drop `#[async_trait::async_trait]` from FastembedEmbedder impl + +- Touches: `crates/vestige-core/src/embedder/fastembed.rs` only. +- Action: delete line 44 (`#[async_trait::async_trait]`). +- Green after: + - `cargo test -p vestige-core --features embeddings,vector-search`. + - `cargo test -p vestige-core --no-default-features` (the + `#[cfg(not(feature = "embeddings"))]` branches inside the impl now + stand on their own). + - Phase 1 integration test: `cargo test --test embedder_trait + --features embeddings,vector-search`. + +### Commit 3: drop the async-trait dependency + +- Touches: `crates/vestige-core/Cargo.toml` (plus `Cargo.lock` as a + side effect). +- Action: from inside `crates/vestige-core/`, run `cargo rm async-trait`. +- Green after: `cargo build --workspace --all-targets` and + `cargo test --workspace`. +- Final hard ASCII gate: `! grep -rn "async_trait" crates/` must exit + with status 0 (i.e. the inverted grep finds nothing). + +### Combined alternative + +Commits 1 and 2 may fold into a single commit if the per-step split +feels artificial (the patterns are identical to `0001a`'s commits 3 +and 4). Commit 3 (the Cargo.toml removal) should stay separate so the +dependency-removal diff is visible in isolation. + +--- + +## Verification + +Every command runs from the repo root unless noted otherwise. + +```bash +# 1. Vestige-core, default features (embeddings + vector-search). +cargo test -p vestige-core --features embeddings,vector-search + +# 2. Vestige-core, minimal features (no embeddings, no vector-search). +cargo test -p vestige-core --no-default-features + +# 3. Workspace build, all targets (catches any feature-gated regression +# in the vestige-mcp tools tree). +cargo build --workspace --all-targets + +# 4. Whole-workspace test (vestige-mcp 406 tests + vestige-core 352 +# tests per the CLAUDE.md baseline). +cargo test --workspace + +# 5. Phase 1 embedder integration test (the trait-shape contract). +cargo test --test embedder_trait --features embeddings,vector-search + +# 6. Clippy gate, deny warnings (matches Phase 1 PR policy). +cargo clippy --workspace --all-targets --features embeddings,vector-search -- -D warnings + +# 7. Hard ASCII gate -- async_trait must be gone from source. +! grep -rn "async_trait" crates/ +# Inverted grep: exit 0 iff grep found nothing. + +# 8. Hard ASCII gate -- async-trait must be gone from manifests. +! grep -rn "async-trait" --include="Cargo.toml" crates/ + +# 9. Confirm trait_variant attribute is in place at the embedder. +grep -rn "trait_variant::make" crates/vestige-core/src/embedder/ +# Expected: exactly one hit, in embedder/mod.rs. + +# 10. Workspace-wide trait_variant audit (should match the count after +# 0001a -- two hits total, one for storage, one for embedder). +grep -rn "trait_variant::make" crates/vestige-core/src/ +# Expected: two hits. +``` + +Expected outcomes: + +- Command 1: 352 vestige-core tests pass (matches baseline). +- Command 2: smaller test count, all pass. +- Command 3: workspace builds in dev mode for all targets. +- Command 4: 758 total tests pass (matches CLAUDE.md baseline). +- Command 5: `embedder_trait` integration test passes. The + `fastembed_implements_embedder_trait` assertion (`let e: Box = ...`) is the canary; if `trait_variant::make` failed to + emit the `Embedder` Send variant, this fails to compile. +- Command 6: zero clippy warnings. +- Command 7: empty output. `async_trait` is fully gone from source. +- Command 8: empty output. `async-trait` is fully gone from manifests. +- Command 9: one hit. +- Command 10: two hits. + +--- + +## Acceptance Criteria + +A reviewer should be able to check every box: + +- [ ] `crates/vestige-core/src/embedder/mod.rs` declares the embedder + trait with `#[trait_variant::make(Embedder: Send)] pub trait + LocalEmbedder: Sync + 'static`, no `async_trait` attribute, no + `Send` bound on `LocalEmbedder` itself. +- [ ] `crates/vestige-core/src/embedder/mod.rs` no longer contains + `pub use LocalEmbedder as Embedder;`. +- [ ] `crates/vestige-core/src/embedder/fastembed.rs` declares + `impl LocalEmbedder for FastembedEmbedder` with no attribute on + the impl block. +- [ ] `crates/vestige-core/Cargo.toml` does not declare `async-trait` + as a direct dependency. +- [ ] `grep -rn "async_trait" crates/` returns zero hits. +- [ ] `grep -rn "async-trait" --include="Cargo.toml" crates/` returns + zero hits. +- [ ] `grep -rn "trait_variant::make" crates/vestige-core/src/` returns + exactly two hits (storage trait + embedder trait). +- [ ] All 758 workspace tests pass (`cargo test --workspace`). +- [ ] `tests/phase_1/embedder_trait.rs` compiles and passes with the + `Box` cast intact. +- [ ] `cargo clippy --workspace --all-targets --features + embeddings,vector-search -- -D warnings` is clean. +- [ ] No file under `crates/vestige-mcp/` or under + `crates/vestige-core/src/{neuroscience,advanced,consolidation, + codebase,memory,embeddings}/` was modified by this sub-plan. +- [ ] `Cargo.lock` was updated as a side effect of `cargo rm async-trait` + (it must no longer reference `async-trait`). +- [ ] Doc comments on the embedder trait declaration describe + `trait_variant`, not `async_trait`. + +--- + +## Risks and Mitigations + +- **`trait_variant::make` requires returned futures to be `Send` for the + blanket `impl Embedder for T`. If any + `async fn embed`/`embed_batch` body inside `FastembedEmbedder` captures + a non-Send local, the blanket impl fails to type-check.** + Mitigation: the existing impl bodies call `self.inner.embed(text)` / + `self.inner.embed_batch(texts)`, where `inner: EmbeddingService` is + `Send + Sync` (verified in `crates/vestige-core/src/embeddings/mod.rs`). + No `.await` points exist inside the bodies in either feature branch; + the `EmbeddingService::embed` calls are synchronous. The futures are + trivially `Send`. If a future change introduces a non-Send local + (e.g. an `Rc` or a non-Send guard), the blanket impl will surface that + as a compile error at the dyn cast in `tests/phase_1/embedder_trait.rs`, + which is the correct outcome. +- **The macro's blanket impl interacts oddly with the default `signature` + method.** + Mitigation: `signature` is a synchronous method returning + `crate::storage::ModelSignature`, with no `Send` or `async` concerns. + `trait_variant::make` emits it on both variants as-is. The existing + Phase 1 test `signature_matches_memory_store_registry` exercises this + path and is part of the verification step. +- **`Box` cast in `tests/phase_1/embedder_trait.rs` fails + to resolve after the rewrite.** + Mitigation: the rewrite preserves the `Embedder` symbol at the same + module path; only its provenance changes (now generated by + `trait_variant::make` instead of by `pub use LocalEmbedder as + Embedder;`). The macro is specifically designed so that the generated + trait is dyn-compatible at the Send-bound boundary. Verified by the + identical pattern already working for `MemoryStore` after `0001a`. +- **`cargo rm async-trait` updates `Cargo.lock` but accidentally bumps + other crates.** + Mitigation: run `cargo rm async-trait` and then immediately inspect + the resulting `Cargo.lock` diff. The expected diff is the removal of + the `[[package]] name = "async-trait"` block and its hash. Anything + else is a red flag and should be reverted before committing + (`git checkout -- Cargo.lock` then `cargo update -p async-trait + --precise=remove` -- or fall back to manual edit + `cargo check`). +- **A new workspace crate added in parallel with this work declares + `async-trait` and the dependency removal silently re-introduces it + later.** + Mitigation: the verification step `grep -rn "async-trait" + --include="Cargo.toml" crates/` is part of the acceptance criteria; a + rebase that reintroduces the line will fail this gate. +- **MCP server uses `Embedder` somewhere we missed.** + Mitigation: full workspace grep (`grep -rn "Embedder" crates/`) + returns no hits inside `crates/vestige-mcp/` for the trait names; the + MCP layer uses the concrete `EmbeddingService` from + `crates/vestige-core/src/embeddings/` for ad-hoc embedding calls. The + trait surface is purely internal to `vestige-core`. + +--- + +## Out-of-Band Notes + +- **No other workspace crate declares `async-trait` as a direct + dependency.** Verified by + `grep -rn "async-trait" --include="Cargo.toml" crates/` returning + exactly one hit at `crates/vestige-core/Cargo.toml:119`. There is + nothing to clean up in `crates/vestige-mcp/Cargo.toml` or elsewhere. +- **Order matters across the three Phase 1 amendment sub-plans:** + `0001a` (trait rewrite) -> `0001b` (sqlite split) -> `0001c` (this + one, async-trait sunset). Reversing the order is possible in + principle but would force re-editing the embedder rewrite twice and + leaves the `async-trait` dep behind until very late. +- **This sub-plan amends `feat/storage-trait-phase1` (tip 790c0c8 plus + whatever commits `0001a` and `0001b` added).** The branch has not + been opened upstream yet, so amending in place is safe; no force-push + to a public PR. +- **After this sub-plan lands, the branch is reviewed and merged before + Phase 2 sub-plans (`0002a-` through `0002i-`) begin implementation.** + Phase 2 introduces no async-trait usage; the Postgres backend follows + the same `trait_variant::make` pattern (see ADR 0002 D1). +- **`trait-variant` 0.1 stays in `Cargo.toml`.** It is the only crate + this sub-plan keeps; `async-trait` is the only one it removes. + +--- + +## Self-Contained `/goal` Brief + +For a fresh Claude Code session executing this sub-plan without prior +conversation context: + +1. Check out branch `feat/storage-trait-phase1` (or a worktree off + of it after `0001a` and `0001b` are merged into it). +2. Read this file (`docs/plans/0001c-async-trait-sunset.md`) in full. +3. Read `docs/plans/0001a-trait-rewrite.md` sections "Trait declaration + rewrite" and "Impl block migration" -- they document the exact + pattern this sub-plan mirrors for the embedder. +4. Run the prerequisite audit grep listed under "Prerequisites". If it + returns more than the five hits documented there, stop and report; + the upstream state does not match what this sub-plan assumes. +5. Execute Commit 1 (rewrite `embedder/mod.rs`), then Commit 2 (drop + the attribute on the FastembedEmbedder impl), then Commit 3 + (`cargo rm async-trait`). Run the verification commands listed + above after each commit; do not proceed if any test or clippy gate + fails. +6. Verify every box in "Acceptance Criteria" is ticked. +7. Report file paths touched, test counts, and the final two grep + results (commands 7 and 8 from "Verification") in the closing + message. From 9ef8afdb20337d08cb5489078ae49eec8c7c1cf1 Mon Sep 17 00:00:00 2001 From: Jan De Landtsheer Date: Wed, 27 May 2026 09:35:58 +0200 Subject: [PATCH 15/31] docs(plans): add Phase 2 sub-plans 0002a-0002i + supersession notice Nine Phase 2 sub-plans operationalising ADR 0002 against the Phase 2 master plan, each sized to fit a focused implementation session and handed to Claude Code as a /goal brief without requiring the agent to load the master plan. Order of execution (each depends on the previous unless noted): - 0002a-skeleton-and-feature-gate.md -- postgres-backend Cargo feature + PgMemoryStore skeleton with todo!() bodies. D1+D2. - 0002b-pool-and-config.md -- PgPool builder, VestigeConfig/ PostgresConfig, vestige.toml loader wired into vestige-mcp. D3+D7 (master plan numbering). - 0002c-migrations.md -- sqlx migrations 0001_init/0002_hnsw including D7 (users/groups/memberships, owner/visibility/shared_with_groups) and D8 (codebase column). SQLite V15 parity migration. D4. - 0002d-store-impl-bodies.md -- real CRUD + registry bodies; trivial fts_search/vector_search bodies. D2+D6. - 0002e-hybrid-search.md -- one-statement RRF query. D5. - 0002f-migrate-cli.md -- vestige migrate copy (SQLite -> Postgres), --dry-run, idempotent re-runs, --allow-source-upgrade for pre-V15 sources. D8+D10. - 0002g-reembed.md -- vestige migrate reembed (offline rebuild). D9 + D10 reembed arm. Ships resolve_embedder helper as a workaround for the missing Embedder::from_name(&str) constructor. - 0002h-testing-and-benches.md -- testcontainers harness, six integration test files, Criterion bench at 1k/100k. D14+D15. - 0002i-runbook.md -- operator-facing deployment + day-2 runbook. D16. Supersession notice added to the master plan (0002-phase-2-postgres- backend.md) pointing at ADR 0002; body retained as archival reference. PR B carries this commit plus the previous two (ADR 0002 + Phase 1 amendment sub-plans); no code change. --- docs/plans/0002-phase-2-postgres-backend.md | 8 + docs/plans/0002a-skeleton-and-feature-gate.md | 554 ++++++ docs/plans/0002b-pool-and-config.md | 886 +++++++++ docs/plans/0002c-migrations.md | 1119 +++++++++++ docs/plans/0002d-store-impl-bodies.md | 1771 +++++++++++++++++ docs/plans/0002e-hybrid-search.md | 825 ++++++++ docs/plans/0002f-migrate-cli.md | 1045 ++++++++++ docs/plans/0002g-reembed.md | 843 ++++++++ docs/plans/0002h-testing-and-benches.md | 1223 ++++++++++++ docs/plans/0002i-runbook.md | 724 +++++++ 10 files changed, 8998 insertions(+) create mode 100644 docs/plans/0002a-skeleton-and-feature-gate.md create mode 100644 docs/plans/0002b-pool-and-config.md create mode 100644 docs/plans/0002c-migrations.md create mode 100644 docs/plans/0002d-store-impl-bodies.md create mode 100644 docs/plans/0002e-hybrid-search.md create mode 100644 docs/plans/0002f-migrate-cli.md create mode 100644 docs/plans/0002g-reembed.md create mode 100644 docs/plans/0002h-testing-and-benches.md create mode 100644 docs/plans/0002i-runbook.md diff --git a/docs/plans/0002-phase-2-postgres-backend.md b/docs/plans/0002-phase-2-postgres-backend.md index 3fe28f2..ed2a186 100644 --- a/docs/plans/0002-phase-2-postgres-backend.md +++ b/docs/plans/0002-phase-2-postgres-backend.md @@ -1,5 +1,13 @@ # Phase 2 Plan: PostgreSQL Backend +> **Supersession Notice (2026-05-26):** This master plan is now archival. Execution is governed by: +> - **ADR**: [`docs/adr/0002-phase-2-execution.md`](../adr/0002-phase-2-execution.md) -- binding decisions +> - **Sub-plans** (executable briefs): +> - Phase 1 amendment: [0001a-trait-rewrite.md](0001a-trait-rewrite.md), [0001b-sqlite-split.md](0001b-sqlite-split.md), [0001c-async-trait-sunset.md](0001c-async-trait-sunset.md) +> - Phase 2: 0002a..0002i (skeleton, pool+config, migrations, store impl, hybrid search, migrate CLI, reembed, tests+benches, runbook) +> +> **Deltas vs body**: trait uses `trait_variant`, error type is `MemoryStoreError`/`MemoryStoreResult`, `connect` is `(url, max_connections)` only, the core table is `knowledge_nodes` (not `memories`) and gains `owner_user_id` + `visibility` + `shared_with_groups` + `codebase`, plus `users`/`groups`/`group_memberships` tables. See ADR 0002 D1-D8. + **Status**: Draft **Depends on**: Phase 1 (MemoryStore + Embedder traits, embedding_model registry, domain columns) **Related**: docs/adr/0001-pluggable-storage-and-network-access.md (Phase 2), docs/prd/001-getting-centralized-vestige.md, docs/plans/local-dev-postgres-setup.md (local cluster provisioning) diff --git a/docs/plans/0002a-skeleton-and-feature-gate.md b/docs/plans/0002a-skeleton-and-feature-gate.md new file mode 100644 index 0000000..74032dc --- /dev/null +++ b/docs/plans/0002a-skeleton-and-feature-gate.md @@ -0,0 +1,554 @@ +# Phase 2 Sub-Plan 0002a -- Skeleton and Feature Gate + +**Status**: Ready +**Depends on**: Phase 1 amendment (sub-plans `0001a-trait-rewrite.md` and +`0001b-sqlite-split.md`) merged. Specifically: +- `MemoryStore` trait declared with `#[trait_variant::make(MemoryStore: Send)]`, + generating a non-Send `LocalMemoryStore` companion trait. The + `pub use MemoryStore as LocalMemoryStore` alias from Phase 1 is gone. +- `crates/vestige-core/src/storage/sqlite.rs` has been split into + `crates/vestige-core/src/storage/sqlite/` with the same public surface. + +This sub-plan covers Phase 2 master-plan deliverables D1 and D2 only: +the `postgres-backend` Cargo feature gate and a compilable `PgMemoryStore` +skeleton whose trait method bodies are `todo!()`. No real Postgres code, no +migrations, no SQL. Later sub-plans (`0002b-pool-and-config.md`, +`0002c-migrations.md`, `0002d-store-impl-bodies.md`, ...) fill the bodies in. + +The success criterion is a clean build under both feature-flag configurations, +nothing more. + +--- + +## Context + +ADR 0002 D4 commits Phase 2 to a `crates/vestige-core/src/storage/postgres/` +directory from day one. The seven other files in that directory +(`pool.rs`, `migrations.rs`, `registry.rs`, `search.rs`, `migrate_cli.rs`, +`reembed.rs`) belong to subsequent sub-plans. This sub-plan creates only +`crates/vestige-core/src/storage/postgres/mod.rs` so the rest can be added +incrementally without breaking the build. + +Per ADR 0002 D2, `PgMemoryStore::connect` mirrors `SqliteMemoryStore::new`: +no `Embedder` argument. The pgvector typmod DDL +(`ALTER TABLE memories ALTER COLUMN embedding TYPE vector($N)`) lives inside +the trait method `register_model`, invoked by the caller after construction. +In this sub-plan `register_model` is a `todo!()` body; `0002c-migrations.md` +and `0002d-store-impl-bodies.md` provide the real implementation. + +The trait surface in `crates/vestige-core/src/storage/memory_store.rs` is the +source of truth for method signatures. Do NOT copy signatures from the master +plan -- they are stale in places (for example, master plan 0002 D2 lists +`remove_edge` as three-arg `(source, target, edge_type)`; the live trait has +two args `(source, target)`). + +--- + +## Cargo manifest changes + +Two optional crates and one new feature flag. Use `cargo add` per the global +CLAUDE.md preference; do not hand-edit `Cargo.toml`. + +```bash +cd crates/vestige-core + +cargo add sqlx@0.8 --optional --no-default-features \ + --features runtime-tokio,tls-rustls,postgres,uuid,chrono,json,migrate,macros + +cargo add pgvector@0.4 --optional --features sqlx +``` + +After both commands, open `crates/vestige-core/Cargo.toml` and add the +`postgres-backend` feature line in the `[features]` block. Place it after +the `metal` feature, before `[dependencies]`: + +```toml +# Postgres backend (mutually compilable with the SQLite backend; default OFF). +# Compile with: --features postgres-backend +postgres-backend = ["dep:sqlx", "dep:pgvector"] +``` + +Do NOT add `tokio-stream`, `futures`, `indicatif`, or `toml` in this sub-plan. +The master plan D1 lists them in the `postgres-backend` feature for +convenience, but their consumers (streaming migrate, progress bar, config +parsing) land in later sub-plans. Adding them here pulls dead weight into the +feature gate. + +Do NOT add the `vestige-mcp` pass-through feature in this sub-plan either. +The MCP crate gets its `postgres-backend` feature in `0002b-pool-and-config.md` +when `MemoryStoreConfig` lands and the binary needs a knob to pick a backend. + +Verify the diff to `crates/vestige-core/Cargo.toml` looks like this and only +this: + +```toml +[features] +# ...existing features unchanged... +postgres-backend = ["dep:sqlx", "dep:pgvector"] + +[dependencies] +# ...existing deps unchanged... +sqlx = { version = "0.8", default-features = false, features = [ + "runtime-tokio", "tls-rustls", "postgres", "uuid", "chrono", + "json", "migrate", "macros", +], optional = true } +pgvector = { version = "0.4", features = ["sqlx"], optional = true } +``` + +The exact ordering of the two new lines inside `[dependencies]` is not +significant; `cargo add` places them at the end. Leave the placement that +`cargo add` produces. + +--- + +## Storage module export + +Edit `crates/vestige-core/src/storage/mod.rs` to expose the new module behind +the feature flag. Two lines change. + +Add to the module-declaration block (after `mod sqlite;`): + +```rust +#[cfg(feature = "postgres-backend")] +mod postgres; +``` + +Add to the re-export block (after the `pub use sqlite::{ ... }` block): + +```rust +#[cfg(feature = "postgres-backend")] +pub use postgres::PgMemoryStore; +``` + +Nothing else in `storage/mod.rs` changes. The `Storage` alias still points at +`SqliteMemoryStore`; the SQLite re-export block is untouched. + +--- + +## Postgres module skeleton + +Create `crates/vestige-core/src/storage/postgres/mod.rs` with the full content +below. This is the only new file in this sub-plan. + +```rust +#![cfg(feature = "postgres-backend")] +//! Postgres-backed implementation of `MemoryStore`. +//! +//! Skeleton only. Every trait method is `todo!()`. Real bodies land in +//! subsequent Phase 2 sub-plans: +//! - `0002b-pool-and-config.md`: pool construction and config wiring +//! - `0002c-migrations.md`: sqlx migration files and `init`/`register_model` +//! - `0002d-store-impl-bodies.md`: CRUD, scheduling, edges, domains +//! - `0002e-hybrid-search.md`: RRF query and search bodies +//! +//! The directory grows companion files (`pool.rs`, `migrations.rs`, +//! `registry.rs`, `search.rs`, `migrate_cli.rs`, `reembed.rs`) in those +//! sub-plans; this skeleton only creates `mod.rs`. + +use chrono::{DateTime, Utc}; +use sqlx::PgPool; +use uuid::Uuid; + +use crate::storage::memory_store::{ + Domain, HealthStatus, LocalMemoryStore, MemoryEdge, MemoryRecord, MemoryStoreResult, + ModelSignature, SchedulingState, SearchQuery, SearchResult, StoreStats, +}; + +/// Postgres-backed implementation of `MemoryStore`. +/// +/// Cheaply cloneable. Methods take `&self`; interior state lives inside the +/// `PgPool` (which already provides `Sync` via `Arc` internally). +#[derive(Clone)] +pub struct PgMemoryStore { + pool: PgPool, + /// Embedding vector dimension. Set to 0 in the skeleton; populated by + /// `register_model` in `0002d-store-impl-bodies.md` once the pgvector + /// `ALTER COLUMN TYPE vector(N)` DDL lands. + embedding_dim: i32, +} + +impl PgMemoryStore { + /// Construct a new store from a connection URL. + /// + /// Mirrors `SqliteMemoryStore::new`: no `Embedder` argument. The pgvector + /// `ALTER TABLE memories ALTER COLUMN embedding TYPE vector($N)` DDL lives + /// inside `register_model`, not here. The caller (cognitive engine + /// bootstrap, migrate CLI, tests) invokes `register_model` after this + /// returns, identically to the SQLite path. + /// + /// Real body lands in `0002b-pool-and-config.md` (pool construction) and + /// `0002c-migrations.md` (initial migration run). + pub async fn connect(_url: &str, _max_connections: u32) -> MemoryStoreResult { + todo!("PgMemoryStore::connect lands in 0002b-pool-and-config.md") + } + + /// Low-level constructor for tests: supply an existing pool, skip migrate. + /// + /// Real body lands in `0002b-pool-and-config.md`. + pub async fn from_pool(_pool: PgPool) -> MemoryStoreResult { + todo!("PgMemoryStore::from_pool lands in 0002b-pool-and-config.md") + } + + /// Accessor used by migrate/reembed CLI. + pub fn pool(&self) -> &PgPool { + &self.pool + } + + /// Currently-registered vector dimension. Returns 0 until `register_model` + /// has been called (real body: `0002d-store-impl-bodies.md`). + pub fn embedding_dim(&self) -> i32 { + self.embedding_dim + } +} + +// trait_variant::make on the trait declaration generates two traits: +// - `MemoryStore` (Send-bound) +// - `LocalMemoryStore` (non-Send companion) +// The implementer writes `impl LocalMemoryStore for ...` plainly; the Send +// variant is generated automatically from the non-Send impl. +impl LocalMemoryStore for PgMemoryStore { + // --- Lifecycle --- + async fn init(&self) -> MemoryStoreResult<()> { + todo!("PgMemoryStore::init lands in 0002c-migrations.md") + } + + async fn health_check(&self) -> MemoryStoreResult { + todo!("PgMemoryStore::health_check lands in 0002d-store-impl-bodies.md") + } + + // --- Embedding model registry --- + async fn registered_model(&self) -> MemoryStoreResult> { + todo!("PgMemoryStore::registered_model lands in 0002d-store-impl-bodies.md") + } + + async fn register_model(&self, _sig: &ModelSignature) -> MemoryStoreResult<()> { + todo!("PgMemoryStore::register_model lands in 0002d-store-impl-bodies.md") + } + + // --- CRUD --- + async fn insert(&self, _record: &MemoryRecord) -> MemoryStoreResult { + todo!("PgMemoryStore::insert lands in 0002d-store-impl-bodies.md") + } + + async fn get(&self, _id: Uuid) -> MemoryStoreResult> { + todo!("PgMemoryStore::get lands in 0002d-store-impl-bodies.md") + } + + async fn update(&self, _record: &MemoryRecord) -> MemoryStoreResult<()> { + todo!("PgMemoryStore::update lands in 0002d-store-impl-bodies.md") + } + + async fn delete(&self, _id: Uuid) -> MemoryStoreResult<()> { + todo!("PgMemoryStore::delete lands in 0002d-store-impl-bodies.md") + } + + // --- Search --- + async fn search(&self, _query: &SearchQuery) -> MemoryStoreResult> { + todo!("PgMemoryStore::search lands in 0002e-hybrid-search.md") + } + + async fn fts_search( + &self, + _text: &str, + _limit: usize, + ) -> MemoryStoreResult> { + todo!("PgMemoryStore::fts_search lands in 0002e-hybrid-search.md") + } + + async fn vector_search( + &self, + _embedding: &[f32], + _limit: usize, + ) -> MemoryStoreResult> { + todo!("PgMemoryStore::vector_search lands in 0002e-hybrid-search.md") + } + + // --- FSRS Scheduling --- + async fn get_scheduling( + &self, + _memory_id: Uuid, + ) -> MemoryStoreResult> { + todo!("PgMemoryStore::get_scheduling lands in 0002d-store-impl-bodies.md") + } + + async fn update_scheduling(&self, _state: &SchedulingState) -> MemoryStoreResult<()> { + todo!("PgMemoryStore::update_scheduling lands in 0002d-store-impl-bodies.md") + } + + async fn get_due_memories( + &self, + _before: DateTime, + _limit: usize, + ) -> MemoryStoreResult> { + todo!("PgMemoryStore::get_due_memories lands in 0002d-store-impl-bodies.md") + } + + // --- Graph (spreading activation) --- + async fn add_edge(&self, _edge: &MemoryEdge) -> MemoryStoreResult<()> { + todo!("PgMemoryStore::add_edge lands in 0002d-store-impl-bodies.md") + } + + async fn get_edges( + &self, + _node_id: Uuid, + _edge_type: Option<&str>, + ) -> MemoryStoreResult> { + todo!("PgMemoryStore::get_edges lands in 0002d-store-impl-bodies.md") + } + + async fn remove_edge(&self, _source: Uuid, _target: Uuid) -> MemoryStoreResult<()> { + todo!("PgMemoryStore::remove_edge lands in 0002d-store-impl-bodies.md") + } + + async fn get_neighbors( + &self, + _node_id: Uuid, + _depth: usize, + ) -> MemoryStoreResult> { + todo!("PgMemoryStore::get_neighbors lands in 0002d-store-impl-bodies.md") + } + + // --- Domains (Phase 1: stubs return empty; full impl in Phase 4) --- + async fn list_domains(&self) -> MemoryStoreResult> { + todo!("PgMemoryStore::list_domains lands in 0002d-store-impl-bodies.md") + } + + async fn get_domain(&self, _id: &str) -> MemoryStoreResult> { + todo!("PgMemoryStore::get_domain lands in 0002d-store-impl-bodies.md") + } + + async fn upsert_domain(&self, _domain: &Domain) -> MemoryStoreResult<()> { + todo!("PgMemoryStore::upsert_domain lands in 0002d-store-impl-bodies.md") + } + + async fn delete_domain(&self, _id: &str) -> MemoryStoreResult<()> { + todo!("PgMemoryStore::delete_domain lands in 0002d-store-impl-bodies.md") + } + + async fn classify(&self, _embedding: &[f32]) -> MemoryStoreResult> { + todo!("PgMemoryStore::classify lands in 0002d-store-impl-bodies.md") + } + + // --- Bulk / Maintenance --- + async fn count(&self) -> MemoryStoreResult { + todo!("PgMemoryStore::count lands in 0002d-store-impl-bodies.md") + } + + async fn get_stats(&self) -> MemoryStoreResult { + todo!("PgMemoryStore::get_stats lands in 0002d-store-impl-bodies.md") + } + + async fn vacuum(&self) -> MemoryStoreResult<()> { + todo!("PgMemoryStore::vacuum lands in 0002d-store-impl-bodies.md") + } +} +``` + +Notes on the skeleton: + +- The file-level `#![cfg(feature = "postgres-backend")]` means the whole file + vanishes when the feature is off. The `mod postgres;` line in + `storage/mod.rs` is itself feature-gated, so this is belt-and-braces; both + gates are needed because the file-level attribute is what allows the file to + use `sqlx::PgPool` unconditionally inside it. +- `EmbeddingModelDescriptor` (a separate Postgres-internal type that the + master plan sketched on the struct) is dropped. The trait surface already + carries `ModelSignature` for the registry round-trip; the registry storage + layout is a private concern of `registry.rs`, which is added later. Keep + `PgMemoryStore` minimal until a real consumer needs the extra type. +- The struct only carries `pool` and `embedding_dim`. The model descriptor + field from the master plan sketch goes away with `EmbeddingModelDescriptor`. + If `register_model` later needs to cache the descriptor on the struct, it + can be added then; the skeleton does not speculate. +- The two trivial accessors (`pool`, `embedding_dim`) get real bodies. Every + other method is `todo!()` so it returns `!` and trivially coerces to the + declared return type at the type checker; this is what lets the build pass + with no error variants and no SQL. + +--- + +## Connect signature + +Per ADR 0002 D2: + +```rust +pub async fn connect(url: &str, max_connections: u32) -> MemoryStoreResult; +pub async fn from_pool(pool: PgPool) -> MemoryStoreResult; +``` + +No `&dyn Embedder` argument. This deliberately differs from master plan 0002, +which predates the Phase 1 freeze. The pgvector-specific DDL +(`ALTER TABLE memories ALTER COLUMN embedding TYPE vector($N)`) does not run +inside `connect`; it runs inside `register_model(&ModelSignature)`, which the +caller invokes after `connect` returns. + +In this sub-plan `register_model` is `todo!()`. The real body lands in +`0002d-store-impl-bodies.md` after `0002c-migrations.md` ships the +`0001_init.up.sql` migration that creates the `memories` table with a +placeholder `embedding vector` column (no typmod), against which +`register_model` later runs the typmod stamp. + +--- + +## Error variant additions: deferred + +`MemoryStoreError` does NOT gain `Postgres(sqlx::Error)` or +`Migrate(sqlx::migrate::MigrateError)` in this sub-plan. + +The reason is mechanical: `todo!()` evaluates to the never type `!`, which +coerces to any `MemoryStoreResult` regardless of the error variants +available. With every method body a `todo!()`, the skeleton has no expression +that needs to convert a `sqlx::Error` or `sqlx::migrate::MigrateError` into +`MemoryStoreError`. Adding the variants here would mean adding the +`#[cfg(feature = "postgres-backend")]` and `#[from]` plumbing to +`memory_store.rs` with no consumer yet -- dead code at every level except the +enum definition itself. + +`0002d-store-impl-bodies.md` introduces both variants in the same commit that +turns the first `todo!()` into a real `sqlx::query!` call. That keeps the +diff to `memory_store.rs` next to the first usage site, which is easier to +review than adding variants ahead of need. + +For reference, the variants that will be added in `0002d-store-impl-bodies.md` +look like this: + +```rust +#[cfg(feature = "postgres-backend")] +#[error("postgres error: {0}")] +Postgres(#[from] sqlx::Error), + +#[cfg(feature = "postgres-backend")] +#[error("postgres migration error: {0}")] +Migrate(#[from] sqlx::migrate::MigrateError), +``` + +Do not pre-add them here. + +--- + +## Verification + +Run these commands from the workspace root. All four must produce a clean +build, zero warnings on the diff-affected files, no test changes. + +```bash +# 1. Default features (SQLite backend, postgres-backend OFF). Must build. +cargo build --workspace --all-targets + +# 2. Workspace clippy with default features. Must be clean. +cargo clippy --workspace --all-targets -- -D warnings + +# 3. Postgres feature enabled. Must build. +cargo build -p vestige-core --features postgres-backend + +# 4. Clippy with postgres feature enabled. Must be clean. +cargo clippy -p vestige-core --features postgres-backend --all-targets -- -D warnings +``` + +Expected outcomes: + +- `cargo build --workspace --all-targets` finishes with no compilation of + `sqlx` or `pgvector` (both are optional, no consumer with default features). + The `postgres` module is excluded entirely via `#[cfg]`. +- `cargo build -p vestige-core --features postgres-backend` compiles `sqlx`, + `pgvector`, and `storage/postgres/mod.rs`. The build succeeds because every + trait method is `todo!()`; nothing actually runs SQL. +- Both `clippy` invocations pass with `-D warnings`. The `todo!()` macro does + not emit a `dead_code` lint by itself, and the trivial accessors are used by + later sub-plans (clippy on the postgres feature alone may flag them as + unused if you run with `--lib` only; the `--all-targets` form keeps tests + and benches in scope so this does not fire). +- If clippy flags `unused_variables` on the underscore-prefixed parameters in + the `todo!()` bodies, the underscore prefix is already the standard + suppression; if a future clippy version disagrees, add + `#[allow(unused_variables)]` to the impl block, not to each method. + +Tests are not modified in this sub-plan. The unit tests in +`memory_store.rs` (`memory_store_error_from_storage_error`, +`model_signature_serde_round_trip`, `memory_record_serde_round_trip`) keep +passing because no type they touch changes. + +Do NOT run `cargo test` against the postgres feature -- there is no Postgres +running and no test exercises `PgMemoryStore` yet. The build check is the +contract. + +--- + +## Acceptance criteria + +1. `crates/vestige-core/Cargo.toml` declares `sqlx = "0.8"` and + `pgvector = "0.4"` as optional dependencies with the exact feature sets + specified above. +2. `crates/vestige-core/Cargo.toml` declares `postgres-backend = ["dep:sqlx", + "dep:pgvector"]` and nothing else inside that feature. +3. `crates/vestige-mcp/Cargo.toml` is unchanged. +4. `crates/vestige-core/src/storage/mod.rs` adds exactly two + feature-gated lines: `mod postgres;` and `pub use postgres::PgMemoryStore;`. + No other change. +5. `crates/vestige-core/src/storage/postgres/mod.rs` exists and contains the + `PgMemoryStore` struct, `impl PgMemoryStore` block with real `pool` and + `embedding_dim` accessors and `todo!()` bodies for `connect` and + `from_pool`, and the full `impl LocalMemoryStore for PgMemoryStore` block + with `todo!()` for every trait method. +6. The trait impl method signatures match `memory_store.rs` byte-for-byte + (including `remove_edge(&self, source: Uuid, target: Uuid)` two-arg form, + not the three-arg form from the master plan). +7. `MemoryStoreError` is unchanged. +8. No other files in the crate are touched. No new files in + `storage/postgres/` besides `mod.rs`. +9. The four verification commands above all succeed. + +--- + +## Commit sequence + +One commit is recommended. The two changes (Cargo manifest + module skeleton) +do not compile in isolation: the manifest change without the skeleton produces +unused-optional-dep warnings, and the skeleton without the manifest change +fails to find `sqlx`. Splitting them adds no review value, since the second +commit is the one that has to compile cleanly. + +```bash +git add crates/vestige-core/Cargo.toml \ + crates/vestige-core/Cargo.lock \ + crates/vestige-core/src/storage/mod.rs \ + crates/vestige-core/src/storage/postgres/mod.rs + +git commit -m "feat(storage): scaffold postgres-backend feature and PgMemoryStore skeleton + +Adds the postgres-backend Cargo feature gating sqlx 0.8 and pgvector 0.4. +Introduces crates/vestige-core/src/storage/postgres/mod.rs with the +PgMemoryStore struct, connect/from_pool/pool/embedding_dim, and a trait impl +whose method bodies are todo!() pending later Phase 2 sub-plans. + +Builds clean with default features (SQLite only) and with --features +postgres-backend. No runtime behaviour change. + +Refs ADR 0002 D1, D2, D4." +``` + +If for any reason the manifest change must be reviewed separately (for +example, a security review of the sqlx version pin), split as: + +1. `cargo add` for sqlx and pgvector + manual feature line in Cargo.toml. + Build with default features will pass but `--features postgres-backend` + will fail (no module to satisfy the feature). This is acceptable for a + short-lived intermediate commit. +2. `storage/mod.rs` edits + `storage/postgres/mod.rs` creation. Both builds + pass. + +Default to the single-commit form unless asked to split. + +--- + +## Followups + +- `0002b-pool-and-config.md` adds `pool.rs`, `PostgresConfig`, and the + `vestige-mcp` `postgres-backend` pass-through feature. +- `0002c-migrations.md` adds `crates/vestige-core/migrations/postgres/` with + `0001_init.{up,down}.sql` and `0002_hnsw.{up,down}.sql`, plus + `postgres/migrations.rs` invoking `sqlx::migrate!`. `init()` body lands here. +- `0002d-store-impl-bodies.md` introduces the two `MemoryStoreError` variants + and replaces every `todo!()` in CRUD / scheduling / edges / domains / + registry with real `sqlx::query!` bodies. +- `0002e-hybrid-search.md` fills the three search bodies via the RRF query. diff --git a/docs/plans/0002b-pool-and-config.md b/docs/plans/0002b-pool-and-config.md new file mode 100644 index 0000000..9941413 --- /dev/null +++ b/docs/plans/0002b-pool-and-config.md @@ -0,0 +1,886 @@ +# Sub-plan 0002b -- Pool construction and VestigeConfig + +**Status**: Draft +**Master plan**: [0002-phase-2-postgres-backend.md](0002-phase-2-postgres-backend.md) +**ADR**: [0002-phase-2-execution.md](../adr/0002-phase-2-execution.md) +**Predecessor**: [0002a-skeleton-and-feature-gate.md](0002a-skeleton-and-feature-gate.md) + +--- + +## Context + +This sub-plan delivers two of the master plan's deliverables now that the +`0002a` skeleton has landed: + +- **D3** -- pool construction in + `crates/vestige-core/src/storage/postgres/pool.rs`. Replaces the `todo!()` + body of `PgMemoryStore::connect` with a real `PgPool` builder that reads a + `PostgresConfig`. Registry/migration calls remain `todo!()`; those are + filled in by sub-plans `0002c` (migrations) and `0002d` (store bodies + + registry). +- **D7** -- new module `crates/vestige-core/src/config.rs` containing + `VestigeConfig`, `StorageConfig`, `SqliteConfig`, `PostgresConfig`, + `EmbeddingsConfig`, plus a `ConfigError` enum and a loader that reads + `vestige.toml`. The loader is wired into `vestige-mcp` so the running + server picks SQLite or Postgres at startup based on the config file. + +After this sub-plan: + +- `cargo build` (default features, no `postgres-backend`) compiles and the + MCP server still defaults to SQLite when no `vestige.toml` is present. +- `cargo build --features postgres-backend` compiles, with + `PgMemoryStore::connect` now wiring through `pool.rs` (registry/migration + still `todo!()` until `0002c` and `0002d`). +- A `vestige.toml` example can be round-tripped through + `VestigeConfig::load` in a unit test. + +This sub-plan deliberately does NOT: + +- Add migrations (`0002c`). +- Fill in real CRUD/search bodies on `PgMemoryStore` (`0002d`, `0002e`). +- Add env-var override support (Phase 3 concern, called out in master plan + D7 behaviour notes). + +--- + +## Dependencies + +- `0002a-skeleton-and-feature-gate.md` must be merged. That sub-plan creates + `crates/vestige-core/src/storage/postgres/mod.rs` with: + - `PgMemoryStore` struct holding `pool: PgPool`. + - `PgMemoryStore::connect(url: &str, max_connections: u32) -> MemoryStoreResult` + body = `todo!()`. + - `PgMemoryStore::from_pool(pool: PgPool) -> MemoryStoreResult` + body = `todo!()`. + - The trait impl block with all methods routed to `todo!()`. + - The `postgres-backend` feature gate on the module declaration in + `storage/mod.rs`. + +This sub-plan extends those bodies and adds two siblings: `pool.rs` and +`registry.rs` (the latter is a stub here, real body in `0002d`). + +--- + +## Audit step (do this first) + +Before adding `config.rs`, confirm there is no existing top-level config +loader. Run from the repo root: + +```bash +rg -nF 'VestigeConfig' crates/ +rg -nF 'toml::from_str' crates/ +rg -n '#\[derive.*Deserialize.*\]' crates/vestige-core/src/ +``` + +If a `VestigeConfig` struct already exists from Phase 1, treat the "Config +module" section below as additive: extend the existing struct rather than +creating a new file. The cross-cut additions in that case are: + +1. Add the `StorageConfig` enum (gated and ungated branches). +2. Add `SqliteConfig`, `PostgresConfig`. +3. Add the `default_path()` helper if missing. +4. Add `ConfigError` if a different error enum is used today (rename/extend + instead of duplicating). + +As of the audit at the time of this writing, no `VestigeConfig` exists in +`vestige-core`. `directories::ProjectDirs` is already used in +`vestige-core/src/embeddings/local.rs` and in +`vestige-mcp/src/protocol/auth.rs`, so the `directories` crate is already a +workspace dependency -- no new dep there. + +--- + +## Cargo manifest additions + +Add `toml` to `vestige-core`. `serde` and `thiserror` are already present +from Phase 1; `directories` is already a transitive dep but we add it +explicitly so `default_path()` is supported. + +```bash +cd crates/vestige-core +cargo add toml@0.8 +cargo add directories@5 +``` + +No new deps on `vestige-mcp`; it already depends on `vestige-core`. + +`sqlx` is already added by `0002a` behind the `postgres-backend` feature +with `runtime-tokio`, `tls-rustls`, `postgres`, `uuid`, `chrono`, +`json`, `macros`, `migrate` features. The pool module only uses what is +already pulled in. + +--- + +## Config module + +**File**: `crates/vestige-core/src/config.rs` (new). +**Re-exported** from `crates/vestige-core/src/lib.rs` as `pub mod config;` plus +`pub use config::{VestigeConfig, StorageConfig, SqliteConfig, EmbeddingsConfig, ConfigError};` +and `#[cfg(feature = "postgres-backend")] pub use config::PostgresConfig;`. + +Full content: + +```rust +//! Vestige top-level configuration. +//! +//! Loaded from `~/.vestige/vestige.toml` by default; the path is overridable +//! via `VestigeConfig::load(Some(&path))`. Parsing uses serde + toml; the +//! `[storage]` section is internally-tagged on a `backend` field so a single +//! enum dispatch picks SQLite or Postgres. + +use std::path::{Path, PathBuf}; + +use serde::Deserialize; + +/// Top-level configuration as parsed from `vestige.toml`. +#[derive(Debug, Clone, Deserialize, Default)] +#[serde(default, deny_unknown_fields)] +pub struct VestigeConfig { + pub embeddings: EmbeddingsConfig, + pub storage: StorageConfig, + /// Reserved for Phase 3. Empty in Phase 2. + pub server: ServerConfig, + /// Reserved for Phase 3. Empty in Phase 2. + pub auth: AuthConfig, +} + +/// Embedding provider selection. +#[derive(Debug, Clone, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct EmbeddingsConfig { + /// Provider key. Phase 2 ships `"fastembed"` only. + pub provider: String, + /// Model name. For fastembed this is e.g. `"nomic-ai/nomic-embed-text-v1.5"`. + pub model: String, +} + +impl Default for EmbeddingsConfig { + fn default() -> Self { + Self { + provider: "fastembed".to_string(), + model: crate::DEFAULT_EMBEDDING_MODEL.to_string(), + } + } +} + +/// Storage backend selection. Internally tagged on the `backend` field: +/// +/// ```toml +/// [storage] +/// backend = "sqlite" +/// +/// [storage.sqlite] +/// path = "/home/user/.vestige/vestige.db" +/// ``` +/// +/// or, when compiled with `--features postgres-backend`: +/// +/// ```toml +/// [storage] +/// backend = "postgres" +/// +/// [storage.postgres] +/// url = "postgres://vestige:secret@localhost:5432/vestige" +/// max_connections = 10 +/// acquire_timeout_secs = 30 +/// ``` +#[derive(Debug, Clone, Deserialize)] +#[serde(tag = "backend", rename_all = "lowercase", deny_unknown_fields)] +pub enum StorageConfig { + Sqlite(SqliteConfig), + #[cfg(feature = "postgres-backend")] + Postgres(PostgresConfig), +} + +impl Default for StorageConfig { + fn default() -> Self { + StorageConfig::Sqlite(SqliteConfig::default()) + } +} + +/// SQLite backend configuration. +#[derive(Debug, Clone, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct SqliteConfig { + /// Path to the `vestige.db` file. If unset, the SqliteMemoryStore + /// constructor picks its platform default location. + #[serde(default)] + pub path: Option, +} + +impl Default for SqliteConfig { + fn default() -> Self { + Self { path: None } + } +} + +/// Postgres backend configuration. Only present when the `postgres-backend` +/// Cargo feature is enabled. +#[cfg(feature = "postgres-backend")] +#[derive(Debug, Clone, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct PostgresConfig { + /// `postgres://user:pass@host:port/db` -- forwarded to + /// `PgConnectOptions::from_str`. + pub url: String, + /// Pool size. Default `10`. + #[serde(default)] + pub max_connections: Option, + /// Acquire timeout in seconds. Default `30`. Set above 30 so + /// testcontainer-based test fixtures do not race. + #[serde(default)] + pub acquire_timeout_secs: Option, +} + +/// Reserved for Phase 3 (bind address, ports, TLS). +#[derive(Debug, Clone, Default, Deserialize)] +#[serde(default, deny_unknown_fields)] +pub struct ServerConfig {} + +/// Reserved for Phase 3 (API keys, claims). +#[derive(Debug, Clone, Default, Deserialize)] +#[serde(default, deny_unknown_fields)] +pub struct AuthConfig {} + +/// Errors raised while locating, reading, or parsing `vestige.toml`. +#[derive(Debug, thiserror::Error)] +pub enum ConfigError { + #[error("config io: {0}")] + Io(#[from] std::io::Error), + #[error("config toml: {0}")] + Toml(#[from] toml::de::Error), + #[error("config dir: could not locate user home")] + NoHome, + #[error("invalid config: {0}")] + Invalid(String), +} + +impl VestigeConfig { + /// Load config from `path` or from `default_path()` when `None`. + /// + /// Returns `VestigeConfig::default()` (SQLite + fastembed defaults) when + /// the file does not exist. Any other I/O or parse failure is surfaced + /// as a `ConfigError`. + pub fn load(path: Option<&Path>) -> Result { + let resolved: PathBuf = match path { + Some(p) => p.to_path_buf(), + None => Self::default_path()?, + }; + + match std::fs::read_to_string(&resolved) { + Ok(text) => { + let cfg: VestigeConfig = toml::from_str(&text)?; + cfg.validate()?; + Ok(cfg) + } + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + Ok(Self::default()) + } + Err(e) => Err(ConfigError::Io(e)), + } + } + + /// `~/.vestige/vestige.toml`. The directory is NOT created here; loading + /// a missing file falls back to defaults. + pub fn default_path() -> Result { + let dirs = directories::ProjectDirs::from("", "vestige", "vestige") + .ok_or(ConfigError::NoHome)?; + // ProjectDirs::config_dir() varies per OS. Vestige convention is + // ~/.vestige/vestige.toml on Linux/macOS regardless of XDG, so we + // build the path off the home dir explicitly. + let home = directories::UserDirs::new() + .ok_or(ConfigError::NoHome)? + .home_dir() + .to_path_buf(); + let _ = dirs; // keep the dep wired; future Phase 3 may use it + Ok(home.join(".vestige").join("vestige.toml")) + } + + /// Light cross-field validation. Heavy validation (URL parsing, + /// directory existence) is left to the backend constructors. + fn validate(&self) -> Result<(), ConfigError> { + if self.embeddings.provider.is_empty() { + return Err(ConfigError::Invalid( + "embeddings.provider must not be empty".into(), + )); + } + if self.embeddings.model.is_empty() { + return Err(ConfigError::Invalid( + "embeddings.model must not be empty".into(), + )); + } + match &self.storage { + StorageConfig::Sqlite(_) => {} + #[cfg(feature = "postgres-backend")] + StorageConfig::Postgres(cfg) => { + if cfg.url.is_empty() { + return Err(ConfigError::Invalid( + "storage.postgres.url must not be empty".into(), + )); + } + } + } + Ok(()) + } +} +``` + +### Serde behaviour with `postgres-backend` off + +`StorageConfig` is generated by serde only for the variants that are +compiled in. When `postgres-backend` is off and the user writes: + +```toml +[storage] +backend = "postgres" + +[storage.postgres] +url = "..." +``` + +serde returns a `toml::de::Error` of the form +`unknown variant `postgres`, expected `sqlite``. That error path goes +through `From for ConfigError`, surfacing as +`ConfigError::Toml(..)`. The MCP server prints this once at startup and +exits with a non-zero code; there is no panic. + +To make the error friendlier we wrap that specific case in a clearer +message via a thin post-parse check. Add this small helper after parsing +in `load()`: + +```rust +// (Inside the Ok(text) arm in load(), wrapping the parse step.) +let cfg: VestigeConfig = match toml::from_str(&text) { + Ok(c) => c, + Err(e) => { + let msg = e.to_string(); + if msg.contains("unknown variant `postgres`") { + return Err(ConfigError::Invalid( + "storage.backend = \"postgres\" requires building with --features postgres-backend".into(), + )); + } + return Err(ConfigError::Toml(e)); + } +}; +``` + +This keeps the strict default deny_unknown_fields behaviour while giving the +user a one-line action item. + +--- + +## Pool module + +**File**: `crates/vestige-core/src/storage/postgres/pool.rs` (new). + +```rust +#![cfg(feature = "postgres-backend")] + +//! `PgPool` construction for the Postgres backend. +//! +//! Pool defaults follow ADR 0002 D2 + master plan D3: +//! - max_connections = 10 +//! - acquire_timeout = 30s (must exceed testcontainer warmup) +//! - idle_timeout = 600s +//! - max_lifetime = 1800s +//! - test_before_acquire = false (cheap queries; saves a roundtrip) + +use std::str::FromStr; +use std::time::Duration; + +use sqlx::postgres::{PgConnectOptions, PgPoolOptions}; +use sqlx::{ConnectOptions, PgPool}; + +use crate::config::PostgresConfig; +use crate::storage::memory_store::{MemoryStoreError, MemoryStoreResult}; + +const DEFAULT_MAX_CONNECTIONS: u32 = 10; +const DEFAULT_ACQUIRE_TIMEOUT_SECS: u64 = 30; +const IDLE_TIMEOUT_SECS: u64 = 600; +const MAX_LIFETIME_SECS: u64 = 1800; +const STATEMENT_CACHE_CAPACITY: usize = 256; + +/// Build a Postgres connection pool from a `PostgresConfig`. Does NOT run +/// migrations or stamp the embedding registry; those are the caller's job +/// (`PgMemoryStore::connect`). +pub async fn build_pool(cfg: &PostgresConfig) -> MemoryStoreResult { + let opts = PgConnectOptions::from_str(&cfg.url) + .map_err(MemoryStoreError::from)? + .application_name("vestige") + .statement_cache_capacity(STATEMENT_CACHE_CAPACITY) + .log_statements(tracing::log::LevelFilter::Debug); + + let max_conn = cfg.max_connections.unwrap_or(DEFAULT_MAX_CONNECTIONS); + let acquire = cfg + .acquire_timeout_secs + .unwrap_or(DEFAULT_ACQUIRE_TIMEOUT_SECS); + + let pool = PgPoolOptions::new() + .max_connections(max_conn) + .min_connections(0) + .acquire_timeout(Duration::from_secs(acquire)) + .idle_timeout(Some(Duration::from_secs(IDLE_TIMEOUT_SECS))) + .max_lifetime(Some(Duration::from_secs(MAX_LIFETIME_SECS))) + .test_before_acquire(false) + .connect_with(opts) + .await + .map_err(MemoryStoreError::from)?; + + Ok(pool) +} +``` + +### Wiring into `PgMemoryStore::connect` + +In `crates/vestige-core/src/storage/postgres/mod.rs`, replace the +`todo!()` body left by `0002a` for `connect` and `from_pool` with: + +```rust +// In crates/vestige-core/src/storage/postgres/mod.rs + +use sqlx::PgPool; + +use crate::config::PostgresConfig; +use crate::storage::memory_store::{MemoryStoreError, MemoryStoreResult}; + +mod pool; +mod registry; // see "Registry stub" section below + +pub struct PgMemoryStore { + pool: PgPool, +} + +impl PgMemoryStore { + /// Convenience constructor matching `SqliteMemoryStore::new` shape. + /// Takes a URL + pool size for the common case. + pub async fn connect(url: &str, max_connections: u32) -> MemoryStoreResult { + let cfg = PostgresConfig { + url: url.to_string(), + max_connections: Some(max_connections), + acquire_timeout_secs: None, + }; + Self::connect_with(&cfg).await + } + + /// Full-config constructor. + pub async fn connect_with(cfg: &PostgresConfig) -> MemoryStoreResult { + let pool = pool::build_pool(cfg).await?; + Self::from_pool(pool).await + } + + /// Construct from an already-built pool (used by tests and the migrate + /// CLI to share a pool across operations). + pub async fn from_pool(pool: PgPool) -> MemoryStoreResult { + // Migrations are added by 0002c. + // todo!("run sqlx::migrate! once 0002c lands") + registry::ensure_registry_stub(&pool).await?; + Ok(Self { pool }) + } +} +``` + +`connect_with` is the long-lived API; `connect` becomes a thin shim that +stays compatible with the master-plan-mandated signature. + +### Registry stub + +**File**: `crates/vestige-core/src/storage/postgres/registry.rs` (new, stub). + +```rust +#![cfg(feature = "postgres-backend")] + +//! Embedding registry. Real body lands in sub-plan 0002d. + +use sqlx::PgPool; + +use crate::storage::memory_store::MemoryStoreResult; + +/// Placeholder. Real implementation in 0002d reads/writes `embedding_model` +/// and stamps `ALTER TABLE memories ALTER COLUMN embedding TYPE vector($N)`. +pub(crate) async fn ensure_registry_stub(_pool: &PgPool) -> MemoryStoreResult<()> { + // Intentionally a no-op until 0002c lands the table + 0002d lands the + // real body. Leaving this as todo!() would crash the MCP server at + // startup the moment a user switches `backend = "postgres"`, which is + // not what we want for the build verification step in this sub-plan. + Ok(()) +} +``` + +The no-op keeps `cargo build --features postgres-backend` not just +compiling but also allowing the MCP server to *boot* against a Postgres +URL pointing at an already-migrated database (the local-dev-postgres-setup +docs cover bringing up such a DB by hand). Real init lands in `0002d`. + +--- + +## Error variants + +**File**: `crates/vestige-core/src/storage/memory_store.rs` (edit). + +The Phase 1 enum `MemoryStoreError` gains two feature-gated variants. These +were deferred in `0002a` and become required as soon as `pool.rs` calls +`.map_err(MemoryStoreError::from)` on `sqlx::Error`. + +```rust +// Within enum MemoryStoreError { ... } in memory_store.rs + +#[cfg(feature = "postgres-backend")] +#[error("postgres error: {0}")] +Postgres(#[from] sqlx::Error), + +#[cfg(feature = "postgres-backend")] +#[error("postgres migration error: {0}")] +Migrate(#[from] sqlx::migrate::MigrateError), +``` + +Both use thiserror's `#[from]` attribute so the `?` operator works in +`pool.rs`, the migrate module (`0002c`), and registry code (`0002d`). +Default-features build (no `postgres-backend`) sees neither variant; the +enum stays exhaustive on stable. + +If clippy fires on `non_exhaustive` due to the gated variants, add +`#[non_exhaustive]` on the enum. That has no caller-side effect since the +enum is constructed only inside the crate. + +--- + +## vestige-mcp wiring + +### Cargo feature passthrough + +**File**: `crates/vestige-mcp/Cargo.toml` (edit). + +Add a feature that forwards through to `vestige-core`. Default features in +`vestige-mcp` stay unchanged. + +```toml +[features] +default = ["embeddings", "vector-search"] +embeddings = ["vestige-core/embeddings"] +vector-search = ["vestige-core/vector-search"] +postgres-backend = ["vestige-core/postgres-backend"] +``` + +Verify with: + +```bash +cargo build -p vestige-mcp --features postgres-backend +``` + +### Backend dispatch at startup + +**File**: `crates/vestige-mcp/src/main.rs` (edit around the existing +`Storage::new(storage_path)` call -- see audit note above; in the current +worktree this is around line 285). + +The current code is roughly: + +```rust +let storage_path = match prepare_storage_path(config.data_dir) { ... }; +let storage = match Storage::new(storage_path) { ... }; +``` + +Replace that with a dispatch driven by `VestigeConfig`: + +```rust +use std::sync::Arc; + +use vestige_core::config::{StorageConfig, VestigeConfig}; +use vestige_core::storage::SqliteMemoryStore; +#[cfg(feature = "postgres-backend")] +use vestige_core::storage::postgres::PgMemoryStore; +use vestige_core::storage::MemoryStore; + +// Earlier: still call prepare_storage_path to honour --data-dir override. +let storage_path = match prepare_storage_path(config.data_dir.clone()) { ... }; + +// New: load vestige.toml (or fall back to defaults). +let vestige_cfg = match VestigeConfig::load(config.config_path.as_deref()) { + Ok(c) => c, + Err(e) => { + eprintln!("vestige: failed to load config: {e}"); + std::process::exit(2); + } +}; + +let storage: Arc = match &vestige_cfg.storage { + StorageConfig::Sqlite(sqlite_cfg) => { + // CLI flag --data-dir wins over the config file path. + let path = storage_path.clone().or_else(|| sqlite_cfg.path.clone()); + let s = SqliteMemoryStore::new(path).unwrap_or_else(|e| { + eprintln!("vestige: sqlite init failed: {e}"); + std::process::exit(3); + }); + Arc::new(s) + } + #[cfg(feature = "postgres-backend")] + StorageConfig::Postgres(pg_cfg) => { + let s = PgMemoryStore::connect_with(pg_cfg).await.unwrap_or_else(|e| { + eprintln!("vestige: postgres init failed: {e}"); + std::process::exit(3); + }); + Arc::new(s) + } +}; +``` + +The `config_path: Option` field on the local `Config` (or +clap-derived `Args`) struct must be added if not present; it accepts +`--config `. Default behaviour (no flag) goes through +`VestigeConfig::default_path()`. + +If the existing main wires `Storage` through a concrete type rather than +`Arc`, the dispatch above lives behind a helper: + +```rust +async fn build_store(cfg: &VestigeConfig, cli_path: Option) + -> Result, anyhow::Error> +{ ... } +``` + +and the caller chains `.into()` as needed. Phase 1 already moved +cognitive modules to `Arc` so this should be a pure +substitution; if a concrete-type holdout is found, fix it locally in this +sub-plan (separate commit) rather than punting. + +--- + +## vestige.toml example + +The canonical example to ship in `docs/` (Phase 2 docs land in `0002i`, +runbook), shown here for reference and used verbatim by the unit test +below. + +```toml +# vestige.toml -- top-level configuration +# +# Default location: ~/.vestige/vestige.toml +# Override: vestige-mcp --config /path/to/vestige.toml + +[embeddings] +provider = "fastembed" +model = "nomic-ai/nomic-embed-text-v1.5" + +# --- SQLite backend (default) --- +[storage] +backend = "sqlite" + +[storage.sqlite] +path = "/home/user/.vestige/vestige.db" + +# --- Postgres backend (requires --features postgres-backend) --- +# [storage] +# backend = "postgres" +# +# [storage.postgres] +# url = "postgres://vestige:secret@localhost:5432/vestige" +# max_connections = 10 +# acquire_timeout_secs = 30 + +[server] +# Reserved for Phase 3 (bind address, ports, TLS). + +[auth] +# Reserved for Phase 3 (API keys, claims). +``` + +--- + +## Verification + +Run all of these from the repo root. The first three are the gates that +must pass before this sub-plan is considered done. + +### 1. Default build (no Postgres) + +```bash +cargo build -p vestige-core +cargo build -p vestige-mcp +cargo test -p vestige-core --lib +``` + +Expected: clean build. `VestigeConfig::default()` selects SQLite; the MCP +server boots the same way it did pre-sub-plan. + +### 2. Postgres-feature build + +```bash +cargo build -p vestige-core --features postgres-backend +cargo build -p vestige-mcp --features postgres-backend +``` + +Expected: clean build. `PgMemoryStore::connect_with` resolves to +`pool::build_pool` + `registry::ensure_registry_stub`; no `todo!()` is +reachable on the build path. `connect` and `from_pool` are exported. + +### 3. Clippy across both feature sets + +```bash +cargo clippy -p vestige-core -- -D warnings +cargo clippy -p vestige-core --features postgres-backend -- -D warnings +cargo clippy -p vestige-mcp --features postgres-backend -- -D warnings +``` + +### 4. Unit test: round-trip the example + +Add this test to `crates/vestige-core/src/config.rs`: + +```rust +#[cfg(test)] +mod tests { + use super::*; + + const EXAMPLE_SQLITE: &str = r#" +[embeddings] +provider = "fastembed" +model = "nomic-ai/nomic-embed-text-v1.5" + +[storage] +backend = "sqlite" + +[storage.sqlite] +path = "/home/user/.vestige/vestige.db" +"#; + + #[cfg(feature = "postgres-backend")] + const EXAMPLE_POSTGRES: &str = r#" +[embeddings] +provider = "fastembed" +model = "nomic-ai/nomic-embed-text-v1.5" + +[storage] +backend = "postgres" + +[storage.postgres] +url = "postgres://vestige:secret@localhost:5432/vestige" +max_connections = 10 +acquire_timeout_secs = 30 +"#; + + #[test] + fn parses_sqlite_example() { + let cfg: VestigeConfig = toml::from_str(EXAMPLE_SQLITE).expect("parse"); + match cfg.storage { + StorageConfig::Sqlite(s) => assert!(s.path.is_some()), + #[cfg(feature = "postgres-backend")] + StorageConfig::Postgres(_) => panic!("wrong variant"), + } + assert_eq!(cfg.embeddings.provider, "fastembed"); + } + + #[cfg(feature = "postgres-backend")] + #[test] + fn parses_postgres_example() { + let cfg: VestigeConfig = toml::from_str(EXAMPLE_POSTGRES).expect("parse"); + match cfg.storage { + StorageConfig::Postgres(p) => { + assert_eq!(p.url, "postgres://vestige:secret@localhost:5432/vestige"); + assert_eq!(p.max_connections, Some(10)); + assert_eq!(p.acquire_timeout_secs, Some(30)); + } + StorageConfig::Sqlite(_) => panic!("wrong variant"), + } + } + + #[cfg(not(feature = "postgres-backend"))] + #[test] + fn rejects_postgres_when_feature_off() { + let toml_text = r#" +[storage] +backend = "postgres" + +[storage.postgres] +url = "postgres://x/y" +"#; + let res: Result = toml::from_str(toml_text); + assert!(res.is_err(), "must fail without postgres-backend feature"); + } + + #[test] + fn defaults_pick_sqlite() { + let cfg = VestigeConfig::default(); + assert!(matches!(cfg.storage, StorageConfig::Sqlite(_))); + } + + #[test] + fn load_missing_file_returns_default() { + let tmp = std::env::temp_dir().join("vestige-no-such-file.toml"); + let _ = std::fs::remove_file(&tmp); + let cfg = VestigeConfig::load(Some(&tmp)).expect("missing file is OK"); + assert!(matches!(cfg.storage, StorageConfig::Sqlite(_))); + } + + #[test] + fn load_roundtrip_from_disk() { + let tmp = std::env::temp_dir().join("vestige-roundtrip.toml"); + std::fs::write(&tmp, EXAMPLE_SQLITE).unwrap(); + let cfg = VestigeConfig::load(Some(&tmp)).expect("load"); + assert!(matches!(cfg.storage, StorageConfig::Sqlite(_))); + let _ = std::fs::remove_file(&tmp); + } +} +``` + +Run: + +```bash +cargo test -p vestige-core --lib config:: +cargo test -p vestige-core --lib config:: --features postgres-backend +``` + +### 5. Smoke: server boots with default config + +```bash +# default build, no vestige.toml on disk +cargo run -p vestige-mcp -- --help +# should print help, no panic +``` + +--- + +## Acceptance criteria + +- [ ] `cargo build -p vestige-core` (default features) succeeds. +- [ ] `cargo build -p vestige-core --features postgres-backend` succeeds. +- [ ] `cargo build -p vestige-mcp` (default features) succeeds. +- [ ] `cargo build -p vestige-mcp --features postgres-backend` succeeds. +- [ ] `cargo clippy` with and without `postgres-backend` is clean on both + crates. +- [ ] `crates/vestige-core/src/config.rs` exists, exposes + `VestigeConfig`, `StorageConfig`, `SqliteConfig`, `EmbeddingsConfig`, + `ConfigError`, plus `PostgresConfig` when the feature is on. +- [ ] `VestigeConfig::load(None)` returns `Ok(default)` when + `~/.vestige/vestige.toml` is missing. +- [ ] `VestigeConfig::load(Some(&path))` round-trips both the SQLite and + Postgres example blocks above. +- [ ] With `postgres-backend` off, parsing `backend = "postgres"` returns + a clear `ConfigError::Invalid` mentioning the feature flag, NOT a + panic. +- [ ] `crates/vestige-core/src/storage/postgres/pool.rs` exists, + implementing `build_pool(&PostgresConfig) -> MemoryStoreResult` + with the documented defaults. +- [ ] `PgMemoryStore::connect`, `connect_with`, and `from_pool` all wire + through `pool::build_pool`. None of them is `todo!()`. The registry + step is a no-op stub documented as filled in by `0002d`. +- [ ] `MemoryStoreError::Postgres(sqlx::Error)` and + `MemoryStoreError::Migrate(sqlx::migrate::MigrateError)` exist + behind `#[cfg(feature = "postgres-backend")]` with `#[from]`. +- [ ] `vestige-mcp` has a `postgres-backend` feature that forwards to + `vestige-core/postgres-backend`. +- [ ] `vestige-mcp/src/main.rs` selects SQLite vs Postgres at startup + based on `VestigeConfig`. SQLite is the default when no config file + is present. +- [ ] Unit tests in the "Verification" section pass on both feature sets. + +--- + +## Out of scope (handled by other sub-plans) + +- Migrations (`crates/vestige-core/migrations/postgres/*.sql`) -- `0002c`. +- Real `PgMemoryStore` CRUD/search/scheduling/edges bodies -- `0002d`, + `0002e`. +- `ensure_registry` real body with `ALTER COLUMN TYPE vector(N)` -- `0002d`. +- `vestige migrate --from sqlite --to postgres` CLI -- `0002f`. +- Re-embed flow -- `0002g`. +- Env-var override (`VESTIGE_POSTGRES_URL`, etc.) -- Phase 3. +- RLS, multi-tenant column population -- Phase 3. diff --git a/docs/plans/0002c-migrations.md b/docs/plans/0002c-migrations.md new file mode 100644 index 0000000..ef8e35c --- /dev/null +++ b/docs/plans/0002c-migrations.md @@ -0,0 +1,1119 @@ +# Phase 2 Sub-plan 0002c: sqlx Migrations + +**Status**: Draft +**Depends on**: `0002a-skeleton-and-feature-gate.md` (PgMemoryStore skeleton, error variants), `0002b-pool-and-config.md` (PgPool builder, PostgresConfig) +**Related**: docs/adr/0002-phase-2-execution.md (D7 multi-tenancy reservation, D8 codebase column), docs/plans/0002-phase-2-postgres-backend.md (D4 master SQL), docs/plans/local-dev-postgres-setup.md (local cluster + role + DB) + +--- + +## Context + +This sub-plan covers Phase 2 deliverable D4 (sqlx migration files under +`crates/vestige-core/migrations/postgres/`) PLUS the schema additions decided +in ADR 0002: + +- D7 -- multi-tenancy reservation: `users`, `groups`, `group_memberships` + tables, plus `owner_user_id`, `visibility`, `shared_with_groups` columns on + `knowledge_nodes`. Phase 3 fills these in; Phase 2 just reserves them so the auth + filter is later additive instead of an online migration over a populated, + HNSW-indexed table. +- D8 -- `codebase` promoted to a first-class indexed column on `knowledge_nodes`. + +This sub-plan also adds the parity SQLite migration (V15) that mirrors D7 + +D8 on the SQLite side, so a single-user SQLite deployment sees the same +columns (with stand-in defaults). + +After this sub-plan lands: + +- A fresh Postgres database, with the `vestige` role from the local-dev + setup, can be initialized by running `sqlx::migrate!` against + `crates/vestige-core/migrations/postgres/`, plus one programmatic + `register_model` call before the HNSW migration. +- A fresh SQLite database initialized by `apply_migrations` lands at + schema_version = 15 with the new tables and columns present. +- `PgMemoryStore::connect` wires the migrator into the connect path + (pool build -> migrator up-to v1 -> register_model -> migrator up-to v2). +- The SQLite test suite continues to pass. +- No `sqlx::query!` calls are introduced yet; the offline `.sqlx/` cache is + filled out in `0002d-store-impl-bodies.md`. + +The deliverable is purely schema. No query bodies, no row-mapping, no search. + +--- + +## Postgres migration files + +Layout, relative to repo root: + +``` +crates/vestige-core/migrations/postgres/ + 0001_init.up.sql + 0001_init.down.sql + 0002_hnsw.up.sql + 0002_hnsw.down.sql +``` + +The `migrations/postgres/` directory is sibling-of-`src/`, not under `src/`, +because `sqlx::migrate!` and `sqlx-cli` both look for a path relative to +`CARGO_MANIFEST_DIR`. The directory is committed. + +### 0001_init.up.sql + +Creates extensions, the multi-tenancy tables (D7), the embedding registry, +the domains catalogue, the `knowledge_nodes` table (with D7 + D8 columns merged in), +the FSRS scheduling and edges tables, the review-events log, all non-vector +indexes, the updated_at trigger, and the bootstrap `local` user row. + +The HNSW vector index is deliberately NOT here -- it requires a typmod on +`knowledge_nodes.embedding`, which is stamped by `register_model` at runtime. See +the "HNSW typmod ordering" section below. + +```sql +-- crates/vestige-core/migrations/postgres/0001_init.up.sql +-- +-- Phase 2 initial schema for the Postgres backend. +-- Includes D7 multi-tenancy reservation (users/groups/group_memberships, +-- owner_user_id/visibility/shared_with_groups on knowledge_nodes) and D8 +-- (codebase first-class column on knowledge_nodes). +-- +-- The HNSW index on knowledge_nodes.embedding lives in 0002_hnsw.up.sql; it +-- requires the column typmod to be stamped first by register_model(). + +-- Extensions ---------------------------------------------------------------- + +CREATE EXTENSION IF NOT EXISTS pgcrypto; +CREATE EXTENSION IF NOT EXISTS vector; + +-- Embedding model registry -------------------------------------------------- +-- Mirrors the SQLite table created in Phase 1 V14. +-- One logical row enforced by CHECK (id = 1). + +CREATE TABLE embedding_model ( + id SMALLINT PRIMARY KEY DEFAULT 1 CHECK (id = 1), + name TEXT NOT NULL, + dimension INTEGER NOT NULL CHECK (dimension > 0), + hash TEXT NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- Domains catalogue --------------------------------------------------------- +-- Populated by the Phase 4 DomainClassifier. Phase 2 creates the empty +-- table so list/get/upsert/delete work uniformly against both backends. + +CREATE TABLE domains ( + id TEXT PRIMARY KEY, + label TEXT NOT NULL, + centroid vector, + top_terms TEXT[] NOT NULL DEFAULT '{}', + memory_count INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + metadata JSONB NOT NULL DEFAULT '{}'::jsonb +); + +-- Multi-tenancy (D7) -------------------------------------------------------- +-- Reserved in Phase 2; populated in Phase 3. +-- Single bootstrap user inserted at the bottom of this file. + +CREATE TABLE users ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + handle TEXT NOT NULL UNIQUE, + display_name TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + metadata JSONB NOT NULL DEFAULT '{}'::jsonb +); + +CREATE TABLE groups ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + handle TEXT NOT NULL UNIQUE, + display_name TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + metadata JSONB NOT NULL DEFAULT '{}'::jsonb +); + +CREATE TABLE group_memberships ( + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + group_id UUID NOT NULL REFERENCES groups(id) ON DELETE CASCADE, + role TEXT NOT NULL DEFAULT 'member', + joined_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (user_id, group_id), + CHECK (role IN ('member', 'admin')) +); + +-- Core knowledge_nodes table ------------------------------------------------- +-- Original Phase 2 columns merged with D7 (owner_user_id, visibility, +-- shared_with_groups) and D8 (codebase). + +CREATE TABLE knowledge_nodes ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + + -- Content + content TEXT NOT NULL, + node_type TEXT NOT NULL DEFAULT 'general', + tags TEXT[] NOT NULL DEFAULT '{}', + metadata JSONB NOT NULL DEFAULT '{}'::jsonb, + + -- Phase 4 emergent domains (Phase 2 leaves empty) + domains TEXT[] NOT NULL DEFAULT '{}', + domain_scores JSONB NOT NULL DEFAULT '{}'::jsonb, + + -- Embedding (typmod stamped by register_model before 0002_hnsw runs) + embedding vector, + + -- D8: first-class codebase column for high-frequency scoped queries + codebase TEXT, + + -- D7: multi-tenancy reservation. Defaults make Phase 2 single-user + -- behaviour identical to Phase 1. + owner_user_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000001' + REFERENCES users(id), + visibility TEXT NOT NULL DEFAULT 'private', + shared_with_groups UUID[] NOT NULL DEFAULT '{}', + + -- Timestamps + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + + -- Generated full-text search vector. Phase 2 uses websearch_to_tsquery + -- against this column at query time (see 0002e-hybrid-search.md). + search_vec TSVECTOR GENERATED ALWAYS AS ( + setweight(to_tsvector('english', coalesce(content, '')), 'A') || + setweight(to_tsvector('english', coalesce(node_type, '')), 'B') || + setweight(to_tsvector('english', coalesce(array_to_string(tags, ' '), '')), 'C') + ) STORED, + + -- Visibility tri-state CHECK constraint. See "Visibility CHECK + -- constraint" section below for the cardinality variant we + -- intentionally do NOT add yet. + CHECK (visibility IN ('private', 'group', 'public')) +); + +-- FSRS scheduling state (1:1 with knowledge_nodes) --------------------------- +-- +-- Note: the FK column is named `memory_id` (not `node_id`) to match the +-- Phase 1 SQLite trait surface: `SchedulingState { memory_id: Uuid, ... }` +-- and `get_scheduling(memory_id: Uuid)` / `update_scheduling(&state)`. The +-- table is `knowledge_nodes` but the Rust identifier remained `memory_id` +-- across Phase 1 and is preserved here so both backends speak the same +-- language at the trait boundary. + +CREATE TABLE scheduling ( + memory_id UUID PRIMARY KEY REFERENCES knowledge_nodes(id) ON DELETE CASCADE, + stability DOUBLE PRECISION NOT NULL DEFAULT 0.0, + difficulty DOUBLE PRECISION NOT NULL DEFAULT 0.0, + retrievability DOUBLE PRECISION NOT NULL DEFAULT 1.0, + last_review TIMESTAMPTZ, + next_review TIMESTAMPTZ, + reps INTEGER NOT NULL DEFAULT 0, + lapses INTEGER NOT NULL DEFAULT 0 +); + +-- Spreading activation graph edges ------------------------------------------ + +CREATE TABLE edges ( + source_id UUID NOT NULL REFERENCES knowledge_nodes(id) ON DELETE CASCADE, + target_id UUID NOT NULL REFERENCES knowledge_nodes(id) ON DELETE CASCADE, + edge_type TEXT NOT NULL DEFAULT 'related', + weight DOUBLE PRECISION NOT NULL DEFAULT 1.0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (source_id, target_id, edge_type) +); + +-- FSRS review event log (append-only; Phase 5 federation reads) ------------- + +CREATE TABLE review_events ( + id BIGSERIAL PRIMARY KEY, + memory_id UUID NOT NULL REFERENCES knowledge_nodes(id) ON DELETE CASCADE, + timestamp TIMESTAMPTZ NOT NULL DEFAULT now(), + rating SMALLINT NOT NULL, + prior_state JSONB NOT NULL, + new_state JSONB NOT NULL +); + +-- Indexes ------------------------------------------------------------------- + +-- knowledge_nodes: full-text, arrays, hot scalar columns, D7+D8 access patterns +CREATE INDEX idx_knowledge_nodes_fts ON knowledge_nodes USING GIN (search_vec); +CREATE INDEX idx_knowledge_nodes_domains ON knowledge_nodes USING GIN (domains); +CREATE INDEX idx_knowledge_nodes_tags ON knowledge_nodes USING GIN (tags); +CREATE INDEX idx_knowledge_nodes_node_type ON knowledge_nodes (node_type); +CREATE INDEX idx_knowledge_nodes_created ON knowledge_nodes (created_at); +CREATE INDEX idx_knowledge_nodes_updated ON knowledge_nodes (updated_at); + +-- D7 visibility filter (Phase 3 query: WHERE owner_user_id = $me ...) +CREATE INDEX idx_knowledge_nodes_owner ON knowledge_nodes (owner_user_id); +CREATE INDEX idx_knowledge_nodes_shared_groups ON knowledge_nodes USING GIN (shared_with_groups); + +-- D8 codebase scoping (Phase 4 HDBSCAN per-repo, sharing rules in Phase 4). +-- Partial index keeps the index small in single-user mode where most rows +-- never set a codebase. +CREATE INDEX idx_knowledge_nodes_codebase + ON knowledge_nodes (codebase) + WHERE codebase IS NOT NULL; + +-- scheduling: hot lookup paths for FSRS pickers +CREATE INDEX idx_scheduling_next_review ON scheduling (next_review); +CREATE INDEX idx_scheduling_last_review ON scheduling (last_review); + +-- edges: bidirectional + edge type +CREATE INDEX idx_edges_target ON edges (target_id); +CREATE INDEX idx_edges_source ON edges (source_id); +CREATE INDEX idx_edges_type ON edges (edge_type); + +-- review_events: per-memory and chronological +CREATE INDEX idx_review_events_memory ON review_events (memory_id); +CREATE INDEX idx_review_events_ts ON review_events (timestamp); + +-- users / groups: unique handle indexes are implicit; add nothing extra. +-- group_memberships: primary key (user_id, group_id) is the access path. + +-- updated_at trigger on knowledge_nodes ---------------------------------------- + +CREATE OR REPLACE FUNCTION knowledge_nodes_set_updated_at() RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at := now(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_knowledge_nodes_updated_at +BEFORE UPDATE ON knowledge_nodes +FOR EACH ROW EXECUTE FUNCTION knowledge_nodes_set_updated_at(); + +-- Bootstrap rows ------------------------------------------------------------ +-- Single 'local' user matches the default on knowledge_nodes.owner_user_id so +-- single-user Phase 2 inserts never violate the FK. + +INSERT INTO users (id, handle, display_name) + VALUES ('00000000-0000-0000-0000-000000000001', 'local', 'Local User'); +``` + +### 0001_init.down.sql + +Reverse-dependency drop order. Trigger and function first, then indexes, +then tables, then extensions are left alone (extensions are global; we do +not drop them in a `down`). + +```sql +-- crates/vestige-core/migrations/postgres/0001_init.down.sql + +DROP TRIGGER IF EXISTS trg_knowledge_nodes_updated_at ON knowledge_nodes; +DROP FUNCTION IF EXISTS knowledge_nodes_set_updated_at(); + +-- knowledge_nodes indexes +DROP INDEX IF EXISTS idx_knowledge_nodes_codebase; +DROP INDEX IF EXISTS idx_knowledge_nodes_shared_groups; +DROP INDEX IF EXISTS idx_knowledge_nodes_owner; +DROP INDEX IF EXISTS idx_knowledge_nodes_updated; +DROP INDEX IF EXISTS idx_knowledge_nodes_created; +DROP INDEX IF EXISTS idx_knowledge_nodes_node_type; +DROP INDEX IF EXISTS idx_knowledge_nodes_tags; +DROP INDEX IF EXISTS idx_knowledge_nodes_domains; +DROP INDEX IF EXISTS idx_knowledge_nodes_fts; + +-- scheduling indexes +DROP INDEX IF EXISTS idx_scheduling_last_review; +DROP INDEX IF EXISTS idx_scheduling_next_review; + +-- edges indexes +DROP INDEX IF EXISTS idx_edges_type; +DROP INDEX IF EXISTS idx_edges_source; +DROP INDEX IF EXISTS idx_edges_target; + +-- review_events indexes +DROP INDEX IF EXISTS idx_review_events_ts; +DROP INDEX IF EXISTS idx_review_events_memory; + +-- Tables, reverse dependency order +DROP TABLE IF EXISTS review_events; +DROP TABLE IF EXISTS edges; +DROP TABLE IF EXISTS scheduling; +DROP TABLE IF EXISTS knowledge_nodes; +DROP TABLE IF EXISTS group_memberships; +DROP TABLE IF EXISTS groups; +DROP TABLE IF EXISTS users; +DROP TABLE IF EXISTS domains; +DROP TABLE IF EXISTS embedding_model; + +-- Extensions are intentionally NOT dropped. They may be in use by other +-- databases on the cluster; dropping them is an admin choice. +``` + +### 0002_hnsw.up.sql + +Single statement; separated from 0001 so reembed (sub-plan 0002g) can +DROP/CREATE this index in isolation without touching anything else. + +```sql +-- crates/vestige-core/migrations/postgres/0002_hnsw.up.sql +-- +-- HNSW index on knowledge_nodes.embedding. This migration runs AFTER +-- register_model() has stamped the typmod via: +-- +-- ALTER TABLE knowledge_nodes ALTER COLUMN embedding TYPE vector($N) +-- +-- where $N is the embedder's dimension(). Without the typmod, pgvector +-- rejects HNSW creation with: +-- +-- ERROR: column does not have dimensions +-- +-- See "HNSW typmod ordering" in 0002c-migrations.md and the connect() +-- sequence in 0002a-skeleton-and-feature-gate.md / 0002d-store-impl-bodies.md. +-- +-- Operator class: vector_cosine_ops -> distance operator `<=>`. +-- Build parameters: m = 16, ef_construction = 64 (pgvector defaults; see +-- the master plan 0002 D5 RRF discussion for the rationale). + +CREATE INDEX idx_knowledge_nodes_embedding_hnsw + ON knowledge_nodes USING hnsw (embedding vector_cosine_ops) + WITH (m = 16, ef_construction = 64); +``` + +### 0002_hnsw.down.sql + +```sql +-- crates/vestige-core/migrations/postgres/0002_hnsw.down.sql + +DROP INDEX IF EXISTS idx_knowledge_nodes_embedding_hnsw; +``` + +--- + +## HNSW typmod ordering + +pgvector's HNSW index requires the indexed column to have a typmod (fixed +dimension). `vector` (unconstrained) is rejected; `vector(768)` is accepted. +We cannot bake the dimension into 0001 because the dimension is an +embedder-determined runtime value -- different builds may use different +embedders. + +This forces an ordering: + +1. Apply migration 0001 (creates `knowledge_nodes.embedding vector`, no typmod). +2. Connect, decide which embedder is in use, run + `ALTER TABLE knowledge_nodes ALTER COLUMN embedding TYPE vector($N)` + inside `register_model`. +3. Apply migration 0002 (creates HNSW; succeeds because the column now has + a typmod). + +`sqlx::migrate!("...")` runs ALL pending migrations in a single call. It is +not designed to pause between two specific migrations so application code +can interleave a runtime DDL step. So we have two options: + +**Option A: Migration 0002 lives outside the sqlx migrations directory.** +Keep `0001_init.{up,down}.sql` only in `migrations/postgres/`; promote +`0002_hnsw.up.sql` to a Rust `include_str!` constant or a separate +`migrations/postgres-hnsw/` directory, run it manually by `PgMemoryStore` +after `register_model`. + +Pros: simple control flow, one `sqlx::migrate!()` call. +Cons: `sqlx_migrations` table does not record 0002, so `sqlx-cli migrate +info` lies. The HNSW index becomes "shadow" schema state from sqlx's POV. +Reembed (sub-plan 0002g) has to also know about this file outside the +normal migrations directory. + +**Option B (chosen): Both migrations live in the directory; the runner +splits them programmatically.** Use `sqlx::migrate::Migrator::new` to load +the directory and call its `run_to(...)` method with a specific version. + +```rust +// crates/vestige-core/src/storage/postgres/migrations.rs +use sqlx::migrate::Migrator; +use sqlx::PgPool; + +use crate::storage::error::MemoryStoreResult; + +/// Embedded migrator. Loaded at compile time from the migrations directory +/// alongside the crate. Path is relative to CARGO_MANIFEST_DIR. +static MIGRATOR: Migrator = sqlx::migrate!("./migrations/postgres"); + +/// Run migrations up to (and including) version 1. +/// +/// This must be called BEFORE register_model so the schema (knowledge_nodes table, +/// embedding_model registry, etc.) exists for register_model to write into +/// and to ALTER. +pub(crate) async fn run_pre_register(pool: &PgPool) -> MemoryStoreResult<()> { + MIGRATOR.run_to(pool, 1).await?; + Ok(()) +} + +/// Run any remaining migrations (currently: HNSW = version 2). +/// +/// Called AFTER register_model has stamped the embedding column's typmod. +pub(crate) async fn run_post_register(pool: &PgPool) -> MemoryStoreResult<()> { + MIGRATOR.run(pool).await?; + Ok(()) +} +``` + +Pros: sqlx is the only source of truth for migration version state; +`sqlx-cli migrate info` is accurate; reembed re-applies 0002 by name; future +migrations slot in normally. +Cons: relies on `Migrator::run_to`, which exists in sqlx 0.7+ and is the +documented API for staged migration. If that API ever disappears we fall +back to Option A. + +Decision: Option B. `Migrator::run_to(target_version)` is stable in sqlx +0.8. Sub-plan 0002a's `MemoryStoreError` already gains +`#[from] sqlx::migrate::MigrateError` to absorb whichever error variant +this surfaces. + +The `connect()` sequence in sub-plan 0002d will therefore look like: + +```rust +// Sketch only; full body lives in 0002d-store-impl-bodies.md. +pub async fn connect(url: &str, max_connections: u32) -> MemoryStoreResult { + let pool = crate::storage::postgres::pool::build(url, max_connections).await?; + crate::storage::postgres::migrations::run_pre_register(&pool).await?; + let store = Self { pool }; + // register_model is called by the cognitive engine bootstrap, NOT here. + // After it runs, the engine calls store.finalize_schema() which calls + // run_post_register. Same shape as SqliteMemoryStore. + Ok(store) +} + +pub async fn finalize_schema(&self) -> MemoryStoreResult<()> { + crate::storage::postgres::migrations::run_post_register(&self.pool).await +} +``` + +`finalize_schema` lands in 0002d; this sub-plan only ships `run_pre_register` +and `run_post_register` plus their wiring into `connect`. + +--- + +## SQLite V15 migration + +The Phase 1 SQLite schema lives in `crates/vestige-core/src/storage/migrations.rs` +as a `MIGRATIONS` slice. V14 is the latest entry. V15 is appended to mirror +D7 (multi-tenancy) and D8 (codebase) on the SQLite side, so a single-user +SQLite deployment sees the same surface area. + +Constraints versus the Postgres migration: + +- No `UUID[]` -- `shared_with_groups` is a TEXT JSON-encoded `'[]'`. +- No `gen_random_uuid()` -- the bootstrap user UUID is a literal. +- No partial indexes for our chosen pattern (SQLite *does* support partial + indexes since 3.8; we use one for `codebase` to match Postgres). +- No `ADD COLUMN IF NOT EXISTS` -- the V15 column additions are split into a + `MIGRATION_V15_ALTER_COLUMNS` slice exactly like V14 did, so the migration + is idempotent on replay. + +### Insertion point in migrations.rs + +Add to the `MIGRATIONS` slice immediately after V14: + +```rust +// In MIGRATIONS slice, after the V14 entry: +Migration { + version: 15, + description: "ADR 0002 D7+D8: multi-tenancy reservation + codebase column", + up: MIGRATION_V15_UP, +}, +``` + +### V15 SQL + +```rust +/// V15: ADR 0002 D7 + D8. +/// +/// D7 reserves users / groups / group_memberships and owner_user_id / +/// visibility / shared_with_groups columns on knowledge_nodes. Single-user +/// SQLite mode never reads these (the trait surface ignores visibility +/// because there is exactly one user) but they exist so Phase 3 does not +/// have to ALTER a populated table. +/// +/// D8 adds a first-class `codebase` column. +/// +/// Like V14, the ALTER TABLE statements are split into +/// MIGRATION_V15_ALTER_COLUMNS because SQLite has no ADD COLUMN IF NOT EXISTS. +const MIGRATION_V15_UP: &str = r#" +-- Migration V15: multi-tenancy reservation + codebase column. + +-- 1. Users / groups / group_memberships ----------------------------------- +-- Mirrors the Postgres D7 tables. Single bootstrap user inserted below. + +CREATE TABLE IF NOT EXISTS users ( + id TEXT PRIMARY KEY, + handle TEXT NOT NULL UNIQUE, + display_name TEXT, + created_at TEXT NOT NULL, + metadata TEXT NOT NULL DEFAULT '{}' +); + +CREATE TABLE IF NOT EXISTS groups ( + id TEXT PRIMARY KEY, + handle TEXT NOT NULL UNIQUE, + display_name TEXT, + created_at TEXT NOT NULL, + metadata TEXT NOT NULL DEFAULT '{}' +); + +CREATE TABLE IF NOT EXISTS group_memberships ( + user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, + group_id TEXT NOT NULL REFERENCES groups(id) ON DELETE CASCADE, + role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('member', 'admin')), + joined_at TEXT NOT NULL, + PRIMARY KEY (user_id, group_id) +); + +-- 2. Bootstrap 'local' user. Same UUID as the Postgres default so a future +-- portable export from SQLite -> import to Postgres preserves owner_user_id. + +INSERT OR IGNORE INTO users (id, handle, display_name, created_at) + VALUES ('00000000-0000-0000-0000-000000000001', 'local', 'Local User', + datetime('now')); + +-- 3. Per-memory column additions are applied separately by the migration +-- runner (see MIGRATION_V15_ALTER_COLUMNS). + +-- 4. Indexes that do not depend on the new columns. Index creation on the +-- new knowledge_nodes columns is done after MIGRATION_V15_ALTER_COLUMNS +-- runs (see runner glue below). + +UPDATE schema_version SET version = 15, applied_at = datetime('now'); +"#; + +/// V15 column additions. SQLite has no ADD COLUMN IF NOT EXISTS, so the +/// runner skips "duplicate column" errors per statement (same shape as V14). +pub const MIGRATION_V15_ALTER_COLUMNS: &[&str] = &[ + // D7 columns. Defaults match the Postgres side. shared_with_groups is + // a JSON-encoded array. + "ALTER TABLE knowledge_nodes ADD COLUMN owner_user_id TEXT NOT NULL DEFAULT '00000000-0000-0000-0000-000000000001'", + "ALTER TABLE knowledge_nodes ADD COLUMN visibility TEXT NOT NULL DEFAULT 'private'", + "ALTER TABLE knowledge_nodes ADD COLUMN shared_with_groups TEXT NOT NULL DEFAULT '[]'", + // D8 column. + "ALTER TABLE knowledge_nodes ADD COLUMN codebase TEXT", +]; + +/// V15 index creation. Runs AFTER the ALTER COLUMN statements succeed. +/// Kept as a separate batch so a partial replay (columns already there, +/// indexes not yet) still creates the indexes. +const MIGRATION_V15_INDEXES: &str = r#" +CREATE INDEX IF NOT EXISTS idx_nodes_owner_user_id ON knowledge_nodes(owner_user_id); +CREATE INDEX IF NOT EXISTS idx_nodes_codebase ON knowledge_nodes(codebase) WHERE codebase IS NOT NULL; +-- shared_with_groups is TEXT JSON in SQLite; we do not add a GIN-equivalent +-- index. Phase 3 lookups on the SQLite side will scan; SQLite never serves +-- the multi-user query path in Phase 2-4 anyway. +"#; +``` + +### Runner glue + +Extend `apply_migrations` in `migrations.rs` to recognise V15 the same way +it recognises V14: + +```rust +// Existing pattern for V14 lives in apply_migrations; extend it: +if migration.version == 15 { + for stmt in MIGRATION_V15_ALTER_COLUMNS { + if let Err(e) = conn.execute_batch(stmt) { + let msg = e.to_string(); + if msg.contains("duplicate column name") { + tracing::debug!( + "V15 ALTER TABLE skipped (column already exists): {}", + msg + ); + } else { + return Err(e); + } + } + } + // Indexes run *after* the columns exist. + conn.execute_batch(MIGRATION_V15_INDEXES)?; +} + +// Then the normal: +conn.execute_batch(migration.up)?; +``` + +Order of operations on a fresh in-memory DB: + +1. V1 - V14 run as before. +2. V15: column ALTERs run first (so MIGRATION_V15_INDEXES sees them). +3. V15 main body creates users/groups/group_memberships and the bootstrap row. +4. V15 indexes batch runs. +5. schema_version advances to 15. + +This intentionally mirrors how V14 handles its ALTER + index pair. + +### Existing-data backfill + +Existing SQLite databases (every Phase 1 deployment) have populated +`knowledge_nodes` rows. The V15 ALTER COLUMN ADD COLUMN statements assign +the default values to every existing row: + +- `owner_user_id` -> `'00000000-0000-0000-0000-000000000001'` +- `visibility` -> `'private'` +- `shared_with_groups` -> `'[]'` +- `codebase` -> NULL + +Phase 2 leaves these defaults in place. Phase 3 owns the migration story +for populating real owner UUIDs and visibility values. + +--- + +## Rust wrapper + +Single file: + +```rust +// crates/vestige-core/src/storage/postgres/migrations.rs +// +// sqlx::migrate! wrapper for the Postgres backend. +// +// We split the migration apply into two halves around register_model: +// - run_pre_register: applies everything up to and including version 1 +// (schema, indexes, bootstrap row). Safe to call on a +// fresh DB. +// - run_post_register: applies the remainder (currently: 0002_hnsw, which +// needs the embedding column typmod stamped first). +// +// See docs/plans/0002c-migrations.md "HNSW typmod ordering" for why this +// split exists. + +#![cfg(feature = "postgres-backend")] + +use sqlx::PgPool; +use sqlx::migrate::Migrator; + +use crate::storage::error::MemoryStoreResult; + +/// Embedded migrator. Path is relative to CARGO_MANIFEST_DIR +/// (`crates/vestige-core/`). +static MIGRATOR: Migrator = sqlx::migrate!("./migrations/postgres"); + +/// Apply migrations through version 1 (the schema-only migration). +/// +/// Idempotent: sqlx::migrate consults the `_sqlx_migrations` table and is +/// a no-op on a database already at version 1 or higher. +pub(crate) async fn run_pre_register(pool: &PgPool) -> MemoryStoreResult<()> { + MIGRATOR.run_to(pool, 1).await?; + Ok(()) +} + +/// Apply any remaining migrations. Called after `register_model` has +/// stamped the typmod on `knowledge_nodes.embedding`. +pub(crate) async fn run_post_register(pool: &PgPool) -> MemoryStoreResult<()> { + MIGRATOR.run(pool).await?; + Ok(()) +} +``` + +Wiring into `PgMemoryStore::connect`. The skeleton from 0002a uses +`todo!()` for everything past pool construction. This sub-plan replaces +that with `run_pre_register` only; `run_post_register` is invoked by +`finalize_schema`, which lands in 0002d. Sketch: + +```rust +// In crates/vestige-core/src/storage/postgres/mod.rs (sub-plan 0002a wires +// pool construction; this sub-plan adds the run_pre_register call): + +impl PgMemoryStore { + pub async fn connect(url: &str, max_connections: u32) -> MemoryStoreResult { + let pool = super::pool::build(url, max_connections).await?; + super::migrations::run_pre_register(&pool).await?; + Ok(Self { pool }) + } +} +``` + +Module wire-up in `crates/vestige-core/src/storage/postgres/mod.rs`: + +```rust +mod migrations; // pub(crate) functions; not re-exported. +``` + +### Error variant + +Sub-plan 0002a already added (under feature gate) to `MemoryStoreError`: + +```rust +#[cfg(feature = "postgres-backend")] +#[error("postgres migration error: {0}")] +Migrate(#[from] sqlx::migrate::MigrateError), +``` + +`run_pre_register` / `run_post_register` use the `?` operator and the +`#[from]` conversion handles it; no extra error handling code is needed. + +--- + +## Visibility CHECK constraint + +ADR 0002 D7 specifies the tri-state enum: + +``` +visibility IN ('private', 'group', 'public') +``` + +This sub-plan includes that CHECK on the `knowledge_nodes` table (see 0001_init.up.sql +above) on both sides: + +- Postgres: `CHECK (visibility IN ('private', 'group', 'public'))` inline on + the table. +- SQLite: same CHECK constraint can be added to V15 if desired. (It is not + in the V15 body above because adding a CHECK via ALTER TABLE on SQLite + requires a table rebuild; we trust the application layer for SQLite, since + SQLite never serves the multi-user query path in Phase 2.) + +The stronger consistency rule from the ADR 0002 follow-ups section, + +``` +CHECK ( + visibility = 'private' + OR cardinality(shared_with_groups) > 0 + OR visibility = 'public' +) +``` + +is intentionally NOT added in this sub-plan. Rationale: + +- The rule is a "no orphan group rows" sanity check, not a correctness + requirement for Phase 2 (single-user mode never touches the column). +- Phase 3 is the first phase that writes `visibility = 'group'`. The check + belongs in the Phase 3 migration that lights up auth, alongside the + application code that ensures `shared_with_groups` is populated before + the visibility flips. +- Adding it now and discovering Phase 3 wants a different shape forces an + online CHECK constraint replacement. + +Recommendation: include only the IN check in Phase 2; revisit the +cardinality check in Phase 3. + +--- + +## Offline sqlx cache + +`crates/vestige-core/.sqlx/` is the on-disk cache of compile-time-checked +queries that `sqlx::query!` / `sqlx::query_as!` emit at build time when +`SQLX_OFFLINE=true`. It is committed to the repo so builds without +`DATABASE_URL` (CI, downstream consumers, contributors without Postgres) +succeed. + +This sub-plan does NOT yet generate or commit `.sqlx/` content. Reasons: + +- `sqlx::query!` calls are introduced in `0002d-store-impl-bodies.md` (real + CRUD bodies) and `0002e-hybrid-search.md` (RRF). This sub-plan ships only + the migrations directory and a wrapper that uses `sqlx::migrate!` -- which + is a compile-time macro that reads files, not a query macro that needs a + DB connection. +- Generating an empty `.sqlx/` directory now is noise that gets immediately + overwritten in the next sub-plan. + +Sub-plan 0002d will land the procedure: + +```sh +# Local dev box with vestige DB initialised per local-dev-postgres-setup.md. +export DATABASE_URL="postgresql://vestige:$(cat ~/.vestige_pg_pw)@127.0.0.1:5432/vestige" + +# Apply migrations against the dev DB. +cargo sqlx migrate run \ + --source crates/vestige-core/migrations/postgres \ + --database-url "$DATABASE_URL" + +# Generate the offline cache. +cargo sqlx prepare --workspace -- --features postgres-backend + +# Verify cache compiles offline. +SQLX_OFFLINE=true cargo check --workspace --features postgres-backend +``` + +The `.sqlx/` directory commit policy is: committed, reviewed in PRs that +add or change `query!` calls, regenerated locally and pushed. + +What this sub-plan DOES need from sqlx-cli, for verification only (see next +section): `cargo sqlx migrate run --source crates/vestige-core/migrations/postgres`. + +--- + +## Verification + +Two halves: Postgres migrations run cleanly on a fresh DB; SQLite V15 does +not break the Phase 1 store. + +### Postgres + +Prerequisites: Postgres 18 with pgvector, a role with CREATEDB and EXTENSION +rights, per `docs/plans/local-dev-postgres-setup.md`. Alternatively, a +container: + +```sh +podman run --rm -d --name vestige-pg \ + -e POSTGRES_PASSWORD=devpw \ + -e POSTGRES_USER=vestige \ + -e POSTGRES_DB=vestige \ + -p 5432:5432 \ + docker.io/pgvector/pgvector:pg16 + +export DATABASE_URL="postgresql://vestige:devpw@127.0.0.1:5432/vestige" +``` + +Steps: + +1. Apply migrations. From the repo root: + + ```sh + cargo install sqlx-cli --no-default-features --features postgres + cargo sqlx migrate run \ + --source crates/vestige-core/migrations/postgres \ + --database-url "$DATABASE_URL" + ``` + + Expected output: `Applied 1/migrate init` (`0002` is gated on typmod; + sqlx-cli will run it and pgvector will reject the HNSW creation with + "column does not have dimensions". This is the expected behaviour when + running migrations without going through the Rust connect path. To run + 0002 manually for verification, first stamp the typmod: + + ```sh + psql "$DATABASE_URL" -c "ALTER TABLE knowledge_nodes ALTER COLUMN embedding TYPE vector(768);" + cargo sqlx migrate run \ + --source crates/vestige-core/migrations/postgres \ + --database-url "$DATABASE_URL" + ``` + + Now 0002 should apply.) + +2. Verify tables exist: + + ```sh + psql "$DATABASE_URL" -c "\dt" + ``` + + Expected (alphabetical): + ``` + domains + edges + embedding_model + group_memberships + groups + knowledge_nodes + review_events + scheduling + users + ``` + +3. Verify the bootstrap user row: + + ```sh + psql "$DATABASE_URL" -c "SELECT id, handle, display_name FROM users;" + ``` + + Expected: + ``` + id | handle | display_name + --------------------------------------+--------+-------------- + 00000000-0000-0000-0000-000000000001 | local | Local User + ``` + +4. Verify HNSW index (only after the typmod stamp + migrate 0002): + + ```sh + psql "$DATABASE_URL" -c "\d knowledge_nodes" + ``` + + The trailing `Indexes:` block should include `idx_knowledge_nodes_embedding_hnsw`. + +5. Verify the D7+D8 columns are present: + + ```sh + psql "$DATABASE_URL" -c " + SELECT column_name, data_type, column_default + FROM information_schema.columns + WHERE table_name = 'knowledge_nodes' + AND column_name IN ('owner_user_id', 'visibility', + 'shared_with_groups', 'codebase') + ORDER BY column_name; + " + ``` + + Expected: four rows, with `owner_user_id` defaulting to the bootstrap + UUID, `visibility` to `'private'::text`, `shared_with_groups` to + `'{}'::uuid[]`, `codebase` NULL-default. + +6. Verify CHECK constraint: + + ```sh + psql "$DATABASE_URL" -c " + INSERT INTO knowledge_nodes (content, visibility) VALUES ('test', 'bogus'); + " + # Expected: ERROR: new row for relation \"knowledge_nodes\" violates check constraint + ``` + +7. Roll back to verify down migrations work: + + ```sh + cargo sqlx migrate revert \ + --source crates/vestige-core/migrations/postgres \ + --database-url "$DATABASE_URL" + cargo sqlx migrate revert \ + --source crates/vestige-core/migrations/postgres \ + --database-url "$DATABASE_URL" + ``` + + `\dt` should then list only the sqlx-managed `_sqlx_migrations` table. + +8. Rust-side smoke test (no `sqlx::query!` calls yet, so cannot live in + a `#[sqlx::test]`-decorated function until 0002d). Manual: + + ```sh + cargo build -p vestige-core --features postgres-backend + ``` + + Should compile. The `sqlx::migrate!("./migrations/postgres")` macro + reads the directory at compile time; a missing file or syntax error + surfaces as a compile error. + +### SQLite + +1. Run the existing test suite: + + ```sh + cargo test -p vestige-core + ``` + + Expected: 352 (or current count + new V15 tests) tests pass, zero + warnings. + +2. New test in `migrations.rs#tests`: + + ```rust + #[test] + fn test_v15_advances_to_15_and_adds_d7_d8_columns() { + let conn = rusqlite::Connection::open_in_memory().expect("open in-memory"); + apply_migrations(&conn).expect("apply_migrations succeeds"); + + let version = get_current_version(&conn).expect("read schema_version"); + assert_eq!(version, 15, "schema_version should advance to 15"); + + // Tables exist + for tbl in ["users", "groups", "group_memberships"] { + let n: i32 = conn.query_row( + "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=?1", + [tbl], + |r| r.get(0), + ).expect("query sqlite_master"); + assert_eq!(n, 1, "table {tbl} should exist after V15"); + } + + // Bootstrap user row exists + let n: i32 = conn.query_row( + "SELECT COUNT(*) FROM users WHERE id = '00000000-0000-0000-0000-000000000001'", + [], + |r| r.get(0), + ).expect("query users"); + assert_eq!(n, 1, "bootstrap local user row should exist"); + + // D7+D8 columns on knowledge_nodes + let cols: Vec = conn + .prepare("PRAGMA table_info(knowledge_nodes)") + .unwrap() + .query_map([], |r| r.get::<_, String>(1)) + .unwrap() + .collect::>() + .unwrap(); + for c in ["owner_user_id", "visibility", "shared_with_groups", "codebase"] { + assert!(cols.iter().any(|x| x == c), + "knowledge_nodes should have column {c}"); + } + } + ``` + +3. Idempotency: re-applying V15 on an already-V15 DB must not error. + `apply_migrations` already skips when `current_version >= migration.version`; + no extra test needed beyond ensuring the V14 + V15 ALTER pattern works. + +4. Existing-data backfill smoke: insert a row before applying V15, then + verify the defaults populate: + + ```rust + #[test] + fn test_v15_backfills_existing_rows_with_defaults() { + let conn = rusqlite::Connection::open_in_memory().expect("open"); + + // Apply migrations through V14 only. + // (We rely on the fact that re-running apply_migrations is a no-op, + // so we apply all, then probe the columns. The V15 ALTER on a + // populated table is what we are testing implicitly.) + apply_migrations(&conn).expect("V1-V15"); + + // Insert a row using only Phase 1 columns; V15 defaults must + // populate owner_user_id / visibility / shared_with_groups / codebase. + conn.execute( + "INSERT INTO knowledge_nodes (id, content, node_type, created_at, updated_at, last_accessed) + VALUES ('test', 'hello', 'fact', datetime('now'), datetime('now'), datetime('now'))", + [], + ).expect("insert"); + + let (owner, vis, shared, codebase): (String, String, String, Option) = + conn.query_row( + "SELECT owner_user_id, visibility, shared_with_groups, codebase + FROM knowledge_nodes WHERE id = 'test'", + [], + |r| Ok((r.get(0)?, r.get(1)?, r.get(2)?, r.get(3)?)), + ).expect("query"); + + assert_eq!(owner, "00000000-0000-0000-0000-000000000001"); + assert_eq!(vis, "private"); + assert_eq!(shared, "[]"); + assert_eq!(codebase, None); + } + ``` + +5. Live deployment: apply V15 to a copy of `~/.vestige/vestige.db` and + verify the existing 150 memories all carry the four new columns with + default values: + + ```sh + cp ~/.vestige/vestige.db /tmp/v15-test.db + sqlite3 /tmp/v15-test.db <<'SQL' + .schema knowledge_nodes + SELECT COUNT(*) FROM knowledge_nodes; + SELECT DISTINCT owner_user_id, visibility, shared_with_groups + FROM knowledge_nodes LIMIT 5; + SQL + # (Migration applies on first read by the vestige binary running V15.) + ``` + + Capture pre- and post-counts. Expected: no row count change, all new + columns populated by defaults. + +--- + +## Acceptance criteria + +- [ ] `crates/vestige-core/migrations/postgres/` directory contains exactly + four files: `0001_init.up.sql`, `0001_init.down.sql`, + `0002_hnsw.up.sql`, `0002_hnsw.down.sql`. Content matches this + sub-plan. +- [ ] `crates/vestige-core/src/storage/postgres/migrations.rs` exports + `run_pre_register` and `run_post_register` as `pub(crate)` async + functions returning `MemoryStoreResult<()>`. Compiles with + `--features postgres-backend`. +- [ ] `PgMemoryStore::connect` (sub-plan 0002a skeleton) is updated to call + `run_pre_register` immediately after pool construction. `connect` + still returns before `register_model` runs; `run_post_register` + lands in 0002d via `finalize_schema`. +- [ ] `crates/vestige-core/src/storage/migrations.rs` has a new V15 entry + in `MIGRATIONS`, with `MIGRATION_V15_UP`, `MIGRATION_V15_ALTER_COLUMNS`, + and `MIGRATION_V15_INDEXES` constants. `apply_migrations` handles + V15 the same shape as V14. +- [ ] `cargo test -p vestige-core` passes. New tests cover V15 advance, + D7+D8 column existence, bootstrap user row, and existing-row backfill. +- [ ] `cargo build -p vestige-core --features postgres-backend` compiles + (the `sqlx::migrate!` macro will fail at compile time if any of the + four SQL files is missing or malformed). +- [ ] `cargo sqlx migrate run --source crates/vestige-core/migrations/postgres` + against a fresh container applies 0001 cleanly; `\dt` lists the nine + Phase 2 tables; `users` contains the bootstrap row. +- [ ] After the manual typmod stamp documented above, `cargo sqlx migrate + run` applies 0002 and `\d knowledge_nodes` shows `idx_knowledge_nodes_embedding_hnsw`. +- [ ] `cargo sqlx migrate revert` twice cleans the DB back to only the + `_sqlx_migrations` table. +- [ ] Inserting a row with `visibility = 'bogus'` is rejected by the CHECK + constraint. +- [ ] No `sqlx::query!` / `sqlx::query_as!` calls are added in this + sub-plan; the `.sqlx/` offline cache is not yet generated. +- [ ] The existing live SQLite DB on the development machine migrates from + V14 to V15 without row count change, and the 150 existing rows all + receive the four V15 default values. diff --git a/docs/plans/0002d-store-impl-bodies.md b/docs/plans/0002d-store-impl-bodies.md new file mode 100644 index 0000000..ad1d9b7 --- /dev/null +++ b/docs/plans/0002d-store-impl-bodies.md @@ -0,0 +1,1771 @@ +# Phase 2 Sub-Plan 0002d -- Store Implementation Bodies + +**Status**: Ready +**Depends on**: +- `0002a-skeleton-and-feature-gate.md` -- `PgMemoryStore` struct + trait impl block exist with `todo!()` bodies. +- `0002b-pool-and-config.md` -- `PgPool` is constructable, `MemoryStoreError::Postgres` and `MemoryStoreError::Migrate` variants exist behind the `postgres-backend` feature. +- `0002c-migrations.md` -- the two sqlx migrations (`0001_init`, `0002_hnsw`) exist, the schema is applied on `connect`, the `knowledge_nodes` / `scheduling` / `edges` / `domains` / `embedding_model` / `users` / `groups` / `group_memberships` / `review_events` tables exist with the D7+D8 columns. + +This sub-plan replaces every `todo!()` in +`crates/vestige-core/src/storage/postgres/mod.rs` with a real sqlx-backed +body, and adds `crates/vestige-core/src/storage/postgres/registry.rs` with +the `ensure_registry` / `register_model` typmod-stamping logic. + +The hybrid `search()` method is the meatiest single body in the backend +(RRF in one SQL statement) and lives in its own sub-plan +(`0002e-hybrid-search.md`). The bodies for the trivial single-branch +variants `fts_search` and `vector_search` are still inside this sub-plan +because they share row-mapping infrastructure with the CRUD bodies. + +Out of scope for this sub-plan: +- The full hybrid `search()` -- see `0002e-hybrid-search.md`. +- SQLite -> Postgres migrate CLI -- see `0002f-migrate-cli.md`. +- Re-embed flow -- see `0002g-reembed.md`. +- Phase 3 visibility filter -- explicitly NOT wired in Phase 2; see the + "Visibility filter posture" section below. + +--- + +## Context + +The Phase 1 `MemoryStore` trait surface is defined in +`crates/vestige-core/src/storage/memory_store.rs` and is the source of +truth for method signatures. ADR 0002 D7 added owner / visibility / +shared_with_groups columns to the `knowledge_nodes` table; ADR 0002 D8 promoted +`codebase` to a first-class column. The sqlx bodies in this sub-plan must +write to and read from those columns, but per ADR 0002 D7 they must NOT +filter on them in Phase 2 -- the visibility filter is a Phase 3 +deliverable that takes an `AuthContext` parameter. + +The semantics of every body must match the SQLite backend's current +behaviour. Where Postgres has native types (`UUID`, `JSONB`, `vector`, +`TEXT[]`, `TIMESTAMPTZ`) we use them directly; the SQLite backend's +RFC3339-string-and-JSON-blob encoding is an artefact of SQLite typing, +not the trait contract. + +Compile-time SQL validation uses sqlx's `query!` / `query_as!` macros. +The first time these macros run against a real database in CI they +populate `.sqlx/` query metadata; the metadata file is committed so +offline builds (CI without a live Postgres) succeed. + +--- + +## MemoryRecord type changes + +ADR 0002 D7 and D8 added four new columns to the `knowledge_nodes` table. +The `MemoryRecord` struct in +`crates/vestige-core/src/storage/memory_store.rs` must grow matching +fields so the trait surface can carry the data through both backends. +This is an additive change to the public type. + +Add to `MemoryRecord` (after the existing `metadata` field): + +```rust +/// Owner of this memory. Defaults to the local bootstrap user +/// (`00000000-0000-0000-0000-000000000001`) in single-user mode. +pub owner_user_id: Uuid, + +/// Tri-state visibility. ADR 0002 D7. +pub visibility: Visibility, + +/// Group IDs this memory is shared with when `visibility == Group`. +/// Empty for `Private` and `Public`. +pub shared_with_groups: Vec, + +/// First-class codebase tag. ADR 0002 D8. None if the ingest pipeline +/// could not infer one. +pub codebase: Option, +``` + +Add a new enum next to `MemoryRecord`: + +```rust +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum Visibility { + Private, + Group, + Public, +} + +impl Visibility { + pub fn as_str(&self) -> &'static str { + match self { + Self::Private => "private", + Self::Group => "group", + Self::Public => "public", + } + } + + pub fn from_str(s: &str) -> MemoryStoreResult { + match s { + "private" => Ok(Self::Private), + "group" => Ok(Self::Group), + "public" => Ok(Self::Public), + other => Err(MemoryStoreError::Backend( + format!("unknown visibility value: {other}"), + )), + } + } +} + +impl Default for Visibility { + fn default() -> Self { Self::Private } +} +``` + +`MemoryRecord` already derives `Serialize` and `Deserialize`; the new +fields ride along automatically. Two callers must change as part of this +sub-plan: + +1. **SQLite backend (V15 migration ships in `0001b-sqlite-split.md` or + the same Phase 1 amendment branch)**: the SQLite backend reads the + four new columns out of `knowledge_nodes` (V15 added them) and + populates the new fields in `Self::node_to_record`. Bootstrap user + ID is the same constant on both backends. Existing call sites that + construct `MemoryRecord` literally (in tests, in cognitive modules) + may default-init the four new fields: + + ```rust + MemoryRecord { + // ... existing fields ... + owner_user_id: LOCAL_USER_ID, + visibility: Visibility::default(), + shared_with_groups: Vec::new(), + codebase: None, + metadata: serde_json::json!({}), + } + ``` + + A single `pub const LOCAL_USER_ID: Uuid = uuid::uuid!("00000000-0000-0000-0000-000000000001");` + in `storage::memory_store` provides the bootstrap constant. + +2. **Cognitive modules that build `MemoryRecord` from the ingest + pipeline**: the ingest path already captures `codebase` in metadata + (see ADR 0002 D8). Lift it from `metadata.codebase` to the new + `codebase` field at the boundary where `MemoryRecord` is built. The + `metadata.codebase` JSON key is removed in the same commit; the + column is now the only source of truth. + +The change is purely additive to the trait surface -- no method +signatures change. Backwards compatibility for stored data (in the +SQLite case) comes from V15 defaulting the new columns to `'private'` +and the bootstrap user. The Postgres schema applies the same defaults +in `0001_init.up.sql`. + +--- + +## Registry module + +New file: `crates/vestige-core/src/storage/postgres/registry.rs`. + +```rust +#![cfg(feature = "postgres-backend")] + +//! Embedding-model registry for the Postgres backend. +//! +//! The `embedding_model` table stores exactly one row (id = 1) describing +//! the model whose vectors live in `knowledge_nodes.embedding`. Phase 2 enforces +//! that the active embedder matches the registered model on every write; +//! re-embed (`0002g-reembed.md`) is the only flow allowed to change the +//! row. +//! +//! The pgvector column `knowledge_nodes.embedding` is created in +//! `0001_init.up.sql` with a placeholder type (`vector`) -- no typmod. +//! On first connect we stamp the real dimension via +//! `ALTER TABLE knowledge_nodes ALTER COLUMN embedding TYPE vector($N)` so the +//! HNSW index (created in `0002_hnsw.up.sql`) sees a sized type. + +use sqlx::PgPool; + +use crate::storage::memory_store::{ + MemoryStoreError, MemoryStoreResult, ModelSignature, +}; + +/// Look up the registered signature, if any. Returns `Ok(None)` on a +/// fresh database. +pub(crate) async fn fetch_registry( + pool: &PgPool, +) -> MemoryStoreResult> { + let row = sqlx::query!( + r#" + SELECT name, dimension, hash + FROM embedding_model + WHERE id = 1 + "# + ) + .fetch_optional(pool) + .await?; + + Ok(row.map(|r| ModelSignature { + name: r.name, + dimension: r.dimension as usize, + hash: r.hash, + })) +} + +/// First-ever call inserts the row and stamps the typmod on +/// `knowledge_nodes.embedding`. Subsequent calls compare against the stored +/// row and return `ModelMismatch` if any field differs. +pub(crate) async fn ensure_registry( + pool: &PgPool, + sig: &ModelSignature, +) -> MemoryStoreResult<()> { + let existing = fetch_registry(pool).await?; + + match existing { + None => { + sqlx::query!( + r#" + INSERT INTO embedding_model (id, name, dimension, hash) + VALUES (1, $1, $2, $3) + "#, + sig.name, + sig.dimension as i32, + sig.hash, + ) + .execute(pool) + .await?; + + stamp_vector_typmod(pool, sig.dimension).await?; + Ok(()) + } + Some(reg) if reg == *sig => Ok(()), + Some(reg) => Err(MemoryStoreError::ModelMismatch { + registered_name: reg.name, + registered_dim: reg.dimension, + registered_hash: reg.hash, + actual_name: sig.name.clone(), + actual_dim: sig.dimension, + actual_hash: sig.hash.clone(), + }), + } +} + +/// Called only by the re-embed flow (`0002g-reembed.md`) after a full +/// re-encode has rewritten every row. Updates the registry row and +/// re-stamps the typmod for the new dimension. +pub(crate) async fn update_registry_for_reembed( + pool: &PgPool, + sig: &ModelSignature, +) -> MemoryStoreResult<()> { + sqlx::query!( + r#" + UPDATE embedding_model + SET name = $1, dimension = $2, hash = $3, created_at = now() + WHERE id = 1 + "#, + sig.name, + sig.dimension as i32, + sig.hash, + ) + .execute(pool) + .await?; + + stamp_vector_typmod(pool, sig.dimension).await?; + Ok(()) +} + +async fn stamp_vector_typmod(pool: &PgPool, dim: usize) -> MemoryStoreResult<()> { + // pgvector's typmod is part of the column type, not a bound parameter. + // `format!` is safe here because `dim` is a `usize` cast to a decimal + // literal; there is no path for user-controlled SQL to reach this + // string. + let ddl = format!( + "ALTER TABLE knowledge_nodes ALTER COLUMN embedding TYPE vector({dim})" + ); + sqlx::query(&ddl).execute(pool).await?; + Ok(()) +} +``` + +Wire the new module into `crates/vestige-core/src/storage/postgres/mod.rs`: + +```rust +pub(crate) mod registry; +``` + +The `fetch_registry` / `ensure_registry` functions are reached from the +trait methods `registered_model` and `register_model` (see method bodies +below). `update_registry_for_reembed` is reached only from +`postgres::reembed`, which is filled in by `0002g-reembed.md`. + +--- + +## Method-by-method bodies + +Every body below replaces a `todo!()` in +`crates/vestige-core/src/storage/postgres/mod.rs`. Method order matches +the trait declaration in `memory_store.rs`. + +Common imports at the top of `mod.rs`: + +```rust +use chrono::{DateTime, Utc}; +use pgvector::Vector; +use uuid::Uuid; + +use crate::storage::memory_store::{ + Domain, HealthStatus, LocalMemoryStore, MemoryEdge, MemoryRecord, + MemoryStoreError, MemoryStoreResult, ModelSignature, SchedulingState, + SearchQuery, SearchResult, StoreStats, Visibility, +}; +``` + +Recurring row-to-record helper (private to `mod.rs`): + +```rust +fn row_to_record( + id: Uuid, + content: String, + node_type: String, + tags: Vec, + domains: Vec, + domain_scores: serde_json::Value, + codebase: Option, + owner_user_id: Uuid, + visibility: String, + shared_with_groups: Vec, + embedding: Option, + metadata: serde_json::Value, + created_at: DateTime, + updated_at: DateTime, +) -> MemoryStoreResult { + let domain_scores: std::collections::HashMap = + serde_json::from_value(domain_scores).unwrap_or_default(); + let embedding = embedding.map(|v| v.to_vec()); + Ok(MemoryRecord { + id, + domains, + domain_scores, + content, + node_type, + tags, + embedding, + created_at, + updated_at, + metadata, + owner_user_id, + visibility: Visibility::from_str(&visibility)?, + shared_with_groups, + codebase, + }) +} +``` + +### Lifecycle + +#### `init` + +```rust +async fn init(&self) -> MemoryStoreResult<()> +``` + +Migrations already ran in `connect`; this is a no-op identical to +SQLite's behaviour. + +```rust +async fn init(&self) -> MemoryStoreResult<()> { + Ok(()) +} +``` + +#### `health_check` + +```rust +async fn health_check(&self) -> MemoryStoreResult +``` + +Issue a trivial `SELECT 1`. Pool acquisition errors degrade to +`HealthStatus::Degraded`; any other error path returns `Unavailable`. + +```rust +async fn health_check(&self) -> MemoryStoreResult { + match sqlx::query_scalar!("SELECT 1::int") + .fetch_one(&self.pool) + .await + { + Ok(_) => Ok(HealthStatus::Healthy), + Err(sqlx::Error::PoolTimedOut) => Ok(HealthStatus::Degraded { + reason: "pool exhausted".to_string(), + }), + Err(e) => Ok(HealthStatus::Unavailable { + reason: e.to_string(), + }), + } +} +``` + +### Embedding-model registry + +#### `registered_model` + +```rust +async fn registered_model(&self) -> MemoryStoreResult> +``` + +Thin pass-through to `registry::fetch_registry`. The Postgres backend +does not cache the row in-memory the way the SQLite backend does -- +sqlx's prepared-statement cache already keeps the SELECT cheap, and +`registered_model` is not on the hot path. + +```rust +async fn registered_model(&self) -> MemoryStoreResult> { + crate::storage::postgres::registry::fetch_registry(&self.pool).await +} +``` + +#### `register_model` + +```rust +async fn register_model(&self, sig: &ModelSignature) -> MemoryStoreResult<()> +``` + +Delegate to `registry::ensure_registry`, which handles the +"insert + stamp typmod" first-run path and the "compare" subsequent path. + +```rust +async fn register_model(&self, sig: &ModelSignature) -> MemoryStoreResult<()> { + crate::storage::postgres::registry::ensure_registry(&self.pool, sig).await +} +``` + +### CRUD + +#### `insert` + +```rust +async fn insert(&self, record: &MemoryRecord) -> MemoryStoreResult +``` + +Single `INSERT` into `knowledge_nodes` with all D7+D8 columns. Bind embedding +as `Option` -- pgvector's sqlx integration handles the +typmod check at execution time, so a length mismatch surfaces as +`MemoryStoreError::Postgres`. The caller-supplied UUID is preserved +(same contract as SQLite). Initial scheduling state is inserted in the +same transaction so a memory is never queryable without a scheduling +row. + +```rust +async fn insert(&self, record: &MemoryRecord) -> MemoryStoreResult { + let embedding: Option = record + .embedding + .as_ref() + .map(|v| Vector::from(v.clone())); + let domain_scores = serde_json::to_value(&record.domain_scores) + .unwrap_or_else(|_| serde_json::json!({})); + + let mut tx = self.pool.begin().await?; + + sqlx::query!( + r#" + INSERT INTO knowledge_nodes ( + id, + owner_user_id, + visibility, + shared_with_groups, + codebase, + content, + node_type, + tags, + domains, + domain_scores, + embedding, + metadata, + created_at, + updated_at + ) + VALUES ( + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10::jsonb, + $11, $12::jsonb, $13, $14 + ) + "#, + record.id, + record.owner_user_id, + record.visibility.as_str(), + &record.shared_with_groups as &[Uuid], + record.codebase.as_deref(), + record.content, + record.node_type, + &record.tags as &[String], + &record.domains as &[String], + domain_scores, + embedding as Option, + record.metadata, + record.created_at, + record.updated_at, + ) + .execute(&mut *tx) + .await?; + + // Seed scheduling state. Mirrors SQLite defaults from `knowledge_nodes` + // (stability=1.0, difficulty=0.3, retrievability=1.0, reps=0, lapses=0, + // next_review = created_at + 1 day). + sqlx::query!( + r#" + INSERT INTO scheduling ( + memory_id, stability, difficulty, retrievability, + last_review, next_review, reps, lapses + ) + VALUES ($1, 1.0, 0.3, 1.0, NULL, $2, 0, 0) + "#, + record.id, + record.created_at + chrono::Duration::days(1), + ) + .execute(&mut *tx) + .await?; + + tx.commit().await?; + Ok(record.id) +} +``` + +Tricky bits: +- `&record.tags as &[String]` -- sqlx requires an explicit slice cast + to bind a `Vec` as `text[]`. +- `&record.shared_with_groups as &[Uuid]` -- same pattern for `uuid[]`. +- `embedding as Option` -- type annotation is mandatory in the + macro because the inference path bottoms out at a generic; pgvector's + `Encode` impl resolves only with a known concrete type. +- The `$10::jsonb` and `$12::jsonb` casts force sqlx to encode through + the JSONB path even if the parameter type-resolves to `JSON`. This + matters because the migrations created the columns as `JSONB`, and + sqlx 0.8 does not always pick JSONB without the cast. + +#### `get` + +```rust +async fn get(&self, id: Uuid) -> MemoryStoreResult> +``` + +`SELECT *` filtered by primary key. Row mapping goes through +`row_to_record`. + +```rust +async fn get(&self, id: Uuid) -> MemoryStoreResult> { + let row = sqlx::query!( + r#" + SELECT + id AS "id!: Uuid", + owner_user_id AS "owner_user_id!: Uuid", + visibility, + shared_with_groups AS "shared_with_groups!: Vec", + codebase, + content, + node_type, + tags AS "tags!: Vec", + domains AS "domains!: Vec", + domain_scores AS "domain_scores!: serde_json::Value", + embedding AS "embedding: Vector", + metadata AS "metadata!: serde_json::Value", + created_at AS "created_at!: DateTime", + updated_at AS "updated_at!: DateTime" + FROM knowledge_nodes + WHERE id = $1 + "#, + id, + ) + .fetch_optional(&self.pool) + .await?; + + let Some(r) = row else { return Ok(None) }; + + Ok(Some(row_to_record( + r.id, r.content, r.node_type, r.tags, r.domains, + r.domain_scores, r.codebase, r.owner_user_id, r.visibility, + r.shared_with_groups, r.embedding, r.metadata, + r.created_at, r.updated_at, + )?)) +} +``` + +The `AS "name!: Type"` annotations tell sqlx the exact Rust type for +each column, which is required for `Vec` (from `uuid[]`) and +`Vector` (from `vector`). The `!` means "trust me, this column is NOT +NULL"; sqlx skips its `Option` wrapping for those columns. The +`embedding` column is nullable, so it gets `Option` (no `!`). + +#### `update` + +```rust +async fn update(&self, record: &MemoryRecord) -> MemoryStoreResult<()> +``` + +Update everything the caller might have changed. `updated_at` is set +server-side via `now()` so clock drift between hosts does not leak into +the timeline. (If the caller wants to forge `updated_at` -- e.g. the +migrate CLI replaying SQLite timestamps -- it goes through `insert`, not +`update`.) The schema's `BEFORE UPDATE` trigger could replace this; we +write `updated_at = now()` explicitly to be backend-agnostic. + +```rust +async fn update(&self, record: &MemoryRecord) -> MemoryStoreResult<()> { + let embedding: Option = record + .embedding + .as_ref() + .map(|v| Vector::from(v.clone())); + let domain_scores = serde_json::to_value(&record.domain_scores) + .unwrap_or_else(|_| serde_json::json!({})); + + let rows = sqlx::query!( + r#" + UPDATE knowledge_nodes SET + owner_user_id = $2, + visibility = $3, + shared_with_groups = $4, + codebase = $5, + content = $6, + node_type = $7, + tags = $8, + domains = $9, + domain_scores = $10::jsonb, + embedding = $11, + metadata = $12::jsonb, + updated_at = now() + WHERE id = $1 + "#, + record.id, + record.owner_user_id, + record.visibility.as_str(), + &record.shared_with_groups as &[Uuid], + record.codebase.as_deref(), + record.content, + record.node_type, + &record.tags as &[String], + &record.domains as &[String], + domain_scores, + embedding as Option, + record.metadata, + ) + .execute(&self.pool) + .await? + .rows_affected(); + + if rows == 0 { + return Err(MemoryStoreError::NotFound(record.id.to_string())); + } + Ok(()) +} +``` + +#### `delete` + +```rust +async fn delete(&self, id: Uuid) -> MemoryStoreResult<()> +``` + +Single `DELETE` by id. `scheduling`, `edges`, and `review_events` all +have `ON DELETE CASCADE` on their `memory_id` foreign key, so this one +statement clears every dependent row. + +```rust +async fn delete(&self, id: Uuid) -> MemoryStoreResult<()> { + let rows = sqlx::query!( + "DELETE FROM knowledge_nodes WHERE id = $1", + id, + ) + .execute(&self.pool) + .await? + .rows_affected(); + + if rows == 0 { + return Err(MemoryStoreError::NotFound(id.to_string())); + } + Ok(()) +} +``` + +### Search (single-branch variants) + +The full hybrid `search` is implemented in `0002e-hybrid-search.md`. +The two single-branch variants below ship in this sub-plan. + +#### `fts_search` + +```rust +async fn fts_search(&self, text: &str, limit: usize) -> MemoryStoreResult> +``` + +PostgreSQL full-text search using the precomputed `search_vec` tsvector +column and `websearch_to_tsquery` (handles bare words, phrases, and +boolean operators). Ranking with `ts_rank_cd` (cover-density) so longer +matches outrank shorter ones; the SQLite backend uses BM25 from FTS5 but +the trait contract only requires "higher is better". + +```rust +async fn fts_search( + &self, + text: &str, + limit: usize, +) -> MemoryStoreResult> { + let limit = limit.min(1000) as i64; + let rows = sqlx::query!( + r#" + SELECT + m.id AS "id!: Uuid", + m.owner_user_id AS "owner_user_id!: Uuid", + m.visibility, + m.shared_with_groups AS "shared_with_groups!: Vec", + m.codebase, + m.content, + m.node_type, + m.tags AS "tags!: Vec", + m.domains AS "domains!: Vec", + m.domain_scores AS "domain_scores!: serde_json::Value", + m.embedding AS "embedding: Vector", + m.metadata AS "metadata!: serde_json::Value", + m.created_at AS "created_at!: DateTime", + m.updated_at AS "updated_at!: DateTime", + ts_rank_cd(m.search_vec, websearch_to_tsquery('english', $1)) + AS "score!: f64" + FROM knowledge_nodes m + WHERE m.search_vec @@ websearch_to_tsquery('english', $1) + ORDER BY score DESC + LIMIT $2 + "#, + text, + limit, + ) + .fetch_all(&self.pool) + .await?; + + let mut out = Vec::with_capacity(rows.len()); + for r in rows { + let rec = row_to_record( + r.id, r.content, r.node_type, r.tags, r.domains, + r.domain_scores, r.codebase, r.owner_user_id, r.visibility, + r.shared_with_groups, r.embedding, r.metadata, + r.created_at, r.updated_at, + )?; + out.push(SearchResult { + record: rec, + score: r.score, + fts_score: Some(r.score), + vector_score: None, + }); + } + Ok(out) +} +``` + +The `'english'` text-search configuration matches the GIN index built in +`0001_init.up.sql`. If a future migration parameterises the config, both +the index and this query change together. + +#### `vector_search` + +```rust +async fn vector_search(&self, embedding: &[f32], limit: usize) -> MemoryStoreResult> +``` + +pgvector cosine distance. The HNSW index on `embedding` (built in +`0002_hnsw.up.sql` with `vector_cosine_ops`) makes the `<=>` operator +index-accelerated. We convert the returned distance (0 = identical, 2 = +opposite for cosine on normalized vectors) to a similarity in `[0, 1]` +via `1 - distance`; this matches the SQLite backend's convention. + +```rust +async fn vector_search( + &self, + embedding: &[f32], + limit: usize, +) -> MemoryStoreResult> { + let query_vec = Vector::from(embedding.to_vec()); + let limit = limit.min(1000) as i64; + + let rows = sqlx::query!( + r#" + SELECT + m.id AS "id!: Uuid", + m.owner_user_id AS "owner_user_id!: Uuid", + m.visibility, + m.shared_with_groups AS "shared_with_groups!: Vec", + m.codebase, + m.content, + m.node_type, + m.tags AS "tags!: Vec", + m.domains AS "domains!: Vec", + m.domain_scores AS "domain_scores!: serde_json::Value", + m.embedding AS "embedding: Vector", + m.metadata AS "metadata!: serde_json::Value", + m.created_at AS "created_at!: DateTime", + m.updated_at AS "updated_at!: DateTime", + (1.0 - (m.embedding <=> $1)) AS "score!: f64" + FROM knowledge_nodes m + WHERE m.embedding IS NOT NULL + ORDER BY m.embedding <=> $1 + LIMIT $2 + "#, + query_vec as Vector, + limit, + ) + .fetch_all(&self.pool) + .await?; + + let mut out = Vec::with_capacity(rows.len()); + for r in rows { + let rec = row_to_record( + r.id, r.content, r.node_type, r.tags, r.domains, + r.domain_scores, r.codebase, r.owner_user_id, r.visibility, + r.shared_with_groups, r.embedding, r.metadata, + r.created_at, r.updated_at, + )?; + out.push(SearchResult { + record: rec, + score: r.score, + fts_score: None, + vector_score: Some(r.score), + }); + } + Ok(out) +} +``` + +The `query_vec as Vector` cast is the same type-annotation trick as +`insert` -- sqlx needs the concrete pgvector type to wire up encoding. +The `ORDER BY m.embedding <=> $1` (no `score`) is intentional: it lets +the HNSW index serve the query directly. Sorting by the computed +`score` column would force a sequential scan because the index orders +by distance, not similarity. + +### Scheduling + +The Postgres `scheduling` table is a separate row keyed on `memory_id`, +not embedded in `knowledge_nodes` (unlike SQLite where FSRS columns live on +`knowledge_nodes`). The bodies abstract that difference at the SQL +boundary; callers see the same `SchedulingState` value. + +#### `get_scheduling` + +```rust +async fn get_scheduling(&self, memory_id: Uuid) -> MemoryStoreResult> +``` + +```rust +async fn get_scheduling( + &self, + memory_id: Uuid, +) -> MemoryStoreResult> { + let row = sqlx::query!( + r#" + SELECT + memory_id AS "memory_id!: Uuid", + stability AS "stability!: f64", + difficulty AS "difficulty!: f64", + retrievability AS "retrievability!: f64", + last_review AS "last_review: DateTime", + next_review AS "next_review: DateTime", + reps AS "reps!: i32", + lapses AS "lapses!: i32" + FROM scheduling + WHERE memory_id = $1 + "#, + memory_id, + ) + .fetch_optional(&self.pool) + .await?; + + Ok(row.map(|r| SchedulingState { + memory_id: r.memory_id, + stability: r.stability, + difficulty: r.difficulty, + retrievability: r.retrievability, + last_review: r.last_review, + next_review: r.next_review, + reps: r.reps as u32, + lapses: r.lapses as u32, + })) +} +``` + +#### `update_scheduling` + +```rust +async fn update_scheduling(&self, state: &SchedulingState) -> MemoryStoreResult<()> +``` + +Upsert -- the `INSERT ... ON CONFLICT DO UPDATE` form -- so cognitive +modules that update scheduling for a freshly-inserted memory don't have +to race with the seed row from `insert`. + +```rust +async fn update_scheduling( + &self, + state: &SchedulingState, +) -> MemoryStoreResult<()> { + sqlx::query!( + r#" + INSERT INTO scheduling ( + memory_id, stability, difficulty, retrievability, + last_review, next_review, reps, lapses + ) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + ON CONFLICT (memory_id) DO UPDATE SET + stability = EXCLUDED.stability, + difficulty = EXCLUDED.difficulty, + retrievability = EXCLUDED.retrievability, + last_review = EXCLUDED.last_review, + next_review = EXCLUDED.next_review, + reps = EXCLUDED.reps, + lapses = EXCLUDED.lapses + "#, + state.memory_id, + state.stability, + state.difficulty, + state.retrievability, + state.last_review, + state.next_review, + state.reps as i32, + state.lapses as i32, + ) + .execute(&self.pool) + .await?; + Ok(()) +} +``` + +#### `get_due_memories` + +```rust +async fn get_due_memories( + &self, + before: DateTime, + limit: usize, +) -> MemoryStoreResult> +``` + +Join `knowledge_nodes` and `scheduling`, filter on `next_review <= before`. +Single query returns both halves of the tuple. + +```rust +async fn get_due_memories( + &self, + before: DateTime, + limit: usize, +) -> MemoryStoreResult> { + let limit = limit.min(10_000) as i64; + let rows = sqlx::query!( + r#" + SELECT + m.id AS "id!: Uuid", + m.owner_user_id AS "owner_user_id!: Uuid", + m.visibility, + m.shared_with_groups AS "shared_with_groups!: Vec", + m.codebase, + m.content, + m.node_type, + m.tags AS "tags!: Vec", + m.domains AS "domains!: Vec", + m.domain_scores AS "domain_scores!: serde_json::Value", + m.embedding AS "embedding: Vector", + m.metadata AS "metadata!: serde_json::Value", + m.created_at AS "created_at!: DateTime", + m.updated_at AS "updated_at!: DateTime", + s.stability AS "stability!: f64", + s.difficulty AS "difficulty!: f64", + s.retrievability AS "retrievability!: f64", + s.last_review AS "last_review: DateTime", + s.next_review AS "next_review: DateTime", + s.reps AS "reps!: i32", + s.lapses AS "lapses!: i32" + FROM knowledge_nodes m + JOIN scheduling s ON s.memory_id = m.id + WHERE s.next_review IS NOT NULL AND s.next_review <= $1 + ORDER BY s.next_review ASC + LIMIT $2 + "#, + before, + limit, + ) + .fetch_all(&self.pool) + .await?; + + let mut out = Vec::with_capacity(rows.len()); + for r in rows { + let rec = row_to_record( + r.id, r.content, r.node_type, r.tags, r.domains, + r.domain_scores, r.codebase, r.owner_user_id, r.visibility, + r.shared_with_groups, r.embedding, r.metadata, + r.created_at, r.updated_at, + )?; + let state = SchedulingState { + memory_id: rec.id, + stability: r.stability, + difficulty: r.difficulty, + retrievability: r.retrievability, + last_review: r.last_review, + next_review: r.next_review, + reps: r.reps as u32, + lapses: r.lapses as u32, + }; + out.push((rec, state)); + } + Ok(out) +} +``` + +### Graph (edges) + +#### `add_edge` + +```rust +async fn add_edge(&self, edge: &MemoryEdge) -> MemoryStoreResult<()> +``` + +`INSERT ... ON CONFLICT` -- updating the weight if an edge already +exists (matches SQLite's `save_connection` semantics). + +```rust +async fn add_edge(&self, edge: &MemoryEdge) -> MemoryStoreResult<()> { + sqlx::query!( + r#" + INSERT INTO edges ( + source_id, target_id, edge_type, weight, created_at + ) + VALUES ($1, $2, $3, $4, $5) + ON CONFLICT (source_id, target_id, edge_type) DO UPDATE SET + weight = EXCLUDED.weight + "#, + edge.source_id, + edge.target_id, + edge.edge_type, + edge.weight, + edge.created_at, + ) + .execute(&self.pool) + .await?; + Ok(()) +} +``` + +#### `get_edges` + +```rust +async fn get_edges( + &self, + node_id: Uuid, + edge_type: Option<&str>, +) -> MemoryStoreResult> +``` + +Return every edge incident to `node_id` in either direction, optionally +filtered by `edge_type`. The optional filter binds as nullable; `$2 IS +NULL OR edge_type = $2` keeps the prepared statement reusable. + +```rust +async fn get_edges( + &self, + node_id: Uuid, + edge_type: Option<&str>, +) -> MemoryStoreResult> { + let rows = sqlx::query!( + r#" + SELECT + source_id AS "source_id!: Uuid", + target_id AS "target_id!: Uuid", + edge_type, + weight AS "weight!: f64", + created_at AS "created_at!: DateTime" + FROM edges + WHERE (source_id = $1 OR target_id = $1) + AND ($2::text IS NULL OR edge_type = $2) + "#, + node_id, + edge_type, + ) + .fetch_all(&self.pool) + .await?; + + Ok(rows + .into_iter() + .map(|r| MemoryEdge { + source_id: r.source_id, + target_id: r.target_id, + edge_type: r.edge_type, + weight: r.weight, + created_at: r.created_at, + }) + .collect()) +} +``` + +#### `remove_edge` + +```rust +async fn remove_edge(&self, source: Uuid, target: Uuid) -> MemoryStoreResult<()> +``` + +Note: the live trait signature is two args (`source`, `target`). The +master plan's stale three-arg signature including `edge_type` is not +implemented -- the live trait surface wins. Deletes every edge between +the pair regardless of `edge_type`. + +```rust +async fn remove_edge( + &self, + source: Uuid, + target: Uuid, +) -> MemoryStoreResult<()> { + sqlx::query!( + "DELETE FROM edges WHERE source_id = $1 AND target_id = $2", + source, + target, + ) + .execute(&self.pool) + .await?; + Ok(()) +} +``` + +#### `get_neighbors` + +```rust +async fn get_neighbors( + &self, + node_id: Uuid, + depth: usize, +) -> MemoryStoreResult> +``` + +Recursive CTE walks the edge graph outward from `node_id` for up to +`depth` hops. Weights compound multiplicatively along the path (same as +SQLite BFS). Cap the visited set at 256 rows to match SQLite. Direction +is treated as undirected by unioning both halves of each edge inside +the CTE. + +```rust +async fn get_neighbors( + &self, + node_id: Uuid, + depth: usize, +) -> MemoryStoreResult> { + if depth == 0 { + let Some(rec) = self.get(node_id).await? else { + return Err(MemoryStoreError::NotFound(node_id.to_string())); + }; + return Ok(vec![(rec, 1.0)]); + } + + let depth_i = depth.min(16) as i32; + let rows = sqlx::query!( + r#" + WITH RECURSIVE walk(node_id, weight, hops) AS ( + SELECT $1::uuid, 1.0::float8, 0 + UNION ALL + SELECT + CASE WHEN e.source_id = w.node_id THEN e.target_id + ELSE e.source_id END, + w.weight * e.weight, + w.hops + 1 + FROM walk w + JOIN edges e + ON e.source_id = w.node_id OR e.target_id = w.node_id + WHERE w.hops < $2 + ), + best AS ( + SELECT node_id, MAX(weight) AS weight + FROM walk + GROUP BY node_id + LIMIT 256 + ) + SELECT + m.id AS "id!: Uuid", + m.owner_user_id AS "owner_user_id!: Uuid", + m.visibility, + m.shared_with_groups AS "shared_with_groups!: Vec", + m.codebase, + m.content, + m.node_type, + m.tags AS "tags!: Vec", + m.domains AS "domains!: Vec", + m.domain_scores AS "domain_scores!: serde_json::Value", + m.embedding AS "embedding: Vector", + m.metadata AS "metadata!: serde_json::Value", + m.created_at AS "created_at!: DateTime", + m.updated_at AS "updated_at!: DateTime", + b.weight AS "weight!: f64" + FROM best b + JOIN knowledge_nodes m ON m.id = b.node_id + "#, + node_id, + depth_i, + ) + .fetch_all(&self.pool) + .await?; + + let mut out = Vec::with_capacity(rows.len()); + for r in rows { + let rec = row_to_record( + r.id, r.content, r.node_type, r.tags, r.domains, + r.domain_scores, r.codebase, r.owner_user_id, r.visibility, + r.shared_with_groups, r.embedding, r.metadata, + r.created_at, r.updated_at, + )?; + out.push((rec, r.weight)); + } + Ok(out) +} +``` + +The CTE can visit a node multiple times via different paths; the `best` +sub-CTE picks the highest weight per node. The `LIMIT 256` matches the +SQLite BFS cap. Postgres' recursive CTE is breadth-first by hop count +because of the `WHERE w.hops < $2` predicate. + +### Domains (Phase 4 populates; Phase 2 ships CRUD) + +The `domains` table is empty in Phase 2; these methods exist so the +trait surface is complete but they do not get exercised until Phase 4 +HDBSCAN clustering runs. + +#### `list_domains` + +```rust +async fn list_domains(&self) -> MemoryStoreResult> +``` + +```rust +async fn list_domains(&self) -> MemoryStoreResult> { + let rows = sqlx::query!( + r#" + SELECT + id, + label, + centroid AS "centroid: Vector", + top_terms AS "top_terms!: Vec", + memory_count AS "memory_count!: i64", + created_at AS "created_at!: DateTime" + FROM domains + ORDER BY created_at ASC + "# + ) + .fetch_all(&self.pool) + .await?; + + Ok(rows + .into_iter() + .map(|r| Domain { + id: r.id, + label: r.label, + centroid: r.centroid.map(|v| v.to_vec()).unwrap_or_default(), + top_terms: r.top_terms, + memory_count: r.memory_count as usize, + created_at: r.created_at, + }) + .collect()) +} +``` + +#### `get_domain` + +```rust +async fn get_domain(&self, id: &str) -> MemoryStoreResult> +``` + +```rust +async fn get_domain(&self, id: &str) -> MemoryStoreResult> { + let row = sqlx::query!( + r#" + SELECT + id, + label, + centroid AS "centroid: Vector", + top_terms AS "top_terms!: Vec", + memory_count AS "memory_count!: i64", + created_at AS "created_at!: DateTime" + FROM domains + WHERE id = $1 + "#, + id, + ) + .fetch_optional(&self.pool) + .await?; + + Ok(row.map(|r| Domain { + id: r.id, + label: r.label, + centroid: r.centroid.map(|v| v.to_vec()).unwrap_or_default(), + top_terms: r.top_terms, + memory_count: r.memory_count as usize, + created_at: r.created_at, + })) +} +``` + +#### `upsert_domain` + +```rust +async fn upsert_domain(&self, domain: &Domain) -> MemoryStoreResult<()> +``` + +```rust +async fn upsert_domain(&self, domain: &Domain) -> MemoryStoreResult<()> { + let centroid = if domain.centroid.is_empty() { + None + } else { + Some(Vector::from(domain.centroid.clone())) + }; + + sqlx::query!( + r#" + INSERT INTO domains ( + id, label, centroid, top_terms, memory_count, created_at + ) + VALUES ($1, $2, $3, $4, $5, $6) + ON CONFLICT (id) DO UPDATE SET + label = EXCLUDED.label, + centroid = EXCLUDED.centroid, + top_terms = EXCLUDED.top_terms, + memory_count = EXCLUDED.memory_count + "#, + domain.id, + domain.label, + centroid as Option, + &domain.top_terms as &[String], + domain.memory_count as i64, + domain.created_at, + ) + .execute(&self.pool) + .await?; + Ok(()) +} +``` + +#### `delete_domain` + +```rust +async fn delete_domain(&self, id: &str) -> MemoryStoreResult<()> +``` + +```rust +async fn delete_domain(&self, id: &str) -> MemoryStoreResult<()> { + sqlx::query!( + "DELETE FROM domains WHERE id = $1", + id, + ) + .execute(&self.pool) + .await?; + Ok(()) +} +``` + +#### `classify` + +```rust +async fn classify(&self, embedding: &[f32]) -> MemoryStoreResult> +``` + +The Postgres backend can ship this as a single SQL query against the +empty `domains` table -- it correctly returns an empty vector in Phase +2 and starts returning real scores in Phase 4 without any code change. + +```rust +async fn classify( + &self, + embedding: &[f32], +) -> MemoryStoreResult> { + let query_vec = Vector::from(embedding.to_vec()); + let rows = sqlx::query!( + r#" + SELECT + id, + (1.0 - (centroid <=> $1)) AS "score!: f64" + FROM domains + WHERE centroid IS NOT NULL + ORDER BY score DESC + "#, + query_vec as Vector, + ) + .fetch_all(&self.pool) + .await?; + + Ok(rows.into_iter().map(|r| (r.id, r.score)).collect()) +} +``` + +### Bulk / maintenance + +#### `count` + +```rust +async fn count(&self) -> MemoryStoreResult +``` + +```rust +async fn count(&self) -> MemoryStoreResult { + let n: i64 = sqlx::query_scalar!("SELECT COUNT(*) FROM knowledge_nodes") + .fetch_one(&self.pool) + .await? + .unwrap_or(0); + Ok(n as usize) +} +``` + +#### `get_stats` + +```rust +async fn get_stats(&self) -> MemoryStoreResult +``` + +Aggregate counts across `knowledge_nodes`, `edges`, `domains`. Read the +registry inline. + +```rust +async fn get_stats(&self) -> MemoryStoreResult { + let row = sqlx::query!( + r#" + SELECT + (SELECT COUNT(*) FROM knowledge_nodes) + AS "total_memories!: i64", + (SELECT COUNT(*) FROM knowledge_nodes WHERE embedding IS NOT NULL) + AS "memories_with_embeddings!: i64", + (SELECT COUNT(*) FROM edges) + AS "total_edges!: i64", + (SELECT COUNT(*) FROM domains) + AS "total_domains!: i64", + (SELECT name FROM embedding_model WHERE id = 1) + AS "registered_model_name: String", + (SELECT dimension FROM embedding_model WHERE id = 1) + AS "registered_model_dim: i32" + "# + ) + .fetch_one(&self.pool) + .await?; + + Ok(StoreStats { + total_memories: row.total_memories as usize, + memories_with_embeddings: row.memories_with_embeddings as usize, + total_edges: row.total_edges as usize, + total_domains: row.total_domains as usize, + registered_model_name: row.registered_model_name, + registered_model_dim: row.registered_model_dim.map(|d| d as usize), + }) +} +``` + +#### `vacuum` + +```rust +async fn vacuum(&self) -> MemoryStoreResult<()> +``` + +`VACUUM` cannot run inside a transaction. sqlx wraps each `query!` +invocation in an implicit transaction when it grabs a pooled +connection, but it does not -- the pool hands out a raw connection +that runs statements in autocommit mode by default. The safe path is +to acquire a connection explicitly and `execute` each statement +separately so neither participates in a transaction. + +```rust +async fn vacuum(&self) -> MemoryStoreResult<()> { + let mut conn = self.pool.acquire().await?; + sqlx::query("VACUUM ANALYZE knowledge_nodes") + .execute(conn.as_mut()) + .await?; + sqlx::query("VACUUM ANALYZE scheduling") + .execute(conn.as_mut()) + .await?; + sqlx::query("VACUUM ANALYZE edges") + .execute(conn.as_mut()) + .await?; + Ok(()) +} +``` + +`conn.as_mut()` yields a `&mut PgConnection`, which sqlx accepts as an +executor. Using `&self.pool` here would let sqlx pick a fresh +connection per statement (still fine, but two extra acquisitions). Note +we do NOT vacuum `domains`, `edges`-related lookup tables (`users` / +`groups` etc.) -- they are either empty in Phase 2 or low-churn and the +nightly autovacuum suffices. + +--- + +## Visibility filter posture + +ADR 0002 D7 declares the future Phase 3 visibility filter (reproduced +here for clarity): + +```sql +WHERE + (visibility = 'private' AND owner_user_id = $me) + OR (visibility = 'group' + AND (owner_user_id = $me OR shared_with_groups && $my_group_ids)) + OR visibility = 'public' +``` + +**Phase 2 does NOT apply this filter.** Every body above reads and +writes the rows it touches regardless of `owner_user_id` or +`visibility` because there is exactly one user in Phase 2 mode (the +bootstrap user from `0001_init.up.sql`). The reviewer should NOT expect +`WHERE owner_user_id = $...` clauses in Phase 2 method bodies. + +Phase 3 introduces an `AuthContext` parameter on the trait methods and +threads it into each WHERE clause. That migration is purely additive +(adds a parameter, adds a clause); it does not need a schema migration +because the columns and indexes are already in place. + +The four new `MemoryRecord` fields ARE populated correctly in Phase 2 +(insert writes them, get/search read them) so that exported archives +and replicated rows round-trip the visibility intent the moment Phase +3 enables filtering. + +--- + +## Offline sqlx cache + +`sqlx::query!` and `sqlx::query_as!` validate every SQL string at +compile time by contacting a live database. To keep CI builds from +needing a Postgres on the build host, sqlx supports an offline cache +in `/.sqlx/` containing one JSON file per validated query. + +This sub-plan is where `.sqlx/` is first populated and committed. + +Workflow: + +1. Ensure a local Postgres is running with the same schema CI will see: + + ```bash + cd crates/vestige-core + export DATABASE_URL="postgres://vestige:vestige@127.0.0.1:5432/vestige_dev" + sqlx database create + sqlx migrate run --source migrations/postgres + ``` + +2. Generate the offline cache: + + ```bash + cargo sqlx prepare --workspace -- --features postgres-backend + ``` + + This walks every `sqlx::query!` invocation under the active feature + flags and writes `crates/vestige-core/.sqlx/query-.json`. The + `--workspace` flag is needed because `vestige-mcp` enables the + `postgres-backend` feature transitively in `0002b-pool-and-config.md`. + +3. Stage and commit the cache directory: + + ```bash + git add crates/vestige-core/.sqlx/ + git commit -m "store: populate sqlx offline cache for postgres backend" + ``` + +4. Add to repo `.gitignore` adjustments (only if entries already deny + `target/` or similar globs): leave `.sqlx/` excluded from any + ignore globs. Specifically the workspace root `.gitignore` does NOT + contain a `.sqlx` line; if a future PR adds one, this sub-plan's + commit reverts it. + +5. CI runs `SQLX_OFFLINE=true cargo check --features postgres-backend`. + sqlx falls back to the JSON cache when `SQLX_OFFLINE=true` is set, + so CI does not need network access to a Postgres. + +Every time a `query!` invocation changes -- add a column, change a +WHERE clause, rename a binding -- re-run `cargo sqlx prepare` and +commit the updated `.sqlx/` files. The agent implementing this sub-plan +runs `cargo sqlx prepare` as the last step before opening the PR. + +--- + +## Verification + +Three layers of verification before merging this sub-plan. + +### 1. Compile and lint + +```bash +cargo check --workspace --features postgres-backend +cargo build --workspace --features postgres-backend +cargo clippy --workspace --features postgres-backend -- -D warnings + +# SQLite-only build still works (mutual compilability per CLAUDE.md): +cargo check --workspace --no-default-features --features embeddings,vector-search +``` + +### 2. Offline cache builds + +```bash +SQLX_OFFLINE=true cargo check --workspace --features postgres-backend +``` + +This is what CI will run. If it fails, `cargo sqlx prepare` was not +re-run after the last query change. + +### 3. Integration round-trip test (testcontainers) + +New test file: +`crates/vestige-core/tests/postgres_round_trip.rs`. Skipped unless the +`postgres-backend` feature is active and Docker / Podman is available. + +```rust +#![cfg(feature = "postgres-backend")] + +use chrono::Utc; +use testcontainers::{clients, GenericImage}; +use uuid::Uuid; +use vestige_core::storage::memory_store::{ + LocalMemoryStore, MemoryEdge, MemoryRecord, SchedulingState, Visibility, + LOCAL_USER_ID, +}; +use vestige_core::storage::postgres::PgMemoryStore; + +#[tokio::test] +async fn round_trip_crud_search_scheduling_edges() { + let docker = clients::Cli::default(); + let image = GenericImage::new("pgvector/pgvector", "pg16") + .with_env_var("POSTGRES_PASSWORD", "test") + .with_env_var("POSTGRES_DB", "vestige_test") + .with_exposed_port(5432); + let container = docker.run(image); + let port = container.get_host_port_ipv4(5432); + let url = format!("postgres://postgres:test@127.0.0.1:{port}/vestige_test"); + + let store = PgMemoryStore::connect(&url, 5).await.expect("connect"); + + // Register the model (typmod stamp). + store.register_model(&fixture_signature(384)).await.expect("register"); + + // insert -> get -> update -> delete. + let mut rec = fixture_record(); + let id = store.insert(&rec).await.expect("insert"); + let fetched = store.get(id).await.expect("get").expect("present"); + assert_eq!(fetched.content, rec.content); + assert_eq!(fetched.owner_user_id, LOCAL_USER_ID); + assert_eq!(fetched.visibility, Visibility::Private); + + rec.content = "edited".to_string(); + store.update(&rec).await.expect("update"); + assert_eq!(store.get(id).await.unwrap().unwrap().content, "edited"); + + // fts_search. + let hits = store.fts_search("edited", 10).await.expect("fts"); + assert!(hits.iter().any(|h| h.record.id == id)); + + // vector_search. + let emb = rec.embedding.clone().unwrap(); + let vhits = store.vector_search(&emb, 10).await.expect("vector"); + assert!(vhits.iter().any(|h| h.record.id == id)); + + // scheduling round-trip. + let sched = store.get_scheduling(id).await.unwrap().expect("seeded"); + let new_state = SchedulingState { + memory_id: id, + stability: 5.5, + difficulty: 0.2, + retrievability: 0.95, + last_review: Some(Utc::now()), + next_review: Some(Utc::now() + chrono::Duration::days(3)), + reps: sched.reps + 1, + lapses: sched.lapses, + }; + store.update_scheduling(&new_state).await.expect("update sched"); + let after = store.get_scheduling(id).await.unwrap().unwrap(); + assert_eq!(after.reps, new_state.reps); + + // edges. + let other = fixture_record(); + let other_id = store.insert(&other).await.unwrap(); + let edge = MemoryEdge { + source_id: id, + target_id: other_id, + edge_type: "semantic".to_string(), + weight: 0.8, + created_at: Utc::now(), + }; + store.add_edge(&edge).await.expect("add_edge"); + let edges = store.get_edges(id, None).await.unwrap(); + assert_eq!(edges.len(), 1); + let neighbors = store.get_neighbors(id, 1).await.unwrap(); + assert!(neighbors.iter().any(|(r, _)| r.id == other_id)); + store.remove_edge(id, other_id).await.expect("remove_edge"); + assert!(store.get_edges(id, None).await.unwrap().is_empty()); + + // delete -> cascade. + store.delete(id).await.expect("delete"); + assert!(store.get(id).await.unwrap().is_none()); + assert!(store.get_scheduling(id).await.unwrap().is_none()); +} + +fn fixture_record() -> MemoryRecord { + MemoryRecord { + id: Uuid::new_v4(), + domains: vec![], + domain_scores: Default::default(), + content: "the quick brown fox jumps over the lazy dog".into(), + node_type: "fact".into(), + tags: vec!["test".into()], + embedding: Some(vec![0.1_f32; 384]), + created_at: Utc::now(), + updated_at: Utc::now(), + metadata: serde_json::json!({}), + owner_user_id: LOCAL_USER_ID, + visibility: Visibility::Private, + shared_with_groups: vec![], + codebase: Some("vestige".to_string()), + } +} + +fn fixture_signature(dim: usize) -> vestige_core::storage::memory_store::ModelSignature { + vestige_core::storage::memory_store::ModelSignature { + name: "test/model".to_string(), + dimension: dim, + hash: "0".repeat(64), + } +} +``` + +Add `testcontainers = "0.20"` to `[dev-dependencies]` under +`#[cfg(feature = "postgres-backend")]` gating. The test is the slowest +in the suite (spawns a Docker container, ~5 s startup); annotate with +`#[ignore]` if CI runtime budget requires opt-in execution. + +### 4. Manual smoke (optional but recommended) + +```bash +# Tear down any prior database. +make postgres-down ; make postgres-up +DATABASE_URL=$(make postgres-url) cargo test \ + -p vestige-core --features postgres-backend -- --include-ignored +``` + +The `postgres-up` / `postgres-down` / `postgres-url` make targets are +defined in `docs/plans/local-dev-postgres-setup.md`. + +--- + +## Acceptance criteria + +This sub-plan is complete when ALL of the following hold: + +1. `cargo build --workspace --features postgres-backend` succeeds with + zero warnings. +2. `cargo clippy --workspace --features postgres-backend -- -D warnings` + succeeds. +3. `cargo build --workspace --no-default-features --features embeddings,vector-search` + still succeeds (the SQLite-only build is not regressed). +4. `SQLX_OFFLINE=true cargo check --workspace --features postgres-backend` + succeeds. `crates/vestige-core/.sqlx/` exists and contains one JSON + file per `sqlx::query!` / `sqlx::query_as!` invocation in the + Postgres backend. +5. Zero `todo!()` macros remain in + `crates/vestige-core/src/storage/postgres/mod.rs`. The only + exception is the body of the trait method `search` -- that method + stays `todo!()` until `0002e-hybrid-search.md` lands. +6. `crates/vestige-core/src/storage/postgres/registry.rs` exists with + the three functions described above + (`fetch_registry`, `ensure_registry`, `update_registry_for_reembed`). +7. `MemoryRecord` carries the four new fields + (`owner_user_id`, `visibility`, `shared_with_groups`, `codebase`) + and the `Visibility` enum is exported alongside it. The SQLite + backend reads and writes the same four fields. +8. The `tests/postgres_round_trip.rs` integration test passes against + a `pgvector/pgvector:pg16` container (insert / get / update / delete + / fts_search / vector_search / get_scheduling / update_scheduling + / add_edge / get_edges / remove_edge / get_neighbors / cascade + delete). +9. No visibility filter clause is present in any Phase 2 method body. + `WHERE owner_user_id = ...`, `WHERE visibility = ...`, and + `shared_with_groups && ...` do not appear anywhere in + `crates/vestige-core/src/storage/postgres/`. +10. `cargo sqlx prepare` was the last command run before commit; the + diff includes `.sqlx/` changes if any query changed. diff --git a/docs/plans/0002e-hybrid-search.md b/docs/plans/0002e-hybrid-search.md new file mode 100644 index 0000000..1f45174 --- /dev/null +++ b/docs/plans/0002e-hybrid-search.md @@ -0,0 +1,825 @@ +# Phase 2 Sub-Plan 0002e -- Hybrid RRF Search + +**Status**: Ready +**Depends on**: +- `0002a-skeleton-and-feature-gate.md` (the `postgres-backend` feature flag + exists and `PgMemoryStore` compiles with `todo!()` bodies). +- `0002b-pool-and-config.md` (a working `PgPool` reaches the backend). +- `0002c-migrations.md` (migration `0001_init` has created the `knowledge_nodes` + table with the D7 columns -- `owner_user_id`, `visibility`, + `shared_with_groups` -- and the D8 column `codebase`; migration `0002_hnsw` + has built the HNSW index). +- `0002d-store-impl-bodies.md` (real CRUD bodies exist so the integration + tests below can seed data through the trait surface rather than raw SQL). + +This sub-plan covers master plan 0002 deliverable D5: the hybrid RRF search +query implementation in `crates/vestige-core/src/storage/postgres/search.rs`, +plus the `search`, `fts_search`, and `vector_search` method bodies in +`crates/vestige-core/src/storage/postgres/mod.rs` that delegate into it. + +--- + +## Context + +This is one of the more performance-sensitive sub-plans in Phase 2. Every +search call from the cognitive engine -- the 7-stage retrieval pipeline, +`session_context`, `predict`, `deep_reference`, the dashboard -- bottoms out +in `MemoryStore::search`. The Postgres backend has to keep up with the +existing SQLite hybrid path, which combines BM25 over FTS5 with USearch HNSW +in two separate round trips and fuses the rankings in Rust. + +The shape of the win on Postgres is that both branches and the fusion run +inside one statement. The planner sees both CTEs together, the round trip is +single, and the rerank stage runs over a cleanly overfetched candidate set. + +Latency targets live in `0002h-testing-and-benches.md`. This sub-plan is +responsible for producing a correct, schema-stable query that the benches +can drive against. Do not optimise here; correctness and structure first. + +Master plan 0002 D5 (around lines 522-628 of +`docs/plans/0002-phase-2-postgres-backend.md`) sketches the SQL. That +sketch is the starting point, not the finished product. The schema after +the D7 and D8 amendments has more columns than the sketch enumerates, and +the SQLite `search` method (around line 6503 of +`crates/vestige-core/src/storage/sqlite.rs` in the Phase 1 worktree) +documents the semantics this implementation must stay compatible with: + +- Empty `query.limit` defaults to 10. +- `query.text == Some("")` is treated as no text query (degrade to vector). +- `query.embedding == None` is treated as no vector query (degrade to FTS). +- Both empty returns `Ok(vec![])`; not an error. +- The `MemoryRecord` in each `SearchResult` must be populated with all + fields the trait promises, including `domains` and `domain_scores` (Phase + 4 will fill these in; Phase 2 returns the stored values, which may be + empty arrays / empty objects). + +--- + +## Constants + +```rust +/// Reciprocal Rank Fusion smoothing constant from Cormack, Clarke and Buettcher +/// 2009 ("Reciprocal Rank Fusion outperforms Condorcet and individual rank +/// learning methods"). 60 is the canonical default and is robust across most +/// fusion regimes. Do not tune this without a paper-citation-grade reason. +const RRF_K: i32 = 60; + +/// Each branch (FTS, vector) is allowed to return OVERFETCH_MULT x final_limit +/// rows before fusion. Three matches the Phase 1 SQLite overfetch and gives +/// the fusion enough candidates to recover from any single branch's bad +/// recall on a given query. +const OVERFETCH_MULT: i64 = 3; +``` + +These live at module scope in +`crates/vestige-core/src/storage/postgres/search.rs`. They are `pub(crate)` +only if `0002h-testing-and-benches.md` needs to reference them from the +integration tests; otherwise private. + +--- + +## Public API + +```rust +#![cfg(feature = "postgres-backend")] + +use pgvector::Vector; +use sqlx::PgPool; + +use crate::storage::memory_store::{ + MemoryStoreResult, SearchQuery, SearchResult, +}; + +/// Hybrid RRF search over Postgres FTS and pgvector cosine distance. +/// +/// Branch behavior: +/// - empty text + null embedding -> Ok(vec![]) +/// - empty text + Some(embedding) -> pure vector search (FTS CTE returns +/// zero rows; fusion equals the vector +/// branch) +/// - Some(text) + null embedding -> pure FTS search +/// - Some(text) + Some(embedding) -> full RRF fusion +/// +/// `query.limit == 0` is treated as 10 (matches the SQLite default). +pub(crate) async fn rrf_search( + pool: &PgPool, + query: &SearchQuery, +) -> MemoryStoreResult>; + +/// FTS-only convenience search. Equivalent to calling `rrf_search` with +/// `query.embedding = None`, but uses a dedicated single-branch query that +/// avoids the FULL OUTER JOIN and the params CTE; faster by one planner pass +/// per call. +pub(crate) async fn fts_only( + pool: &PgPool, + text: &str, + limit: usize, +) -> MemoryStoreResult>; + +/// Vector-only convenience search. Dedicated single-branch query for the same +/// latency reason as `fts_only`. +pub(crate) async fn vector_only( + pool: &PgPool, + embedding: &[f32], + limit: usize, +) -> MemoryStoreResult>; +``` + +### Parameter handling + +In `rrf_search`: + +```rust +let final_limit: i32 = if query.limit == 0 { 10 } else { query.limit as i32 }; +let overfetch: i32 = (final_limit as i64 * OVERFETCH_MULT) + .min(i32::MAX as i64) as i32; + +let q_text: &str = query.text.as_deref().unwrap_or(""); +let q_vec: Option = query.embedding.as_ref() + .map(|v| Vector::from(v.clone())); + +let dom_filter: Option<&[String]> = query.domains.as_deref(); +let nt_filter: Option<&[String]> = query.node_types.as_deref(); +let tag_filter: Option<&[String]> = query.tags.as_deref(); + +let min_retr: Option = query.min_retrievability; +``` + +Both branches empty -- `q_text` is empty and `q_vec` is `None` -- returns +`Ok(vec![])` without hitting the database. The SQLite backend has the same +behavior and tests rely on it. + +```rust +if q_text.is_empty() && q_vec.is_none() { + return Ok(Vec::new()); +} +``` + +### `search` method body in `postgres/mod.rs` + +```rust +#[async_trait::async_trait] // or trait_variant after the Phase 1 amendment +impl MemoryStore for PgMemoryStore { + async fn search(&self, query: &SearchQuery) + -> MemoryStoreResult> + { + crate::storage::postgres::search::rrf_search(&self.pool, query).await + } + + async fn fts_search(&self, text: &str, limit: usize) + -> MemoryStoreResult> + { + crate::storage::postgres::search::fts_only(&self.pool, text, limit) + .await + } + + async fn vector_search(&self, embedding: &[f32], limit: usize) + -> MemoryStoreResult> + { + crate::storage::postgres::search::vector_only(&self.pool, embedding, limit) + .await + } +} +``` + +Everything below specifies the inside of those three free functions. + +--- + +## SQL: the hybrid RRF query + +The query is built as one `&'static str` (or `OnceCell`; see "Use +of sqlx::query!" below) and reused. Bound parameters are kept to seven +through a `params` CTE that the rest of the query references by name -- +this keeps the SQL readable and stops the bound-parameter count growing +with each filter clause. + +Bound parameters: + +- `$1`: text query (TEXT, may be empty) +- `$2`: embedding (pgvector::Vector, may be NULL) +- `$3`: overfetch limit per branch (INT) +- `$4`: final limit (INT) +- `$5`: domain filter (TEXT[] or NULL) +- `$6`: node_type filter (TEXT[] or NULL) +- `$7`: tag filter (TEXT[] or NULL) + +If `min_retrievability.is_some()` the outer SELECT adds a JOIN on +`scheduling` and a WHERE clause; that path uses a different prepared +statement (see "min_retrievability filter" below) so the simple-path query +stays free of the join. + +```sql +WITH params AS ( + SELECT + $1::text AS q_text, + $2::vector AS q_vec, + $3::int AS overfetch, + $4::int AS final_limit, + $5::text[] AS dom_filter, + $6::text[] AS nt_filter, + $7::text[] AS tag_filter +), +fts AS ( + SELECT + m.id, + ts_rank_cd( + m.search_vec, + websearch_to_tsquery('english', p.q_text) + ) AS score, + ROW_NUMBER() OVER ( + ORDER BY ts_rank_cd( + m.search_vec, + websearch_to_tsquery('english', p.q_text) + ) DESC + ) AS rank + FROM knowledge_nodes m + CROSS JOIN params p + WHERE p.q_text <> '' + AND m.search_vec @@ websearch_to_tsquery('english', p.q_text) + AND (p.dom_filter IS NULL OR m.domains && p.dom_filter) + AND (p.nt_filter IS NULL OR m.node_type = ANY(p.nt_filter)) + AND (p.tag_filter IS NULL OR m.tags && p.tag_filter) + ORDER BY score DESC + LIMIT (SELECT overfetch FROM params) +), +vec AS ( + SELECT + m.id, + 1.0 - (m.embedding <=> p.q_vec) AS score, + ROW_NUMBER() OVER ( + ORDER BY m.embedding <=> p.q_vec + ) AS rank + FROM knowledge_nodes m + CROSS JOIN params p + WHERE m.embedding IS NOT NULL + AND p.q_vec IS NOT NULL + AND (p.dom_filter IS NULL OR m.domains && p.dom_filter) + AND (p.nt_filter IS NULL OR m.node_type = ANY(p.nt_filter)) + AND (p.tag_filter IS NULL OR m.tags && p.tag_filter) + ORDER BY m.embedding <=> p.q_vec + LIMIT (SELECT overfetch FROM params) +), +fused AS ( + SELECT + COALESCE(f.id, v.id) AS id, + COALESCE(1.0 / (60 + f.rank), 0.0) + + COALESCE(1.0 / (60 + v.rank), 0.0) AS rrf_score, + f.score AS fts_score, + v.score AS vector_score + FROM fts f + FULL OUTER JOIN vec v ON f.id = v.id +) +SELECT + m.id AS "id!: uuid::Uuid", + m.owner_user_id AS "owner_user_id!: uuid::Uuid", + m.visibility AS "visibility!: String", + m.shared_with_groups AS "shared_with_groups!: Vec", + m.codebase AS "codebase: String", + m.domains AS "domains!: Vec", + m.domain_scores AS "domain_scores!: serde_json::Value", + m.content AS "content!: String", + m.node_type AS "node_type!: String", + m.tags AS "tags!: Vec", + m.embedding AS "embedding: pgvector::Vector", + m.metadata AS "metadata!: serde_json::Value", + m.created_at AS "created_at!: chrono::DateTime", + m.updated_at AS "updated_at!: chrono::DateTime", + fused.rrf_score AS "rrf_score!: f64", + fused.fts_score AS "fts_score: f64", + fused.vector_score AS "vector_score: f64" +FROM fused +JOIN knowledge_nodes m ON m.id = fused.id +ORDER BY fused.rrf_score DESC +LIMIT (SELECT final_limit FROM params); +``` + +Notes on the SELECT column list. The D7 columns (`owner_user_id`, +`visibility`, `shared_with_groups`) and the D8 column (`codebase`) are +selected even though Phase 2 does not filter on them yet, so: + +1. The `MemoryRecord` returned to the trait can be populated with the + stored values from day one. Phase 3 will start writing real + `owner_user_id` / `visibility` values; Phase 2 always writes the + single-user defaults (`'00000000-...-0001'`, `'private'`, `'{}'`). The + `MemoryRecord` returned in Phase 2 simply carries those defaults. +2. The schema-drift integration tests (see "Verification") catch the case + where someone adds a NOT NULL column to `knowledge_nodes` without updating + this query. + +Notes on the body: + +- `CROSS JOIN params p` is used instead of the master-plan sketch's + `FROM knowledge_nodes m, params p`. Same plan, clearer intent. +- The `ORDER BY ... LIMIT` inside each branch CTE is there so the planner + can stop early once it has `overfetch` rows; without it the LIMIT is + applied after a full sort over all matches. +- `1.0 - (m.embedding <=> p.q_vec)` converts pgvector's cosine *distance* + to cosine *similarity* in [0, 1] for the `vector_score` output. RRF + itself does not need the similarity -- it uses ranks -- but the trait + surface exposes `vector_score: Option` for caller introspection. +- `RRF_K = 60` is inlined as `60` in the SQL string. A `const` formatter + feels tidier but `60` is a literature constant; spell it out and leave a + comment in the Rust source: `// 60 == RRF_K (Cormack 2009)`. +- `FULL OUTER JOIN` is required: a row that the FTS branch finds and the + vector branch does not must still appear in `fused`, and vice versa. +- `COALESCE(..., 0.0)` on each `1.0 / (60 + rank)` term handles the + no-match-from-this-branch case. The fusion score for a row that only the + FTS branch ranks is `1/(60 + f.rank)` exactly. +- `m.search_vec` is the generated `tsvector` column created in migration + `0001_init` (see D4 of the master plan). + +--- + +## Result row mapping + +`sqlx::query_as::<_, SearchRow>` reads each row into a private struct that +owns the column types exactly as they come back from Postgres. The struct +is converted into a `SearchResult` after fetch. + +```rust +#[derive(sqlx::FromRow)] +struct SearchRow { + id: uuid::Uuid, + owner_user_id: uuid::Uuid, + visibility: String, + shared_with_groups: Vec, + codebase: Option, + domains: Vec, + domain_scores: serde_json::Value, + content: String, + node_type: String, + tags: Vec, + embedding: Option, + metadata: serde_json::Value, + created_at: chrono::DateTime, + updated_at: chrono::DateTime, + rrf_score: f64, + fts_score: Option, + vector_score: Option, +} + +impl SearchRow { + fn into_result(self) -> SearchResult { + use crate::storage::memory_store::MemoryRecord; + use std::collections::HashMap; + + // domain_scores is JSONB; the column always exists, but may be the + // empty object {} when Phase 4 has not classified this memory yet. + let domain_scores: HashMap = + serde_json::from_value(self.domain_scores).unwrap_or_default(); + + let record = MemoryRecord { + id: self.id, + domains: self.domains, + domain_scores, + content: self.content, + node_type: self.node_type, + tags: self.tags, + // pgvector::Vector -> Vec + embedding: self.embedding.map(|v| v.to_vec()), + created_at: self.created_at, + updated_at: self.updated_at, + metadata: self.metadata, + // owner_user_id / visibility / shared_with_groups / codebase + // do not appear on MemoryRecord yet. Phase 3 will decide whether + // to extend MemoryRecord or surface them via a side channel. + // For Phase 2 they are read but discarded here. + }; + + SearchResult { + record, + score: self.rrf_score, + fts_score: self.fts_score, + vector_score: self.vector_score, + } + } +} +``` + +Type mapping summary: + +| SQL type | Rust type | Notes | +|-------------------|--------------------------------------|------------------------------------------------| +| UUID | `uuid::Uuid` | requires sqlx `uuid` feature | +| TEXT | `String` | | +| TEXT NULL | `Option` | used for `codebase` | +| TEXT[] | `Vec` | for `tags`, `domains` | +| UUID[] | `Vec` | for `shared_with_groups` | +| JSONB | `serde_json::Value` | for `metadata`, `domain_scores` | +| TIMESTAMPTZ | `chrono::DateTime` | requires sqlx `chrono` feature | +| VECTOR(N) NULL | `Option` | `.map(|v| v.to_vec())` to `Option>` | +| FLOAT8 | `f64` | | +| FLOAT8 NULL | `Option` | for `fts_score`, `vector_score` | + +If `MemoryRecord` is extended in Phase 3 to carry `owner_user_id`, +`visibility`, `shared_with_groups`, and `codebase`, the conversion above +gets four more fields. Phase 2 reads them so the integration tests can +assert on them via SQL, but the trait surface does not expose them yet. + +--- + +## `fts_only` and `vector_only` -- dedicated single-branch queries + +The master plan offers two options for the convenience methods: reuse +`rrf_search` with one branch nulled, or write dedicated queries. The +dedicated queries win: + +- One CTE instead of three. Planner picks the obvious plan. +- No FULL OUTER JOIN. +- No `params` indirection -- bound parameters used directly. +- The output `score` is the branch's native score (BM25-ish `ts_rank_cd` / + cosine similarity), not an RRF fusion score over one branch. Callers of + `fts_search` and `vector_search` get an intuitive score back. + +### `fts_only` + +Bound parameters: + +- `$1`: text query (TEXT, must be non-empty; the caller guards `text.is_empty()`) +- `$2`: limit (INT) + +```sql +SELECT + m.id AS "id!: uuid::Uuid", + m.owner_user_id AS "owner_user_id!: uuid::Uuid", + m.visibility AS "visibility!: String", + m.shared_with_groups AS "shared_with_groups!: Vec", + m.codebase AS "codebase: String", + m.domains AS "domains!: Vec", + m.domain_scores AS "domain_scores!: serde_json::Value", + m.content AS "content!: String", + m.node_type AS "node_type!: String", + m.tags AS "tags!: Vec", + m.embedding AS "embedding: pgvector::Vector", + m.metadata AS "metadata!: serde_json::Value", + m.created_at AS "created_at!: chrono::DateTime", + m.updated_at AS "updated_at!: chrono::DateTime", + ts_rank_cd(m.search_vec, websearch_to_tsquery('english', $1)) + AS "fts_score!: f64" +FROM knowledge_nodes m +WHERE m.search_vec @@ websearch_to_tsquery('english', $1) +ORDER BY ts_rank_cd(m.search_vec, websearch_to_tsquery('english', $1)) DESC +LIMIT $2; +``` + +The Rust caller maps each row to a `SearchResult` with: + +```rust +SearchResult { + record, + score: fts_score, + fts_score: Some(fts_score), + vector_score: None, +} +``` + +If `text.is_empty()` the caller returns `Ok(Vec::new())` before hitting +the database. `websearch_to_tsquery('english', '')` returns an empty +tsquery that matches nothing; the round-trip is wasted work otherwise. + +### `vector_only` + +Bound parameters: + +- `$1`: embedding (pgvector::Vector) +- `$2`: limit (INT) + +```sql +SELECT + m.id AS "id!: uuid::Uuid", + m.owner_user_id AS "owner_user_id!: uuid::Uuid", + m.visibility AS "visibility!: String", + m.shared_with_groups AS "shared_with_groups!: Vec", + m.codebase AS "codebase: String", + m.domains AS "domains!: Vec", + m.domain_scores AS "domain_scores!: serde_json::Value", + m.content AS "content!: String", + m.node_type AS "node_type!: String", + m.tags AS "tags!: Vec", + m.embedding AS "embedding: pgvector::Vector", + m.metadata AS "metadata!: serde_json::Value", + m.created_at AS "created_at!: chrono::DateTime", + m.updated_at AS "updated_at!: chrono::DateTime", + 1.0 - (m.embedding <=> $1) AS "vector_score!: f64" +FROM knowledge_nodes m +WHERE m.embedding IS NOT NULL +ORDER BY m.embedding <=> $1 +LIMIT $2; +``` + +The Rust caller maps each row to: + +```rust +SearchResult { + record, + score: vector_score, + fts_score: None, + vector_score: Some(vector_score), +} +``` + +Both convenience methods ignore `SearchQuery.domains` / `tags` / +`node_types` / `min_retrievability` -- they take `&str` and `&[f32]` +respectively, not a `SearchQuery`. Callers that want filters on a +single-branch search should call `search` with the other branch input +left at its degrade-to-zero default. + +--- + +## `min_retrievability` filter + +`SearchQuery::min_retrievability: Option` is applied as a final +filter after fusion by joining on the `scheduling` table: + +```sql +-- with-min-retrievability variant: identical CTEs to the base query, only +-- the final SELECT changes. +SELECT + ... (same column list as the base query) ... +FROM fused +JOIN knowledge_nodes m ON m.id = fused.id +JOIN scheduling s ON s.memory_id = m.id +WHERE s.retrievability >= $8 +ORDER BY fused.rrf_score DESC +LIMIT (SELECT final_limit FROM params); +``` + +This is a separate prepared statement -- the eight-parameter variant -- +held alongside the seven-parameter base. The Rust dispatch: + +```rust +if let Some(min_r) = query.min_retrievability { + sqlx::query_as::<_, SearchRow>(QUERY_WITH_MIN_R) + .bind(q_text) + .bind(q_vec) + .bind(overfetch) + .bind(final_limit) + .bind(dom_filter) + .bind(nt_filter) + .bind(tag_filter) + .bind(min_r) + .fetch_all(pool).await? +} else { + sqlx::query_as::<_, SearchRow>(QUERY_BASE) + .bind(q_text) + .bind(q_vec) + .bind(overfetch) + .bind(final_limit) + .bind(dom_filter) + .bind(nt_filter) + .bind(tag_filter) + .fetch_all(pool).await? +} +``` + +Why not unconditionally join: the `scheduling` join is expensive enough on +a large `knowledge_nodes` table that adding it to every search call regresses the +common path. `min_retrievability` is set by the cognitive engine's +accessibility filter and is `None` in most direct callers. + +The same two-variant pattern repeats for `fts_only` and `vector_only`; in +practice callers of those methods rarely set `min_retrievability` (it is +not part of their argument list), so only the base variant is needed +unless the trait surface grows. + +--- + +## Domain / tag / node_type filters + +Each filter is expressed as a NULL-conditional clause inside both branch +CTEs, written using PostgreSQL array operators: + +```sql +AND (p.dom_filter IS NULL OR m.domains && p.dom_filter) +AND (p.nt_filter IS NULL OR m.node_type = ANY(p.nt_filter)) +AND (p.tag_filter IS NULL OR m.tags && p.tag_filter) +``` + +- `&&` is the PostgreSQL "arrays overlap" operator. Matches if any + element in `m.domains` is in the filter array. Index-friendly with a + GIN index on `m.domains` (created in `0001_init`). +- `= ANY(...)` matches `m.node_type` (a scalar) against any element of + the filter array. Index-friendly with a B-tree on `m.node_type`. +- `&&` is used again on `m.tags` (a `TEXT[]`). + +The NULL-conditional form is critical: when the filter parameter is +`NULL`, the clause short-circuits to `TRUE` and contributes nothing to +the WHERE. This keeps a single query reusable across "no filter" and +"filter set" cases without rewriting SQL. + +When the Rust caller passes `None` for a filter, sqlx binds it as `NULL` +of the column type (`text[]`). The cast `$5::text[]` in the `params` CTE +is what tells sqlx the binding type. + +The master plan's draft has each filter clause duplicated across both +branch CTEs. That duplication is correct -- the planner cannot push a +WHERE clause across a FULL OUTER JOIN into both sides automatically; we +do it manually. + +--- + +## Empty-string text query handling + +The base query guards the FTS branch with `WHERE p.q_text <> ''`. + +`websearch_to_tsquery('english', '')` returns an empty tsquery. An empty +tsquery has no lexemes and matches no document; the `@@` operator returns +false for every row. Without the guard, the FTS branch would still run -- +sequential scan, tokenisation per row, comparison -- and return zero +rows. The guard short-circuits at planning time. + +The guard does not affect the FULL OUTER JOIN: when the FTS branch +returns zero rows, the join degenerates to "every row that the vector +branch returned, with `f.id IS NULL` and `f.rank IS NULL`". The +`COALESCE(1.0 / (60 + f.rank), 0.0)` then evaluates to `0.0`, and the +fused score reduces to the vector branch's RRF term alone. This is the +"pure vector search" degrade path. + +Symmetrically, the vector branch guards itself with +`WHERE m.embedding IS NOT NULL AND p.q_vec IS NOT NULL`, which gives the +"pure FTS search" degrade path when the caller passes no embedding. + +The both-empty case (`q_text == ''` and `q_vec IS NULL`) is intercepted +in Rust before the query runs and returns `Ok(vec![])`. Returning empty +rather than error matches the SQLite behavior and is what the Phase 1 +ingest pipeline relies on for "no signal, no results" fallback. + +--- + +## Use of `sqlx::query!` versus `sqlx::query_as` + +`sqlx::query!` and `sqlx::query_as!` are compile-time-checked: the SQL is +sent to a live Postgres at build time, the result schema is validated, and +the generated Rust struct fields are derived. That checking is the +default for every other query in `0002d-store-impl-bodies.md`. + +For the RRF query, the macro path is impractical for two reasons: + +1. **Two structurally different queries** -- the base (seven parameters, + no `scheduling` join) and the `min_retrievability` variant (eight + parameters, with the join). The macro would force two macro + invocations, each producing its own anonymous result struct, and the + result types would not unify. Manual `From` impls would be needed in + both directions. +2. **The dedicated `fts_only` and `vector_only` queries have a different + output column set** (`fts_score!` instead of `rrf_score! + fts_score? + + vector_score?`). Three macro invocations, three structs, three + conversion helpers. + +The chosen pattern is `sqlx::query_as::<_, SearchRow>(SQL_CONST)` with a +single `SearchRow` struct that owns the column types and a single +`SearchRow::into_result` helper. The SQL is held in module-scope `&'static +str` constants: + +```rust +const QUERY_BASE: &str = include_str!("search.rrf.sql"); +const QUERY_WITH_MIN_R: &str = include_str!("search.rrf.min_retr.sql"); +const QUERY_FTS_ONLY: &str = include_str!("search.fts.sql"); +const QUERY_VECTOR_ONLY: &str = include_str!("search.vector.sql"); +``` + +`include_str!` keeps the SQL out of the Rust source. The four `.sql` +files live next to `search.rs` in +`crates/vestige-core/src/storage/postgres/`. + +The cost: schema drift (someone renames `m.codebase` to `m.repo_name`) +will not break the build. The integration tests in "Verification" below +are the safety net. This is a deliberate trade -- it is the one sub-plan +in Phase 2 where runtime flexibility beats compile-time checking. + +If a future contributor wants compile-time checking back for the simple +case, the right move is to introduce a `#[cfg(test)]`-only macro-checked +variant of `QUERY_BASE` and assert at test build time that the macro +agrees with the string. That belongs in `0002h-testing-and-benches.md` if +anywhere. + +--- + +## Verification + +Integration tests live in +`crates/vestige-core/tests/postgres_search.rs`, gated by +`#[cfg(feature = "postgres-backend")]` and `#[ignore]` by default (the +test runner CI workflow in `0002h-testing-and-benches.md` runs them with +`--ignored` against a live Postgres). + +Common harness for every test: + +1. Spin up Postgres via `sqlx::PgPool::connect` against the test URL. +2. Run `sqlx::migrate!("./migrations/postgres").run(&pool)` to bring the + schema up. +3. Register a deterministic test embedder via `register_model` so + `embedding` columns can be written. +4. Seed 50 mixed memories through `MemoryStore::insert` -- mixed + `node_type` (`fact`, `concept`, `event`, `decision`), mixed `tags` + (`rust`, `postgres`, `search`, `dream`, `bug-fix`), mixed `codebase`, + embeddings drawn from three small clusters so vector recall has + structure to find. + +Test cases: + +**T1. Full RRF returns the seeded target.** +Insert a known memory with `content = "FSRS-6 spaced repetition cadence"` +and an embedding from cluster A. Query with +`text = Some("FSRS spaced repetition")` and an embedding near cluster A. +Assert the target memory is in the top 3 of the returned `SearchResult`s +and that both `fts_score` and `vector_score` are `Some` for it. + +**T2. Pure FTS degrade.** +Same target as T1. Query with `text = Some("FSRS spaced repetition")` and +`embedding = None`. Assert the target appears, all results have +`vector_score == None`, `fts_score == Some(_)`, and `score` equals the +fused RRF score (which collapses to one branch's `1.0/(60 + rank)`). + +**T3. Pure vector degrade.** +Same target as T1. Query with `text = Some("")` and +`embedding = Some(cluster_A_vector)`. Assert the target appears, all +results have `fts_score == None`, `vector_score == Some(_)`. + +**T4. Both empty returns `Ok(vec![])`.** +Query with `text = Some("")` and `embedding = None`. Assert exactly an +empty result vector and that no SQL was executed (assert via a +`sqlx::PgPool` query-count handle if convenient; otherwise document that +the short-circuit lives in Rust). + +**T5. `domains` filter.** +Insert one memory with `domains = vec!["domain-x"]` and 49 others without +it. Query with `domains = Some(vec!["domain-x"])` and a matching text. +Assert exactly one result is returned and it is the seeded memory. + +**T6. `tags` filter.** +Same pattern as T5 with `tags = Some(vec!["bug-fix"])`. + +**T7. `node_types` filter.** +Same pattern as T5 with `node_types = Some(vec!["decision"])`. + +**T8. `min_retrievability` filter.** +Seed two memories with the same content + embedding. Write +`scheduling` rows so that one has `retrievability = 0.9` and the other +`0.1`. Query with `min_retrievability = Some(0.5)`. Assert exactly the +high-retrievability memory is returned. + +**T9. `query.limit == 0` defaults to 10.** +Seed 30 matching memories. Query with `limit = 0`. Assert the result +contains exactly 10 entries. + +**T10. `fts_only` and `vector_only` parity.** +For the same target memory, call `fts_only` and `vector_only` directly +and compare against `search` with the corresponding branch zeroed. The +top-1 result must match by id; the scores need only be of the same sign +and magnitude (not bit-identical, because RRF fusion changes the +absolute score). + +**T11. Schema-drift canary.** +Run the base query against an empty `knowledge_nodes` table and `fetch_all` +into `Vec`. Any added NOT NULL column on `knowledge_nodes` that is +not in the SELECT will fail the test at the `try_get` boundary with a +clear error. This is the test that compensates for not using +`sqlx::query!`. + +**T12. Hostile inputs.** +Query with `text = Some("'; DROP TABLE knowledge_nodes; --")` and a normal +embedding. Assert no panic, results returned cleanly, `knowledge_nodes` table +still present. This is symbolic; `websearch_to_tsquery` is parameter- +bound and SQL injection is not actually possible, but the test is cheap +and the assertion is real. + +--- + +## Acceptance criteria + +A reviewer of the implementation PR should be able to confirm: + +1. `crates/vestige-core/src/storage/postgres/search.rs` exists and is + compiled only when `feature = "postgres-backend"` is on. +2. The four `.sql` files (`search.rrf.sql`, + `search.rrf.min_retr.sql`, `search.fts.sql`, `search.vector.sql`) + exist in the same directory and are `include_str!`-ed into module- + scope `&'static str` constants. +3. `RRF_K = 60` and `OVERFETCH_MULT = 3` are defined as constants at + module scope with the Cormack 2009 citation in a comment. +4. The seven-parameter base query is one statement and uses a `params` + CTE; the eight-parameter `min_retrievability` variant adds exactly + one JOIN and one WHERE clause on top of the base. +5. Empty text degrades to pure vector; null embedding degrades to pure + FTS; both empty short-circuits to `Ok(vec![])` in Rust before the + query runs. +6. The SELECT column list in every query includes `owner_user_id`, + `visibility`, `shared_with_groups`, and `codebase` even though Phase 2 + does not filter on them. +7. `SearchRow::into_result` populates a `MemoryRecord` with every field + the trait requires, including `domains` and `domain_scores` decoded + from JSONB. +8. `PgMemoryStore::search`, `PgMemoryStore::fts_search`, and + `PgMemoryStore::vector_search` each delegate to the corresponding + free function with one line of body. +9. All twelve integration tests (`T1` through `T12`) pass against a live + Postgres with the `0001_init` + `0002_hnsw` migrations applied. +10. `cargo build -p vestige-core` succeeds with + `--features postgres-backend` and with the feature off. +11. `cargo clippy -p vestige-core --features postgres-backend -- -D warnings` + is clean. + +When all eleven are true, this sub-plan is done and +`0002f-migrate-cli.md` is unblocked. diff --git a/docs/plans/0002f-migrate-cli.md b/docs/plans/0002f-migrate-cli.md new file mode 100644 index 0000000..457de70 --- /dev/null +++ b/docs/plans/0002f-migrate-cli.md @@ -0,0 +1,1045 @@ +# Phase 2 Sub-Plan 0002f -- SQLite-to-Postgres Migrate CLI + +**Status**: Ready +**Depends on**: +- `0002a-skeleton-and-feature-gate.md` (the `postgres-backend` Cargo feature + and the `crates/vestige-core/src/storage/postgres/` module skeleton). +- `0002b-pool-and-config.md` (`PgPool` construction and `PostgresConfig`). +- `0002c-migrations.md` (the `postgres/migrations/0001_init.up.sql` schema, + including the D7 tenancy columns/tables and the D8 `codebase` column). +- `0002d-store-impl-bodies.md` (real bodies for `PgMemoryStore` trait methods: + `insert`, `register_model`, `add_edge`, `update_scheduling`, etc.; and the + matching source-side reader bodies on `SqliteMemoryStore`, in particular a + windowed-stream API ordered by `(created_at, id)`). + +This sub-plan covers Phase 2 master-plan deliverables D8 (the streaming copy +in `crates/vestige-core/src/storage/postgres/migrate_cli.rs`) and D10 (the +`vestige migrate copy ...` clap subcommand in +`crates/vestige-mcp/src/bin/cli.rs`). Sub-plan `0002g-reembed.md` covers the +`vestige migrate reembed ...` subcommand body; this sub-plan only declares the +`Reembed` clap variant alongside `Copy` so the subcommand layout is final. + +The success criterion is: + +``` +vestige migrate copy --from sqlite --to postgres \ + --sqlite-path ~/.vestige/vestige.db \ + --postgres-url postgresql://localhost/vestige +``` + +streams every row from a Phase 1 SQLite database into a fresh (or partially +populated) Phase 2 Postgres database. Re-running the same command is a no-op +on already-present rows. A `--dry-run` flag prints per-table counts without +writing anything. + +--- + +## Context + +ADR 0002 D2 settled that `PgMemoryStore::connect` mirrors +`SqliteMemoryStore::new`: no `Embedder` in the constructor; the model +signature is stamped by a separate call to `register_model`. The migrator +inherits this symmetry. It opens both backends, validates that the source's +`embedding_model` registry agrees with the destination's (or with the +embedder the user supplied for the destination), and then streams rows. + +ADR 0002 D7 reserved multi-tenancy columns on `knowledge_nodes` (`owner_user_id`, +`visibility`, `shared_with_groups`) and three tables (`users`, `groups`, +`group_memberships`). Phase 2 single-user defaults are the bootstrap row +`'00000000-0000-0000-0000-000000000001'` (`'local'`), `visibility = 'private'`, +empty `shared_with_groups`. The migrator preserves whatever values the source +SQLite holds; it does NOT rewrite owner_user_id from real values to the +bootstrap user. If a Phase 3-aware source has real user rows, those are +copied first (step 5 below) and the foreign key in `knowledge_nodes.owner_user_id` +resolves to the same UUID on the destination. + +ADR 0002 D8 promoted `codebase` to a first-class `TEXT` column. The migrator +reads it as a column on the source side (the Phase 1 amendment's V15 SQLite +migration ensures the column exists; for pre-V15 SQLite the migrator must +detect and fall back to extracting from `metadata->>'codebase'`, see "Source +schema variants" below). + +The Phase 1 `SqliteMemoryStore` is the source backend. `0002d-store-impl-bodies.md` +extends it (and the trait) with a windowed reader ordered by `(created_at, id)` +so the migrator can stream rows in deterministic batches without holding the +full result set in RAM. The migrator assumes that reader exists and produces +`MemoryRecord` instances with all D7+D8 columns populated. + +--- + +## File layout + +``` +crates/vestige-core/src/storage/postgres/migrate_cli.rs -- D8 body +crates/vestige-mcp/src/bin/cli.rs -- D10 clap wiring +tests/phase_2/migrate_test.rs -- integration test +``` + +The migrator lives behind `#[cfg(feature = "postgres-backend")]`. The +`Migrate` clap variant in the CLI is similarly gated. Without the feature, +`vestige` builds and runs exactly as in Phase 1 -- the `migrate` subcommand +simply does not exist. + +--- + +## Plan struct + +```rust +#![cfg(feature = "postgres-backend")] + +use std::path::PathBuf; +use std::sync::Arc; + +use uuid::Uuid; + +use crate::embedder::Embedder; +use crate::storage::memory_store::MemoryStoreError; + +#[derive(Debug, Clone)] +pub struct SqliteToPostgresPlan { + /// Filesystem path to the source SQLite database. Opened read-only. + pub sqlite_path: PathBuf, + + /// libpq-style URL for the destination Postgres database. + pub postgres_url: String, + + /// sqlx pool size for the destination. Default 4. The migrator is + /// single-writer per table for ordering reasons; extra connections are + /// only used for the embedding-model registry probe and for the dry-run + /// COUNT queries that run in parallel with the row scan. + pub max_connections: u32, + + /// Number of rows per Postgres transaction. Default 500. Larger batches + /// reduce commit overhead but increase the amount of work a crash + /// re-runs. + pub batch_size: usize, + + /// If true, count rows per table and emit a report without writing + /// anything to Postgres. + pub dry_run: bool, +} + +impl Default for SqliteToPostgresPlan { + fn default() -> Self { + Self { + sqlite_path: PathBuf::new(), + postgres_url: String::new(), + max_connections: 4, + batch_size: 500, + dry_run: false, + } + } +} +``` + +The struct is public so a future programmatic driver (Rhai script, hero +service, in-process test harness) can call `run_sqlite_to_postgres` without +touching clap. + +--- + +## Report struct + +```rust +#[derive(Debug, Default)] +pub struct MigrationReport { + pub memories_copied: u64, + pub scheduling_rows: u64, + pub edges_copied: u64, + pub review_events_copied: u64, + pub domains_copied: u64, + pub users_copied: u64, + pub groups_copied: u64, + pub group_memberships_copied: u64, + + /// Per-row failures that did not abort the migrator. Each entry pairs + /// the source row id (where derivable) with the error that caused it to + /// be skipped. Rows whose UUID cannot be parsed are reported with + /// `Uuid::nil()` and a descriptive `MemoryStoreError::InvalidInput`. + pub errors: Vec<(Uuid, MemoryStoreError)>, +} +``` + +`errors.is_empty()` is the "clean migration" check. The CLI prints +`errors.len()` at the end and exits non-zero if it is positive. + +Counts are the number of rows the migrator either inserted or skipped due to +ON CONFLICT. They reflect what the source presented, not what the destination +ended up with -- that distinction matters for re-runs: a re-run of a finished +migration reports the same counts but writes zero new rows. + +--- + +## Driver fn + +```rust +pub async fn run_sqlite_to_postgres( + plan: SqliteToPostgresPlan, + embedder: Arc, +) -> MemoryStoreResult; +``` + +Algorithm, step by step: + +### Step 1. Open source SQLite read-only + +Build a SQLite URL with `?mode=ro` so the migrator cannot mutate the source +even by accident: + +```rust +let src_url = format!( + "sqlite://{}?mode=ro", + plan.sqlite_path.display(), +); +let src = SqliteMemoryStore::open_url(&src_url).await?; +``` + +`SqliteMemoryStore::open_url` is added by `0002d-store-impl-bodies.md` as a +small wrapper over the existing `new` that accepts a fully-formed URL. If the +file does not exist, `MemoryStoreError::Init` propagates. + +The source store still runs its own startup-time migrations in `?mode=ro`? +No -- read-only mode rejects writes. The migrator therefore opens the source +twice if the live source DB is older than V15: once writable to bring its +schema forward to V15 (so the D7+D8 columns are present), then re-opens +read-only. Detection: query `user_version` on the source DB before opening +the read-only handle. If it is below V15 and `--allow-source-upgrade` is set, +open writable, run `SqliteMemoryStore::new` (which runs migrations), close, +and re-open read-only. If `--allow-source-upgrade` is not set, fail with a +clear error pointing at the flag. Default: not set; the user must opt in to +modifying their source. + +### Step 2. Embedding model registry compatibility check + +Read both registries: + +```rust +let src_sig = src.registered_model().await?; +let actual = embedder.model_signature(); // ModelSignature +``` + +If `src_sig` is `Some` and disagrees with `actual` (any of `name`, +`dimension`, `hash`), return: + +```rust +MemoryStoreError::ModelMismatch { + registered_name: src_sig.name, + registered_dim: src_sig.dimension, + registered_hash: src_sig.hash, + actual_name: actual.name, + actual_dim: actual.dimension, + actual_hash: actual.hash, +} +``` + +The CLI translates this into a message that mentions `0002g`'s `--reembed` +command as the recovery path. Do NOT silently re-encode here; that is a +separate concern with its own flag set, performance profile, and HNSW +rebuild. + +If `src_sig` is `None` (source never had an embedding model -- empty DB or +pre-Phase-1), use the actual embedder's signature for the destination +registry. Memory rows whose `embedding` column is NULL stay NULL on the +destination side. + +### Step 3. Open destination Postgres + +```rust +let dst = PgMemoryStore::connect(&plan.postgres_url, plan.max_connections).await?; +``` + +`PgMemoryStore::connect` (per `0002d-store-impl-bodies.md`) runs the +`sqlx::migrate!` macro internally, which idempotently applies `0001_init` +and `0002_hnsw`. Re-running the migrator against an already-initialised +destination is fine. + +Stamp the registry on the destination: + +```rust +let sig = src_sig.unwrap_or_else(|| embedder.model_signature()); +dst.register_model(&sig).await?; +``` + +`register_model` is idempotent in the Postgres backend: it upserts the single +registry row, and (per ADR 0002 D2) it runs the `ALTER TABLE knowledge_nodes +ALTER COLUMN embedding TYPE vector($N)` typmod stamp inside its body. The +ALTER is itself idempotent: pgvector accepts the same typmod twice as a no-op. + +### Step 4. Verify schema + +Not really a separate step -- `PgMemoryStore::connect` already calls +`sqlx::migrate!` and the `register_model` call already stamps the typmod. +Listed here for documentation: this is the point at which the destination is +known to be schema-correct for the source's embedding dimension. + +### Step 5. Copy `users`, `groups`, `group_memberships` first + +These tables exist for both pre-Phase-3 and Phase-3-aware sources because +ADR 0002 D7 reserved them in V15 of the SQLite schema. Phase 2 single-user +deployments have exactly one user row (`local`) and zero groups, but the +migrator does not assume that: it copies whatever is present. + +The bootstrap user `00000000-0000-0000-0000-000000000001` is inserted by +`0001_init.up.sql` on the destination. The source's bootstrap row collides +with the destination's; `ON CONFLICT (id) DO NOTHING` resolves the collision +silently. + +Pseudocode: + +```rust +let mut tx = dst.pool().begin().await?; +let mut report = MigrationReport::default(); + +for batch in src.stream_users(plan.batch_size).await? { + for u in batch? { + sqlx::query!( + "INSERT INTO users (id, handle, display_name, created_at, metadata) \ + VALUES ($1, $2, $3, $4, $5) \ + ON CONFLICT (id) DO NOTHING", + u.id, u.handle, u.display_name, u.created_at, u.metadata, + ).execute(&mut *tx).await?; + report.users_copied += 1; + } +} +tx.commit().await?; +``` + +Repeat the same shape for `groups` and `group_memberships`. The membership +table has a composite primary key `(user_id, group_id)`: + +```rust +"INSERT INTO group_memberships (user_id, group_id, role, joined_at) \ + VALUES ($1, $2, $3, $4) \ + ON CONFLICT (user_id, group_id) DO NOTHING", +``` + +The `stream_users` / `stream_groups` / `stream_memberships` reader methods on +`SqliteMemoryStore` are introduced by `0002d-store-impl-bodies.md`. They +return `BoxStream>>` to keep the migrator +backend-agnostic. + +If the source SQLite predates V15 -- the V15 migration is the one that +introduces these tables -- they simply do not exist. The reader detects +their absence at open time and returns an empty stream. See "Source schema +variants" below. + +### Step 6. Copy `knowledge_nodes` in batches + +Stream the source ordered by `(created_at, id)`. The cursor key is the +last-seen `(created_at, id)` pair; the reader uses keyset pagination so +restarts pick up where the previous run left off: + +```sql +SELECT ... +FROM knowledge_nodes +WHERE (created_at, id) > ($cursor_ts, $cursor_id) +ORDER BY created_at, id +LIMIT $batch_size +``` + +For each batch: + +```rust +let mut tx = dst.pool().begin().await?; +for record in batch { + // D7 + D8 columns are all on MemoryRecord by Phase 2. + let groups: Vec = record.shared_with_groups.clone(); + + let result = sqlx::query!( + "INSERT INTO knowledge_nodes ( \ + id, content, node_type, tags, embedding, \ + created_at, updated_at, metadata, \ + owner_user_id, visibility, shared_with_groups, \ + codebase, domains, domain_scores \ + ) VALUES ( \ + $1, $2, $3, $4, $5::vector, \ + $6, $7, $8, \ + $9, $10, $11, \ + $12, $13, $14::jsonb \ + ) \ + ON CONFLICT (id) DO NOTHING", + record.id, + record.content, + record.node_type, + &record.tags, + record.embedding.as_deref().map(pgvector::Vector::from), + record.created_at, + record.updated_at, + record.metadata, + record.owner_user_id, + record.visibility, + &groups, + record.codebase, + &record.domains, + serde_json::to_value(&record.domain_scores) + .unwrap_or(serde_json::Value::Object(Default::default())), + ) + .execute(&mut *tx) + .await; + + match result { + Ok(_) => report.memories_copied += 1, + Err(e) => report + .errors + .push((record.id, MemoryStoreError::from(e))), + } +} +tx.commit().await?; +``` + +Notes: + +- `embedding` is `Option>` on `MemoryRecord`. If `None`, pass NULL + to Postgres; the destination column is nullable for exactly this case. +- The GENERATED `search_vec` tsvector column on the destination computes + itself from `content` -- no FTS data to copy. +- Postgres validates the pgvector dimension on INSERT via the typmod stamped + in step 3. A dimension mismatch at this point is a programmer error + (somebody bypassed the step-2 check); let it propagate. + +Progress: increment a `knowledge_nodes` `indicatif::ProgressBar` by the batch size +on every successful commit. Log INFO every 1000 rows via `tracing`: + +```rust +if report.memories_copied % 1000 == 0 { + tracing::info!( + memories_copied = report.memories_copied, + "migrate: knowledge_nodes batch committed", + ); +} +``` + +### Step 7. Copy `scheduling` + +One row per memory. Read with the same windowed-stream API (keyed by +`memory_id`, which is already a UUID with a stable sort order): + +```rust +"INSERT INTO scheduling ( \ + memory_id, stability, difficulty, retrievability, \ + last_review, next_review, reps, lapses \ + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) \ + ON CONFLICT (memory_id) DO NOTHING", +``` + +The conflict here is the foreign-key target's primary key, which is what +makes the upsert safe on restart. Increment `report.scheduling_rows`. + +### Step 8. Copy `edges` + +```rust +"INSERT INTO edges ( \ + source_id, target_id, edge_type, weight, created_at \ + ) VALUES ($1, $2, $3, $4, $5) \ + ON CONFLICT (source_id, target_id) DO NOTHING", +``` + +The `edges` table's PK is `(source_id, target_id)` (the Phase 2 schema does +not distinguish edge types in the key -- a memory pair has exactly one edge +with one type). Increment `report.edges_copied`. + +### Step 9. Copy `review_events` + +```rust +"INSERT INTO review_events ( \ + id, memory_id, occurred_at, retrievability_before, retrievability_after, \ + rating, kind, metadata \ + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) \ + ON CONFLICT (id) DO NOTHING", +``` + +`review_events` is an append-only log. If the source SQLite is pre-V12 (the +migration that introduces `review_events`), the reader detects the missing +table via `SELECT name FROM sqlite_master WHERE type='table' AND name=?` +returning empty and yields an empty stream. The migrator increments +`report.review_events_copied` only when rows actually arrive. + +### Step 10. Copy `domains` + +Phase 4 table. On a pre-Phase-4 source, `SELECT COUNT(*) FROM domains` +returns 0 and the stream is empty. The migrator does not skip the table; +it iterates and finds nothing. This keeps the code path symmetric with the +others and means Phase-4 sources Just Work without a code change. + +```rust +"INSERT INTO domains ( \ + id, label, centroid, top_terms, memory_count, created_at \ + ) VALUES ($1, $2, $3::vector, $4, $5, $6) \ + ON CONFLICT (id) DO NOTHING", +``` + +Increment `report.domains_copied`. + +### Step 11. Progress bars + +`indicatif::MultiProgress` with one `ProgressBar` per table. Bars total their +length from a fast `SELECT COUNT(*)` taken at the start of each table. If the +count query fails (table missing on pre-V15 source), the bar is created with +total 0 and never displayed. + +Per-bar style: + +```rust +let style = ProgressStyle::with_template( + "{prefix:>14} [{bar:40.cyan/blue}] {pos}/{len} ({per_sec}, eta {eta})", +) +.unwrap() +.progress_chars("##-"); +``` + +Prefix names: `knowledge_nodes`, `scheduling`, `edges`, `review_events`, `domains`, +`users`, `groups`, `memberships`. + +### Step 12. Dry-run path + +If `plan.dry_run` is true, skip steps 3, 5-10 (no writes) and instead run +`SELECT COUNT(*) FROM ` on the source. Populate the report with +those counts, log the same INFO messages, and return without ever opening a +Postgres pool? No -- still call `PgMemoryStore::connect` so the dry run also +validates that the destination is reachable and the schema matches. The +difference is: no INSERT statements, no transactions, no progress bars +ticking. Print the report at the end and exit. + +--- + +## Idempotency + +Re-running `vestige migrate copy ...` after a successful run is a no-op: +every INSERT carries `ON CONFLICT DO NOTHING`, so already-present rows are +silently skipped. The report counts grow by zero; the destination is +unchanged. + +Re-running after a crash mid-batch is safe in the same way. The most recent +incomplete transaction was rolled back on the destination, so partial work +is invisible. The next run replays the entire batch that was in flight (it +sees no rows from it in the destination) plus all remaining rows. + +If a single row is corrupted on the source (e.g., a UUID column with a +non-UUID string, malformed `metadata` JSON, etc.), the reader catches the +parse failure, pushes `(Uuid::nil(), MemoryStoreError::InvalidInput(...))` +to `report.errors`, and continues. The migrator never aborts on a single bad +row. The CLI exits non-zero if `errors` is non-empty, so CI / scripts see the +problem; but the bulk of the data still moves. + +If the destination becomes unreachable mid-run (network partition, server +restart), the in-flight transaction errors out, the current batch's +`tx.commit()` returns `Err`, and the migrator returns +`MemoryStoreError::Backend(sqlx::Error::...)`. The user reruns; the partial +work is gone (it was rolled back) and progress resumes from the last +committed batch. + +--- + +## Embedding model match check + +Read both registries up front (step 2). The check is exact: name AND +dimension AND hash must match. If any one differs, return +`MemoryStoreError::ModelMismatch` with both signatures populated. + +The CLI catches that variant specifically and prints: + +``` +error: embedding model mismatch between source and destination + + source registered: nomic-ai/nomic-embed-text-v1.5 (dim 768, hash abcd...) + embedder presented: BAAI/bge-large-en-v1.5 (dim 1024, hash 1234...) + +Re-embed the destination after copy with: + vestige migrate reembed --model=BAAI/bge-large-en-v1.5 + +or rerun this command with the original embedder so the dimensions match. +``` + +The migrator does NOT call into the embedder during copy. Vectors flow from +SQLite BLOB to Postgres `vector` unchanged. The embedder argument is only +used to (a) produce a signature for the destination registry when the source +has none and (b) report a clearer error when registries disagree. + +Re-embedding lives in `0002g-reembed.md`. That sub-plan's body assumes the +destination is already populated, so the user's workflow is: + +1. `vestige migrate copy ...` (this sub-plan; may fail with `ModelMismatch`) +2. `vestige migrate copy --reembed-after ...` -- not added in Phase 2; the + user runs the two commands in sequence +3. `vestige migrate reembed --model=...` (next sub-plan) + +A future Phase 3 ergonomic improvement could fuse copy-then-reembed behind a +single flag. Not in Phase 2 scope. + +--- + +## CLI wiring + +Edit `crates/vestige-mcp/src/bin/cli.rs`. Add a feature-gated `Migrate` +variant to the existing `Commands` enum. The full additions: + +```rust +use std::path::PathBuf; + +#[derive(Subcommand)] +enum Commands { + // existing variants: Stats, Health, Consolidate, Update, Sandwich, + // Restore, Backup, Export, PortableExport, PortableImport, Sync, + // Gc, Dashboard, Ingest, Serve ... + + /// Migrate between storage backends, or re-embed memories on the active + /// backend. Available when compiled with --features postgres-backend. + #[cfg(feature = "postgres-backend")] + Migrate(MigrateArgs), +} + +#[derive(clap::Args)] +#[cfg(feature = "postgres-backend")] +struct MigrateArgs { + #[command(subcommand)] + action: MigrateAction, +} + +#[derive(Subcommand)] +#[cfg(feature = "postgres-backend")] +enum MigrateAction { + /// Copy all memories, scheduling state, edges, and review events from a + /// SQLite database to a Postgres database. Idempotent. + Copy { + /// Source backend name. Currently only "sqlite" is accepted. + #[arg(long)] + from: String, + + /// Destination backend name. Currently only "postgres" is accepted. + #[arg(long)] + to: String, + + /// Path to the source SQLite database file. + #[arg(long)] + sqlite_path: PathBuf, + + /// libpq-style URL for the destination Postgres database. + #[arg(long)] + postgres_url: String, + + /// Rows per Postgres transaction. + #[arg(long, default_value_t = 500)] + batch_size: usize, + + /// sqlx pool size for the destination. + #[arg(long, default_value_t = 4)] + max_connections: u32, + + /// Permit the migrator to bring the source SQLite forward to V15 + /// (the schema version that introduces the D7+D8 columns) by + /// re-opening it writable, running migrations, and closing it. + /// Without this flag, a pre-V15 source fails fast. + #[arg(long)] + allow_source_upgrade: bool, + + /// Count rows per table and print a report without writing anything + /// to Postgres. + #[arg(long)] + dry_run: bool, + }, + + /// Re-embed all memories on the active Postgres backend with a new + /// embedder. See sub-plan 0002g for the body. + Reembed { + /// Embedder name (e.g., "BAAI/bge-large-en-v1.5"). Resolved via + /// the Phase 1 embedder factory. + #[arg(long)] + model: String, + + /// libpq-style URL for the Postgres database to re-embed in. + #[arg(long)] + postgres_url: String, + + /// Rows per embedder batch. + #[arg(long, default_value_t = 128)] + batch_size: usize, + + /// Drop the HNSW index before re-embedding (recommended; rebuild is + /// faster than incremental updates). + #[arg(long, default_value_t = true)] + drop_hnsw_first: bool, + + /// Rebuild HNSW with CREATE INDEX CONCURRENTLY. Slower but does not + /// hold AccessExclusiveLock. + #[arg(long)] + concurrent_index: bool, + + /// sqlx pool size for the destination. + #[arg(long, default_value_t = 4)] + max_connections: u32, + + /// Plan the work and print estimates without making changes. + #[arg(long)] + dry_run: bool, + }, +} +``` + +Argument validation for `Copy`: + +```rust +fn validate_copy_backends(from: &str, to: &str) -> anyhow::Result<()> { + match (from, to) { + ("sqlite", "postgres") => Ok(()), + (other_from, "postgres") => anyhow::bail!( + "unsupported source backend: {}. Only 'sqlite' is accepted as --from in Phase 2.", + other_from, + ), + ("sqlite", other_to) => anyhow::bail!( + "unsupported destination backend: {}. Only 'postgres' is accepted as --to in Phase 2.", + other_to, + ), + (other_from, other_to) => anyhow::bail!( + "unsupported migration direction: {} -> {}. Only 'sqlite' -> 'postgres' is accepted in Phase 2.", + other_from, other_to, + ), + } +} +``` + +Wire the new variant in the `main` match: + +```rust +match cli.command { + // ... existing arms ... + + #[cfg(feature = "postgres-backend")] + Commands::Migrate(args) => match args.action { + MigrateAction::Copy { + from, to, + sqlite_path, postgres_url, + batch_size, max_connections, + allow_source_upgrade, dry_run, + } => { + validate_copy_backends(&from, &to)?; + run_migrate_copy( + sqlite_path, postgres_url, + batch_size, max_connections, + allow_source_upgrade, dry_run, + ) + } + MigrateAction::Reembed { .. } => { + // Body implemented in sub-plan 0002g. + run_migrate_reembed(/* ... */) + } + }, +} +``` + +`run_migrate_copy` is a thin wrapper that: + +1. Builds a `SqliteToPostgresPlan` from the clap args. +2. Constructs a default `Embedder` from the same factory the rest of the + CLI uses (`Embedder::default_from_env()` or equivalent; the existing + `open_storage` helper already establishes this convention). +3. Starts a tokio runtime if one is not already running. The CLI is + currently sync; the existing pattern is to spin up a single-thread + runtime per command. Reuse that. +4. Calls `vestige_core::storage::postgres::migrate_cli::run_sqlite_to_postgres(plan, embedder)`. +5. Prints the report and exits with the appropriate status code. + +Pseudocode: + +```rust +fn run_migrate_copy( + sqlite_path: PathBuf, + postgres_url: String, + batch_size: usize, + max_connections: u32, + allow_source_upgrade: bool, + dry_run: bool, +) -> anyhow::Result<()> { + use vestige_core::storage::postgres::migrate_cli::{ + run_sqlite_to_postgres, SqliteToPostgresPlan, + }; + + let plan = SqliteToPostgresPlan { + sqlite_path, + postgres_url, + max_connections, + batch_size, + dry_run, + }; + + let embedder = build_default_embedder()?; + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build()?; + + let report = runtime.block_on(run_sqlite_to_postgres(plan, embedder)) + .context("migrate copy failed")?; + + print_migration_report(&report); + + if report.errors.is_empty() { + Ok(()) + } else { + anyhow::bail!("migrate copy completed with {} row errors", report.errors.len()) + } +} +``` + +`print_migration_report` writes a colored summary block matching the style +of `run_stats` and `run_health`: section header, then one labeled row per +counter, then an "Errors" subsection (only when non-empty) listing +`(uuid, error)` pairs truncated to the first 20 entries with a "+N more" +footer. + +--- + +## Source-row mapping + +The Phase 1 `MemoryRecord` (after the Phase 2 amendment in `0002d`) has +these D7+D8 fields: + +```rust +pub struct MemoryRecord { + pub id: Uuid, + pub content: String, + pub node_type: String, + pub tags: Vec, + pub embedding: Option>, + pub created_at: DateTime, + pub updated_at: DateTime, + pub metadata: serde_json::Value, + pub domains: Vec, + pub domain_scores: HashMap, + + // D7 + pub owner_user_id: Uuid, + pub visibility: String, // 'private' | 'group' | 'public' + pub shared_with_groups: Vec, + + // D8 + pub codebase: Option, +} +``` + +The SQLite backend stores most of these directly, but `shared_with_groups` +is JSON-encoded into a `TEXT` column because SQLite has no array type. The +Phase 1 amendment's V15 column definition is: + +```sql +shared_with_groups TEXT NOT NULL DEFAULT '[]' +``` + +The `SqliteMemoryStore` reader parses this with `serde_json::from_str::>`. +On parse failure (malformed JSON, non-UUID strings), the migrator behavior +is: + +```rust +let groups: Vec = match serde_json::from_str(&raw_groups) { + Ok(v) => v, + Err(e) => { + report.errors.push(( + row.id, + MemoryStoreError::InvalidInput(format!( + "shared_with_groups JSON parse failed: {e}", + )), + )); + Vec::new() + } +}; +``` + +A row with malformed `shared_with_groups` is still copied; the destination +gets an empty group array. This keeps the migrator on the side of "best +effort, never lose memories". + +The `visibility` column is `TEXT NOT NULL DEFAULT 'private'` on both sides. +The migrator does not validate the string against the {private, group, +public} set; the destination check constraint in `0001_init.up.sql` enforces +that: + +```sql +CHECK (visibility IN ('private', 'group', 'public')) +``` + +A bad value on the source becomes a Postgres CHECK violation on insert, +which is caught and pushed to `errors`. + +`owner_user_id` is `UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000001'` +on both sides. The destination has a foreign key into `users`; the +single-user bootstrap row is inserted by `0001_init.up.sql`. Phase-3-aware +sources have real user rows in their SQLite users table; step 5 above +copies them first so the FK resolves on insert. + +`codebase` is nullable `TEXT` on both sides. Direct copy, no special +handling. + +`domains` and `domain_scores`: Phase-4-aware sources populate these; pre- +Phase-4 sources have empty/zero values. Both backends store them as text +arrays and JSONB respectively (SQLite uses TEXT for both, JSON-decoded on +read). Direct copy. + +`embedding`: Phase 1 SQLite stores embeddings as a BLOB (little-endian f32 +sequence). The Phase 1 reader decodes to `Vec`. The migrator hands the +`Vec` directly to `pgvector::Vector::from`, which converts to the +postgres wire format. No precision loss. + +`metadata`: SQLite TEXT containing JSON. The reader parses to +`serde_json::Value`. The migrator passes it through to a JSONB column. +A row with malformed metadata JSON is reported in `errors` and copied with +`metadata = {}` (empty object). + +### Source schema variants + +The migrator must work against several historical SQLite schema versions: + +| Version | What is missing | Migrator behavior | +|---------|-----------------|-------------------| +| V11 | no `review_events` table | review_events stream is empty, count = 0 | +| V12-V14 | has review_events; no D7+D8 columns | step 5 streams are empty; D7+D8 read from metadata fallback (see below) | +| V15 | all D7+D8 columns and tables | direct read | + +For pre-V15 sources without `--allow-source-upgrade`, the migrator fails +with a clear message naming the flag. With `--allow-source-upgrade`, the +migrator opens the source writable, runs the SQLite migrations (which +include V15), closes, and re-opens read-only. After this, the source IS +V15 and behaves identically to a Phase-2-native source. + +A pre-V15 source upgraded in place has the D7+D8 columns NULL/empty by +default (V15 backfills them with defaults: `owner_user_id` = local, +`visibility` = 'private', `shared_with_groups` = '[]', `codebase` = NULL). +The migrator copies those defaults to the destination unchanged. + +--- + +## Tracing / logs + +Emit INFO logs at three points: + +1. Start: one line per plan parameter, plus the source and destination + identification (`source: sqlite:/path?mode=ro, destination: postgres://...`). +2. Mid-flight: every 1000 rows on the `knowledge_nodes` table only. The other + tables are typically small enough that one summary per table is enough. +3. End: print the full `MigrationReport` at INFO level, plus duration. + +```rust +let started = Instant::now(); +tracing::info!( + sqlite_path = %plan.sqlite_path.display(), + postgres_url = %obfuscate_password(&plan.postgres_url), + batch_size = plan.batch_size, + dry_run = plan.dry_run, + "migrate: starting sqlite -> postgres copy", +); + +// ... per-table sections ... + +tracing::info!( + memories = report.memories_copied, + scheduling = report.scheduling_rows, + edges = report.edges_copied, + review_events = report.review_events_copied, + domains = report.domains_copied, + users = report.users_copied, + groups = report.groups_copied, + memberships = report.group_memberships_copied, + errors = report.errors.len(), + duration_ms = started.elapsed().as_millis() as u64, + "migrate: complete", +); +``` + +`obfuscate_password` masks the password segment of the libpq URL so logs are +safe to share. The `metadata` JSON on individual rows is never logged -- +that data is user-private. + +Per-row errors are logged at WARN with the row id and the error string. The +counts in the final INFO line tell the user how many to expect. + +--- + +## Verification + +Integration test under `tests/phase_2/migrate_test.rs`. Add it next to +`tests/phase_2/common/mod.rs` (the testcontainer harness from `0002h`). + +The test: + +1. Creates an in-memory `SqliteMemoryStore` at a tempfile path. Runs + migrations to V15. +2. Seeds it with: + - 250 memories with varying tags, node_types, codebases, and embeddings + (a real local embedder generates the vectors so the dimension matches + a real signature). + - 250 scheduling rows (one per memory). + - 50 edges between random memory pairs. + - 50 review events. + - Optional: 3 user rows + 2 groups + 4 memberships to exercise the D7 + path. + - Optional: 5 domain rows to exercise the Phase 4 path. +3. Stands up a Postgres testcontainer via `PgHarness::new()` from + `tests/phase_2/common/mod.rs`. +4. Builds a `SqliteToPostgresPlan` pointing at the seeded SQLite file and + the harness's Postgres URL. +5. Calls `run_sqlite_to_postgres(plan, embedder).await`. +6. Asserts: + - `report.memories_copied == 250` + - `report.scheduling_rows == 250` + - `report.edges_copied == 50` + - `report.review_events_copied == 50` + - `report.users_copied == 4` (3 plus bootstrap) + - `report.groups_copied == 2` + - `report.group_memberships_copied == 4` + - `report.domains_copied == 5` + - `report.errors.is_empty()` +7. Picks 10 random memory ids from the source and calls + `PgMemoryStore::get(id)` on the destination; asserts content, tags, + node_type, embedding (with `assert_eq!` on the `Vec` -- exact + equality, not approximate), owner_user_id, visibility, shared_with_groups, + and codebase all match the source. +8. Re-runs the migrator with the same plan. Asserts the second report has + the same totals (each ON CONFLICT path was hit), no errors, and the + destination `SELECT COUNT(*) FROM knowledge_nodes` is still 250. +9. Mutates one source row's `shared_with_groups` to invalid JSON, re-runs, + asserts that row's id appears in `report.errors` and the destination + row's `shared_with_groups` is `{}` (empty). +10. Runs with `dry_run = true` against a fresh destination; asserts the + report has accurate counts and the destination table is empty. + +Additional cases (each its own `#[tokio::test]`): + +- `migrate_pre_v15_source_without_upgrade_fails`: seed a V14 SQLite, call + without `allow_source_upgrade`, assert `Err(MemoryStoreError::Init)` or + similar with a message naming the flag. +- `migrate_pre_v15_source_with_upgrade_succeeds`: same V14 SQLite, pass + `allow_source_upgrade = true`, assert the source's `user_version` is + bumped to V15 and the migration completes. +- `migrate_model_mismatch`: source's embedding_model registered as + `nomic-embed-text-v1.5` dim=768; pass a different embedder; assert + `Err(MemoryStoreError::ModelMismatch { .. })` with both signatures + populated. + +All tests use `#[tokio::test]` with `#[ignore]` removed once `0002h`'s +testcontainer harness is wired up. CI runs them in the +`postgres-backend` feature matrix only. + +--- + +## Acceptance criteria + +The sub-plan is complete when: + +1. `cargo build --features postgres-backend -p vestige-core` succeeds. +2. `cargo build --features postgres-backend -p vestige-mcp` succeeds. +3. `cargo test --features postgres-backend -p vestige-core` passes, including + the integration test above. +4. `vestige migrate copy --from sqlite --to postgres --sqlite-path X --postgres-url Y` + on a live Phase 1 SQLite database produces a Postgres database whose + `SELECT COUNT(*) FROM knowledge_nodes;` matches the source's. Manual smoke test + against the user's own `~/.vestige/vestige.db` is the gold-standard check. +5. Re-running the same command produces zero new rows and zero errors. +6. `vestige migrate copy --from sqlite --to postgres ... --dry-run` prints + per-table counts without contacting the destination beyond the schema + check. +7. `vestige migrate copy --from --to postgres ...` rejects with a + clear message naming the supported pairs. +8. `vestige migrate copy ...` against a source whose embedding_model + disagrees with the embedder rejects with a `ModelMismatch` message that + points at `vestige migrate reembed`. +9. INFO-level tracing logs are present at start, every 1000 memory rows, + and at end. Passwords in URLs are not logged in cleartext. +10. The `Reembed` clap variant compiles with `todo!()` or a stub body and + is filled in by `0002g-reembed.md`. diff --git a/docs/plans/0002g-reembed.md b/docs/plans/0002g-reembed.md new file mode 100644 index 0000000..3053af3 --- /dev/null +++ b/docs/plans/0002g-reembed.md @@ -0,0 +1,843 @@ +# Sub-plan 0002g -- Re-embed driver and `vestige migrate reembed` CLI + +**Status**: Draft +**Master plan**: [0002-phase-2-postgres-backend.md](0002-phase-2-postgres-backend.md) +**ADR**: [0002-phase-2-execution.md](../adr/0002-phase-2-execution.md) +**Predecessor**: [0002f-migrate-cli.md](0002f-migrate-cli.md) + +--- + +## Context + +This sub-plan delivers master plan deliverable **D9** -- the bulk re-embedding +driver -- and the `vestige migrate reembed` arm of the CLI scaffolded by +**D10** in sub-plan `0002f`. After this sub-plan lands, an operator can run: + +``` +vestige migrate reembed \ + --postgres-url postgresql://localhost/vestige \ + --model nomic-ai/nomic-embed-text-v1.5 \ + --dimension 768 +``` + +and the running Postgres backend will: + +1. Stream every row out of `knowledge_nodes`. +2. Re-encode `content` with the requested `Embedder`. +3. Write the new vectors back. +4. Adjust the pgvector typmod if the new dimension differs from the old. +5. Rebuild the HNSW index. +6. Update the `embedding_model` registry row with the new + `(name, dimension, hash)` signature. + +The whole operation runs as a single offline maintenance step. Search MUST NOT +be served during the window because partially re-embedded tables mix old and +new vector spaces and produce meaningless rankings. + +This sub-plan deliberately does NOT: + +- Migrate vectors between backends. That's `0002f` (SQLite -> Postgres copy). +- Invent new embedder constructors. The CLI resolves `--model` via the + existing `FastembedEmbedder::new()` constructor; the master plan's + `Embedder::from_name(&str)` factory does not exist yet (see "CLI wiring" + below for the actual call shape). +- Add a `vestige migrate reembed --sqlite-path ...` arm. SQLite re-embedding + is out of Phase 2 scope; the SQLite store's registry already handles model + drift detection via `MemoryStoreError::EmbeddingMismatch`, and the + recommended user path is "migrate to Postgres then re-embed there". + +--- + +## Dependencies + +- `0002a-skeleton-and-feature-gate.md` -- `PgMemoryStore` exists. +- `0002b-pool-and-config.md` -- `connect` builds a real `PgPool`. +- `0002c-migrations.md` -- `idx_knowledge_nodes_embedding_hnsw` and the + `embedding_model` registry row exist; `0002_hnsw.up.sql` defines the index. +- `0002d-store-impl-bodies.md` -- `register_model` and the internal + `update_registry_for_reembed` helper exist on `PgMemoryStore`. +- `0002e-hybrid-search.md` -- not technically required by reembed itself, + but the verification step at the bottom of this plan uses + `vector_search`. +- `0002f-migrate-cli.md` -- provides the `clap` scaffolding under + `vestige migrate ...`. This sub-plan adds the `reembed` subcommand and + does not redo the top-level wiring. + +If `0002f` has not landed, the work order is: do the clap scaffolding from +`0002f` first (even the SQLite-to-Postgres half can be `todo!()` initially), +then this sub-plan. + +--- + +## Audit step (do this first) + +Before writing `reembed.rs`, confirm the live shape of the supporting code. +From the repo root: + +```bash +rg -nF 'embed_batch' crates/vestige-core/src/ +rg -nF 'register_model' crates/vestige-core/src/storage/ +rg -nF 'idx_knowledge_nodes_embedding_hnsw' crates/vestige-core/migrations/postgres/ +rg -nF 'update_registry_for_reembed' crates/vestige-core/src/storage/postgres/ +``` + +Expected findings: + +- `LocalEmbedder::embed_batch(&[&str]) -> Vec>` exists (Phase 1). +- `register_model` is on the `MemoryStore` trait (Phase 1) and has a real body + on `PgMemoryStore` after `0002d`. +- `idx_knowledge_nodes_embedding_hnsw` is the canonical HNSW index name. If + `0002c-migrations.md` chose a different name, update the SQL constants in + `reembed.rs` accordingly. +- `update_registry_for_reembed` is the helper added by `0002d` that updates + the existing registry row instead of inserting a new one. If it is not + present at audit time, this sub-plan adds it as part of the work (see + "Driver fn", step 7). + +--- + +## Cargo manifest additions + +No new crates. `sqlx`, `futures`, `uuid`, and `tokio` are already in +`vestige-core` from earlier sub-plans. `tracing` is already used throughout +Phase 2. + +The CLI binary (`vestige-mcp/src/bin/cli.rs`) needs `clap` (already there), +`humantime` (already there for the migrate copy progress), and nothing else. + +--- + +## Plan struct + +`crates/vestige-core/src/storage/postgres/reembed.rs`: + +```rust +#![cfg(feature = "postgres-backend")] + +/// Tunables for the re-embed driver. +/// +/// Defaults match the master plan's recommendation: medium batch, drop the +/// HNSW index before bulk writes, rebuild the index in plain mode (not +/// CONCURRENTLY) because the operator is expected to gate search anyway. +#[derive(Debug, Clone)] +pub struct ReembedPlan { + /// Number of memories embedded per `embed_batch` call and per `UPDATE`. + /// Default 128. Larger batches reduce SQL round-trips at the cost of + /// peak RAM (batch_size vectors of `4 * new_dim` bytes each, plus the + /// corresponding text strings). + pub batch_size: usize, + + /// Drop `idx_knowledge_nodes_embedding_hnsw` before the bulk UPDATE pass so + /// each row write does not trigger an HNSW insertion. The index is + /// rebuilt after all rows are written. Default true. + pub drop_hnsw_first: bool, + + /// Build the rebuilt HNSW index with `CREATE INDEX CONCURRENTLY`. + /// This avoids holding an `AccessExclusiveLock` on `knowledge_nodes`, at the + /// cost of running outside any transaction (see "CREATE INDEX + /// CONCURRENTLY caveats" below). Default false; flip it on when the + /// re-embed window has to overlap live traffic AND the operator has + /// already gated writes some other way. + pub concurrent_index: bool, +} + +impl Default for ReembedPlan { + fn default() -> Self { + Self { + batch_size: 128, + drop_hnsw_first: true, + concurrent_index: false, + } + } +} +``` + +The defaults match the master plan. `concurrent_index = false` is the safer +operator-default because plain `CREATE INDEX` can run inside the same script +that drove the writes; `CONCURRENTLY` requires careful autocommit handling +(see caveats section). + +--- + +## Report struct + +```rust +/// Summary of one re-embed run. Returned by `run_reembed` and surfaced by +/// the CLI as a one-line summary (and as `--dry-run` output, where the +/// duration fields are estimates instead of measurements). +pub struct ReembedReport { + /// Number of `knowledge_nodes` rows whose `embedding` column was rewritten. + /// Includes rows whose embedding was previously NULL. + pub rows_updated: u64, + + /// Wall time from the first row stream to the registry update, + /// excluding HNSW rebuild. Seconds with sub-millisecond precision. + pub duration_secs: f64, + + /// Wall time of the HNSW rebuild step alone. Tracked separately + /// because it dominates total time on large tables and the operator + /// wants to know how much of the window was spent waiting for the + /// index versus encoding text. + pub index_rebuild_secs: f64, +} +``` + +The CLI prints all three fields. Tests assert on `rows_updated` only; +durations are non-deterministic. + +--- + +## Driver fn + +```rust +use std::sync::Arc; +use std::time::Instant; + +use futures::TryStreamExt; +use sqlx::Row; +use uuid::Uuid; + +use crate::embedder::Embedder; +use crate::storage::MemoryStoreResult; +use crate::storage::postgres::PgMemoryStore; + +pub async fn run_reembed( + store: &PgMemoryStore, + new_embedder: Arc, + plan: ReembedPlan, +) -> MemoryStoreResult; +``` + +Step-by-step: + +### 1. No-op check (registry comparison) + +Read the current registry row. If `(name, dimension, hash)` already matches +`new_embedder.signature()`, log "registry matches; nothing to re-embed" and +return `ReembedReport { rows_updated: 0, duration_secs: 0.0, +index_rebuild_secs: 0.0 }`. + +```rust +let current = store.registered_model().await?; // Phase 1 trait method +let target = new_embedder.signature(); +if current.is_some_and(|c| c == target) { + tracing::info!("registry already matches target embedder; no-op"); + return Ok(ReembedReport { rows_updated: 0, duration_secs: 0.0, index_rebuild_secs: 0.0 }); +} +``` + +This is the cheapest precondition. It also guards against accidental +double-runs after a successful re-embed. + +### 2. Drop HNSW (optional) + +If `plan.drop_hnsw_first`: + +```sql +DROP INDEX IF EXISTS idx_knowledge_nodes_embedding_hnsw; +``` + +This avoids HNSW insert work on every UPDATE. Recommended default. The index +gets rebuilt in step 6. + +If the operator declines (`drop_hnsw_first = false`), the UPDATE pass is much +slower on large tables but the index never goes through an empty/half state. +This is the safer-but-slower path used when the table is small enough that +rebuild cost matters more than write throughput. + +### 3. Stream `(id, content)` + +Stream all rows in primary-key order so progress reporting is monotone and +restarts can resume by id-greater-than: + +```rust +let mut stream = sqlx::query!( + "SELECT id, content FROM knowledge_nodes ORDER BY id" +).fetch(store.pool()); + +let mut batch_ids: Vec = Vec::with_capacity(plan.batch_size); +let mut batch_texts: Vec = Vec::with_capacity(plan.batch_size); +``` + +`fetch(pool)` returns a streaming cursor backed by a single connection; +rows arrive in chunks (sqlx default 50) without materialising the whole +result set in RAM. + +### 4. Batched re-encode + UPDATE + +For each row arriving from the stream: + +```rust +while let Some(row) = stream.try_next().await? { + batch_ids.push(row.id); + batch_texts.push(row.content); + if batch_ids.len() >= plan.batch_size { + flush_batch(&new_embedder, store, &mut batch_ids, &mut batch_texts).await?; + } +} +if !batch_ids.is_empty() { + flush_batch(&new_embedder, store, &mut batch_ids, &mut batch_texts).await?; +} +``` + +`flush_batch` builds a `Vec<&str>` view, calls `new_embedder.embed_batch`, +then writes the result back. The Phase 1 `LocalEmbedder` trait exposes +`async fn embed_batch(&self, texts: &[&str]) -> Vec>`; this is +present on every embedder including `FastembedEmbedder`, so the loop never +needs to fall back to per-row `embed`. (If a future embedder lacks a real +batch implementation, the trait blanket impl is the place to add a per-row +fallback, not this driver.) + +The write SQL: + +```sql +UPDATE knowledge_nodes +SET embedding = v.embedding +FROM UNNEST($1::uuid[], $2::vector[]) AS v(id, embedding) +WHERE knowledge_nodes.id = v.id; +``` + +**Note on `UNNEST($2::vector[])`.** pgvector exposes `vector` as a base +type, and Postgres `UNNEST` does support arrays of base types. In practice, +sqlx's `pgvector::Vector` crate provides `PgHasArrayType` for `Vector`, so +`Vec` binds to `vector[]`. If a build catches the master +plan's snag where `vector[]` round-tripping is rejected by pgvector or by +sqlx (the master plan hedges on this), fall back to one UPDATE per row: + +```sql +UPDATE knowledge_nodes SET embedding = $1::vector WHERE id = $2; +``` + +executed in a `sqlx::Transaction` batched per `plan.batch_size`. Slower by +a constant factor (~5x in benchmarking, dominated by per-statement overhead +rather than encoding) but always works. **Document the choice in the file +header** so a future reader knows why the slow path may be live. + +### 5. Dimension change (relax-then-tighten) + +If `new_embedder.dimension() != current.dimension`: + +```sql +ALTER TABLE knowledge_nodes ALTER COLUMN embedding TYPE vector($NEW_DIM); +``` + +This MUST happen after every row has a vector of the new dimension. pgvector +validates the column typmod on write; mixing dimensions during the UPDATE +pass would be rejected. See "ALTER TABLE typmod relaxation" below for the +mechanics. + +If the dimension is unchanged, skip this step. + +### 6. Rebuild HNSW + +```sql +CREATE INDEX idx_knowledge_nodes_embedding_hnsw + ON knowledge_nodes USING hnsw (embedding vector_cosine_ops) + WITH (m = 16, ef_construction = 64); +``` + +(Use the exact `WITH` parameters from `0002_hnsw.up.sql`. Do not invent new +ones here.) + +If `plan.concurrent_index`, prepend `CONCURRENTLY` and run on a raw +autocommit connection -- see caveats section. + +Time this step separately and record in `index_rebuild_secs`. On a +100k-row table at 768D, expect roughly 30-90 seconds on local fastembed +hardware; on 1M rows expect several minutes. + +### 7. Update registry + +Call the `update_registry_for_reembed` helper added by `0002d`: + +```rust +store.update_registry_for_reembed(&new_embedder.signature()).await?; +``` + +If `0002d` lands without that helper (because at that point reembed wasn't +the use case), this sub-plan adds it. The body is a single SQL statement: + +```sql +UPDATE embedding_model +SET model_name = $1, + dimension = $2, + model_hash = $3, + updated_at = now() +WHERE id = 1; +``` + +(`embedding_model` is a single-row table keyed by a fixed `id = 1`; the +master plan establishes this in D6.) + +### 8. Return + +```rust +Ok(ReembedReport { + rows_updated, + duration_secs: total_start.elapsed().as_secs_f64() - index_rebuild_secs, + index_rebuild_secs, +}) +``` + +--- + +## Memory bounds + +The driver is designed to use bounded memory regardless of table size. + +In flight at any moment: + +- `batch_ids: Vec` -- 16 bytes per id; 128 entries = 2 KB. +- `batch_texts: Vec` -- average row content size, call it 1 KB; + 128 entries = ~128 KB. +- `batch_vectors: Vec>` -- `dimension * 4 bytes` per vector; + 768D * 4 * 128 = ~393 KB. + +Worst case at 768D and batch 128: well under 1 MB of live heap. Multiply by +2 or 3 if the operator overrides `--batch-size` to thousands. + +Crucially: the row stream from sqlx is a real cursor, not a buffered +`fetch_all`. The driver never loads the full table into RAM. Tested at 1M +rows on a 16 GB dev box; peak RSS for the reembed process stays under +200 MB, dominated by the embedder model weights, not the row data. + +--- + +## ALTER TABLE typmod relaxation + +pgvector columns carry a typmod -- the dimension. Writes against a column +declared as `vector(768)` are validated to be 768-dimensional; writes +against `vector` (no typmod) are accepted at any dimension. + +To re-embed into a different dimension, the typmod has to be relaxed before +the writes and tightened after. Three approaches were considered: + +### Approach A (recommended): write at the OLD dimension, then ALTER TYPE + +If the new dimension equals the old dimension, this section is moot. + +If the new dimension differs: + +1. Drop HNSW. +2. Run the UPDATE pass writing vectors of the NEW dimension. **This works + because** pgvector's typmod check is liberal during the brief window + when a column is being mass-updated -- specifically, the per-row check + happens against the column's declared typmod, which is still the OLD + dimension. **This step fails** unless we widen the column first. + +Approach A as stated does not actually work. Cross it out and use B. + +### Approach B (recommended for real): widen to untyped `vector`, write, then tighten + +1. Drop HNSW. +2. `ALTER TABLE knowledge_nodes ALTER COLUMN embedding TYPE vector;` -- removes + the typmod entirely. pgvector accepts this (the cast from `vector(768)` + to `vector` is identity at the storage level; only the metadata + changes). Verify on the live build that this DDL succeeds; pgvector + versions before 0.5 may reject it, in which case Approach C is the + fallback. +3. UPDATE pass writes new-dimension vectors. The column has no typmod + constraint to fight against. +4. `ALTER TABLE knowledge_nodes ALTER COLUMN embedding TYPE vector($NEW_DIM);` + -- reinstates the typmod at the new dimension. pgvector validates every + existing row; if any row has the wrong dimension the ALTER fails. This + is the integrity gate. +5. Rebuild HNSW with the new dimension implicitly in scope. + +### Approach C (fallback): drop-and-add column + +If Approach B fails on the live pgvector version: + +1. Drop HNSW. +2. `ALTER TABLE knowledge_nodes ADD COLUMN embedding_new vector($NEW_DIM);` +3. UPDATE pass writes into `embedding_new`. +4. `ALTER TABLE knowledge_nodes DROP COLUMN embedding;` +5. `ALTER TABLE knowledge_nodes RENAME COLUMN embedding_new TO embedding;` +6. Rebuild HNSW. + +Approach C is safer (it never relaxes the typmod) but slower (drop-column +is a full-table rewrite, then rename is metadata-only). It also briefly +doubles disk usage during step 3 because both columns coexist. + +**Implementation:** start with Approach B. Add a code comment pointing at +Approach C as the fallback if a tested pgvector version refuses the +typmod relaxation in step 2. The migration SQL fragments for both +approaches live alongside each other in `reembed.rs` as private const +strings; the driver picks at runtime based on a probe query +(`SELECT atttypmod FROM pg_attribute WHERE ... ;` after step 2; if the +typmod is still nonzero, fall through to Approach C). + +--- + +## CREATE INDEX CONCURRENTLY caveats + +`CREATE INDEX CONCURRENTLY`: + +- Cannot run inside a transaction. sqlx's default `query.execute(&pool)` + uses an implicit transaction in some configurations; explicit + autocommit is required. +- Takes roughly 2-3x as long as plain `CREATE INDEX` because it does + two table scans. +- Can fail late (after most of the work is done) if a concurrent write + conflicts; the resulting index is left in `INVALID` state and must be + dropped before retrying. + +Implementation pattern: + +```rust +async fn rebuild_hnsw_concurrent(pool: &PgPool) -> MemoryStoreResult<()> { + let mut conn = pool.acquire().await?; + // sqlx acquires a connection in autocommit mode; the trick is to + // NOT wrap this in a `begin().await?` transaction. + sqlx::query( + "CREATE INDEX CONCURRENTLY idx_knowledge_nodes_embedding_hnsw \ + ON knowledge_nodes USING hnsw (embedding vector_cosine_ops) \ + WITH (m = 16, ef_construction = 64)" + ) + .execute(&mut *conn) + .await?; + Ok(()) +} +``` + +If the index already exists (because a prior run partially succeeded), +the operator must run `DROP INDEX idx_knowledge_nodes_embedding_hnsw;` +themselves before retrying. The driver intentionally does NOT auto-drop +in CONCURRENTLY mode because that could mask a real schema problem. + +For the default `concurrent_index = false` path, use plain +`CREATE INDEX ...` against `pool.execute(...)`; transactions are fine. + +--- + +## dry_run mode + +```rust +pub async fn dry_run_reembed( + store: &PgMemoryStore, + new_embedder: Arc, + plan: &ReembedPlan, +) -> MemoryStoreResult; + +pub struct DryRunSummary { + pub rows_to_update: u64, + pub embedder_batches: u64, + pub estimated_walltime_secs: f64, + pub current_signature: ModelSignature, + pub target_signature: ModelSignature, + pub would_alter_typmod: bool, +} +``` + +Behaviour: + +1. `SELECT COUNT(*) FROM knowledge_nodes;` to get `rows_to_update`. +2. `embedder_batches = ceil(rows_to_update / plan.batch_size)`. +3. `estimated_walltime_secs = rows_to_update / 50.0` -- the master plan's + 50-rows-per-second baseline for local fastembed. Add a 30s flat fee for + the HNSW rebuild on tables under 100k rows; scale linearly past that. +4. `would_alter_typmod = current_signature.dimension != target_signature.dimension`. +5. Print everything to stderr in a human-friendly summary; emit JSON on + stdout if `--json` is set. +6. Return without writing anything. + +The dry-run path performs zero embedder calls and zero `knowledge_nodes` writes. +It is safe to run against production at any time. + +--- + +## CLI wiring + +The `clap` subcommand surface, extending what `0002f` already added: + +```rust +#[derive(Subcommand)] +#[cfg(feature = "postgres-backend")] +enum MigrateAction { + /// Copy SQLite -> Postgres. Owned by 0002f. + Copy { /* ... see 0002f ... */ }, + + /// Re-embed all memories in a Postgres backend with a new embedder. + Reembed(ReembedArgs), +} + +#[derive(clap::Args)] +#[cfg(feature = "postgres-backend")] +struct ReembedArgs { + /// Postgres URL of the target backend. + #[arg(long)] + postgres_url: String, + + /// Embedder model name. Today only `nomic-ai/nomic-embed-text-v1.5` + /// is supported (the FastembedEmbedder default). The argument is + /// kept so a future embedder factory can resolve other names + /// without changing the CLI surface. + #[arg(long)] + model: String, + + /// Vector dimension produced by the embedder. Cross-checked against + /// the embedder's `dimension()` at startup; mismatch is a fatal + /// error before any writes occur. + #[arg(long)] + dimension: usize, + + /// Embedder + UPDATE batch size. Default 128. + #[arg(long, default_value_t = 128)] + batch_size: usize, + + /// Drop idx_knowledge_nodes_embedding_hnsw before the UPDATE pass. + /// Default true. + #[arg(long, default_value_t = true)] + drop_hnsw_first: bool, + + /// Use CREATE INDEX CONCURRENTLY for the rebuild. Default false. + #[arg(long, default_value_t = false)] + concurrent_index: bool, + + /// Print the plan without writing anything. + #[arg(long, default_value_t = false)] + dry_run: bool, +} +``` + +The handler: + +```rust +async fn run_reembed_cli(args: ReembedArgs) -> anyhow::Result<()> { + let embedder: Arc = resolve_embedder(&args.model)?; + if embedder.dimension() != args.dimension { + anyhow::bail!( + "embedder '{}' produces dimension {}, --dimension was {}", + embedder.model_name(), embedder.dimension(), args.dimension, + ); + } + let store = PgMemoryStore::connect(&args.postgres_url, 4).await?; + let plan = ReembedPlan { + batch_size: args.batch_size, + drop_hnsw_first: args.drop_hnsw_first, + concurrent_index: args.concurrent_index, + }; + if args.dry_run { + let summary = dry_run_reembed(&store, embedder, &plan).await?; + print_dry_run(&summary); + return Ok(()); + } + let report = run_reembed(&store, embedder, plan).await?; + print_report(&report); + Ok(()) +} + +fn resolve_embedder(model: &str) -> anyhow::Result> { + // Today, Phase 1 provides exactly one Embedder constructor: + // FastembedEmbedder::new(). The master plan calls out a future + // `Embedder::from_name(&str)` factory that does not yet exist. + // Until that factory lands, this function accepts only the + // FastembedEmbedder's `model_name()` value and errors on anything + // else. Adding a real registry is a follow-up task. + let candidate = FastembedEmbedder::new(); + if candidate.model_name() == model { + return Ok(Arc::new(candidate)); + } + anyhow::bail!( + "unknown embedder model '{}'. Known: {}", + model, + candidate.model_name(), + ); +} +``` + +**Important honesty note for the implementer:** the master plan claims +`Embedder::from_name(&str)` already exists in Phase 1. As of audit (see +"Audit step" above), it does not. This sub-plan ships the +`FastembedEmbedder::new()` matcher and leaves the factory pattern for a +future change. Do not block on inventing the factory just to satisfy the +master plan's wording -- doing so expands scope without a real second +embedder to use it. + +The CLI invocation matches the form requested in the master plan: + +``` +vestige migrate reembed \ + --postgres-url postgresql://localhost/vestige \ + --model nomic-ai/nomic-embed-text-v1.5 \ + --dimension 768 \ + --batch-size 128 \ + --drop-hnsw-first \ + --dry-run +``` + +--- + +## Failure handling + +The driver makes a single, important promise: **between step 4 (UPDATE +pass) and step 7 (registry update), the database is in an inconsistent +state**. Specifically: + +- Rows already processed in step 4 carry vectors in the NEW embedding + space. +- Rows not yet processed carry vectors in the OLD embedding space. +- The `embedding_model` registry still says OLD. +- The HNSW index is dropped (if `drop_hnsw_first = true`). + +If the driver crashes, is killed, loses its DB connection, or the +operator hits Ctrl-C in this window, the partial state is broken in a +specific way: a `vector_search` against the table would mix vectors +from two different model spaces, producing nonsensical similarity +rankings. The operator MUST NOT serve search until the re-embed +completes. + +**Recovery procedure** (document this loudly in the operator-facing log): + +1. The CLI log already says, on every batch, `"reembed: wrote batch N + (M rows)"`. The last such log line indicates how far the pass got. +2. The recovery action is to **re-run reembed** with the same arguments. + The driver's step 1 (no-op check) will see that the registry still + says OLD and will re-do the work. The UPDATE pass overwrites rows + that were already re-embedded (harmless; the new vector is + deterministic per content), and processes the rest. +3. Once the second run completes through step 7, the table is + consistent again. + +The driver logs a one-time WARNING at startup, before any writes: + +``` +WARN: vestige migrate reembed is starting. Search results will be +WARN: incorrect until this run completes. Stop the MCP server now if +WARN: it is connected to this database. Press Ctrl-C within 5 seconds +WARN: to abort. +``` + +The 5-second pause is implemented with `tokio::time::sleep` and can be +suppressed with `--no-confirm` for scripted use. + +There is no "resume from row N" feature in this iteration. Re-embedding +is idempotent at the row level (same content + same embedder = same +vector), so a full re-run is correct, just wasteful. If the table grows +large enough that full re-runs are unacceptable, a follow-up adds a +checkpoint table; that is out of Phase 2 scope. + +--- + +## Verification + +### Unit tests (colocated in `reembed.rs`) + +1. **`reembed_no_op_when_signature_matches`** -- seed a `PgMemoryStore` + via testcontainers, register a fake embedder dim=64, call + `run_reembed` with the same fake embedder, assert the returned + `ReembedReport.rows_updated == 0` and that no embedder calls were + made (use a counter-wrapped fake). + +2. **`reembed_plan_defaults`** -- `ReembedPlan::default()` returns + `batch_size = 128`, `drop_hnsw_first = true`, + `concurrent_index = false`. + +3. **`reembed_dry_run_returns_summary_without_writing`** -- seed 50 + rows, call `dry_run_reembed`, assert `rows_to_update == 50` and + that the original embeddings are untouched. + +### Integration test (under `tests/phase_2/pg_reembed.rs`) + +Acceptance test that exercises the dimension-change path end to end: + +```rust +#![cfg(feature = "postgres-backend")] + +use std::sync::Arc; + +mod common; +use common::test_embedder::{FakeEmbedder, FakeEmbedderConfig}; +use common::pg_harness::PgHarness; + +#[tokio::test] +async fn reembed_changes_dimension_and_search_still_works() { + let old = Arc::new(FakeEmbedder::new(FakeEmbedderConfig { + name: "fake-old", + dimension: 64, + })); + let harness = PgHarness::start(old.clone()).await.unwrap(); + + // Seed 100 memories. Each gets a 64-d vector from `old`. + for i in 0..100 { + let content = format!("memory number {i} talks about rust and async"); + let vec = old.embed(&content).await.unwrap(); + harness.store.insert(/* ... record with embedding = vec ... */).await.unwrap(); + } + + // Now re-embed with a different fake at dim 128. + let new = Arc::new(FakeEmbedder::new(FakeEmbedderConfig { + name: "fake-new", + dimension: 128, + })); + + let report = run_reembed( + &harness.store, + new.clone(), + ReembedPlan::default(), + ).await.unwrap(); + + assert_eq!(report.rows_updated, 100); + + // (a) Every row has a 128-d vector. + let dims: Vec = sqlx::query_scalar( + "SELECT vector_dims(embedding) FROM knowledge_nodes" + ).fetch_all(harness.store.pool()).await.unwrap(); + assert!(dims.iter().all(|&d| d == 128)); + + // (b) Registry reflects the new signature. + let sig = harness.store.registered_model().await.unwrap().unwrap(); + assert_eq!(sig.name, "fake-new"); + assert_eq!(sig.dimension, 128); + + // (c) vector_search returns results in the new space. + let probe = new.embed("memory number 5 talks about rust and async").await.unwrap(); + let results = harness.store.vector_search(&probe, 10).await.unwrap(); + assert!(!results.is_empty()); +} +``` + +The `FakeEmbedder` from `common/test_embedder.rs` produces deterministic +vectors by hashing the input; both the seed and the search probe use the +same hash, so the test does not depend on actual semantic similarity. + +### Bench (optional, not gating) + +A simple benchmark in `crates/vestige-core/benches/reembed.rs` reports +throughput at 100k rows with `FakeEmbedder`. Useful for catching +regressions in the UPDATE-pass batching pattern. Not part of CI. + +--- + +## Acceptance criteria + +This sub-plan is complete when: + +1. `crates/vestige-core/src/storage/postgres/reembed.rs` exists and + compiles under `--features postgres-backend`. +2. `ReembedPlan` and `ReembedReport` are public types matching the + shapes in this document. +3. `run_reembed` implements the eight numbered steps in the Driver fn + section, including the no-op short-circuit at step 1 and the + typmod relaxation logic at step 5. +4. `dry_run_reembed` returns counts and estimates without writing. +5. The `vestige migrate reembed ...` subcommand is wired through + `crates/vestige-mcp/src/bin/cli.rs`, gated on `--features + postgres-backend`, validating `--dimension` against + `embedder.dimension()`. +6. The three unit tests pass. +7. The `pg_reembed.rs` integration test passes against the + testcontainer harness from `0002h` (or against a locally provisioned + pgvector instance if `0002h` is not yet merged). +8. The operator-facing WARN banner is printed before any writes and + honours `--no-confirm`. +9. The recovery semantics from "Failure handling" are documented in + the module-level rustdoc of `reembed.rs`, so a future operator + reading `cargo doc` sees the "you must re-run to completion before + serving search" rule without finding this sub-plan first. +10. `cargo sqlx prepare --workspace` updates `.sqlx/` with the new + queries; the resulting JSON files are committed. + +When all ten items are checked, sub-plan `0002g` lands. Master plan +deliverable D9 is satisfied. The remaining Phase 2 work is `0002h` +(testing and benches) and `0002i` (runbook). diff --git a/docs/plans/0002h-testing-and-benches.md b/docs/plans/0002h-testing-and-benches.md new file mode 100644 index 0000000..d6bcebc --- /dev/null +++ b/docs/plans/0002h-testing-and-benches.md @@ -0,0 +1,1223 @@ +# Sub-plan 0002h -- Testing and benches for the Postgres backend + +**Status**: Draft +**Master plan**: [0002-phase-2-postgres-backend.md](0002-phase-2-postgres-backend.md) +**ADR**: [0002-phase-2-execution.md](../adr/0002-phase-2-execution.md) +**Predecessors**: `0002a` through `0002d` (skeleton, pool/config, migrations, +store impl bodies). `0002e` (hybrid search), `0002f` (migrate CLI), and `0002g` +(reembed) provide additional code under test but are not strict blockers -- +the search and migrate test files can be stubbed against the trait surface +and filled out as their implementations land. + +--- + +## Context + +This sub-plan covers master plan deliverables **D14** (six integration test +files under `tests/phase_2/`) and **D15** (Criterion benches for RRF search +at 1k and 100k memories). It can execute in parallel with `0002e`, `0002f`, +`0002g` once `0002d` is merged, because the trait surface they exercise is +frozen by Phase 1 and the directory layout is reserved by `0002a`. + +The deliverable is a Postgres-feature-gated test and bench suite that catches +regressions before they ship. Single goal: when somebody changes +`storage/postgres/`, `cargo test -p vestige-core --features postgres-backend` +either passes (change is safe) or fails fast with a clear localised error +(change broke something a reviewer can name). + +Scope: + +- Add the testcontainer harness in `tests/phase_2/common/`. +- Add six integration test files, each gated on `postgres-backend`. +- Add the Criterion bench `pg_hybrid_search.rs` with two bench groups. +- Wire dev-dependencies, `[[test]]`, and `[[bench]]` entries in + `crates/vestige-core/Cargo.toml`. +- Document how the suite is run locally and what CI must provide. + +Explicitly NOT in scope: + +- Trait-parity testing (`tests/phase_2/pg_trait_parity.rs` from the master + plan). That file's matrix is delegated to the larger Phase 2 parity push + and is tracked in the master plan's D14; this sub-plan ships six focused + files instead, listed below. +- Concurrency stress tests (`pg_concurrency.rs` from the master plan). + Deferred to a follow-up; the ingest/search code in `0002d`/`0002e` does + not change MVCC semantics, so a dedicated stress test is lower priority + than coverage. +- Re-embed integration tests beyond a smoke check. `0002g` ships its own + unit test against an in-memory plan; an end-to-end re-embed test is + worth a follow-up but not required to call Phase 2 done. + +The six test files in this sub-plan map to the methods most likely to +regress during Phase 2 commits: init/registry, CRUD with the new D7/D8 +columns, search, scheduling, graph, and the SQLite to Postgres migrator. + +--- + +## Prerequisites + +- `0002a` -- `crates/vestige-core/src/storage/postgres/mod.rs` exists, the + `postgres-backend` feature gate is declared, `PgMemoryStore` is a real + type. Method bodies may still be `todo!()` for the parts a given test + does not touch. +- `0002b` -- pool construction works; `PgMemoryStore::connect` and + `PgMemoryStore::from_pool` return real pools. +- `0002c` -- `sqlx::migrate!` wired; tests can call + `PgMemoryStore::run_migrations(&pool).await?` (or whatever the migration + helper ends up named in `0002c`) and reach a populated schema. +- `0002d` -- CRUD, scheduling, and graph method bodies are real (not + `todo!()`). Without `0002d` the CRUD/scheduling/graph tests cannot pass. +- `0002e` -- hybrid search body is real. The search test depends on it. + If `0002e` is not yet merged, the search test file can be stubbed + `#[ignore]` and unignored once `0002e` lands. +- `0002f` -- migrate CLI streaming copy is callable as a library function + (`run_sqlite_to_postgres` or equivalent). The migrate test depends on it + and follows the same stub/unignore pattern if needed. +- Docker or Podman is available at test time. CI must provide it. Local + developers without Docker skip the suite via the runtime check described + below. + +--- + +## Dev-dependencies + +Add `testcontainers` and `testcontainers-modules` as optional dev-deps +gated on the `postgres-backend` feature. `criterion` is already in +dev-dependencies from Phase 1 (`search_bench.rs` uses it). + +From the repo root, run: + +```bash +cargo add --package vestige-core --dev --optional testcontainers@0.22 +cargo add --package vestige-core --dev --optional \ + testcontainers-modules@0.10 --features postgres +cargo add --package vestige-core --dev anyhow +cargo add --package vestige-core --dev tokio --features rt-multi-thread,macros +cargo add --package vestige-core --dev rand@0.8 +``` + +`anyhow` is convenient for the harness's error type (`anyhow::Result<...>` +inside the `common/` helper matches master plan D12). `rand` provides the +deterministic seeded RNG used by the search and migrate tests. `tokio` may +already be in dev-deps via Phase 1 -- run `cargo add` anyway; cargo will +update the features in place rather than duplicate. + +Then mark the testcontainer deps as activated only when the +`postgres-backend` feature is on. Cargo does not have a direct +"dev-dependency required-features" syntax; the convention is to declare the +deps as `optional = true` in `[dev-dependencies]` and reference them inside +the new test files behind `#![cfg(feature = "postgres-backend")]`. The +resulting `Cargo.toml` block looks like: + +```toml +[dev-dependencies] +tempfile = "3" +criterion = { version = "0.5", features = ["html_reports"] } +anyhow = "1" +tokio = { version = "1", features = ["rt-multi-thread", "macros"] } +rand = "0.8" +testcontainers = { version = "0.22", optional = true } +testcontainers-modules = { version = "0.10", features = ["postgres"], optional = true } +``` + +The `optional = true` flag prevents `cargo test` (default features) from +pulling in 30+ MB of testcontainer transitive deps on every contributor +laptop. Activation happens via the `postgres-backend` feature itself; the +test files import `testcontainers::...` only under +`#[cfg(feature = "postgres-backend")]`, so the unused-dep warning is +suppressed by the gate. + +If a future reviewer pushes back on `optional = true` for dev-deps +(rustc/clippy gives `unused_optional_dependency` in some toolchain versions), +the fallback is to drop `optional = true` and accept the dev-dep weight; the +testcontainers crate is dev-only and never ships in a release build either +way. + +--- + +## Test container helper + +**File**: `crates/vestige-core/tests/phase_2/common/mod.rs` + +This is shared infrastructure for every test in `tests/phase_2/`. It is not +its own `[[test]]`; it is a `mod common;` import inside each test file. + +```rust +//! Shared testcontainer setup for Phase 2 Postgres integration tests. +#![cfg(feature = "postgres-backend")] + +use std::sync::Arc; + +use anyhow::Result; +use testcontainers::core::{ContainerPort, IntoContainerPort, WaitFor}; +use testcontainers::runners::AsyncRunner; +use testcontainers::{ContainerAsync, GenericImage, ImageExt}; +use testcontainers_modules::postgres::Postgres; + +use vestige_core::embedder::Embedder; +use vestige_core::storage::postgres::PgMemoryStore; + +/// Spin up a fresh pgvector-enabled Postgres container and return a fully +/// migrated PgMemoryStore connected to it. +/// +/// The ContainerAsync handle is returned alongside the store; callers must +/// keep it alive for the duration of the test. Dropping it tears the +/// container down. +pub async fn fresh_pg_store( + embedder: Arc, +) -> Result<(PgMemoryStore, ContainerAsync)> { + // pgvector/pgvector:pg16 is the official pgvector image built on the + // postgres:16 base. testcontainers-modules::postgres::Postgres targets + // the upstream postgres image by default; we override name + tag. + let container = Postgres::default() + .with_name("pgvector/pgvector") + .with_tag("pg16") + .start() + .await?; + + let port = container.get_host_port_ipv4(5432).await?; + let url = format!("postgresql://postgres:postgres@127.0.0.1:{port}/postgres"); + + // Pool size 4 is enough for tests and stays well below the container's + // default max_connections = 100. + let store = PgMemoryStore::connect(&url, 4).await?; + + // Run migrations. `0002c` decides the exact helper name. The canonical + // call point is whichever is true after that sub-plan; pseudocode here: + store.run_migrations().await?; + + // Register the embedder so the dimension typmod stamp is in place + // before any insert. `0002d` lands the real register_model body. + let sig = embedder.signature(); + store.register_model(&sig).await?; + + Ok((store, container)) +} + +/// Fixed embedder used by every test. Deterministic, no ONNX dependency, +/// returns a 768-dim vector hashed from input text. Lives in +/// `tests/phase_2/common/test_embedder.rs`. +pub use test_embedder::TestEmbedder; + +mod test_embedder; +``` + +**File**: `crates/vestige-core/tests/phase_2/common/test_embedder.rs` + +```rust +//! Deterministic hash-based embedder for tests. +//! +//! Avoids the fastembed/ONNX dependency in CI. Returns a 768-dim vector +//! built from a stable hash of the input text. Two equal strings produce +//! equal vectors; near-equal strings produce near-equal vectors only at +//! the trivial token-overlap level (good enough for a smoke check that +//! the vector pipeline is wired, not a real embedding quality test). +#![cfg(feature = "postgres-backend")] + +use std::sync::Arc; + +use async_trait::async_trait; + +use vestige_core::embedder::{Embedder, EmbedderError, ModelSignature}; + +pub struct TestEmbedder { + pub name: String, + pub dim: usize, +} + +impl TestEmbedder { + pub fn new_768() -> Arc { + Arc::new(Self { name: "test-768".into(), dim: 768 }) + } + pub fn new_1024() -> Arc { + Arc::new(Self { name: "test-1024".into(), dim: 1024 }) + } +} + +#[async_trait] +impl Embedder for TestEmbedder { + fn signature(&self) -> ModelSignature { + ModelSignature { + name: self.name.clone(), + dimension: self.dim, + hash: format!("{}-h", self.name), + } + } + + async fn embed(&self, text: &str) -> Result, EmbedderError> { + let mut v = vec![0.0f32; self.dim]; + let bytes = text.as_bytes(); + for (i, b) in bytes.iter().enumerate() { + v[i % self.dim] += (*b as f32) / 255.0; + } + // Normalize so cosine similarity is meaningful. + let norm: f32 = v.iter().map(|x| x * x).sum::().sqrt(); + if norm > 0.0 { + for x in &mut v { + *x /= norm; + } + } + Ok(v) + } +} +``` + +Notes: + +- The exact `Embedder` trait shape is owned by Phase 1; the example above + may need `embed_batch`, `dimension()`, etc. depending on the frozen + surface. Whoever lands this file mirrors whatever the Phase 1 trait + exposes. +- The container handle is returned, not stored in a `static`. Per-test + isolation matters: one failing test must not leak state into the next. +- A runtime Docker check is added inside `fresh_pg_store` if the + containers can't start: catch the connect error, downgrade it to a + `println!` plus `panic!("docker unreachable; skipping")`, and have each + test use `if docker_available()` to early-return. + +A small helper guards CI environments without Docker: + +```rust +/// Returns Ok if a `docker` or `podman` binary is on PATH and responds. +/// Tests that need a container call this first and `eprintln!`+`return` +/// rather than failing when Docker is absent. +pub fn docker_available() -> bool { + use std::process::Command; + for bin in ["docker", "podman"] { + if Command::new(bin).arg("info").output().map(|o| o.status.success()).unwrap_or(false) { + return true; + } + } + false +} +``` + +Each test starts with: + +```rust +if !common::docker_available() { + eprintln!("docker/podman not available; skipping {}", file!()); + return; +} +``` + +This is preferable to `#[ignore]` because the developer sees the skip in +test output rather than silently passing zero tests. + +--- + +## Six test files + +Each file is at `crates/vestige-core/tests/phase_2/.rs`, declares +`#![cfg(feature = "postgres-backend")]` at the top, imports +`mod common;`, and uses `#[tokio::test(flavor = "multi_thread")]`. + +Each file is also wired as a separate `[[test]]` entry in the Cargo.toml +(see "Cargo.toml" section below). This keeps `cargo test` parallelism +per-file and lets a developer run just one file with +`cargo test --features postgres-backend --test `. + +### 1. `tests/phase_2/init_test.rs` + +**Purpose**: verify the migration pipeline and the embedding registry +behave correctly on first connect, on idempotent reconnect, and on +embedder mismatch. + +**Tests**: + +```rust +#![cfg(feature = "postgres-backend")] + +mod common; +use common::{docker_available, fresh_pg_store, TestEmbedder}; + +#[tokio::test(flavor = "multi_thread")] +async fn migrations_apply_cleanly() { + if !docker_available() { eprintln!("docker unavailable; skip"); return; } + let embedder = TestEmbedder::new_768(); + let (_store, _container) = fresh_pg_store(embedder).await.unwrap(); + // If we reached here, sqlx::migrate! ran 0001_init + 0002_hnsw without + // error against a fresh pgvector container. +} + +#[tokio::test(flavor = "multi_thread")] +async fn registry_persists_after_first_connect() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _container) = fresh_pg_store(embedder.clone()).await.unwrap(); + let registered = store.registered_model().await.unwrap(); + assert!(registered.is_some()); + let sig = registered.unwrap(); + assert_eq!(sig.name, "test-768"); + assert_eq!(sig.dimension, 768); +} + +#[tokio::test(flavor = "multi_thread")] +async fn second_connect_with_same_embedder_is_idempotent() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store_a, container) = fresh_pg_store(embedder.clone()).await.unwrap(); + // Reuse the same container, build a second store against the same URL, + // call register_model again. Must not error. + let port = container.get_host_port_ipv4(5432).await.unwrap(); + let url = format!("postgresql://postgres:postgres@127.0.0.1:{port}/postgres"); + let store_b = vestige_core::storage::postgres::PgMemoryStore::connect(&url, 4).await.unwrap(); + store_b.register_model(&embedder.signature()).await.unwrap(); + assert_eq!( + store_a.registered_model().await.unwrap().unwrap().name, + store_b.registered_model().await.unwrap().unwrap().name, + ); +} + +#[tokio::test(flavor = "multi_thread")] +async fn second_connect_with_different_embedder_returns_mismatch() { + if !docker_available() { return; } + let e768 = TestEmbedder::new_768(); + let (_store, container) = fresh_pg_store(e768).await.unwrap(); + let port = container.get_host_port_ipv4(5432).await.unwrap(); + let url = format!("postgresql://postgres:postgres@127.0.0.1:{port}/postgres"); + let store2 = vestige_core::storage::postgres::PgMemoryStore::connect(&url, 4).await.unwrap(); + let e1024 = TestEmbedder::new_1024(); + let err = store2.register_model(&e1024.signature()).await; + assert!(matches!(err, Err(vestige_core::storage::MemoryStoreError::EmbeddingMismatch { .. }))); +} +``` + +### 2. `tests/phase_2/crud_test.rs` + +**Purpose**: insert + get + update + delete round-trip; non-existent id +returns `Ok(None)`; D7+D8 columns (`owner_user_id`, `visibility`, +`shared_with_groups`, `codebase`) round-trip correctly. + +**Tests**: + +```rust +#![cfg(feature = "postgres-backend")] + +mod common; +use common::{docker_available, fresh_pg_store, TestEmbedder}; +use vestige_core::memory::{MemoryRecord, Visibility}; +use uuid::Uuid; + +#[tokio::test(flavor = "multi_thread")] +async fn insert_get_update_delete_roundtrip() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _container) = fresh_pg_store(embedder.clone()).await.unwrap(); + + let mut rec = MemoryRecord::new("hello world"); + rec.tags = vec!["test".into(), "crud".into()]; + rec.embedding = Some(embedder.embed(&rec.content).await.unwrap()); + let id = store.insert(&rec).await.unwrap(); + + let got = store.get(&id).await.unwrap().unwrap(); + assert_eq!(got.content, "hello world"); + assert_eq!(got.tags, vec!["test", "crud"]); + + let mut updated = got.clone(); + updated.content = "hello updated".into(); + updated.embedding = Some(embedder.embed("hello updated").await.unwrap()); + store.update(&updated).await.unwrap(); + let after = store.get(&id).await.unwrap().unwrap(); + assert_eq!(after.content, "hello updated"); + + store.delete(&id).await.unwrap(); + assert!(store.get(&id).await.unwrap().is_none()); +} + +#[tokio::test(flavor = "multi_thread")] +async fn get_nonexistent_returns_ok_none() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _container) = fresh_pg_store(embedder).await.unwrap(); + let missing = Uuid::new_v4(); + assert!(store.get(&missing).await.unwrap().is_none()); +} + +#[tokio::test(flavor = "multi_thread")] +async fn update_nonexistent_returns_not_found() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _container) = fresh_pg_store(embedder.clone()).await.unwrap(); + let mut rec = MemoryRecord::new("ghost"); + rec.id = Uuid::new_v4(); + rec.embedding = Some(embedder.embed("ghost").await.unwrap()); + // Contract: update on a missing id is Err(NotFound) or Ok with + // rows_updated == 0. Whichever 0002d picks is what this test asserts. + let res = store.update(&rec).await; + // Adjust to actual contract once 0002d lands: + assert!(res.is_err() || res.is_ok()); +} + +#[tokio::test(flavor = "multi_thread")] +async fn d7_d8_columns_roundtrip() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _container) = fresh_pg_store(embedder.clone()).await.unwrap(); + + let owner = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap(); + let group_a = Uuid::new_v4(); + let group_b = Uuid::new_v4(); + + let mut rec = MemoryRecord::new("contextful"); + rec.owner_user_id = owner; + rec.visibility = Visibility::Group; + rec.shared_with_groups = vec![group_a, group_b]; + rec.codebase = Some("vestige".to_string()); + rec.embedding = Some(embedder.embed(&rec.content).await.unwrap()); + + let id = store.insert(&rec).await.unwrap(); + let got = store.get(&id).await.unwrap().unwrap(); + + assert_eq!(got.owner_user_id, owner); + assert_eq!(got.visibility, Visibility::Group); + assert_eq!(got.shared_with_groups, vec![group_a, group_b]); + assert_eq!(got.codebase.as_deref(), Some("vestige")); +} +``` + +### 3. `tests/phase_2/search_test.rs` + +**Purpose**: exercise the three search modes (fts only, vector only, +hybrid), then the domain/tag/node_type/min_retrievability filters, then +the empty-query edge case. + +**Tests**: + +```rust +#![cfg(feature = "postgres-backend")] + +mod common; +use common::{docker_available, fresh_pg_store, TestEmbedder}; +use vestige_core::memory::MemoryRecord; +use vestige_core::storage::SearchQuery; + +async fn seed(store: &impl vestige_core::storage::MemoryStore, embedder: &(impl vestige_core::embedder::Embedder + ?Sized)) { + let seeds: &[(&str, &[&str], &str)] = &[ + ("rust async trait", &["rust", "async"], "code"), + ("postgres hnsw vector", &["postgres", "vector"], "code"), + ("fastembed onnx model", &["embeddings", "onnx"], "model"), + ("breakfast tacos recipe", &["food"], "note"), + ("morning bike commute", &["health"], "event"), + ]; + for (text, tags, node_type) in seeds { + let mut r = MemoryRecord::new(*text); + r.tags = tags.iter().map(|s| s.to_string()).collect(); + r.node_type = node_type.to_string(); + r.embedding = Some(embedder.embed(text).await.unwrap()); + store.insert(&r).await.unwrap(); + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn fts_only_returns_keyword_matches() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _c) = fresh_pg_store(embedder.clone()).await.unwrap(); + seed(&store, embedder.as_ref()).await; + + let q = SearchQuery { text: Some("rust".into()), embedding: None, limit: 10, ..Default::default() }; + let hits = store.search(&q).await.unwrap(); + assert!(hits.iter().any(|h| h.content.contains("rust async trait"))); +} + +#[tokio::test(flavor = "multi_thread")] +async fn vector_only_returns_semantic_matches() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _c) = fresh_pg_store(embedder.clone()).await.unwrap(); + seed(&store, embedder.as_ref()).await; + + let qe = embedder.embed("vector search").await.unwrap(); + let q = SearchQuery { text: None, embedding: Some(qe), limit: 10, ..Default::default() }; + let hits = store.search(&q).await.unwrap(); + assert!(!hits.is_empty()); +} + +#[tokio::test(flavor = "multi_thread")] +async fn hybrid_returns_rrf_fused_results() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _c) = fresh_pg_store(embedder.clone()).await.unwrap(); + seed(&store, embedder.as_ref()).await; + + let qe = embedder.embed("postgres vector").await.unwrap(); + let q = SearchQuery { + text: Some("postgres".into()), + embedding: Some(qe), + limit: 10, + ..Default::default() + }; + let hits = store.search(&q).await.unwrap(); + let top = hits.first().unwrap(); + assert!(top.content.contains("postgres")); + // RRF score must be at least the floor of two contributions at rank 0. + assert!(top.score >= 1.0 / 61.0); +} + +#[tokio::test(flavor = "multi_thread")] +async fn filter_by_tag_and_node_type() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _c) = fresh_pg_store(embedder.clone()).await.unwrap(); + seed(&store, embedder.as_ref()).await; + + let q = SearchQuery { + text: Some("model".into()), + tags: vec!["embeddings".into()], + node_type: Some("model".into()), + limit: 10, + ..Default::default() + }; + let hits = store.search(&q).await.unwrap(); + assert!(hits.iter().all(|h| h.tags.contains(&"embeddings".into()))); + assert!(hits.iter().all(|h| h.node_type == "model")); +} + +#[tokio::test(flavor = "multi_thread")] +async fn min_retrievability_filter() { + // After 0002e ships the filter wiring this exercises it. For now, + // assert the empty / pass-through case: min_retrievability = 0.0 + // returns all results. + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _c) = fresh_pg_store(embedder.clone()).await.unwrap(); + seed(&store, embedder.as_ref()).await; + + let q = SearchQuery { text: Some("rust".into()), min_retrievability: 0.0, limit: 10, ..Default::default() }; + let hits = store.search(&q).await.unwrap(); + assert!(!hits.is_empty()); +} + +#[tokio::test(flavor = "multi_thread")] +async fn empty_query_returns_ok_empty_or_all() { + // Contract chosen in 0002e; this test asserts whichever it picks. + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _c) = fresh_pg_store(embedder).await.unwrap(); + let q = SearchQuery { text: None, embedding: None, limit: 10, ..Default::default() }; + let hits = store.search(&q).await.unwrap(); + let _ = hits; // assert is intentionally weak until 0002e fixes the contract +} +``` + +### 4. `tests/phase_2/scheduling_test.rs` + +**Purpose**: FSRS state round-trip via `get_scheduling` / +`update_scheduling` with `ON CONFLICT DO UPDATE` semantics, and +`get_due_memories` paging. + +**Tests**: + +```rust +#![cfg(feature = "postgres-backend")] + +mod common; +use common::{docker_available, fresh_pg_store, TestEmbedder}; +use chrono::{Duration, Utc}; +use vestige_core::memory::MemoryRecord; +use vestige_core::scheduling::SchedulingState; + +#[tokio::test(flavor = "multi_thread")] +async fn scheduling_update_and_get_roundtrip() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _c) = fresh_pg_store(embedder.clone()).await.unwrap(); + + let mut rec = MemoryRecord::new("fsrs target"); + rec.embedding = Some(embedder.embed("fsrs target").await.unwrap()); + let id = store.insert(&rec).await.unwrap(); + + let s = SchedulingState { + memory_id: id, + stability: 2.5, + difficulty: 6.7, + reps: 1, + lapses: 0, + next_review: Utc::now() + Duration::days(1), + last_review: Some(Utc::now()), + }; + store.update_scheduling(&s).await.unwrap(); + + let back = store.get_scheduling(&id).await.unwrap().unwrap(); + assert!((back.stability - 2.5).abs() < 1e-6); + assert_eq!(back.reps, 1); +} + +#[tokio::test(flavor = "multi_thread")] +async fn scheduling_on_conflict_overwrites() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _c) = fresh_pg_store(embedder.clone()).await.unwrap(); + + let mut rec = MemoryRecord::new("repeating"); + rec.embedding = Some(embedder.embed("repeating").await.unwrap()); + let id = store.insert(&rec).await.unwrap(); + + for reps in [1u32, 2, 3] { + let s = SchedulingState { + memory_id: id, + stability: reps as f32, + difficulty: 5.0, + reps, + lapses: 0, + next_review: Utc::now() + Duration::days(reps as i64), + last_review: Some(Utc::now()), + }; + store.update_scheduling(&s).await.unwrap(); + } + let final_state = store.get_scheduling(&id).await.unwrap().unwrap(); + assert_eq!(final_state.reps, 3); +} + +#[tokio::test(flavor = "multi_thread")] +async fn get_due_memories_pages() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _c) = fresh_pg_store(embedder.clone()).await.unwrap(); + + let now = Utc::now(); + // Insert 25 due memories with next_review in the past. + for i in 0..25 { + let mut rec = MemoryRecord::new(format!("due {i}")); + rec.embedding = Some(embedder.embed(&rec.content).await.unwrap()); + let id = store.insert(&rec).await.unwrap(); + let s = SchedulingState { + memory_id: id, + stability: 1.0, + difficulty: 5.0, + reps: 1, + lapses: 0, + next_review: now - Duration::hours(i as i64 + 1), + last_review: Some(now - Duration::hours(i as i64 + 2)), + }; + store.update_scheduling(&s).await.unwrap(); + } + let page1 = store.get_due_memories(now, 10, 0).await.unwrap(); + let page2 = store.get_due_memories(now, 10, 10).await.unwrap(); + let page3 = store.get_due_memories(now, 10, 20).await.unwrap(); + assert_eq!(page1.len(), 10); + assert_eq!(page2.len(), 10); + assert_eq!(page3.len(), 5); +} +``` + +### 5. `tests/phase_2/graph_test.rs` + +**Purpose**: `add_edge`, `get_edges`, `remove_edge`, and `get_neighbors` +with a non-trivial depth. + +**Tests**: + +```rust +#![cfg(feature = "postgres-backend")] + +mod common; +use common::{docker_available, fresh_pg_store, TestEmbedder}; +use vestige_core::memory::MemoryRecord; +use vestige_core::storage::Edge; + +async fn insert_n(store: &impl vestige_core::storage::MemoryStore, embedder: &(impl vestige_core::embedder::Embedder + ?Sized), n: usize) -> Vec { + let mut ids = Vec::with_capacity(n); + for i in 0..n { + let mut r = MemoryRecord::new(format!("node {i}")); + r.embedding = Some(embedder.embed(&r.content).await.unwrap()); + ids.push(store.insert(&r).await.unwrap()); + } + ids +} + +#[tokio::test(flavor = "multi_thread")] +async fn add_get_remove_edge() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _c) = fresh_pg_store(embedder.clone()).await.unwrap(); + let ids = insert_n(&store, embedder.as_ref(), 3).await; + + let e = Edge { + source_id: ids[0], + target_id: ids[1], + edge_type: "semantic".into(), + strength: 0.8, + activation_count: 0, + created_at: chrono::Utc::now(), + last_activated: None, + }; + store.add_edge(&e).await.unwrap(); + + let edges = store.get_edges(&ids[0]).await.unwrap(); + assert_eq!(edges.len(), 1); + assert_eq!(edges[0].target_id, ids[1]); + + store.remove_edge(&ids[0], &ids[1], "semantic").await.unwrap(); + assert!(store.get_edges(&ids[0]).await.unwrap().is_empty()); +} + +#[tokio::test(flavor = "multi_thread")] +async fn get_neighbors_with_depth() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + let (store, _c) = fresh_pg_store(embedder.clone()).await.unwrap(); + let ids = insert_n(&store, embedder.as_ref(), 5).await; + + // Chain: 0 -> 1 -> 2 -> 3 -> 4 + for w in ids.windows(2) { + let e = Edge { + source_id: w[0], + target_id: w[1], + edge_type: "semantic".into(), + strength: 1.0, + activation_count: 0, + created_at: chrono::Utc::now(), + last_activated: None, + }; + store.add_edge(&e).await.unwrap(); + } + + let depth_1 = store.get_neighbors(&ids[0], 1).await.unwrap(); + let depth_2 = store.get_neighbors(&ids[0], 2).await.unwrap(); + let depth_4 = store.get_neighbors(&ids[0], 4).await.unwrap(); + + assert_eq!(depth_1.len(), 1); + assert_eq!(depth_2.len(), 2); + assert_eq!(depth_4.len(), 4); +} +``` + +### 6. `tests/phase_2/migrate_test.rs` + +**Purpose**: seed SQLite with a small dataset, run the migrator, verify +counts and a sample row. + +**Tests**: + +```rust +#![cfg(feature = "postgres-backend")] + +mod common; +use common::{docker_available, fresh_pg_store, TestEmbedder}; +use vestige_core::memory::MemoryRecord; +use vestige_core::storage::{SqliteMemoryStore, MemoryStore}; +use vestige_core::storage::postgres::migrate_cli::run_sqlite_to_postgres; + +#[tokio::test(flavor = "multi_thread")] +async fn sqlite_to_postgres_small_corpus() { + if !docker_available() { return; } + let embedder = TestEmbedder::new_768(); + + // Seed SQLite (in-memory or tempfile). + let tmp = tempfile::tempdir().unwrap(); + let sqlite_path = tmp.path().join("seed.db"); + let sqlite = SqliteMemoryStore::new(&sqlite_path).unwrap(); + sqlite.register_model(&embedder.signature()).await.unwrap(); + for i in 0..50 { + let mut r = MemoryRecord::new(format!("seed row {i}")); + r.tags = vec![format!("tag-{}", i % 3)]; + r.embedding = Some(embedder.embed(&r.content).await.unwrap()); + sqlite.insert(&r).await.unwrap(); + } + + // Spin up Postgres and migrate. + let (pg, _container) = fresh_pg_store(embedder.clone()).await.unwrap(); + let report = run_sqlite_to_postgres(&sqlite, &pg, embedder.clone()).await.unwrap(); + + assert_eq!(report.memories_copied, 50); + assert_eq!(pg.count().await.unwrap(), 50); + + // Spot-check a sample row. + let sample_id = sqlite.list_ids(1, 0).await.unwrap()[0]; + let from_sqlite = sqlite.get(&sample_id).await.unwrap().unwrap(); + let from_pg = pg.get(&sample_id).await.unwrap().unwrap(); + assert_eq!(from_sqlite.content, from_pg.content); + assert_eq!(from_sqlite.tags, from_pg.tags); +} +``` + +If `0002f` is not yet merged when this sub-plan executes, the test file is +still added but the body sits behind `#[ignore = "depends on 0002f"]`, +removed once `0002f` lands. + +--- + +## How tests are run + +```bash +# Run all six phase_2 integration tests: +cargo test -p vestige-core --features postgres-backend --test '*' + +# Run a single file: +cargo test -p vestige-core --features postgres-backend --test init_test +cargo test -p vestige-core --features postgres-backend --test crud_test +cargo test -p vestige-core --features postgres-backend --test search_test +cargo test -p vestige-core --features postgres-backend --test scheduling_test +cargo test -p vestige-core --features postgres-backend --test graph_test +cargo test -p vestige-core --features postgres-backend --test migrate_test + +# SQLite-only sanity check (must continue to pass, Phase 1 unchanged): +cargo test -p vestige-core +``` + +Requirements: + +- Docker or Podman must be reachable. `testcontainers` connects via the + default Docker socket (`/var/run/docker.sock` on Linux, `~/.docker/run/docker.sock` + or the Docker Desktop socket on macOS, the Podman REST socket if + `DOCKER_HOST` points there). +- On a developer machine without Docker, the suite skips at runtime via + the `docker_available()` check in `common/mod.rs`. The test output + includes a `docker unavailable; skip` line per test so the developer + knows the tests were not silently dropped. +- The pgvector image (`pgvector/pgvector:pg16`) is pulled on first run; + ~200 MB. A pre-pulled image keeps the per-run overhead at the cold-start + container boot (~2-5 seconds). + +--- + +## Benches + +**File**: `crates/vestige-core/benches/pg_hybrid_search.rs` + +Two Criterion benches: `search_1k` and `search_100k`. Both gated on the +`postgres-backend` feature via `required-features` in the bench entry and +via a top-of-file `#![cfg(feature = "postgres-backend")]`. + +```rust +//! Criterion benches for the Postgres backend's hybrid RRF search. +#![cfg(feature = "postgres-backend")] + +use std::sync::Arc; +use std::sync::OnceLock; + +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use rand::{rngs::StdRng, Rng, SeedableRng}; +use testcontainers::runners::AsyncRunner; +use testcontainers::{ContainerAsync, ImageExt}; +use testcontainers_modules::postgres::Postgres; +use tokio::runtime::Runtime; + +use vestige_core::embedder::Embedder; +use vestige_core::memory::MemoryRecord; +use vestige_core::storage::postgres::PgMemoryStore; +use vestige_core::storage::{MemoryStore, SearchQuery}; + +// Bench fixture lives in tests/phase_2/common/test_embedder.rs; +// duplicate the type here under benches/ so the bench compiles without +// depending on tests/. +mod test_embedder; +use test_embedder::TestEmbedder; + +struct Bench { + rt: Runtime, + store: PgMemoryStore, + embedder: Arc, + _container: ContainerAsync, + query_embedding: Vec, +} + +async fn build_bench(rows: usize) -> Bench { + let rt_handle = tokio::runtime::Handle::current(); + let _ = rt_handle; // proves we are inside an executor + let embedder = TestEmbedder::new_768(); + let container = Postgres::default() + .with_name("pgvector/pgvector") + .with_tag("pg16") + .start() + .await + .unwrap(); + let port = container.get_host_port_ipv4(5432).await.unwrap(); + let url = format!("postgresql://postgres:postgres@127.0.0.1:{port}/postgres"); + let store = PgMemoryStore::connect(&url, 8).await.unwrap(); + store.run_migrations().await.unwrap(); + store.register_model(&embedder.signature()).await.unwrap(); + + let mut rng = StdRng::seed_from_u64(0xc0ffee); + let vocab = [ + "rust", "postgres", "vector", "hnsw", "fastembed", "onnx", + "search", "memory", "fsrs", "consolidate", "graph", "edge", + "async", "trait", "tokio", "sqlx", "pgvector", "embedding", + ]; + for i in 0..rows { + let words: String = (0..8) + .map(|_| vocab[rng.gen_range(0..vocab.len())]) + .collect::>() + .join(" "); + let mut r = MemoryRecord::new(format!("{i}: {words}")); + r.tags = vec![format!("tag-{}", i % 7)]; + r.embedding = Some(embedder.embed(&r.content).await.unwrap()); + store.insert(&r).await.unwrap(); + } + let query_embedding = embedder.embed("postgres vector search").await.unwrap(); + Bench { + rt: tokio::runtime::Runtime::new().unwrap(), + store, + embedder, + _container: container, + query_embedding, + } +} + +fn bench_search_1k(c: &mut Criterion) { + let rt = tokio::runtime::Runtime::new().unwrap(); + let bench = rt.block_on(build_bench(1_000)); + c.bench_function("pg_search_1k", |b| { + b.iter(|| { + let q = SearchQuery { + text: Some("postgres vector".into()), + embedding: Some(bench.query_embedding.clone()), + limit: 10, + ..Default::default() + }; + let hits = bench.rt.block_on(bench.store.search(&q)).unwrap(); + black_box(hits); + }) + }); +} + +// Heavy: 100k rows; seed time runs into minutes. Gated by an env var so +// `cargo bench --features postgres-backend --bench pg_hybrid_search` does +// not pay the cost by default. +fn bench_search_100k(c: &mut Criterion) { + if std::env::var("VESTIGE_BENCH_HEAVY").is_err() { + eprintln!("skip pg_search_100k (set VESTIGE_BENCH_HEAVY=1 to enable)"); + return; + } + let rt = tokio::runtime::Runtime::new().unwrap(); + let bench = rt.block_on(build_bench(100_000)); + c.bench_function("pg_search_100k", |b| { + b.iter(|| { + let q = SearchQuery { + text: Some("postgres vector".into()), + embedding: Some(bench.query_embedding.clone()), + limit: 10, + ..Default::default() + }; + let hits = bench.rt.block_on(bench.store.search(&q)).unwrap(); + black_box(hits); + }) + }); +} + +criterion_group!(benches, bench_search_1k, bench_search_100k); +criterion_main!(benches); +``` + +**File**: `crates/vestige-core/benches/test_embedder.rs` + +Duplicate of `tests/phase_2/common/test_embedder.rs`. Cargo's bench target +cannot `mod` into `tests/`; the duplication is the standard fix. Keep both +files in sync; if either grows non-trivially, refactor into a shared +`pub(crate)` module under `src/embedder/test_support.rs` gated on +`#[cfg(any(test, feature = "test-support"))]`. + +`VESTIGE_BENCH_HEAVY` gate: the 100k seed step takes several minutes (one +`INSERT` per row plus HNSW upsert). Skipping by default keeps `cargo bench` +under a minute for the 1k bench. Document this gate in the runbook +(`0002i`). + +--- + +## Cargo.toml + +Final state of the relevant sections of +`crates/vestige-core/Cargo.toml` after this sub-plan lands: + +```toml +[dev-dependencies] +tempfile = "3" +criterion = { version = "0.5", features = ["html_reports"] } +anyhow = "1" +tokio = { version = "1", features = ["rt-multi-thread", "macros"] } +rand = "0.8" +testcontainers = { version = "0.22", optional = true } +testcontainers-modules = { version = "0.10", features = ["postgres"], optional = true } + +[[bench]] +name = "search_bench" +harness = false + +[[bench]] +name = "pg_hybrid_search" +harness = false +required-features = ["postgres-backend"] + +[[test]] +name = "init_test" +path = "tests/phase_2/init_test.rs" +required-features = ["postgres-backend"] + +[[test]] +name = "crud_test" +path = "tests/phase_2/crud_test.rs" +required-features = ["postgres-backend"] + +[[test]] +name = "search_test" +path = "tests/phase_2/search_test.rs" +required-features = ["postgres-backend"] + +[[test]] +name = "scheduling_test" +path = "tests/phase_2/scheduling_test.rs" +required-features = ["postgres-backend"] + +[[test]] +name = "graph_test" +path = "tests/phase_2/graph_test.rs" +required-features = ["postgres-backend"] + +[[test]] +name = "migrate_test" +path = "tests/phase_2/migrate_test.rs" +required-features = ["postgres-backend"] +``` + +Notes: + +- `required-features = ["postgres-backend"]` on each `[[test]]` ensures + the file is only built (and only counted by `cargo test`) when the + feature is on. Cargo silently skips it otherwise -- exactly the desired + behavior for default `cargo test` runs. +- The benches use the same `required-features` shape so default + `cargo bench` is unaffected. + +--- + +## CI considerations + +- GitHub Actions / Forgejo Actions runners need Docker available. Default + `ubuntu-latest` runners include Docker. Self-hosted Forgejo runners on + TFGrid VMs must install `docker.io` or run `podman` with the Docker + socket compatibility shim. Document the runner requirement in the + runbook (`0002i`). +- The Postgres feature tests should run in a separate CI matrix entry to + isolate failures and skip them entirely on platforms (Windows runners + if any) where the pgvector image is not available. +- Cache the `pgvector/pgvector:pg16` image between runs. The + `docker/setup-buildx-action` cache or a simple `docker pull` step before + the test step keeps cold-start under the existing CI time budget. +- Skip CI: contributors without Docker can still merge changes that do + not touch `storage/postgres/`. The pre-merge required check is "phase_2 + tests pass on the runner with Docker"; the local pre-commit hook does + not gate on it. +- Bench CI: do not run `pg_search_100k` in regular CI; only run it + manually or on a scheduled weekly job and post results to the PR + description / ADR comment trail. + +Recommended CI job shape (sketch): + +```yaml +jobs: + postgres-tests: + runs-on: ubuntu-latest + services: + # no `postgres` service block needed; testcontainers manages its own + steps: + - uses: actions/checkout@v4 + - run: docker pull pgvector/pgvector:pg16 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test -p vestige-core --features postgres-backend --test '*' +``` + +--- + +## Verification + +After all files are in place: + +```bash +# Default build still clean (no postgres deps pulled in): +cargo build -p vestige-core +cargo test -p vestige-core + +# Postgres feature build + integration tests: +cargo build -p vestige-core --features postgres-backend +cargo test -p vestige-core --features postgres-backend + +# Just the new tests: +cargo test -p vestige-core --features postgres-backend --test '*' + +# Quick bench sanity check (1k only): +cargo bench -p vestige-core --features postgres-backend --bench pg_hybrid_search -- --quick + +# Heavy bench (manual, multi-minute seed step): +VESTIGE_BENCH_HEAVY=1 cargo bench -p vestige-core \ + --features postgres-backend \ + --bench pg_hybrid_search -- --quick + +# Clippy with everything on: +cargo clippy -p vestige-core --features postgres-backend --all-targets -- -D warnings +``` + +Expected results: + +- Default build is unchanged; no testcontainers deps in `Cargo.lock`'s + default resolution. +- With `--features postgres-backend`, all six integration tests pass on a + machine with Docker available, or each prints `docker unavailable; skip` + and exits 0. +- `cargo bench ... -- --quick` produces a `pg_search_1k` line with a + p50 below the master plan's 10 ms target on a developer laptop (looser + on a CI runner -- the target is informative, not gated). + +--- + +## Acceptance criteria + +- [ ] `crates/vestige-core/tests/phase_2/common/mod.rs` and + `test_embedder.rs` exist and compile under + `--features postgres-backend`. +- [ ] All six integration test files exist, each with + `#![cfg(feature = "postgres-backend")]` at the top. +- [ ] Each test file has a corresponding `[[test]]` entry in + `Cargo.toml` with `required-features = ["postgres-backend"]`. +- [ ] `crates/vestige-core/benches/pg_hybrid_search.rs` exists with + `search_1k` and `search_100k` benches, the latter gated on + `VESTIGE_BENCH_HEAVY`. +- [ ] `[[bench]] name = "pg_hybrid_search"` entry present with + `required-features = ["postgres-backend"]`. +- [ ] `testcontainers@0.22` and `testcontainers-modules@0.10` with the + `postgres` feature are in `[dev-dependencies]` of `vestige-core`. +- [ ] `anyhow`, `tokio`, `rand` are in `[dev-dependencies]`. +- [ ] `cargo build -p vestige-core` (default features) is unchanged: no + testcontainers in the build graph; no new warnings. +- [ ] `cargo test -p vestige-core` (default features) passes with no + changes to the Phase 1 test count beyond what `0002a..g` already + moved. +- [ ] `cargo test -p vestige-core --features postgres-backend --test '*'` + passes on a runner with Docker available, or skips cleanly with the + `docker unavailable; skip` lines. +- [ ] `cargo bench -p vestige-core --features postgres-backend + --bench pg_hybrid_search -- --quick` runs `pg_search_1k` to + completion and does NOT run `pg_search_100k` unless + `VESTIGE_BENCH_HEAVY=1`. +- [ ] `cargo clippy -p vestige-core --features postgres-backend + --all-targets -- -D warnings` is clean. +- [ ] The runbook (`0002i`) gets a one-paragraph "How to run the test + suite locally" callout referring back to this sub-plan's + "Verification" section. (`0002i` is owned separately; this sub-plan + just lists the dependency.) + +--- + +## Open questions for the implementer + +1. **Migration helper name.** `0002c` decides whether + `PgMemoryStore::run_migrations(&self)` or + `vestige_core::storage::postgres::migrations::run(&pool)` is the public + call. Update `common/mod.rs` to match. +2. **Update-on-missing contract.** `0002d` decides whether + `MemoryStore::update` returns `Err(NotFound)` or `Ok(())` with zero + affected rows when the id does not exist. The CRUD test stub here + accepts either; tighten the assert once the contract is fixed. +3. **Empty-query search contract.** `0002e` decides whether + `SearchQuery { text: None, embedding: None }` is `Ok(empty)` or an + error. Same tightening pattern as #2. +4. **Pool size for 100k bench.** Current value is 8; if the bench + bottlenecks on the pool, tune up to 16 or 32 and document in the + bench file's leading doc comment. +5. **Shared `TestEmbedder` location.** Currently duplicated between + `tests/phase_2/common/test_embedder.rs` and + `benches/test_embedder.rs`. If duplication bothers a reviewer, lift to + `crates/vestige-core/src/embedder/test_support.rs` behind a + `test-support` Cargo feature pulled in by both `tests` and `benches`. + Out of scope for this sub-plan; record as a follow-up. diff --git a/docs/plans/0002i-runbook.md b/docs/plans/0002i-runbook.md new file mode 100644 index 0000000..f63694f --- /dev/null +++ b/docs/plans/0002i-runbook.md @@ -0,0 +1,724 @@ +# Phase 2 Sub-Plan 0002i -- Postgres Ops Runbook + +**Status**: Ready +**Depends on**: Phase 2 sub-plans 0002a through 0002h merged (or at least +their interfaces stable). The runbook documents behaviour produced by those +sub-plans: feature gate, config schema, migrations, `vestige migrate` CLI, +hybrid search, and the test harness. Nothing in this sub-plan compiles or +runs; the deliverable is a single Markdown file. + +This sub-plan covers Phase 2 master-plan deliverable D16 only: a one-page +operator-facing runbook for deploying Vestige with the Postgres backend. + +--- + +## Context + +Why a runbook. The ADR (0002) and the master plan (0002) are written for +implementors. They settle execution-level decisions and itemise deliverables. +They are not deployable instructions. A separate document is needed for the +operator who has to install pgvector, take backups, recover from a failed +re-embed, and decide whether to roll a migration back. The runbook is that +document. + +Who reads it. Ops people, not developers. Concretely: someone who has a +shell on a Linux host, knows how to use `psql` and `systemctl`, and has been +handed a built `vestige-mcp` binary plus a `vestige.toml`. They are not +expected to read Rust source or follow internal Cargo features. They do +know what a backup is, what a connection pool is, and how to read a +PostgreSQL log. + +In scope: deployment of the Postgres backend on a single host or a small +cluster, day-to-day monitoring, scheduled and ad-hoc backups, embedding +migration via `vestige migrate reembed`, and troubleshooting the failure +modes most likely to land in an operator's lap. + +Out of scope: local development setup -- that lives in +`docs/plans/local-dev-postgres-setup.md` and the runbook links to it for +developer onboarding only. Network exposure of the Vestige HTTP API +(Phase 3), federation (Phase 5), Postgres TLS / certificate handling, and +multi-tenant operation are also out of scope; the runbook explicitly +flags them as "see Phase N" so operators do not improvise. + +This sub-plan is the plan for producing the runbook. It outlines the +runbook structure, inlines the runbook body as the canonical "this is what +the file should say" text, and lists acceptance criteria. The implementation +agent for D16 copies the inlined body into `docs/runbook/postgres.md`, +creating `docs/runbook/` if it does not already exist. No other files in the +repository are modified. + +--- + +## Deliverable + +The artifact produced by executing this sub-plan is exactly one new file: + +``` +docs/runbook/postgres.md +``` + +It is NOT under `docs/plans/`. Plans describe how Vestige gets built; +runbooks describe how Vestige gets operated. The two directories are +deliberately separated. + +Side effect: create the directory `docs/runbook/` if it does not exist. +Do not add an index file, README, or any other content under `docs/runbook/` +in this sub-plan -- only `postgres.md`. + +This sub-plan document (`docs/plans/0002i-runbook.md`) is itself NOT a +deliverable in the operator sense. It is the plan for producing the runbook, +and lives under `docs/plans/` with the other Phase 2 sub-plans. + +--- + +## Runbook structure + +The runbook is organised as a flat list of ten sections, in order. Operators +read it top to bottom on first deployment; subsequent visits jump to a +specific section. Section numbering matches the inlined body below. + +1. **Prerequisites** -- what must already be installed and available on the + host before Vestige even tries to connect. PostgreSQL 16 or newer + (18 on Arch is fine), pgvector >= 0.5, pgcrypto (for `gen_random_uuid`), + sufficient disk for the HNSW index, OS user permissions on the data + directory. + +2. **Initial setup** -- one-time tasks: create the database role, create + the database, install required extensions, and lay down an initial + `vestige.toml`. Includes the canonical `CREATE EXTENSION` calls and a + minimal config snippet. + +3. **First connect** -- what happens the first time `vestige-mcp` starts + against an empty `vestige` database: sqlx applies the bundled + migrations, `register_model` stamps the embedding column type, and the + registry row is written. How an operator verifies each step succeeded + using `psql`. + +4. **Connection pool tuning** -- default of 10 connections per + `vestige-mcp` instance, when to raise it, how to size the Postgres + server-side `max_connections` and `shared_buffers` accordingly. Cross- + reference to `vestige.toml` and to ADR 0002 D2 / open question Q5. + +5. **Backup discipline** -- `pg_dump` and `pg_restore` invocations, + recommended frequency, which tables matter (knowledge_nodes and scheduling + are critical and not regenerable; review_events is append-only and + replayable from clients; edges are reconstructable from spreading + activation runs; domains can be recomputed by Phase 4 once it ships). + Also covers backup verification (restore-to-tmp drill). + +6. **Migration between embeddings** -- the `vestige migrate reembed` + workflow: when an operator needs it (model upgrade, dim change), + downtime expectations, how to verify completion via the + `embedding_model` registry and HNSW presence, and how to recover from + an interrupted run. + +7. **Re-clustering domains** -- a brief forward reference. Domain + clustering is owned by Phase 4 (`docs/plans/0004-phase-4-emergent-domain-classification.md`); + until Phase 4 ships, operators should not invoke any re-clustering + workflow manually. The runbook section is intentionally one paragraph + long and points at the Phase 4 plan. + +8. **Monitoring** -- the small set of pg_catalog and pg_stat_* queries + that answer "is Vestige healthy?": `pg_stat_activity` for stuck queries, + `pg_stat_statements` for query patterns (if the extension is enabled), + index sizes for the HNSW, and how to spot a half-built HNSW after a + failed migration. + +9. **Troubleshooting** -- a table of common errors with the symptom and + the fix. Extension missing, pool exhausted, embedding dimension + mismatch, FTS language config (`'english'` vs `'simple'`), migrations + partially applied. + +10. **Rollback caveats** -- every `*.up.sql` has a `*.down.sql`, but + downgrades destroy data (HNSW gets dropped, vector column type + reverts, domain rows vanish). The runbook tells operators to always + take a backup before applying a new migration, even though sqlx will + do its best to be idempotent. + +--- + +## Runbook body + +The full text below is what should be copied verbatim into +`docs/runbook/postgres.md`. ASCII only. Code blocks use fenced syntax with +language hints. Operator-facing prose; second person ("you") for +instructions. Where a command requires sudo, the prompt shows it explicitly. + +```markdown +# Vestige Postgres Backend -- Operator Runbook + +This runbook covers deploying, operating, monitoring, and recovering a +Vestige installation that uses the Postgres backend. It is written for +operators handling a built `vestige-mcp` binary and a `vestige.toml`. + +For local development setup, see +`docs/plans/local-dev-postgres-setup.md`. For the architectural rationale, +see `docs/adr/0001-pluggable-storage-and-network-access.md` and +`docs/adr/0002-phase-2-execution.md`. For the deliverable-level plan, see +`docs/plans/0002-phase-2-postgres-backend.md`. + +--- + +## 1. Prerequisites + +Before Vestige can connect: + +- PostgreSQL server, version 16 or newer. Arch ships 18.x; Debian stable + ships 16.x; both work. +- `pgvector` extension, version 0.5 or newer. Distro packages: + `pgvector` on Arch, `postgresql-16-pgvector` on Debian/Ubuntu. +- `pgcrypto` extension, shipped with the PostgreSQL contrib package + (`postgresql-contrib` on Debian, included in the base `postgresql` + package on Arch). Vestige uses `gen_random_uuid()` from pgcrypto for + primary keys. +- Disk space: budget roughly 4x the size of your `knowledge_nodes.embedding` + column for the HNSW index. With 768-dim float32 vectors at 100k + memories, that is about 1.2 GB for the embeddings plus 4-5 GB for the + HNSW index. Plan accordingly. +- OS user: the `postgres` system user (or whatever user owns + `/var/lib/postgres/data`) must have read/write on the data directory. + Vestige itself does not need filesystem access to Postgres; it talks + TCP only. +- Network: Vestige and Postgres can be on the same host (loopback) or + different hosts. If different hosts, allow the Vestige host's IP in + `pg_hba.conf` and on any firewall. + +--- + +## 2. Initial setup + +These steps run once per Postgres cluster. + +### 2.1 Install extensions + +As the `postgres` superuser: + +```sh +sudo -u postgres psql -d vestige <<'SQL' +CREATE EXTENSION IF NOT EXISTS vector; +CREATE EXTENSION IF NOT EXISTS pgcrypto; +SQL +``` + +Verify: + +```sh +sudo -u postgres psql -d vestige -c \ + "SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector','pgcrypto');" +``` + +You should see two rows. If `vector` is missing, the pgvector package was +not installed for the right PostgreSQL major version; reinstall it. + +### 2.2 Create the role and database + +The `vestige` role owns its own database; it does NOT need superuser. +Extensions must be installed by `postgres`, not by `vestige`. + +```sh +sudo -u postgres psql -v ON_ERROR_STOP=1 <<'SQL' +CREATE ROLE vestige WITH LOGIN CREATEDB PASSWORD 'CHANGE_ME'; +CREATE DATABASE vestige OWNER vestige ENCODING 'UTF8'; +GRANT ALL PRIVILEGES ON DATABASE vestige TO vestige; +SQL + +sudo -u postgres psql -d vestige -v ON_ERROR_STOP=1 <<'SQL' +GRANT ALL ON SCHEMA public TO vestige; +ALTER SCHEMA public OWNER TO vestige; +ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO vestige; +ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO vestige; +ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON FUNCTIONS TO vestige; +SQL +``` + +Replace `CHANGE_ME` with a strong password and store it where Vestige can +read it (typically `~/.vestige_pg_pw`, mode 600, owned by the user running +`vestige-mcp`). + +### 2.3 Minimal `vestige.toml` + +```toml +[storage] +backend = "postgres" + +[storage.postgres] +url = "postgresql://vestige:CHANGE_ME@127.0.0.1:5432/vestige" +max_connections = 10 +``` + +The `url` field accepts a `${VAR}` placeholder; in practice operators +either inline the password or export `DATABASE_URL` and reference +`url = "${DATABASE_URL}"`. See `docs/CONFIGURATION.md` for the full +schema once Phase 3 lands. + +--- + +## 3. First connect + +When `vestige-mcp` starts against an empty `vestige` database, it: + +1. Builds a `PgPool` of `max_connections` (default 10) connections. +2. Runs every migration in `crates/vestige-core/migrations/postgres/` + in order. The bundled migrations are `0001_init` (tables, non-vector + indexes) and `0002_hnsw` (HNSW index on `knowledge_nodes.embedding`). +3. Calls `register_model` once it knows the active embedder's dimension. + This issues `ALTER TABLE knowledge_nodes ALTER COLUMN embedding TYPE + vector($N)` and inserts a row into `embedding_model`. +4. Begins accepting MCP requests. + +To verify after the first start: + +```sh +sudo -u postgres psql -d vestige <<'SQL' +-- All expected tables present. +\dt +-- embedding_model has exactly one row. +SELECT name, dimension, hash FROM embedding_model; +-- The HNSW index exists. +SELECT indexname FROM pg_indexes + WHERE tablename = 'knowledge_nodes' AND indexname LIKE '%hnsw%'; +SQL +``` + +Expected: `knowledge_nodes`, `scheduling`, `edges`, `domains`, `review_events`, +`embedding_model`, `users`, `groups`, `group_memberships`; one row in +`embedding_model`; one `idx_knowledge_nodes_embedding_hnsw` index. + +If a migration fails mid-way, the partial state lands in +`_sqlx_migrations`. See section 9 for recovery. + +--- + +## 4. Connection pool tuning + +Defaults: + +- Vestige client pool: `max_connections = 10` per `vestige-mcp` instance. +- Postgres server: `max_connections = 100` (default). + +Math: one MCP client with the default pool uses up to 10 server slots. +Five concurrent MCP clients use up to 50 slots. The remaining 50 cover +`psql` sessions, background workers, and headroom for replication or +backup processes. + +When to raise: + +- More than three MCP clients connecting to one Postgres instance. +- Long-running queries (above 500ms p99) showing pool wait time in + Vestige logs (look for `pool acquire timed out` warnings). +- A noticeable number of concurrent dream/consolidation runs. + +How to raise: + +```toml +[storage.postgres] +max_connections = 20 # client side, per vestige-mcp instance +``` + +And on the Postgres server, edit `postgresql.conf`: + +```conf +max_connections = 200 +shared_buffers = 2GB # roughly 25 percent of RAM, never above 8GB +``` + +Then restart Postgres (`sudo systemctl restart postgresql`). Vestige +clients pick up their own `max_connections` change on next restart. + +Do not raise pool sizes blindly. Past about 4x the CPU core count, +Postgres throughput drops; a small connection pooler (PgBouncer in +transaction mode) is the right answer above ~200 client connections, +but Vestige's expected scale rarely needs that. + +--- + +## 5. Backup discipline + +### 5.1 Which tables matter + +| Table | Backup priority | Regenerable? | +|-------|-----------------|--------------| +| `knowledge_nodes` | Critical | No | +| `scheduling` | Critical | No (FSRS state) | +| `embedding_model` | Critical | No (one row, but stamps the column type) | +| `users`, `groups`, `group_memberships` | Critical | No (Phase 3 will populate) | +| `review_events` | Important | Replayable by clients but tedious | +| `edges` | Optional | Yes (recomputed by spreading activation) | +| `domains` | Optional | Yes (Phase 4 recomputes by clustering) | + +For a typical single-operator install, dumping the whole database is +fastest and simplest. Skip the optional tables only if dump size becomes +a bandwidth problem. + +### 5.2 Full logical backup + +```sh +pg_dump --host=127.0.0.1 --username=vestige --format=custom \ + --file=vestige-$(date -u +%Y%m%dT%H%M%SZ).dump \ + vestige +``` + +The custom format compresses by default and works with parallel restore. +File size for 10k memories: roughly 80 MB. + +Frequency recommendations: + +- Daily for any installation with active ingest. +- Before every `vestige migrate reembed` run (see section 6). +- Before every Postgres major-version upgrade. +- Retain at least 7 daily, 4 weekly, 3 monthly dumps. Compress with + `--format=custom` (already gzipped) and keep them on different + storage from the database itself. + +### 5.3 Restore + +To a fresh database: + +```sh +sudo -u postgres createdb -O vestige vestige_restore +pg_restore --host=127.0.0.1 --username=vestige --dbname=vestige_restore \ + --jobs=4 vestige-20260301T030000Z.dump +``` + +To replace the live database (destructive; only after taking a fresh +dump): + +```sh +sudo systemctl stop vestige-mcp # or however the service is run +sudo -u postgres dropdb vestige +sudo -u postgres createdb -O vestige vestige +pg_restore --host=127.0.0.1 --username=vestige --dbname=vestige \ + --jobs=4 vestige-20260301T030000Z.dump +sudo systemctl start vestige-mcp +``` + +### 5.4 Restore drill + +Run a restore-to-throwaway-database every month and run `vestige search` +or a manual `psql` count against it. A backup you have not restored is a +backup you do not have. + +```sh +sudo -u postgres createdb -O vestige vestige_restore_drill +pg_restore --host=127.0.0.1 --username=vestige --dbname=vestige_restore_drill \ + --jobs=4 vestige-latest.dump +PGPASSWORD="$(cat ~/.vestige_pg_pw)" psql -h 127.0.0.1 -U vestige \ + -d vestige_restore_drill \ + -c 'SELECT count(*) FROM knowledge_nodes;' +sudo -u postgres dropdb vestige_restore_drill +``` + +--- + +## 6. Migration between embeddings + +Use `vestige migrate reembed` when: + +- Upgrading to a new embedding model that produces a different dimension + (for example, swapping from `nomic-embed-text-v1.5` 768D to a 1024D + model). +- Switching providers and the model hash differs even at the same + dimension. + +What it does: + +1. Reads every row from `knowledge_nodes`, re-encodes the `content` column + through the new embedder, and writes the new vector back. +2. Drops the HNSW index before the re-encode loop (this is the default; + `--concurrent-index` keeps it during the run at the cost of speed). +3. Updates the `embedding_model` row with the new name, dimension, and + hash. +4. Rebuilds the HNSW index with the new vectors. + +### 6.1 Before starting + +- Take a fresh backup (section 5.2). The tool refuses to start without a + `--yes` flag if it detects no recent backup; ignore at your peril. +- Stop ingest. Vestige's MCP server can stay running for read-only + access, but pause any client that calls `smart_ingest` or + `update_scheduling`. +- Have the new embedder model available locally. The CLI loads it + before the first row is touched; if loading fails, no data is changed. + +### 6.2 Running + +```sh +vestige migrate reembed --model= --yes +``` + +Add `--concurrent-index` if you cannot accept the brief window during +HNSW rebuild where queries do not use the index (sequential scan +fallback works but is slow). + +The tool prints a progress bar via `indicatif`. Expected throughput: +roughly 200 memories per second per CPU core for a 768D ONNX model. +10,000 memories on an 8-core box: about 6 seconds, plus HNSW rebuild +(another 30-90 seconds at that scale). + +### 6.3 Verifying completion + +```sh +sudo -u postgres psql -d vestige <<'SQL' +-- Registry reflects the new model. +SELECT name, dimension, hash FROM embedding_model; +-- HNSW index is present and not partial. +SELECT indexname, indexdef + FROM pg_indexes + WHERE tablename = 'knowledge_nodes' AND indexname LIKE '%hnsw%'; +-- All rows have a non-null embedding of the new dimension. +SELECT count(*) FILTER (WHERE embedding IS NULL) AS missing, + count(*) AS total + FROM knowledge_nodes; +SQL +``` + +Expected: registry shows the new model name and dimension, one HNSW +index, zero missing embeddings. + +### 6.4 Recovering from an interrupted run + +`vestige migrate reembed` is restartable. On interruption: + +- The `embedding_model` row may or may not have been updated. Check it + manually and roll forward by re-running with `--yes --resume` (the + tool detects the inconsistency and finishes the rows that still hold + old embeddings). +- The HNSW index may be missing. Re-running the command rebuilds it as + its last step. +- If the system is in a state the tool refuses to reason about, restore + from the backup taken in 6.1. + +--- + +## 7. Re-clustering domains + +Domain clustering is owned by Phase 4 +(`docs/plans/0004-phase-4-emergent-domain-classification.md`). Until +Phase 4 ships, the `domains` table is reserved schema and is populated +only by tests. Operators must not invoke any domain re-clustering +workflow manually; there is no supported one in Phase 2. + +When Phase 4 lands, this section is replaced with the real procedure. + +--- + +## 8. Monitoring + +### 8.1 Quick health check + +```sh +PGPASSWORD="$(cat ~/.vestige_pg_pw)" psql -h 127.0.0.1 -U vestige -d vestige <<'SQL' +SELECT count(*) AS memory_count FROM knowledge_nodes; +SELECT name, dimension FROM embedding_model; +SELECT pg_size_pretty(pg_database_size('vestige')) AS db_size; +SQL +``` + +### 8.2 In-flight queries + +```sql +SELECT pid, now() - query_start AS runtime, state, query + FROM pg_stat_activity + WHERE datname = 'vestige' AND state <> 'idle' + ORDER BY runtime DESC NULLS LAST; +``` + +Anything over 5 seconds with `state = 'active'` deserves a look. HNSW +search queries should land well under 100ms on properly-sized hardware. + +### 8.3 Query pattern analysis + +If `pg_stat_statements` is loaded (`shared_preload_libraries = +'pg_stat_statements'` in `postgresql.conf`): + +```sql +SELECT calls, mean_exec_time, query + FROM pg_stat_statements + WHERE query ILIKE '%knowledge_nodes%' + ORDER BY mean_exec_time DESC + LIMIT 20; +``` + +Look for hybrid-search queries that have drifted above 100ms p50. The +usual culprit is a missing or half-built HNSW index. + +### 8.4 Index health + +```sql +SELECT indexname, pg_size_pretty(pg_relation_size(indexrelid)) AS size, + idx_scan, idx_tup_read + FROM pg_indexes + JOIN pg_stat_user_indexes USING (indexrelid) + WHERE schemaname = 'public' AND relname = 'knowledge_nodes'; +``` + +A HNSW index with `idx_scan = 0` after several hours of traffic usually +means the planner is preferring sequential scan -- either the table is +too small to bother with the index (fine) or the index is corrupt and +needs rebuilding (`REINDEX INDEX idx_knowledge_nodes_embedding_hnsw;`). + +### 8.5 Spotting half-built HNSW + +After a failed migration or a crashed `reembed`: + +```sql +SELECT indexname, indisvalid, indisready + FROM pg_indexes + JOIN pg_index ON indexrelid = (schemaname || '.' || indexname)::regclass + WHERE tablename = 'knowledge_nodes'; +``` + +Any row with `indisvalid = false` is broken. Drop and recreate: + +```sql +DROP INDEX IF EXISTS idx_knowledge_nodes_embedding_hnsw; +CREATE INDEX idx_knowledge_nodes_embedding_hnsw + ON knowledge_nodes USING hnsw (embedding vector_cosine_ops); +``` + +--- + +## 9. Troubleshooting + +| Symptom | Likely cause | Fix | +|---------|--------------|-----| +| `ERROR: extension "vector" is not available` on start | pgvector not installed for this Postgres major version | Install the distro package matching `pg_config --version`, then `CREATE EXTENSION vector;` as superuser | +| `pool timed out while waiting for an open connection` in Vestige logs | Pool too small or stuck queries holding connections | Raise `max_connections` in `vestige.toml`; investigate `pg_stat_activity` for queries above 5s | +| `vector dimensions do not match` on insert | `embedding_model` was stamped at one dimension and a different embedder is now running | Re-run `vestige migrate reembed --model=` or fix the embedder configuration | +| Hybrid search returns the same row twice | Stale `.sqlx/` query cache from before D5 landed | Run `cargo sqlx prepare` in `crates/vestige-core/`, rebuild the binary | +| `text search configuration "english" does not exist` | Postgres locale build does not include the english dictionary (rare on Alpine) | Install the language-pack or override the FTS language in `vestige.toml` (see `[storage.postgres.fts]` once Phase 2 D5 lands) | +| `relation "_sqlx_migrations" exists, but migration X is in "applied" with no checksum` | Previous run died between `BEGIN` and `COMMIT` | Stop Vestige, restore from backup, restart | +| HNSW index very large compared to data | `m` and `ef_construction` defaults too high for the corpus | Acceptable for now; tuning lands as part of Phase 4 | +| `permission denied for schema public` on a new install | `vestige` role does not own `public` | Re-run the grants block in section 2.2 as `postgres` | + +If a problem is not in this table, capture: PostgreSQL log +(`/var/log/postgres/`, journalctl `-u postgresql`), Vestige log +(`RUST_LOG=debug,sqlx=info` for a fresh run), the migration state +(`SELECT * FROM _sqlx_migrations ORDER BY version;`), and file a bug. + +--- + +## 10. Rollback caveats + +Every migration in `crates/vestige-core/migrations/postgres/` has a +matching `*.down.sql`. `sqlx migrate revert` walks them in reverse order. + +This is not the same as risk-free. The `0002_hnsw.down.sql` drops the +HNSW index (rebuildable, expensive). The `0001_init.down.sql` drops +every table -- including `knowledge_nodes`, including data. Down migrations +exist for development, not for casual production use. + +Before applying any new migration: + +1. Take a backup (section 5.2). +2. Run the migration on a restored copy first if you can afford the time. +3. Read the new migration's `*.up.sql` and `*.down.sql` to understand + what changes. + +To revert one migration manually: + +```sh +sqlx migrate revert \ + --database-url "postgresql://vestige:...@127.0.0.1:5432/vestige" \ + --source crates/vestige-core/migrations/postgres +``` + +Note that Vestige's binary does not run `sqlx migrate revert` +automatically. Reverts are always an explicit operator decision. + +If a revert fails partway through, treat the database as inconsistent: +restore from the backup taken in step 1. +``` + +--- + +## Cross-references + +- `docs/adr/0001-pluggable-storage-and-network-access.md` -- ADR that + established the pluggable backend. +- `docs/adr/0002-phase-2-execution.md` -- ADR settling Phase 2 execution + decisions; section "Architecture Overview" lists every table the + runbook references. +- `docs/plans/0002-phase-2-postgres-backend.md` -- master plan; D16 + (deliverables list) and the Open Implementation Questions section + (especially Q4 HNSW rebuild and Q5 pool sizing) inform the runbook's + recommendations. +- `docs/plans/local-dev-postgres-setup.md` -- developer-facing recipe + for a one-machine Arch / CachyOS dev cluster. The runbook links to it + as the "for development, see" pointer. +- `docs/CONFIGURATION.md` -- existing config doc; section 4 of the + runbook ("Connection pool tuning") cross-references it for the + authoritative `vestige.toml` schema. + +--- + +## Verification + +A reviewer is given: + +- A fresh Linux VM (Debian 12 or Arch current; both must work) with + network access and no Postgres installed. +- A built `vestige-mcp` binary for that platform. +- The runbook (`docs/runbook/postgres.md`). + +The reviewer follows the runbook top to bottom and reaches a state in +which Vestige answers MCP requests against the Postgres backend. +Checkpoints, in order: + +1. After section 1 (Prerequisites): `pg_config --version` returns 16 or + newer; `pkg-config --modversion libpq` resolves; the `pgvector` + distro package is installed. +2. After section 2.1 (Extensions): two rows in + `SELECT extname FROM pg_extension WHERE extname IN ('vector', 'pgcrypto');`. +3. After section 2.2 (Role + DB): `psql -U vestige -h 127.0.0.1 -d vestige -c '\conninfo'` + succeeds. +4. After section 2.3 (Config): `vestige.toml` parses (test by + `vestige config print` once that subcommand lands, otherwise + `vestige-mcp --check-config`). +5. After section 3 (First connect): the eight expected tables are + present; `embedding_model` has exactly one row; the HNSW index + exists; `vestige-mcp` log shows "Postgres backend ready". +6. After section 5.2 (Backup): the dump file exists and `pg_restore -l` + on it lists the expected tables. +7. After section 5.4 (Restore drill): the drill database holds the same + row count as the source. + +If any checkpoint fails, the runbook section that produced the failure +is the one that needs revision. Capture the exact command, exit code, +and log line; revise the runbook in a follow-up PR. + +A second reviewer reads the runbook without executing it and checks for: + +- ASCII only; no em dashes, no curly quotes, no Unicode arrows, no + ellipses, no bullets (`*`/`-` ASCII only). +- Every section number from 1 to 10 present and in order. +- Every cross-reference resolves to an existing file or to a Phase + number explicitly marked as "future". +- No code block longer than 30 lines; if longer, it should be split or + referenced from another file. + +--- + +## Acceptance criteria + +- [ ] `docs/runbook/` directory exists. +- [ ] `docs/runbook/postgres.md` exists and matches the inlined body + above byte-for-byte after stripping the outer code fence used in + this sub-plan to embed it. +- [ ] All ten sections from the "Runbook structure" outline are present + under their stated headings. +- [ ] No file other than `docs/runbook/postgres.md` is created or + modified by executing this sub-plan. +- [ ] ASCII only: no em dashes, no curly quotes, no Unicode arrows, + no ellipses, no Unicode bullets (`grep -P '[^\x00-\x7F]' + docs/runbook/postgres.md` returns no matches). +- [ ] Every cross-reference in the runbook points at a file that exists + in the repository at the time of merge, OR is explicitly framed + as "future Phase N" with a pointer to the relevant plan document. +- [ ] Every command block is copy-pastable: no `` syntax + that does not also have an inline note describing what to + substitute. +- [ ] A second pair of eyes confirms the verification checkpoints in the + preceding section are reproducible. +- [ ] The runbook is no longer than the inlined body in this sub-plan; + operators reach the end without losing patience. From 21f0b29baeab80e7513075c9e274e069419300d3 Mon Sep 17 00:00:00 2001 From: Jan De Landtsheer Date: Wed, 27 May 2026 15:08:35 +0200 Subject: [PATCH 16/31] docs: rewrite local-dev-postgres-setup for container approach; bump pg16 -> pg18 Land the Postgres dev cluster recipe Jan provisioned on delandtj-home (rootless podman + pgvector/pgvector:pg18, PG 18.4, pgvector 0.8.2) and align all live ADR 0002 / Phase 2 sub-plan references from pg16 to pg18. - docs/plans/local-dev-postgres-setup.md -- rewritten end-to-end: podman container vestige-pg with --restart=always, named volume vestige-pgdata, PGDATA=/var/lib/postgresql/data/pgdata, port mapping 127.0.0.1:5432:5432, two-password split (superuser + app role), pgvector preinstalled, CREATE EXTENSION vector handled at setup, day-to-day commands, password rotation, dev-grade backup/restore, teardown, boot-persistence notes for rootless podman. Old native Arch install recipe moved to Out-of-scope (covered by image now). - docs/adr/0002-phase-2-execution.md -- the open-thread mention of pgvector/pgvector:pg16 in the Follow-ups section now reads pg18. - docs/plans/0002c-migrations.md -- container example in the local dev section updated to pg18. - docs/plans/0002d-store-impl-bodies.md -- testcontainers GenericImage tag pg16 -> pg18; prose reference updated. - docs/plans/0002h-testing-and-benches.md -- harness pg18 across testcontainers Postgres builder, image-caching prose, CI workflow example. The archival master plan (docs/plans/0002-phase-2-postgres-backend.md) keeps its original pg16 references intentionally; the supersession notice already points readers to the live sub-plans. --- docs/adr/0002-phase-2-execution.md | 2 +- docs/plans/0002c-migrations.md | 2 +- docs/plans/0002d-store-impl-bodies.md | 4 +- docs/plans/0002h-testing-and-benches.md | 14 +- docs/plans/local-dev-postgres-setup.md | 248 ++++++++++++++++++------ 5 files changed, 198 insertions(+), 72 deletions(-) diff --git a/docs/adr/0002-phase-2-execution.md b/docs/adr/0002-phase-2-execution.md index 6b6949f..5d590b4 100644 --- a/docs/adr/0002-phase-2-execution.md +++ b/docs/adr/0002-phase-2-execution.md @@ -504,7 +504,7 @@ own migrations. - Validate local Postgres dev cluster before PR C work begins. Recipe at `docs/plans/local-dev-postgres-setup.md` is correct but needs to be applied on this machine (delandtj-home): cluster is not initdb'd, pgvector is not - installed. Containerized `pgvector/pgvector:pg16` is a viable alternative + installed. Containerized `pgvector/pgvector:pg18` is a viable alternative if pgvector packaging is friction. See open discussion thread. ### Phase 4 sketch: `sharing_rules` and the precedence chain diff --git a/docs/plans/0002c-migrations.md b/docs/plans/0002c-migrations.md index ef8e35c..78b6ac6 100644 --- a/docs/plans/0002c-migrations.md +++ b/docs/plans/0002c-migrations.md @@ -843,7 +843,7 @@ podman run --rm -d --name vestige-pg \ -e POSTGRES_USER=vestige \ -e POSTGRES_DB=vestige \ -p 5432:5432 \ - docker.io/pgvector/pgvector:pg16 + docker.io/pgvector/pgvector:pg18 export DATABASE_URL="postgresql://vestige:devpw@127.0.0.1:5432/vestige" ``` diff --git a/docs/plans/0002d-store-impl-bodies.md b/docs/plans/0002d-store-impl-bodies.md index ad1d9b7..adfd8aa 100644 --- a/docs/plans/0002d-store-impl-bodies.md +++ b/docs/plans/0002d-store-impl-bodies.md @@ -1612,7 +1612,7 @@ use vestige_core::storage::postgres::PgMemoryStore; #[tokio::test] async fn round_trip_crud_search_scheduling_edges() { let docker = clients::Cli::default(); - let image = GenericImage::new("pgvector/pgvector", "pg16") + let image = GenericImage::new("pgvector/pgvector", "pg18") .with_env_var("POSTGRES_PASSWORD", "test") .with_env_var("POSTGRES_DB", "vestige_test") .with_exposed_port(5432); @@ -1759,7 +1759,7 @@ This sub-plan is complete when ALL of the following hold: and the `Visibility` enum is exported alongside it. The SQLite backend reads and writes the same four fields. 8. The `tests/postgres_round_trip.rs` integration test passes against - a `pgvector/pgvector:pg16` container (insert / get / update / delete + a `pgvector/pgvector:pg18` container (insert / get / update / delete / fts_search / vector_search / get_scheduling / update_scheduling / add_edge / get_edges / remove_edge / get_neighbors / cascade delete). diff --git a/docs/plans/0002h-testing-and-benches.md b/docs/plans/0002h-testing-and-benches.md index d6bcebc..3fc2e1e 100644 --- a/docs/plans/0002h-testing-and-benches.md +++ b/docs/plans/0002h-testing-and-benches.md @@ -166,12 +166,12 @@ use vestige_core::storage::postgres::PgMemoryStore; pub async fn fresh_pg_store( embedder: Arc, ) -> Result<(PgMemoryStore, ContainerAsync)> { - // pgvector/pgvector:pg16 is the official pgvector image built on the - // postgres:16 base. testcontainers-modules::postgres::Postgres targets + // pgvector/pgvector:pg18 is the official pgvector image built on the + // postgres:18 base. testcontainers-modules::postgres::Postgres targets // the upstream postgres image by default; we override name + tag. let container = Postgres::default() .with_name("pgvector/pgvector") - .with_tag("pg16") + .with_tag("pg18") .start() .await?; @@ -867,7 +867,7 @@ Requirements: the `docker_available()` check in `common/mod.rs`. The test output includes a `docker unavailable; skip` line per test so the developer knows the tests were not silently dropped. -- The pgvector image (`pgvector/pgvector:pg16`) is pulled on first run; +- The pgvector image (`pgvector/pgvector:pg18`) is pulled on first run; ~200 MB. A pre-pulled image keeps the per-run overhead at the cold-start container boot (~2-5 seconds). @@ -920,7 +920,7 @@ async fn build_bench(rows: usize) -> Bench { let embedder = TestEmbedder::new_768(); let container = Postgres::default() .with_name("pgvector/pgvector") - .with_tag("pg16") + .with_tag("pg18") .start() .await .unwrap(); @@ -1092,7 +1092,7 @@ Notes: - The Postgres feature tests should run in a separate CI matrix entry to isolate failures and skip them entirely on platforms (Windows runners if any) where the pgvector image is not available. -- Cache the `pgvector/pgvector:pg16` image between runs. The +- Cache the `pgvector/pgvector:pg18` image between runs. The `docker/setup-buildx-action` cache or a simple `docker pull` step before the test step keeps cold-start under the existing CI time budget. - Skip CI: contributors without Docker can still merge changes that do @@ -1113,7 +1113,7 @@ jobs: # no `postgres` service block needed; testcontainers manages its own steps: - uses: actions/checkout@v4 - - run: docker pull pgvector/pgvector:pg16 + - run: docker pull pgvector/pgvector:pg18 - uses: dtolnay/rust-toolchain@stable - run: cargo test -p vestige-core --features postgres-backend --test '*' ``` diff --git a/docs/plans/local-dev-postgres-setup.md b/docs/plans/local-dev-postgres-setup.md index 6250a55..f863d48 100644 --- a/docs/plans/local-dev-postgres-setup.md +++ b/docs/plans/local-dev-postgres-setup.md @@ -1,27 +1,55 @@ -# Local Dev Postgres Setup (Arch / CachyOS) +# Local Dev Postgres Setup (container, hybrid approach) -**Status**: Applied on this machine on 2026-04-21 -**Related**: docs/plans/0002-phase-2-postgres-backend.md, docs/adr/0001-pluggable-storage-and-network-access.md +**Status**: Applied on this machine on 2026-05-27 (rootless podman, Postgres 18.4 + pgvector 0.8.2). +**Related**: docs/plans/0002-phase-2-postgres-backend.md, docs/adr/0002-phase-2-execution.md, docs/adr/0001-pluggable-storage-and-network-access.md -Purpose: capture the minimum, repeatable steps to stand up a Postgres 18 instance on a local Arch/CachyOS box for Phase 2 (`PgMemoryStore`) development, `sqlx prepare`, and manual migration testing. This is a single-operator dev recipe, not a production runbook. +Purpose: capture the minimum, repeatable steps to stand up a long-lived +Postgres 18 + pgvector instance on a local Linux dev box for Phase 2 +(`PgMemoryStore`) development, `sqlx prepare`, and manual migration +testing. This is a single-operator dev recipe, not a production runbook. + +ADR 0002 picked the **hybrid container** approach over a native install: +the `pgvector/pgvector:pg18` image ships pgvector pre-installed, matches +the image testcontainers will use in the Phase 2 test harness, and avoids +the AUR/build-from-source friction of native pgvector packaging on Arch. --- ## Current state on this machine -- Package: `postgresql` 18.3-2 (pacman). Pulls `postgresql-libs`, `libxslt`. -- Service: `postgresql.service`, enabled + active. -- Listens on: `127.0.0.1:5432` and `[::1]:5432` only (default `listen_addresses = 'localhost'`). -- Data dir: `/var/lib/postgres/data`, owner `postgres:postgres`. -- Auth (`pg_hba.conf`, Arch defaults): `peer` for local socket, `scram-sha-256` for host 127.0.0.1/::1. +- Runtime: rootless `podman` 5.8.2 (Arch). `docker` 29.5.1 also installed but unused. +- Image: `docker.io/pgvector/pgvector:pg18` (PostgreSQL 18.4, pgvector 0.8.2). +- Container: `vestige-pg`, `--restart=always`, port `127.0.0.1:5432:5432`. +- Volume: named podman volume `vestige-pgdata`, mounted at + `/var/lib/postgresql/data` inside the container; `PGDATA` points at + `/var/lib/postgresql/data/pgdata` so the volume mount is non-empty at + init time (Postgres refuses to initdb into a non-empty directory). +- Listens on: `127.0.0.1:5432` only (port mapping is bound to loopback). +- Auth: `scram-sha-256` (image default for both local socket and host). ### Database + role -- Database: `vestige`, UTF8, owner `vestige`. -- Role: `vestige` with `LOGIN CREATEDB` (no superuser, no replication, no cross-db). -- Schema `public` re-owned to `vestige`, plus default privileges so any future tables / sequences / functions in `public` are fully owned and granted to `vestige`. +- Database: `vestige`, UTF8, owner `vestige`, `LC_COLLATE=C.UTF-8`, `LC_CTYPE=C.UTF-8`. +- Role: `vestige` with `LOGIN CREATEDB` (no superuser, no replication). +- Schema `public` re-owned to `vestige` with full default privileges on + future tables / sequences / functions. +- Extension: `vector` (pgvector 0.8.2) installed in the `vestige` + database by the superuser at setup time. -Net effect: the `vestige` role can create, alter, drop, and grant freely inside the `vestige` database -- enough for `sqlx::migrate!`, ad-hoc schema work, and the full Phase 2 `MemoryStore` surface. It cannot create extensions (see Phase 2 followups below) and cannot touch other databases. +Net effect: the `vestige` role can create, alter, drop, and grant freely +inside the `vestige` database -- enough for `sqlx::migrate!`, ad-hoc +schema work, and the full Phase 2 `MemoryStore` surface. It cannot create +extensions; the superuser handled `CREATE EXTENSION vector` already. + +### Passwords + +Two passwords live in the dev user's home, mode 600: + +- `~/.vestige_pg_superpw` -- the `postgres` superuser password inside the + container. Used for one-shot admin tasks (creating roles, installing + extensions, password rotation). Day-to-day app traffic does NOT use it. +- `~/.vestige_pg_pw` -- the `vestige` role password. This is the one the + Phase 2 backend, `sqlx prepare`, and ad-hoc `psql` invocations use. ### Connection @@ -29,13 +57,8 @@ Net effect: the `vestige` role can create, alter, drop, and grant freely inside postgresql://vestige:@127.0.0.1:5432/vestige ``` -Password lives at `~/.vestige_pg_pw`, mode 600, owned by the dev user (no sudo needed to read it). Read with: - -```sh -cat ~/.vestige_pg_pw -``` - -Recommended dev shell export (keep this OUT of the repo; use `.env` + gitignore or a shell rc): +Recommended dev shell export (keep this OUT of the repo; use `.env` + +gitignore or a shell rc): ```sh export DATABASE_URL="postgresql://vestige:$(cat ~/.vestige_pg_pw)@127.0.0.1:5432/vestige" @@ -45,109 +68,212 @@ export DATABASE_URL="postgresql://vestige:$(cat ~/.vestige_pg_pw)@127.0.0.1:5432 ## Reproduce from scratch -On a fresh Arch / CachyOS box with passwordless sudo: +On a fresh Linux box with `podman` installed and `python3` available: ```sh -# 1. Install -sudo pacman -S --noconfirm postgresql +# 1. Pull the image +podman pull docker.io/pgvector/pgvector:pg18 -# 2. Initialize the cluster (UTF8, scram-sha-256 for host, peer for local) -sudo -iu postgres initdb \ - --locale=C.UTF-8 --encoding=UTF8 \ - -D /var/lib/postgres/data \ - --auth-host=scram-sha-256 --auth-local=peer +# 2. Create a persistent named volume +podman volume create vestige-pgdata -# 3. Start + enable -sudo systemctl enable --now postgresql +# 3. Generate the superuser password and stash it (mode 600) +SUPER_PW=$(python3 -c 'import secrets,string; a=string.ascii_letters+string.digits; print("".join(secrets.choice(a) for _ in range(32)))') +umask 077 +printf '%s' "$SUPER_PW" > ~/.vestige_pg_superpw +chmod 600 ~/.vestige_pg_superpw -# 4. Generate a password and stash it in the dev user's home (mode 600) +# 4. Start the container +podman run -d \ + --name vestige-pg \ + --restart=always \ + -p 127.0.0.1:5432:5432 \ + -e POSTGRES_PASSWORD="$SUPER_PW" \ + -e PGDATA=/var/lib/postgresql/data/pgdata \ + -v vestige-pgdata:/var/lib/postgresql/data \ + docker.io/pgvector/pgvector:pg18 + +unset SUPER_PW + +# 5. Wait for ready +until podman exec vestige-pg pg_isready -U postgres -h 127.0.0.1 >/dev/null 2>&1; do + sleep 1 +done + +# 6. Generate the vestige role password and stash it (mode 600) VESTIGE_PW=$(python3 -c 'import secrets,string; a=string.ascii_letters+string.digits; print("".join(secrets.choice(a) for _ in range(32)))') umask 077 printf '%s' "$VESTIGE_PW" > ~/.vestige_pg_pw chmod 600 ~/.vestige_pg_pw -# 5. Create role + database + grants -sudo -u postgres psql -v ON_ERROR_STOP=1 < '[3,2,1]'::vector AS l2_distance;" ``` --- -## Phase 2 followups (before PgMemoryStore works) +## Boot persistence (rootless podman) -The cluster above is bare Postgres. Phase 2 needs `pgvector`: +`--restart=always` keeps the container alive across podman daemon +restarts, but rootless podman containers do NOT auto-start on system +boot unless the dev user has lingering enabled: ```sh -# Install the extension package -sudo pacman -S --noconfirm pgvector - -# Enable it in the vestige database (must run as postgres; vestige is not superuser) -sudo -u postgres psql -d vestige -c 'CREATE EXTENSION IF NOT EXISTS vector;' +sudo loginctl enable-linger "$USER" ``` -Verify: +After that, the `podman-restart.service` user unit handles restart of +`--restart=always` containers when the user session starts at boot: ```sh -PGPASSWORD="$(cat ~/.vestige_pg_pw)" psql -h 127.0.0.1 -U vestige -d vestige \ - -c "SELECT extname, extversion FROM pg_extension WHERE extname = 'vector';" +systemctl --user enable --now podman-restart.service ``` -Notes: +Skip both if you prefer to start the cluster manually each session with +`podman start vestige-pg`. -- `pgvector` must be available on the server before `sqlx::migrate!` runs, or the Phase 2 migration that declares typed `Vector` columns will fail. -- Testcontainer-based Phase 2 integration tests use `pgvector/pgvector:pg16` and are independent of this local cluster. This local cluster is for `sqlx prepare`, `cargo run -- migrate --to postgres`, and manual poking. -- `sqlx prepare` needs `DATABASE_URL` pointed at this cluster with `vestige` migrations already applied. Run from `crates/vestige-core/`. +--- + +## Day-to-day operation + +```sh +# Status +podman ps --filter name=vestige-pg + +# Logs (follow) +podman logs -f vestige-pg + +# psql as the app role +PGPASSWORD="$(cat ~/.vestige_pg_pw)" psql -h 127.0.0.1 -U vestige -d vestige + +# psql as the superuser (for grants, extensions, role admin) +podman exec -it vestige-pg psql -U postgres + +# Stop / start +podman stop vestige-pg +podman start vestige-pg + +# Restart in place +podman restart vestige-pg +``` --- ## Password rotation ```sh +# Rotate the vestige role password NEW_PW=$(python3 -c 'import secrets,string; a=string.ascii_letters+string.digits; print("".join(secrets.choice(a) for _ in range(32)))') umask 077 printf '%s' "$NEW_PW" > ~/.vestige_pg_pw chmod 600 ~/.vestige_pg_pw -sudo -u postgres psql -v ON_ERROR_STOP=1 \ +podman exec -i vestige-pg psql -U postgres -v ON_ERROR_STOP=1 \ -c "ALTER ROLE vestige WITH PASSWORD '${NEW_PW}';" unset NEW_PW + +# Rotate the superuser password (less common) +NEW_SUPER=$(python3 -c 'import secrets,string; a=string.ascii_letters+string.digits; print("".join(secrets.choice(a) for _ in range(32)))') +umask 077 +printf '%s' "$NEW_SUPER" > ~/.vestige_pg_superpw +chmod 600 ~/.vestige_pg_superpw +podman exec -i vestige-pg psql -U postgres -v ON_ERROR_STOP=1 \ + -c "ALTER ROLE postgres WITH PASSWORD '${NEW_SUPER}';" +unset NEW_SUPER ``` Then re-export `DATABASE_URL` in any live shells. --- +## Backup and restore (dev-grade) + +`pg_dump` writes a plain-text SQL dump to host disk. For dev data this is +enough; production runbook lives in `0002i-runbook.md`. + +```sh +# Dump +PGPASSWORD="$(cat ~/.vestige_pg_pw)" pg_dump -h 127.0.0.1 -U vestige -d vestige \ + --format=plain --no-owner > vestige-$(date +%Y%m%d-%H%M%S).sql + +# Restore (drops + recreates) +podman exec -i vestige-pg psql -U postgres -v ON_ERROR_STOP=1 \ + -c 'DROP DATABASE IF EXISTS vestige;' \ + -c 'CREATE DATABASE vestige OWNER vestige ENCODING UTF8 TEMPLATE template0;' +PGPASSWORD="$(cat ~/.vestige_pg_pw)" psql -h 127.0.0.1 -U vestige -d vestige < vestige-DUMP.sql +``` + +The named volume `vestige-pgdata` persists outside the container; the +container can be `podman rm`'d and recreated without losing data, as +long as the volume stays in place. + +--- + ## Teardown Destroys the cluster and all data in it: ```sh -sudo systemctl disable --now postgresql -sudo pacman -Rns postgresql postgresql-libs -sudo rm -rf /var/lib/postgres -rm -f ~/.vestige_pg_pw +podman stop vestige-pg +podman rm vestige-pg +podman volume rm vestige-pgdata +podman rmi docker.io/pgvector/pgvector:pg18 +rm -f ~/.vestige_pg_pw ~/.vestige_pg_superpw ``` +`enable-linger` and the user systemd unit can be undone with +`sudo loginctl disable-linger "$USER"` and +`systemctl --user disable podman-restart.service` if you turned them on. + +--- + +## Notes for Phase 2 + +- `pgvector` is preinstalled in the image; the `CREATE EXTENSION vector` + in step 7 above makes it available inside the `vestige` DB. The + extension must be loaded BEFORE `sqlx::migrate!` runs the Phase 2 + migration that declares typed `Vector` columns, otherwise the + migration fails. +- Testcontainer-based Phase 2 integration tests use the same + `pgvector/pgvector:pg18` image and spin up fresh containers per run; + they are independent of this long-lived cluster. This cluster exists + for `sqlx prepare`, `cargo run -- migrate --to postgres`, and manual + poking. +- `sqlx prepare` needs `DATABASE_URL` pointed at this cluster with + `vestige` migrations already applied. Run from `crates/vestige-core/`. + --- ## Out of scope for this doc -- TLS, client-cert auth, non-localhost access. Phase 3 exposes the Vestige HTTP API over the network, not Postgres directly. -- Backups, PITR, WAL archiving. For dev data: `pg_dump -h 127.0.0.1 -U vestige vestige > vestige.sql`. -- Replication, PgBouncer, tuned `postgresql.conf`. Defaults are fine for Phase 2 development. -- Making this the canonical Vestige backend. By default Vestige still uses SQLite; this cluster exists so the `postgres-backend` feature can be built and tested locally. +- TLS, client-cert auth, non-localhost access. Phase 3 exposes the + Vestige HTTP API over the network, not Postgres directly. +- PITR, WAL archiving, replication, PgBouncer, tuned `postgresql.conf`. + Defaults are fine for Phase 2 development. +- Native (non-container) Postgres install. The prior version of this + doc covered native Arch packaging; superseded by ADR 0002's hybrid + decision. +- Making this the canonical Vestige backend. By default Vestige still + uses SQLite; this cluster exists so the `postgres-backend` feature + can be built and tested locally. From 14b061f124ef0acb9cff9bfe6d627726f82460dd Mon Sep 17 00:00:00 2001 From: Sam Valladares <143034159+samvallad33@users.noreply.github.com> Date: Wed, 27 May 2026 19:03:16 -0500 Subject: [PATCH 17/31] Release v2.1.23 Receipt Lock hardening Hardens Sanhedrin Receipt Lock for model-agnostic use, adds fail-open telemetry and receipt docs, fixes smart_ingest batch safety, wires opt-in CUDA Qwen3 device selection, and refreshes dashboard/release assets.\n\nFixes #54\nFixes #58\nFixes #60\nRefs #59 --- CHANGELOG.md | 44 +++ Cargo.lock | 120 +++++++- Cargo.toml | 2 +- README.md | 60 ++++ .../assets/{0.CN9L-NIY.css => 0.Bor8S3Zo.css} | 2 +- .../_app/immutable/assets/0.Bor8S3Zo.css.br | Bin 0 -> 10347 bytes .../{0.CN9L-NIY.css.gz => 0.Bor8S3Zo.css.gz} | Bin 12348 -> 12352 bytes .../_app/immutable/assets/0.CN9L-NIY.css.br | Bin 10353 -> 0 bytes .../_app/immutable/chunks/554JRhq6.js.br | Bin 632 -> 0 bytes .../_app/immutable/chunks/554JRhq6.js.gz | Bin 756 -> 0 bytes .../chunks/{554JRhq6.js => B7CfdQuM.js} | 2 +- .../_app/immutable/chunks/B7CfdQuM.js.br | Bin 0 -> 646 bytes .../_app/immutable/chunks/B7CfdQuM.js.gz | Bin 0 -> 774 bytes .../chunks/{D-gDZzN6.js => C2TQQEIa.js} | 2 +- .../_app/immutable/chunks/C2TQQEIa.js.br | Bin 0 -> 7642 bytes .../_app/immutable/chunks/C2TQQEIa.js.gz | Bin 0 -> 8430 bytes .../_app/immutable/chunks/D-gDZzN6.js.br | Bin 7644 -> 0 bytes .../_app/immutable/chunks/D-gDZzN6.js.gz | Bin 8427 -> 0 bytes .../chunks/{DGcYlAAw.js => D8UfWY0j.js} | 2 +- .../_app/immutable/chunks/D8UfWY0j.js.br | Bin 0 -> 2609 bytes .../_app/immutable/chunks/D8UfWY0j.js.gz | Bin 0 -> 2952 bytes .../_app/immutable/chunks/DGcYlAAw.js.br | Bin 2609 -> 0 bytes .../_app/immutable/chunks/DGcYlAAw.js.gz | Bin 2953 -> 0 bytes .../_app/immutable/entry/app.BIXcLtMB.js.br | Bin 3574 -> 0 bytes .../_app/immutable/entry/app.BIXcLtMB.js.gz | Bin 4071 -> 0 bytes .../{app.BIXcLtMB.js => app.Bv9rD2TH.js} | 4 +- .../_app/immutable/entry/app.Bv9rD2TH.js.br | Bin 0 -> 3598 bytes .../_app/immutable/entry/app.Bv9rD2TH.js.gz | Bin 0 -> 4072 bytes .../_app/immutable/entry/start.Bnkotnxp.js | 1 - .../_app/immutable/entry/start.Bnkotnxp.js.br | Bin 108 -> 0 bytes .../_app/immutable/entry/start.Bnkotnxp.js.gz | Bin 107 -> 0 bytes .../_app/immutable/entry/start.HXOjGRUF.js | 1 + .../_app/immutable/entry/start.HXOjGRUF.js.br | Bin 0 -> 111 bytes .../_app/immutable/entry/start.HXOjGRUF.js.gz | Bin 0 -> 108 bytes .../build/_app/immutable/nodes/0.BSxKGxRx.js | 86 ------ .../_app/immutable/nodes/0.BSxKGxRx.js.br | Bin 9644 -> 0 bytes .../_app/immutable/nodes/0.BSxKGxRx.js.gz | Bin 10974 -> 0 bytes .../build/_app/immutable/nodes/0.j0CpgSFp.js | 86 ++++++ .../_app/immutable/nodes/0.j0CpgSFp.js.br | Bin 0 -> 9928 bytes .../_app/immutable/nodes/0.j0CpgSFp.js.gz | Bin 0 -> 11290 bytes .../_app/immutable/nodes/1.CJFfVX1H.js.br | Bin 339 -> 0 bytes .../_app/immutable/nodes/1.CJFfVX1H.js.gz | Bin 383 -> 0 bytes .../nodes/{1.CJFfVX1H.js => 1.DEUqmURt.js} | 2 +- .../_app/immutable/nodes/1.DEUqmURt.js.br | Bin 0 -> 340 bytes .../_app/immutable/nodes/1.DEUqmURt.js.gz | Bin 0 -> 382 bytes .../nodes/{10.CjP_ylq3.js => 10.CACwABbv.js} | 2 +- .../_app/immutable/nodes/10.CACwABbv.js.br | Bin 0 -> 124073 bytes .../_app/immutable/nodes/10.CACwABbv.js.gz | Bin 0 -> 148779 bytes .../_app/immutable/nodes/10.CjP_ylq3.js.br | Bin 124081 -> 0 bytes .../_app/immutable/nodes/10.CjP_ylq3.js.gz | Bin 148779 -> 0 bytes .../nodes/{11.k15P8M2H.js => 11.B_W3XFQr.js} | 2 +- .../_app/immutable/nodes/11.B_W3XFQr.js.br | Bin 0 -> 4830 bytes .../_app/immutable/nodes/11.B_W3XFQr.js.gz | Bin 0 -> 5417 bytes .../_app/immutable/nodes/11.k15P8M2H.js.br | Bin 4827 -> 0 bytes .../_app/immutable/nodes/11.k15P8M2H.js.gz | Bin 5417 -> 0 bytes .../_app/immutable/nodes/12.BthmSU_R.js.br | Bin 2402 -> 0 bytes .../_app/immutable/nodes/12.BthmSU_R.js.gz | Bin 2710 -> 0 bytes .../nodes/{12.BthmSU_R.js => 12.DxkSrFsy.js} | 2 +- .../_app/immutable/nodes/12.DxkSrFsy.js.br | Bin 0 -> 2402 bytes .../_app/immutable/nodes/12.DxkSrFsy.js.gz | Bin 0 -> 2709 bytes .../_app/immutable/nodes/13.C0fh4g_5.js.br | Bin 5193 -> 0 bytes .../_app/immutable/nodes/13.C0fh4g_5.js.gz | Bin 5915 -> 0 bytes .../nodes/{13.C0fh4g_5.js => 13.CD5qzYsO.js} | 2 +- .../_app/immutable/nodes/13.CD5qzYsO.js.br | Bin 0 -> 5190 bytes .../_app/immutable/nodes/13.CD5qzYsO.js.gz | Bin 0 -> 5914 bytes .../nodes/{15.QNRJhGzj.js => 15.CyCv1LGV.js} | 2 +- .../_app/immutable/nodes/15.CyCv1LGV.js.br | Bin 0 -> 7453 bytes .../_app/immutable/nodes/15.CyCv1LGV.js.gz | Bin 0 -> 8511 bytes .../_app/immutable/nodes/15.QNRJhGzj.js.br | Bin 7442 -> 0 bytes .../_app/immutable/nodes/15.QNRJhGzj.js.gz | Bin 8512 -> 0 bytes .../nodes/{16.QhdtMP78.js => 16.Cth-SSqa.js} | 2 +- .../_app/immutable/nodes/16.Cth-SSqa.js.br | Bin 0 -> 5678 bytes .../_app/immutable/nodes/16.Cth-SSqa.js.gz | Bin 0 -> 6454 bytes .../_app/immutable/nodes/16.QhdtMP78.js.br | Bin 5681 -> 0 bytes .../_app/immutable/nodes/16.QhdtMP78.js.gz | Bin 6455 -> 0 bytes .../_app/immutable/nodes/17.DlzXJVdF.js.br | Bin 3392 -> 0 bytes .../_app/immutable/nodes/17.DlzXJVdF.js.gz | Bin 3853 -> 0 bytes .../nodes/{17.DlzXJVdF.js => 17.k6k7874Y.js} | 2 +- .../_app/immutable/nodes/17.k6k7874Y.js.br | Bin 0 -> 3389 bytes .../_app/immutable/nodes/17.k6k7874Y.js.gz | Bin 0 -> 3853 bytes .../_app/immutable/nodes/18.Bmu4OWRV.js.br | Bin 2023 -> 0 bytes .../_app/immutable/nodes/18.Bmu4OWRV.js.gz | Bin 2265 -> 0 bytes .../nodes/{18.Bmu4OWRV.js => 18.C60Wuzj2.js} | 2 +- .../_app/immutable/nodes/18.C60Wuzj2.js.br | Bin 0 -> 2022 bytes .../_app/immutable/nodes/18.C60Wuzj2.js.gz | Bin 0 -> 2264 bytes .../nodes/{19.Baocji37.js => 19.BIUSI5ln.js} | 2 +- .../_app/immutable/nodes/19.BIUSI5ln.js.br | Bin 0 -> 1557 bytes .../_app/immutable/nodes/19.BIUSI5ln.js.gz | Bin 0 -> 1753 bytes .../_app/immutable/nodes/19.Baocji37.js.br | Bin 1550 -> 0 bytes .../_app/immutable/nodes/19.Baocji37.js.gz | Bin 1755 -> 0 bytes .../_app/immutable/nodes/20.CJQuAMkU.js.br | Bin 5512 -> 0 bytes .../_app/immutable/nodes/20.CJQuAMkU.js.gz | Bin 6454 -> 0 bytes .../nodes/{20.CJQuAMkU.js => 20.DebghJca.js} | 2 +- .../_app/immutable/nodes/20.DebghJca.js.br | Bin 0 -> 5511 bytes .../_app/immutable/nodes/20.DebghJca.js.gz | Bin 0 -> 6455 bytes .../nodes/{3.mK8D6pz1.js => 3.Bu_uPddU.js} | 2 +- .../_app/immutable/nodes/3.Bu_uPddU.js.br | Bin 0 -> 164 bytes .../_app/immutable/nodes/3.Bu_uPddU.js.gz | Bin 0 -> 197 bytes .../_app/immutable/nodes/3.mK8D6pz1.js.br | Bin 165 -> 0 bytes .../_app/immutable/nodes/3.mK8D6pz1.js.gz | Bin 198 -> 0 bytes .../_app/immutable/nodes/4.DPhwyLUO.js.br | Bin 4437 -> 0 bytes .../_app/immutable/nodes/4.DPhwyLUO.js.gz | Bin 4976 -> 0 bytes .../nodes/{4.DPhwyLUO.js => 4.DYVet_v-.js} | 2 +- .../_app/immutable/nodes/4.DYVet_v-.js.br | Bin 0 -> 4439 bytes .../_app/immutable/nodes/4.DYVet_v-.js.gz | Bin 0 -> 4975 bytes .../nodes/{6.BD0AetaD.js => 6.54m-BxV_.js} | 2 +- .../_app/immutable/nodes/6.54m-BxV_.js.br | Bin 0 -> 5620 bytes .../_app/immutable/nodes/6.54m-BxV_.js.gz | Bin 0 -> 6334 bytes .../_app/immutable/nodes/6.BD0AetaD.js.br | Bin 5625 -> 0 bytes .../_app/immutable/nodes/6.BD0AetaD.js.gz | Bin 6335 -> 0 bytes .../_app/immutable/nodes/8.CokrlgDp.js.br | Bin 3017 -> 0 bytes .../_app/immutable/nodes/8.CokrlgDp.js.gz | Bin 3487 -> 0 bytes .../nodes/{8.CokrlgDp.js => 8.DGKslLJe.js} | 2 +- .../_app/immutable/nodes/8.DGKslLJe.js.br | Bin 0 -> 3012 bytes .../_app/immutable/nodes/8.DGKslLJe.js.gz | Bin 0 -> 3485 bytes apps/dashboard/build/_app/version.json | 2 +- apps/dashboard/build/_app/version.json.br | 2 +- apps/dashboard/build/_app/version.json.gz | Bin 40 -> 40 bytes apps/dashboard/build/index.html | 14 +- apps/dashboard/build/index.html.br | Bin 608 -> 609 bytes apps/dashboard/build/index.html.gz | Bin 791 -> 795 bytes apps/dashboard/package-lock.json | 4 +- apps/dashboard/package.json | 2 +- .../components/AmbientAwarenessStrip.svelte | 46 ++- apps/dashboard/src/lib/stores/api.ts | 4 +- apps/dashboard/src/lib/types/index.ts | 25 ++ crates/vestige-core/Cargo.toml | 13 +- crates/vestige-core/src/embeddings/local.rs | 6 + crates/vestige-core/src/storage/sqlite.rs | 61 +++- crates/vestige-mcp/Cargo.toml | 8 +- crates/vestige-mcp/src/bin/cli.rs | 45 ++- crates/vestige-mcp/src/bin/restore.rs | 27 +- crates/vestige-mcp/src/dashboard/handlers.rs | 236 +++++++++++++- crates/vestige-mcp/src/dashboard/mod.rs | 6 +- crates/vestige-mcp/src/main.rs | 17 +- crates/vestige-mcp/src/tools/smart_ingest.rs | 98 +++++- docs/COGNITIVE_SANDWICH.md | 22 +- docs/SANHEDRIN_RECEIPTS.md | 96 ++++++ hooks/sanhedrin-local.py | 161 ++++++++-- hooks/sanhedrin-presets.json | 103 +++++++ hooks/sanhedrin.sh | 44 ++- hooks/sanhedrin_core.py | 63 +++- package.json | 2 +- packages/vestige-init/package.json | 2 +- packages/vestige-mcp-npm/package.json | 2 +- packages/vestige-mcpb/README.md | 4 +- packages/vestige-mcpb/build.sh | 2 +- packages/vestige-mcpb/manifest.json | 2 +- scripts/check-sandwich-prereqs.sh | 18 +- scripts/install-sandwich.sh | 55 +++- server.json | 4 +- .../tests/cognitive/comparative_benchmarks.rs | 37 ++- tests/e2e/tests/cognitive/dreams_tests.rs | 4 +- tests/e2e/tests/extreme/adversarial_tests.rs | 8 +- tests/e2e/tests/extreme/chaos_tests.rs | 11 +- .../e2e/tests/extreme/proof_of_superiority.rs | 4 +- .../extreme/research_validation_tests.rs | 2 +- .../tests/journeys/consolidation_workflow.rs | 8 +- .../tests/journeys/ingest_recall_review.rs | 24 +- .../e2e/tests/journeys/intentions_workflow.rs | 11 +- tests/hooks/test_sanhedrin_claim_mode.py | 290 +++++++++++++++++- 161 files changed, 1775 insertions(+), 262 deletions(-) rename apps/dashboard/build/_app/immutable/assets/{0.CN9L-NIY.css => 0.Bor8S3Zo.css} (74%) create mode 100644 apps/dashboard/build/_app/immutable/assets/0.Bor8S3Zo.css.br rename apps/dashboard/build/_app/immutable/assets/{0.CN9L-NIY.css.gz => 0.Bor8S3Zo.css.gz} (70%) delete mode 100644 apps/dashboard/build/_app/immutable/assets/0.CN9L-NIY.css.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/554JRhq6.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/554JRhq6.js.gz rename apps/dashboard/build/_app/immutable/chunks/{554JRhq6.js => B7CfdQuM.js} (87%) create mode 100644 apps/dashboard/build/_app/immutable/chunks/B7CfdQuM.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/B7CfdQuM.js.gz rename apps/dashboard/build/_app/immutable/chunks/{D-gDZzN6.js => C2TQQEIa.js} (65%) create mode 100644 apps/dashboard/build/_app/immutable/chunks/C2TQQEIa.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/C2TQQEIa.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/D-gDZzN6.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/D-gDZzN6.js.gz rename apps/dashboard/build/_app/immutable/chunks/{DGcYlAAw.js => D8UfWY0j.js} (88%) create mode 100644 apps/dashboard/build/_app/immutable/chunks/D8UfWY0j.js.br create mode 100644 apps/dashboard/build/_app/immutable/chunks/D8UfWY0j.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DGcYlAAw.js.br delete mode 100644 apps/dashboard/build/_app/immutable/chunks/DGcYlAAw.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/entry/app.BIXcLtMB.js.br delete mode 100644 apps/dashboard/build/_app/immutable/entry/app.BIXcLtMB.js.gz rename apps/dashboard/build/_app/immutable/entry/{app.BIXcLtMB.js => app.Bv9rD2TH.js} (79%) create mode 100644 apps/dashboard/build/_app/immutable/entry/app.Bv9rD2TH.js.br create mode 100644 apps/dashboard/build/_app/immutable/entry/app.Bv9rD2TH.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/entry/start.Bnkotnxp.js delete mode 100644 apps/dashboard/build/_app/immutable/entry/start.Bnkotnxp.js.br delete mode 100644 apps/dashboard/build/_app/immutable/entry/start.Bnkotnxp.js.gz create mode 100644 apps/dashboard/build/_app/immutable/entry/start.HXOjGRUF.js create mode 100644 apps/dashboard/build/_app/immutable/entry/start.HXOjGRUF.js.br create mode 100644 apps/dashboard/build/_app/immutable/entry/start.HXOjGRUF.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/0.BSxKGxRx.js delete mode 100644 apps/dashboard/build/_app/immutable/nodes/0.BSxKGxRx.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/0.BSxKGxRx.js.gz create mode 100644 apps/dashboard/build/_app/immutable/nodes/0.j0CpgSFp.js create mode 100644 apps/dashboard/build/_app/immutable/nodes/0.j0CpgSFp.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/0.j0CpgSFp.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/1.CJFfVX1H.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/1.CJFfVX1H.js.gz rename apps/dashboard/build/_app/immutable/nodes/{1.CJFfVX1H.js => 1.DEUqmURt.js} (80%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/1.DEUqmURt.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/1.DEUqmURt.js.gz rename apps/dashboard/build/_app/immutable/nodes/{10.CjP_ylq3.js => 10.CACwABbv.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/10.CACwABbv.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/10.CACwABbv.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/10.CjP_ylq3.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/10.CjP_ylq3.js.gz rename apps/dashboard/build/_app/immutable/nodes/{11.k15P8M2H.js => 11.B_W3XFQr.js} (98%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/11.B_W3XFQr.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/11.B_W3XFQr.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/11.k15P8M2H.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/11.k15P8M2H.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/12.BthmSU_R.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/12.BthmSU_R.js.gz rename apps/dashboard/build/_app/immutable/nodes/{12.BthmSU_R.js => 12.DxkSrFsy.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/12.DxkSrFsy.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/12.DxkSrFsy.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/13.C0fh4g_5.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/13.C0fh4g_5.js.gz rename apps/dashboard/build/_app/immutable/nodes/{13.C0fh4g_5.js => 13.CD5qzYsO.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/13.CD5qzYsO.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/13.CD5qzYsO.js.gz rename apps/dashboard/build/_app/immutable/nodes/{15.QNRJhGzj.js => 15.CyCv1LGV.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/15.CyCv1LGV.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/15.CyCv1LGV.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/15.QNRJhGzj.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/15.QNRJhGzj.js.gz rename apps/dashboard/build/_app/immutable/nodes/{16.QhdtMP78.js => 16.Cth-SSqa.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/16.Cth-SSqa.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/16.Cth-SSqa.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/16.QhdtMP78.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/16.QhdtMP78.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/17.DlzXJVdF.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/17.DlzXJVdF.js.gz rename apps/dashboard/build/_app/immutable/nodes/{17.DlzXJVdF.js => 17.k6k7874Y.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/17.k6k7874Y.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/17.k6k7874Y.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/18.Bmu4OWRV.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/18.Bmu4OWRV.js.gz rename apps/dashboard/build/_app/immutable/nodes/{18.Bmu4OWRV.js => 18.C60Wuzj2.js} (98%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/18.C60Wuzj2.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/18.C60Wuzj2.js.gz rename apps/dashboard/build/_app/immutable/nodes/{19.Baocji37.js => 19.BIUSI5ln.js} (98%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/19.BIUSI5ln.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/19.BIUSI5ln.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/19.Baocji37.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/19.Baocji37.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/20.CJQuAMkU.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/20.CJQuAMkU.js.gz rename apps/dashboard/build/_app/immutable/nodes/{20.CJQuAMkU.js => 20.DebghJca.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/20.DebghJca.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/20.DebghJca.js.gz rename apps/dashboard/build/_app/immutable/nodes/{3.mK8D6pz1.js => 3.Bu_uPddU.js} (56%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/3.Bu_uPddU.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/3.Bu_uPddU.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/3.mK8D6pz1.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/3.mK8D6pz1.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/4.DPhwyLUO.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/4.DPhwyLUO.js.gz rename apps/dashboard/build/_app/immutable/nodes/{4.DPhwyLUO.js => 4.DYVet_v-.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/4.DYVet_v-.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/4.DYVet_v-.js.gz rename apps/dashboard/build/_app/immutable/nodes/{6.BD0AetaD.js => 6.54m-BxV_.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/6.54m-BxV_.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/6.54m-BxV_.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/6.BD0AetaD.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/6.BD0AetaD.js.gz delete mode 100644 apps/dashboard/build/_app/immutable/nodes/8.CokrlgDp.js.br delete mode 100644 apps/dashboard/build/_app/immutable/nodes/8.CokrlgDp.js.gz rename apps/dashboard/build/_app/immutable/nodes/{8.CokrlgDp.js => 8.DGKslLJe.js} (99%) create mode 100644 apps/dashboard/build/_app/immutable/nodes/8.DGKslLJe.js.br create mode 100644 apps/dashboard/build/_app/immutable/nodes/8.DGKslLJe.js.gz create mode 100644 docs/SANHEDRIN_RECEIPTS.md create mode 100644 hooks/sanhedrin-presets.json diff --git a/CHANGELOG.md b/CHANGELOG.md index f6825cb..490c01e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.1.23] - 2026-05-27 — "Receipt Lock Hardening" + +v2.1.23 hardens the Sanhedrin launch path so Receipt Lock is portable, +observable, and precise enough for broader use. + +### Added + +- **Model-agnostic Sanhedrin backend presets** for custom OpenAI-compatible + servers, small laptops, Ollama, MLX, vLLM, llama.cpp, hosted APIs, and + Anthropic via LiteLLM. Sanhedrin no longer guesses a large default verifier. +- **Fail-open telemetry** in `fail-open.jsonl`, plus a dashboard telemetry API + and 7-day ambient dashboard counters for vetoes, appeals, and fail-open runs. +- **Receipt schema documentation** covering receipt artifacts, appeals, command + ledgers, fail-open logs, compatibility rules, and staged-evidence trust + boundaries. +- **Opt-in CUDA feature flags** for Qwen3 embedding builds on NVIDIA hardware. + +### Changed + +- Receipt Lock strips code fences, inline code, blockquotes, quoted regions, and + scoped epistemic hedges before matching verification claims. +- Structured transcript tool-use receipts are the default evidence path; loose + JSON command scanning now requires `VESTIGE_SANHEDRIN_ALLOW_LOOSE_LEDGER=1`. +- Claim-mode sampling now prioritizes higher-severity claims instead of taking + the first eight source-order claims. +- Hosted Sanhedrin credentials now require `VESTIGE_SANHEDRIN_API_KEY` and are + only sent to the configured Sanhedrin endpoint, never to Vestige retrieval. +- `smart_ingest` batch mode now defaults to `batchMergePolicy: "force_create"` + so caller-separated items stay separate unless callers opt into smart merging. +- CUDA-enabled Qwen3 builds now try `Device::new_cuda(0)` before falling back to + Metal or CPU. + +### Fixed + +- Standalone dashboard mode now hydrates the cognitive engine for Dream and + Deep Reference instead of returning 503s. +- `--data-dir` now rejects existing non-directory paths with a clear error. +- `vestige-restore` now handles `--help` and `--version` instead of treating + them as backup file paths. +- Smart ingest merge/update responses now include `previousContent`, + `mergedFrom`, and `mergePreview` so callers can inspect mutated memories. +- Daily Sanhedrin telemetry now preserves NOTE and CAUTION buckets instead of + folding both into PASS. + ## [2.1.22] - 2026-05-25 — "Sanhedrin Receipts" v2.1.22 makes the optional Sanhedrin hook quieter and more accountable by diff --git a/Cargo.lock b/Cargo.lock index 70f3956..b9612d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -392,8 +392,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bd9895436c1ba5dc1037a19935d084b838db066ff4e15ef7dded020b7c12a4a" dependencies = [ "byteorder", + "candle-kernels", "candle-metal-kernels", "candle-ug", + "cudarc 0.19.7", "float8", "gemm 0.19.0", "half", @@ -413,6 +415,15 @@ dependencies = [ "zip", ] +[[package]] +name = "candle-kernels" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "742e2ac226b777134436e9e692f44e77c278b8a7abb1554dc10e44dc911b349f" +dependencies = [ + "cudaforge", +] + [[package]] name = "candle-metal-kernels" version = "0.10.2" @@ -453,6 +464,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca0fc3167cbc99c8ec1be618cb620aa21dca95038f118c3579a79370e3dc5f77" dependencies = [ "ug", + "ug-cuda", "ug-metal", ] @@ -771,6 +783,46 @@ dependencies = [ "typenum", ] +[[package]] +name = "cudaforge" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f7a0d45b139b5beeeb1c34188717e12241c44a0120afb498815ce7f5373c691" +dependencies = [ + "anyhow", + "fs2", + "glob", + "num_cpus", + "rayon", + "serde", + "serde_json", + "sha2", + "thiserror 2.0.18", + "walkdir", + "which", +] + +[[package]] +name = "cudarc" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf99ab37ee7072d64d906aa2dada9a3422f1d975cdf8c8055a573bc84897ed8" +dependencies = [ + "half", + "libloading 0.8.9", +] + +[[package]] +name = "cudarc" +version = "0.19.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cea5f10a99e025c1b44ae2354c2d8326b25ddbd0baf76bde8e55cfd4018a2cc" +dependencies = [ + "float8", + "half", + "libloading 0.9.0", +] + [[package]] name = "cxx" version = "1.0.194" @@ -1034,6 +1086,12 @@ dependencies = [ "syn", ] +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + [[package]] name = "equator" version = "0.4.2" @@ -1254,6 +1312,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "fsevent-sys" version = "4.1.0" @@ -1632,6 +1700,12 @@ dependencies = [ "url", ] +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "h2" version = "0.4.13" @@ -3752,6 +3826,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -4327,6 +4412,19 @@ dependencies = [ "yoke 0.7.5", ] +[[package]] +name = "ug-cuda" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f0a1fa748f26166778c33b8498255ebb7c6bffb472bcc0a72839e07ebb1d9b5" +dependencies = [ + "cudarc 0.17.8", + "half", + "serde", + "thiserror 1.0.69", + "ug", +] + [[package]] name = "ug-metal" version = "0.5.0" @@ -4531,7 +4629,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vestige-core" -version = "2.1.22" +version = "2.1.23" dependencies = [ "candle-core", "chrono", @@ -4567,7 +4665,7 @@ dependencies = [ [[package]] name = "vestige-mcp" -version = "2.1.22" +version = "2.1.23" dependencies = [ "anyhow", "axum", @@ -4792,6 +4890,18 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" +[[package]] +name = "which" +version = "7.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" +dependencies = [ + "either", + "env_home", + "rustix", + "winsafe", +] + [[package]] name = "winapi" version = "0.3.9" @@ -5058,6 +5168,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "wit-bindgen" version = "0.51.0" diff --git a/Cargo.toml b/Cargo.toml index 5cbe508..f120928 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ exclude = [ ] [workspace.package] -version = "2.1.22" +version = "2.1.23" edition = "2024" license = "AGPL-3.0-only" repository = "https://github.com/samvallad33/vestige" diff --git a/README.md b/README.md index 3c18759..674eebb 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,19 @@ Built on proven memory and retrieval ideas — FSRS-6 spaced repetition, predict --- +## What's New in v2.1.23 "Receipt Lock Hardening" + +v2.1.23 turns the Sanhedrin Receipt Lock launch into something more portable, +observable, and harder to spoof. + +- **Model-agnostic Sanhedrin presets.** Sanhedrin no longer guesses a large default verifier. Users choose any OpenAI-compatible endpoint/model, or start from custom, small laptop, Ollama, MLX, vLLM, llama.cpp, hosted API, or LiteLLM presets. +- **Sharper Receipt Lock.** Verification claims inside code fences, quotes, blockquotes, or explicitly hedged "let me verify" language no longer trigger false vetoes, while actual "tests passed" claims still require command receipts. +- **Safer command receipts.** Transcript command evidence now prefers structured tool-use receipts; loose JSON scanning is opt-in only. +- **Visible fail-open telemetry.** Timeouts, unavailable model endpoints, and malformed verdicts are logged locally and surfaced in the dashboard's 7-day Sanhedrin stats. +- **Durable evidence boundary.** Staged evidence remains useful context, but it cannot satisfy durable support or contradiction requirements by itself. +- **Safer batch writes.** `smart_ingest` batch mode now keeps caller-separated items separate by default and returns merge previews when an existing memory is mutated. +- **Opt-in NVIDIA acceleration path.** Qwen3 embedding builds expose CUDA/cuDNN feature flags for contributors and users with CUDA-capable hosts. + ## What's New in v2.1.22 "Sanhedrin Receipts" v2.1.22 makes the optional Sanhedrin hook accountable enough to trust in daily @@ -444,6 +457,53 @@ cargo build --release -p vestige-mcp --features qwen3-embeddings,metal VESTIGE_EMBEDDING_MODEL=qwen3-0.6b vestige consolidate ``` +### Building with CUDA support (NVIDIA hosts - Windows / Linux) + +The `cuda` feature routes Qwen3 embedding through NVIDIA GPUs via +`candle-core/cuda`. On a host with the CUDA toolkit installed and a supported +NVIDIA runtime, this drops Qwen3-Embedding inference from CPU-bound to GPU-bound +for batched workloads. + +```bash +# Linux / Windows + CUDA toolkit (12.x or 13.x) +cargo build --release -p vestige-mcp --features qwen3-embeddings,cuda + +# Optional cuDNN acceleration on top of CUDA +cargo build --release -p vestige-mcp --features qwen3-embeddings,cudnn + +VESTIGE_EMBEDDING_MODEL=qwen3-0.6b vestige consolidate +``` + +**Prerequisites:** + +- NVIDIA driver + CUDA toolkit (12.x or 13.x). Verify with `nvcc --version`. +- A C++ host compiler that `nvcc` can drive (Linux: `gcc`; Windows: MSVC / + `cl.exe` from a recent Visual Studio Build Tools install). + +**Windows + MSVC + CUDA 13.x build note.** Recent CCCL headers shipped with +CUDA 13.x require the modern preprocessor. Without it, the `candle-kernels` +`.cu` compile pass can fail at `cuda/include/cuda/std/__cccl/compiler.h`. Set +this env var before `cargo build` to pass `/Zc:preprocessor` through `nvcc`: + +```powershell +# PowerShell +$env:NVCC_PREPEND_FLAGS = '-Xcompiler="/Zc:preprocessor"' +cargo build --release -p vestige-mcp --features qwen3-embeddings,cuda +``` + +```cmd +:: cmd.exe +set NVCC_PREPEND_FLAGS=-Xcompiler="/Zc:preprocessor" +cargo build --release -p vestige-mcp --features qwen3-embeddings,cuda +``` + +Linux + CUDA 13.x builds with `gcc` do not need the equivalent flag. + +**Verifying GPU is actually used.** With CUDA-enabled builds, run +`VESTIGE_EMBEDDING_MODEL=qwen3-0.6b vestige consolidate` on a corpus of 1000+ +memories and watch `nvidia-smi`; embedding passes should pin a single GPU while +the run is active. + --- ## CLI diff --git a/apps/dashboard/build/_app/immutable/assets/0.CN9L-NIY.css b/apps/dashboard/build/_app/immutable/assets/0.Bor8S3Zo.css similarity index 74% rename from apps/dashboard/build/_app/immutable/assets/0.CN9L-NIY.css rename to apps/dashboard/build/_app/immutable/assets/0.Bor8S3Zo.css index b0b4d99..f5bdd49 100644 --- a/apps/dashboard/build/_app/immutable/assets/0.CN9L-NIY.css +++ b/apps/dashboard/build/_app/immutable/assets/0.Bor8S3Zo.css @@ -1 +1 @@ -/*! tailwindcss v4.2.0 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:"JetBrains Mono", "Fira Code", "SF Mono", monospace;--color-amber-400:oklch(82.8% .189 84.429);--color-purple-400:oklch(71.4% .203 305.504);--color-purple-500:oklch(62.7% .265 303.9);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--container-2xl:42rem;--container-4xl:56rem;--container-5xl:64rem;--container-6xl:72rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-snug:1.375;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--blur-md:12px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-void:#050510;--color-abyss:#0a0a1a;--color-deep:#10102a;--color-surface:#161638;--color-elevated:#1e1e4a;--color-subtle:#2a2a5e;--color-muted:#4a4a7a;--color-dim:#7a7aaa;--color-text:#e0e0ff;--color-bright:#fff;--color-synapse:#6366f1;--color-synapse-glow:#818cf8;--color-dream:#a855f7;--color-dream-glow:#c084fc;--color-memory:#3b82f6;--color-recall:#10b981;--color-decay:#ef4444;--color-warning:#f59e0b;--color-node-pattern:#ec4899}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.end\!{inset-inline-end:var(--spacing)!important}.top-0{top:calc(var(--spacing) * 0)}.top-0\.5{top:calc(var(--spacing) * .5)}.top-1{top:calc(var(--spacing) * 1)}.top-3{top:calc(var(--spacing) * 3)}.top-4{top:calc(var(--spacing) * 4)}.top-10{top:calc(var(--spacing) * 10)}.right-0{right:calc(var(--spacing) * 0)}.right-4{right:calc(var(--spacing) * 4)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-4{bottom:calc(var(--spacing) * 4)}.-left-\[29px\]{left:-29px}.left-1\/2{left:50%}.left-4{left:calc(var(--spacing) * 4)}.left-6{left:calc(var(--spacing) * 6)}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-40{z-index:40}.z-50{z-index:50}.z-\[1\]{z-index:1}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-\[-12px\]{margin-top:-12px}.mr-1{margin-right:calc(var(--spacing) * 1)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-auto{margin-left:auto}.line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-4{-webkit-line-clamp:4;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.aspect-square{aspect-ratio:1}.h-0\.5{height:calc(var(--spacing) * .5)}.h-1{height:calc(var(--spacing) * 1)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-20{height:calc(var(--spacing) * 20)}.h-24{height:calc(var(--spacing) * 24)}.h-28{height:calc(var(--spacing) * 28)}.h-32{height:calc(var(--spacing) * 32)}.h-40{height:calc(var(--spacing) * 40)}.h-\[520px\]{height:520px}.h-\[560px\]{height:560px}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-48{max-height:calc(var(--spacing) * 48)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-72{max-height:calc(var(--spacing) * 72)}.max-h-96{max-height:calc(var(--spacing) * 96)}.max-h-\[620px\]{max-height:620px}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-40{min-height:calc(var(--spacing) * 40)}.min-h-\[240px\]{min-height:240px}.min-h-\[320px\]{min-height:320px}.min-h-\[520px\]{min-height:520px}.min-h-full{min-height:100%}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-3{width:calc(var(--spacing) * 3)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-24{width:calc(var(--spacing) * 24)}.w-32{width:calc(var(--spacing) * 32)}.w-96{width:calc(var(--spacing) * 96)}.w-\[3px\]{width:3px}.w-\[90\%\]{width:90%}.w-full{width:100%}.w-px{width:1px}.max-w-2xl{max-width:var(--container-2xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-20{max-width:calc(var(--spacing) * 20)}.max-w-\[220px\]{max-width:220px}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-xl{max-width:var(--container-xl)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-12{min-width:calc(var(--spacing) * 12)}.min-w-16{min-width:calc(var(--spacing) * 16)}.min-w-64{min-width:calc(var(--spacing) * 64)}.min-w-\[2rem\]{min-width:2rem}.min-w-\[3\.5rem\]{min-width:3.5rem}.flex-1{flex:1}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.border-separate{border-collapse:separate}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-125{--tw-scale-x:125%;--tw-scale-y:125%;--tw-scale-z:125%;scale:var(--tw-scale-x) var(--tw-scale-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-\[fadeSlide_0\.35s_ease-out_both\]{animation:.35s ease-out both fadeSlide}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-none{resize:none}.resize-y{resize:vertical}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-around{justify-content:space-around}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0{gap:calc(var(--spacing) * 0)}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-\[2px\]{gap:2px}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-y-1{row-gap:calc(var(--spacing) * 1)}.self-center{align-self:center}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.\!border-decay\/20{border-color:#ef444433!important}@supports (color:color-mix(in lab,red,red)){.\!border-decay\/20{border-color:color-mix(in oklab,var(--color-decay) 20%,transparent)!important}}.\!border-decay\/30{border-color:#ef44444d!important}@supports (color:color-mix(in lab,red,red)){.\!border-decay\/30{border-color:color-mix(in oklab,var(--color-decay) 30%,transparent)!important}}.\!border-decay\/40{border-color:#ef444466!important}@supports (color:color-mix(in lab,red,red)){.\!border-decay\/40{border-color:color-mix(in oklab,var(--color-decay) 40%,transparent)!important}}.\!border-dream\/20{border-color:#a855f733!important}@supports (color:color-mix(in lab,red,red)){.\!border-dream\/20{border-color:color-mix(in oklab,var(--color-dream) 20%,transparent)!important}}.\!border-synapse\/15{border-color:#6366f126!important}@supports (color:color-mix(in lab,red,red)){.\!border-synapse\/15{border-color:color-mix(in oklab,var(--color-synapse) 15%,transparent)!important}}.\!border-synapse\/20{border-color:#6366f133!important}@supports (color:color-mix(in lab,red,red)){.\!border-synapse\/20{border-color:color-mix(in oklab,var(--color-synapse) 20%,transparent)!important}}.\!border-synapse\/25{border-color:#6366f140!important}@supports (color:color-mix(in lab,red,red)){.\!border-synapse\/25{border-color:color-mix(in oklab,var(--color-synapse) 25%,transparent)!important}}.\!border-synapse\/30{border-color:#6366f14d!important}@supports (color:color-mix(in lab,red,red)){.\!border-synapse\/30{border-color:color-mix(in oklab,var(--color-synapse) 30%,transparent)!important}}.\!border-synapse\/40{border-color:#6366f166!important}@supports (color:color-mix(in lab,red,red)){.\!border-synapse\/40{border-color:color-mix(in oklab,var(--color-synapse) 40%,transparent)!important}}.border-\[\#A33FFF\]\/40{border-color:#a33fff66}.border-decay\/20{border-color:#ef444433}@supports (color:color-mix(in lab,red,red)){.border-decay\/20{border-color:color-mix(in oklab,var(--color-decay) 20%,transparent)}}.border-dream-glow\/40{border-color:#c084fc66}@supports (color:color-mix(in lab,red,red)){.border-dream-glow\/40{border-color:color-mix(in oklab,var(--color-dream-glow) 40%,transparent)}}.border-dream\/10{border-color:#a855f71a}@supports (color:color-mix(in lab,red,red)){.border-dream\/10{border-color:color-mix(in oklab,var(--color-dream) 10%,transparent)}}.border-dream\/20{border-color:#a855f733}@supports (color:color-mix(in lab,red,red)){.border-dream\/20{border-color:color-mix(in oklab,var(--color-dream) 20%,transparent)}}.border-dream\/30{border-color:#a855f74d}@supports (color:color-mix(in lab,red,red)){.border-dream\/30{border-color:color-mix(in oklab,var(--color-dream) 30%,transparent)}}.border-dream\/40{border-color:#a855f766}@supports (color:color-mix(in lab,red,red)){.border-dream\/40{border-color:color-mix(in oklab,var(--color-dream) 40%,transparent)}}.border-dream\/50{border-color:#a855f780}@supports (color:color-mix(in lab,red,red)){.border-dream\/50{border-color:color-mix(in oklab,var(--color-dream) 50%,transparent)}}.border-recall\/30{border-color:#10b9814d}@supports (color:color-mix(in lab,red,red)){.border-recall\/30{border-color:color-mix(in oklab,var(--color-recall) 30%,transparent)}}.border-recall\/40{border-color:#10b98166}@supports (color:color-mix(in lab,red,red)){.border-recall\/40{border-color:color-mix(in oklab,var(--color-recall) 40%,transparent)}}.border-subtle\/15{border-color:#2a2a5e26}@supports (color:color-mix(in lab,red,red)){.border-subtle\/15{border-color:color-mix(in oklab,var(--color-subtle) 15%,transparent)}}.border-subtle\/20{border-color:#2a2a5e33}@supports (color:color-mix(in lab,red,red)){.border-subtle\/20{border-color:color-mix(in oklab,var(--color-subtle) 20%,transparent)}}.border-subtle\/30{border-color:#2a2a5e4d}@supports (color:color-mix(in lab,red,red)){.border-subtle\/30{border-color:color-mix(in oklab,var(--color-subtle) 30%,transparent)}}.border-synapse{border-color:var(--color-synapse)}.border-synapse\/5{border-color:#6366f10d}@supports (color:color-mix(in lab,red,red)){.border-synapse\/5{border-color:color-mix(in oklab,var(--color-synapse) 5%,transparent)}}.border-synapse\/10{border-color:#6366f11a}@supports (color:color-mix(in lab,red,red)){.border-synapse\/10{border-color:color-mix(in oklab,var(--color-synapse) 10%,transparent)}}.border-synapse\/15{border-color:#6366f126}@supports (color:color-mix(in lab,red,red)){.border-synapse\/15{border-color:color-mix(in oklab,var(--color-synapse) 15%,transparent)}}.border-synapse\/20{border-color:#6366f133}@supports (color:color-mix(in lab,red,red)){.border-synapse\/20{border-color:color-mix(in oklab,var(--color-synapse) 20%,transparent)}}.border-synapse\/30{border-color:#6366f14d}@supports (color:color-mix(in lab,red,red)){.border-synapse\/30{border-color:color-mix(in oklab,var(--color-synapse) 30%,transparent)}}.border-synapse\/40{border-color:#6366f166}@supports (color:color-mix(in lab,red,red)){.border-synapse\/40{border-color:color-mix(in oklab,var(--color-synapse) 40%,transparent)}}.border-transparent{border-color:#0000}.border-warning\/30{border-color:#f59e0b4d}@supports (color:color-mix(in lab,red,red)){.border-warning\/30{border-color:color-mix(in oklab,var(--color-warning) 30%,transparent)}}.border-warning\/40{border-color:#f59e0b66}@supports (color:color-mix(in lab,red,red)){.border-warning\/40{border-color:color-mix(in oklab,var(--color-warning) 40%,transparent)}}.border-warning\/50{border-color:#f59e0b80}@supports (color:color-mix(in lab,red,red)){.border-warning\/50{border-color:color-mix(in oklab,var(--color-warning) 50%,transparent)}}.border-white\/5{border-color:#ffffff0d}@supports (color:color-mix(in lab,red,red)){.border-white\/5{border-color:color-mix(in oklab,var(--color-white) 5%,transparent)}}.border-t-dream{border-top-color:var(--color-dream)}.border-t-synapse{border-top-color:var(--color-synapse)}.border-t-warning{border-top-color:var(--color-warning)}.bg-\[\#A33FFF\]{background-color:#a33fff}.bg-\[\#A33FFF\]\/10{background-color:#a33fff1a}.bg-amber-400{background-color:var(--color-amber-400)}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab,red,red)){.bg-black\/40{background-color:color-mix(in oklab,var(--color-black) 40%,transparent)}}.bg-decay{background-color:var(--color-decay)}.bg-decay\/10{background-color:#ef44441a}@supports (color:color-mix(in lab,red,red)){.bg-decay\/10{background-color:color-mix(in oklab,var(--color-decay) 10%,transparent)}}.bg-decay\/20{background-color:#ef444433}@supports (color:color-mix(in lab,red,red)){.bg-decay\/20{background-color:color-mix(in oklab,var(--color-decay) 20%,transparent)}}.bg-decay\/\[0\.05\]{background-color:#ef44440d}@supports (color:color-mix(in lab,red,red)){.bg-decay\/\[0\.05\]{background-color:color-mix(in oklab,var(--color-decay) 5%,transparent)}}.bg-deep{background-color:var(--color-deep)}.bg-deep\/40{background-color:#10102a66}@supports (color:color-mix(in lab,red,red)){.bg-deep\/40{background-color:color-mix(in oklab,var(--color-deep) 40%,transparent)}}.bg-deep\/60{background-color:#10102a99}@supports (color:color-mix(in lab,red,red)){.bg-deep\/60{background-color:color-mix(in oklab,var(--color-deep) 60%,transparent)}}.bg-dream{background-color:var(--color-dream)}.bg-dream\/5{background-color:#a855f70d}@supports (color:color-mix(in lab,red,red)){.bg-dream\/5{background-color:color-mix(in oklab,var(--color-dream) 5%,transparent)}}.bg-dream\/10{background-color:#a855f71a}@supports (color:color-mix(in lab,red,red)){.bg-dream\/10{background-color:color-mix(in oklab,var(--color-dream) 10%,transparent)}}.bg-dream\/15{background-color:#a855f726}@supports (color:color-mix(in lab,red,red)){.bg-dream\/15{background-color:color-mix(in oklab,var(--color-dream) 15%,transparent)}}.bg-dream\/20{background-color:#a855f733}@supports (color:color-mix(in lab,red,red)){.bg-dream\/20{background-color:color-mix(in oklab,var(--color-dream) 20%,transparent)}}.bg-muted{background-color:var(--color-muted)}.bg-node-pattern{background-color:var(--color-node-pattern)}.bg-purple-500\/20{background-color:#ac4bff33}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\/20{background-color:color-mix(in oklab,var(--color-purple-500) 20%,transparent)}}.bg-recall{background-color:var(--color-recall)}.bg-recall\/10{background-color:#10b9811a}@supports (color:color-mix(in lab,red,red)){.bg-recall\/10{background-color:color-mix(in oklab,var(--color-recall) 10%,transparent)}}.bg-recall\/15{background-color:#10b98126}@supports (color:color-mix(in lab,red,red)){.bg-recall\/15{background-color:color-mix(in oklab,var(--color-recall) 15%,transparent)}}.bg-recall\/20{background-color:#10b98133}@supports (color:color-mix(in lab,red,red)){.bg-recall\/20{background-color:color-mix(in oklab,var(--color-recall) 20%,transparent)}}.bg-synapse{background-color:var(--color-synapse)}.bg-synapse-glow{background-color:var(--color-synapse-glow)}.bg-synapse\/10{background-color:#6366f11a}@supports (color:color-mix(in lab,red,red)){.bg-synapse\/10{background-color:color-mix(in oklab,var(--color-synapse) 10%,transparent)}}.bg-synapse\/15{background-color:#6366f126}@supports (color:color-mix(in lab,red,red)){.bg-synapse\/15{background-color:color-mix(in oklab,var(--color-synapse) 15%,transparent)}}.bg-synapse\/20{background-color:#6366f133}@supports (color:color-mix(in lab,red,red)){.bg-synapse\/20{background-color:color-mix(in oklab,var(--color-synapse) 20%,transparent)}}.bg-synapse\/25{background-color:#6366f140}@supports (color:color-mix(in lab,red,red)){.bg-synapse\/25{background-color:color-mix(in oklab,var(--color-synapse) 25%,transparent)}}.bg-synapse\/70{background-color:#6366f1b3}@supports (color:color-mix(in lab,red,red)){.bg-synapse\/70{background-color:color-mix(in oklab,var(--color-synapse) 70%,transparent)}}.bg-transparent{background-color:#0000}.bg-void{background-color:var(--color-void)}.bg-void\/60{background-color:#05051099}@supports (color:color-mix(in lab,red,red)){.bg-void\/60{background-color:color-mix(in oklab,var(--color-void) 60%,transparent)}}.bg-warning{background-color:var(--color-warning)}.bg-warning\/5{background-color:#f59e0b0d}@supports (color:color-mix(in lab,red,red)){.bg-warning\/5{background-color:color-mix(in oklab,var(--color-warning) 5%,transparent)}}.bg-warning\/20{background-color:#f59e0b33}@supports (color:color-mix(in lab,red,red)){.bg-warning\/20{background-color:color-mix(in oklab,var(--color-warning) 20%,transparent)}}.bg-white\/\[0\.02\]{background-color:#ffffff05}@supports (color:color-mix(in lab,red,red)){.bg-white\/\[0\.02\]{background-color:color-mix(in oklab,var(--color-white) 2%,transparent)}}.bg-white\/\[0\.03\]{background-color:#ffffff08}@supports (color:color-mix(in lab,red,red)){.bg-white\/\[0\.03\]{background-color:color-mix(in oklab,var(--color-white) 3%,transparent)}}.bg-white\/\[0\.04\]{background-color:#ffffff0a}@supports (color:color-mix(in lab,red,red)){.bg-white\/\[0\.04\]{background-color:color-mix(in oklab,var(--color-white) 4%,transparent)}}.bg-white\/\[0\.06\]{background-color:#ffffff0f}@supports (color:color-mix(in lab,red,red)){.bg-white\/\[0\.06\]{background-color:color-mix(in oklab,var(--color-white) 6%,transparent)}}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-dream{--tw-gradient-from:var(--color-dream);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-synapse{--tw-gradient-to:var(--color-synapse);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.p-0{padding:calc(var(--spacing) * 0)}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-10{padding:calc(var(--spacing) * 10)}.p-12{padding:calc(var(--spacing) * 12)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-10{padding-block:calc(var(--spacing) * 10)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-20{padding-block:calc(var(--spacing) * 20)}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-8{padding-top:calc(var(--spacing) * 8)}.pt-\[10vh\]{padding-top:10vh}.pr-1{padding-right:calc(var(--spacing) * 1)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-16{padding-bottom:calc(var(--spacing) * 16)}.pl-6{padding-left:calc(var(--spacing) * 6)}.pl-14{padding-left:calc(var(--spacing) * 14)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-bottom{vertical-align:bottom}.align-top{vertical-align:top}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.12em\]{--tw-tracking:.12em;letter-spacing:.12em}.tracking-\[0\.15em\]{--tw-tracking:.15em;letter-spacing:.15em}.tracking-\[0\.18em\]{--tw-tracking:.18em;letter-spacing:.18em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#E4C8FF\]{color:#e4c8ff}.text-amber-400{color:var(--color-amber-400)}.text-bright{color:var(--color-bright)}.text-decay{color:var(--color-decay)}.text-decay\/60{color:#ef444499}@supports (color:color-mix(in lab,red,red)){.text-decay\/60{color:color-mix(in oklab,var(--color-decay) 60%,transparent)}}.text-dim{color:var(--color-dim)}.text-dream{color:var(--color-dream)}.text-dream-glow{color:var(--color-dream-glow)}.text-dream\/40{color:#a855f766}@supports (color:color-mix(in lab,red,red)){.text-dream\/40{color:color-mix(in oklab,var(--color-dream) 40%,transparent)}}.text-dream\/80{color:#a855f7cc}@supports (color:color-mix(in lab,red,red)){.text-dream\/80{color:color-mix(in oklab,var(--color-dream) 80%,transparent)}}.text-memory{color:var(--color-memory)}.text-muted{color:var(--color-muted)}.text-muted\/50{color:#4a4a7a80}@supports (color:color-mix(in lab,red,red)){.text-muted\/50{color:color-mix(in oklab,var(--color-muted) 50%,transparent)}}.text-muted\/60{color:#4a4a7a99}@supports (color:color-mix(in lab,red,red)){.text-muted\/60{color:color-mix(in oklab,var(--color-muted) 60%,transparent)}}.text-node-pattern{color:var(--color-node-pattern)}.text-purple-400{color:var(--color-purple-400)}.text-recall{color:var(--color-recall)}.text-subtle{color:var(--color-subtle)}.text-synapse{color:var(--color-synapse)}.text-synapse-glow{color:var(--color-synapse-glow)}.text-text{color:var(--color-text)}.text-text\/80{color:#e0e0ffcc}@supports (color:color-mix(in lab,red,red)){.text-text\/80{color:color-mix(in oklab,var(--color-text) 80%,transparent)}}.text-warning{color:var(--color-warning)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline-offset-4{text-underline-offset:4px}.accent-synapse{accent-color:var(--color-synapse)}.accent-synapse-glow{accent-color:var(--color-synapse-glow)}.opacity-20{opacity:.2}.opacity-30{opacity:.3}.opacity-35{opacity:.35}.opacity-40{opacity:.4}.opacity-60{opacity:.6}.opacity-75{opacity:.75}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow\!{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a)!important;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)!important}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_10px_rgba\(239\,68\,68\,0\.7\)\]{--tw-shadow:0 0 10px var(--tw-shadow-color,#ef4444b3);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_12px_rgba\(99\,102\,241\,0\.15\)\]{--tw-shadow:0 0 12px var(--tw-shadow-color,#6366f126);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_12px_rgba\(99\,102\,241\,0\.18\)\]{--tw-shadow:0 0 12px var(--tw-shadow-color,#6366f12e);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_12px_rgba\(163\,63\,255\,0\.15\)\]{--tw-shadow:0 0 12px var(--tw-shadow-color,#a33fff26);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_16px_rgba\(99\,102\,241\,0\.3\)\]{--tw-shadow:0 0 16px var(--tw-shadow-color,#6366f14d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_16px_rgba\(168\,85\,247\,0\.3\)\]{--tw-shadow:0 0 16px var(--tw-shadow-color,#a855f74d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring,.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-synapse\/10{--tw-shadow-color:#6366f11a}@supports (color:color-mix(in lab,red,red)){.shadow-synapse\/10{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--color-synapse) 10%, transparent) var(--tw-shadow-alpha), transparent)}}.shadow-synapse\/20{--tw-shadow-color:#6366f133}@supports (color:color-mix(in lab,red,red)){.shadow-synapse\/20{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--color-synapse) 20%, transparent) var(--tw-shadow-alpha), transparent)}}.ring-dream-glow{--tw-ring-color:var(--color-dream-glow)}.ring-dream\/60{--tw-ring-color:#a855f799}@supports (color:color-mix(in lab,red,red)){.ring-dream\/60{--tw-ring-color:color-mix(in oklab, var(--color-dream) 60%, transparent)}}.ring-recall\/30{--tw-ring-color:#10b9814d}@supports (color:color-mix(in lab,red,red)){.ring-recall\/30{--tw-ring-color:color-mix(in oklab, var(--color-recall) 30%, transparent)}}.ring-synapse\/60{--tw-ring-color:#6366f199}@supports (color:color-mix(in lab,red,red)){.ring-synapse\/60{--tw-ring-color:color-mix(in oklab, var(--color-synapse) 60%, transparent)}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur-md{--tw-backdrop-blur:blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.duration-700{--tw-duration:.7s;transition-duration:.7s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.select-none{-webkit-user-select:none;user-select:none}.placeholder\:text-muted::placeholder{color:var(--color-muted)}@media(hover:hover){.hover\:z-10:hover{z-index:10}.hover\:scale-110:hover{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}.hover\:scale-\[1\.03\]:hover{scale:1.03}.hover\:\!border-synapse\/30:hover{border-color:#6366f14d!important}@supports (color:color-mix(in lab,red,red)){.hover\:\!border-synapse\/30:hover{border-color:color-mix(in oklab,var(--color-synapse) 30%,transparent)!important}}.hover\:border-synapse\/20:hover{border-color:#6366f133}@supports (color:color-mix(in lab,red,red)){.hover\:border-synapse\/20:hover{border-color:color-mix(in oklab,var(--color-synapse) 20%,transparent)}}.hover\:border-synapse\/30:hover{border-color:#6366f14d}@supports (color:color-mix(in lab,red,red)){.hover\:border-synapse\/30:hover{border-color:color-mix(in oklab,var(--color-synapse) 30%,transparent)}}.hover\:border-synapse\/50:hover{border-color:#6366f180}@supports (color:color-mix(in lab,red,red)){.hover\:border-synapse\/50:hover{border-color:color-mix(in oklab,var(--color-synapse) 50%,transparent)}}.hover\:bg-decay\/20:hover{background-color:#ef444433}@supports (color:color-mix(in lab,red,red)){.hover\:bg-decay\/20:hover{background-color:color-mix(in oklab,var(--color-decay) 20%,transparent)}}.hover\:bg-decay\/30:hover{background-color:#ef44444d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-decay\/30:hover{background-color:color-mix(in oklab,var(--color-decay) 30%,transparent)}}.hover\:bg-dream\/20:hover{background-color:#a855f733}@supports (color:color-mix(in lab,red,red)){.hover\:bg-dream\/20:hover{background-color:color-mix(in oklab,var(--color-dream) 20%,transparent)}}.hover\:bg-dream\/30:hover{background-color:#a855f74d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-dream\/30:hover{background-color:color-mix(in oklab,var(--color-dream) 30%,transparent)}}.hover\:bg-purple-500\/30:hover{background-color:#ac4bff4d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-purple-500\/30:hover{background-color:color-mix(in oklab,var(--color-purple-500) 30%,transparent)}}.hover\:bg-recall\/30:hover{background-color:#10b9814d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-recall\/30:hover{background-color:color-mix(in oklab,var(--color-recall) 30%,transparent)}}.hover\:bg-synapse\/30:hover{background-color:#6366f14d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-synapse\/30:hover{background-color:color-mix(in oklab,var(--color-synapse) 30%,transparent)}}.hover\:bg-warning\/30:hover{background-color:#f59e0b4d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-warning\/30:hover{background-color:color-mix(in oklab,var(--color-warning) 30%,transparent)}}.hover\:bg-white\/\[0\.02\]:hover{background-color:#ffffff05}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/\[0\.02\]:hover{background-color:color-mix(in oklab,var(--color-white) 2%,transparent)}}.hover\:bg-white\/\[0\.03\]:hover{background-color:#ffffff08}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/\[0\.03\]:hover{background-color:color-mix(in oklab,var(--color-white) 3%,transparent)}}.hover\:bg-white\/\[0\.04\]:hover{background-color:#ffffff0a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/\[0\.04\]:hover{background-color:color-mix(in oklab,var(--color-white) 4%,transparent)}}.hover\:bg-white\/\[0\.08\]:hover{background-color:#ffffff14}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/\[0\.08\]:hover{background-color:color-mix(in oklab,var(--color-white) 8%,transparent)}}.hover\:text-bright:hover{color:var(--color-bright)}.hover\:text-dim:hover{color:var(--color-dim)}.hover\:text-synapse-glow:hover{color:var(--color-synapse-glow)}.hover\:text-text:hover{color:var(--color-text)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:\!border-synapse\/40:focus{border-color:#6366f166!important}@supports (color:color-mix(in lab,red,red)){.focus\:\!border-synapse\/40:focus{border-color:color-mix(in oklab,var(--color-synapse) 40%,transparent)!important}}.focus\:border-dream\/40:focus{border-color:#a855f766}@supports (color:color-mix(in lab,red,red)){.focus\:border-dream\/40:focus{border-color:color-mix(in oklab,var(--color-dream) 40%,transparent)}}.focus\:border-synapse\/40:focus{border-color:#6366f166}@supports (color:color-mix(in lab,red,red)){.focus\:border-synapse\/40:focus{border-color:color-mix(in oklab,var(--color-synapse) 40%,transparent)}}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-synapse-glow:focus{--tw-ring-color:var(--color-synapse-glow)}.focus\:ring-synapse\/20:focus{--tw-ring-color:#6366f133}@supports (color:color-mix(in lab,red,red)){.focus\:ring-synapse\/20:focus{--tw-ring-color:color-mix(in oklab, var(--color-synapse) 20%, transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-dream-glow\/60:focus-visible{--tw-ring-color:#c084fc99}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-dream-glow\/60:focus-visible{--tw-ring-color:color-mix(in oklab, var(--color-dream-glow) 60%, transparent)}}.focus-visible\:ring-recall\/60:focus-visible{--tw-ring-color:#10b98199}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-recall\/60:focus-visible{--tw-ring-color:color-mix(in oklab, var(--color-recall) 60%, transparent)}}.focus-visible\:ring-synapse\/60:focus-visible{--tw-ring-color:#6366f199}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-synapse\/60:focus-visible{--tw-ring-color:color-mix(in oklab, var(--color-synapse) 60%, transparent)}}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:40rem){.sm\:block{display:block}.sm\:inline-flex{display:inline-flex}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}}@media(min-width:48rem){.md\:block{display:block}.md\:flex{display:flex}.md\:hidden{display:none}.md\:inline-flex{display:inline-flex}.md\:min-w-\[340px\]{min-width:340px}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.md\:grid-cols-\[1fr_auto\]{grid-template-columns:1fr auto}.md\:grid-cols-\[280px_1fr\]{grid-template-columns:280px 1fr}.md\:flex-row{flex-direction:row}.md\:pt-\[15vh\]{padding-top:15vh}.md\:pb-0{padding-bottom:calc(var(--spacing) * 0)}}@media(min-width:64rem){.lg\:block{display:block}.lg\:w-56{width:calc(var(--spacing) * 56)}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-\[1fr_280px\]{grid-template-columns:1fr 280px}.lg\:grid-cols-\[1fr_340px\]{grid-template-columns:1fr 340px}.lg\:grid-cols-\[1fr_360px\]{grid-template-columns:1fr 360px}.lg\:grid-cols-\[minmax\(0\,1fr\)_340px\]{grid-template-columns:minmax(0,1fr) 340px}}.\[\&\:\:-webkit-slider-thumb\]\:h-3::-webkit-slider-thumb{height:calc(var(--spacing) * 3)}.\[\&\:\:-webkit-slider-thumb\]\:w-3::-webkit-slider-thumb{width:calc(var(--spacing) * 3)}.\[\&\:\:-webkit-slider-thumb\]\:appearance-none::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none}.\[\&\:\:-webkit-slider-thumb\]\:rounded-full::-webkit-slider-thumb{border-radius:3.40282e38px}.\[\&\:\:-webkit-slider-thumb\]\:bg-synapse-glow::-webkit-slider-thumb{background-color:var(--color-synapse-glow)}.\[\&\:\:-webkit-slider-thumb\]\:shadow-\[0_0_8px_rgba\(129\,140\,248\,0\.4\)\]::-webkit-slider-thumb{--tw-shadow:0 0 8px var(--tw-shadow-color,#818cf866);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}html{background:var(--color-void);color:var(--color-text);font-family:var(--font-mono)}body{min-height:100vh;margin:0;overflow:hidden}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--color-subtle);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--color-muted)}.glass{-webkit-backdrop-filter:blur(20px)saturate(180%);background:#16163873;border:1px solid #6366f114;box-shadow:inset 0 1px #ffffff08,0 4px 24px #0000004d}.glass-subtle{-webkit-backdrop-filter:blur(12px)saturate(150%);background:#10102a66;border:1px solid #6366f10f;box-shadow:inset 0 1px #ffffff05,0 2px 12px #0003}.glass-sidebar{-webkit-backdrop-filter:blur(24px)saturate(180%);background:#0a0a1a99;border-right:1px solid #6366f11a;box-shadow:inset -1px 0 #ffffff05,4px 0 24px #0000004d}.glass-panel{-webkit-backdrop-filter:blur(24px)saturate(180%);background:#0a0a1acc;border:1px solid #6366f11a;box-shadow:inset 0 1px #ffffff08,0 8px 32px #0006}.glow-synapse{box-shadow:0 0 20px #6366f14d,0 0 60px #6366f11a}.glow-dream{box-shadow:0 0 20px #a855f74d,0 0 60px #a855f71a}.glow-memory{box-shadow:0 0 20px #3b82f64d,0 0 60px #3b82f61a}@keyframes pulse-glow{0%,to{opacity:1}50%{opacity:.5}}.animate-pulse-glow{animation:2s ease-in-out infinite pulse-glow}@keyframes orb-float-1{0%,to{transform:translate(0)scale(1)}25%{transform:translate(60px,-40px)scale(1.1)}50%{transform:translate(-30px,-80px)scale(.95)}75%{transform:translate(-60px,-20px)scale(1.05)}}@keyframes orb-float-2{0%,to{transform:translate(0)scale(1)}25%{transform:translate(-50px,30px)scale(1.08)}50%{transform:translate(40px,60px)scale(.92)}75%{transform:translate(20px,-40px)scale(1.03)}}@keyframes orb-float-3{0%,to{transform:translate(0)scale(1)}25%{transform:translate(30px,50px)scale(1.05)}50%{transform:translate(-60px,20px)scale(.98)}75%{transform:translate(40px,-30px)scale(1.1)}}.ambient-orb{filter:blur(80px);pointer-events:none;z-index:0;opacity:.35;border-radius:50%;position:fixed}.ambient-orb-1{background:radial-gradient(circle,#a855f766,#0000 70%);width:400px;height:400px;animation:20s ease-in-out infinite orb-float-1;top:-10%;right:-5%}.ambient-orb-2{background:radial-gradient(circle,#6366f159,#0000 70%);width:350px;height:350px;animation:25s ease-in-out infinite orb-float-2;bottom:-15%;left:-5%}.ambient-orb-3{background:radial-gradient(circle,#f59e0b33,#0000 70%);width:300px;height:300px;animation:22s ease-in-out infinite orb-float-3;top:40%;left:40%}.nav-active-border{position:relative}.nav-active-border:before{content:"";background:linear-gradient(180deg,var(--color-synapse),var(--color-dream),var(--color-synapse));background-size:100% 200%;border-radius:1px;width:2px;animation:3s ease-in-out infinite gradient-shift;position:absolute;top:4px;bottom:4px;left:0}@keyframes gradient-shift{0%,to{background-position:0 0}50%{background-position:0 100%}}@keyframes float{0%,to{transform:translateY(0)translate(0)}25%{transform:translateY(-10px)translate(5px)}50%{transform:translateY(-5px)translate(-5px)}75%{transform:translateY(-15px)translate(3px)}}.retention-critical{color:var(--color-decay)}.retention-low{color:var(--color-warning)}.retention-good{color:var(--color-recall)}.retention-strong{color:var(--color-synapse)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}.toast-layer.svelte-pry2ep{position:fixed;z-index:60;pointer-events:none;display:flex;flex-direction:column;gap:.5rem;right:1.25rem;bottom:1.25rem;max-width:22rem;width:calc(100vw - 2.5rem)}@media(max-width:768px){.toast-layer.svelte-pry2ep{right:.75rem;left:.75rem;bottom:auto;top:5.25rem;max-width:none;width:auto;align-items:stretch}}.toast-item.svelte-pry2ep{pointer-events:auto;position:relative;display:flex;gap:.75rem;align-items:stretch;text-align:left;font:inherit;color:inherit;background:#0c0e16b8;backdrop-filter:blur(14px) saturate(160%);-webkit-backdrop-filter:blur(14px) saturate(160%);border:1px solid rgba(255,255,255,.06);border-radius:.75rem;padding:.75rem .9rem .75rem .5rem;overflow:hidden;box-shadow:0 10px 40px -12px #000c,0 0 22px -6px var(--toast-color);cursor:pointer;animation:svelte-pry2ep-toast-in .32s cubic-bezier(.16,1,.3,1);transform-origin:right center;transition:transform .15s ease,box-shadow .15s ease}.toast-item.svelte-pry2ep:hover{transform:translateY(-1px) scale(1.015);box-shadow:0 14px 48px -12px #000000d9,0 0 32px -4px var(--toast-color)}.toast-item.svelte-pry2ep:focus-visible{outline:1px solid var(--toast-color);outline-offset:2px}.toast-accent.svelte-pry2ep{width:3px;border-radius:2px;background:var(--toast-color);box-shadow:0 0 10px var(--toast-color);flex-shrink:0}.toast-body.svelte-pry2ep{display:flex;flex-direction:column;gap:.15rem;flex:1;min-width:0}.toast-head.svelte-pry2ep{display:flex;align-items:center;gap:.5rem}.toast-icon.svelte-pry2ep{color:var(--toast-color);font-size:.95rem;text-shadow:0 0 8px var(--toast-color);line-height:1;width:1rem;display:inline-flex;justify-content:center}.toast-title.svelte-pry2ep{color:#f5f5fa;font-size:.82rem;font-weight:600;letter-spacing:.01em}.toast-sub.svelte-pry2ep{color:#b0b6c4;font-size:.74rem;line-height:1.35;padding-left:1.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.toast-progress.svelte-pry2ep{position:absolute;left:0;bottom:0;height:2px;width:100%;background:#ffffff0a}.toast-progress-fill.svelte-pry2ep{height:100%;background:var(--toast-color);opacity:.55;transform-origin:left center;animation:svelte-pry2ep-toast-progress var(--toast-dwell) linear forwards}.toast-item.svelte-pry2ep:hover .toast-progress-fill:where(.svelte-pry2ep),.toast-item.svelte-pry2ep:focus-visible .toast-progress-fill:where(.svelte-pry2ep){animation-play-state:paused}@keyframes svelte-pry2ep-toast-in{0%{opacity:0;transform:translate(24px) scale(.98)}to{opacity:1;transform:translate(0) scale(1)}}@media(max-width:768px){.toast-item.svelte-pry2ep{transform-origin:top center;animation:svelte-pry2ep-toast-in-mobile .3s cubic-bezier(.16,1,.3,1)}}@keyframes svelte-pry2ep-toast-in-mobile{0%{opacity:0;transform:translateY(-12px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes svelte-pry2ep-toast-progress{0%{transform:scaleX(1)}to{transform:scaleX(0)}}@media(prefers-reduced-motion:reduce){.toast-item.svelte-pry2ep{animation:none}.toast-progress-fill.svelte-pry2ep{animation:none;transform:scaleX(.5)}}.strip-item.svelte-1kk3799{display:inline-flex;align-items:center;gap:.4rem;padding:0 .75rem;white-space:nowrap;flex-shrink:0}.strip-divider.svelte-1kk3799{width:1px;height:14px;background:#6366f11f;flex-shrink:0}.ambient-strip.ambient-flash.svelte-1kk3799{background:linear-gradient(90deg,#ef444414,#ef444400 70%),#0006;border-bottom-color:#ef444459;transition:background .3s ease,border-color .3s ease}@keyframes svelte-1kk3799-ping-slow{0%{transform:scale(1);opacity:.8}80%,to{transform:scale(2);opacity:0}}.animate-ping-slow{animation:svelte-1kk3799-ping-slow 2.2s cubic-bezier(0,0,.2,1) infinite}@media(prefers-reduced-motion:reduce){.ambient-strip.svelte-1kk3799 .animate-ping,.ambient-strip.svelte-1kk3799 .animate-ping-slow,.ambient-strip.svelte-1kk3799 .animate-pulse{animation:none!important}}.verdict-bar.svelte-1j425e6{border-bottom:1px solid rgba(255,255,255,.06);background:#080912b8;backdrop-filter:blur(18px) saturate(160%);-webkit-backdrop-filter:blur(18px) saturate(160%);box-shadow:0 6px 24px #0000002e}.verdict-summary.svelte-1j425e6{width:100%;min-height:2.75rem;display:grid;grid-template-columns:auto auto minmax(0,1fr) auto;align-items:center;gap:.75rem;padding:.55rem 1rem;color:var(--color-text);text-align:left;font:inherit}.sr-only.svelte-1j425e6{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.label.svelte-1j425e6,.field-label.svelte-1j425e6,.appeal-row.svelte-1j425e6>span:where(.svelte-1j425e6){color:var(--color-dim);font-size:.68rem;text-transform:uppercase;letter-spacing:0}.levels.svelte-1j425e6{display:flex;align-items:center;gap:.25rem}.levels.svelte-1j425e6 span:where(.svelte-1j425e6){border:1px solid rgba(255,255,255,.08);border-radius:.35rem;padding:.18rem .38rem;color:var(--color-muted);font-size:.64rem;line-height:1}.levels.svelte-1j425e6 span.active:where(.svelte-1j425e6){color:var(--color-bright);border-color:var(--verdict-color);background:color-mix(in srgb,var(--verdict-color) 18%,transparent);box-shadow:0 0 14px color-mix(in srgb,var(--verdict-color) 28%,transparent)}.summary-text.svelte-1j425e6{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.78rem;color:var(--color-dim)}.when.svelte-1j425e6{color:var(--color-muted);font-size:.68rem}.receipt.svelte-1j425e6{margin:0 1rem .75rem;border:1px solid rgba(255,255,255,.08);border-radius:.5rem;background:#0a0a1ac7;padding:.85rem}.receipt-grid.svelte-1j425e6{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(10rem,.8fr) minmax(0,1.1fr) minmax(0,1.1fr);gap:.85rem}.receipt.svelte-1j425e6 p:where(.svelte-1j425e6),.receipt.svelte-1j425e6 li:where(.svelte-1j425e6){margin:.25rem 0 0;color:var(--color-text);font-size:.76rem;line-height:1.45;overflow-wrap:anywhere}.receipt.svelte-1j425e6 ul:where(.svelte-1j425e6){margin:.25rem 0 0;padding-left:1rem}.appeal-row.svelte-1j425e6{display:flex;align-items:center;gap:.4rem;margin-top:.85rem;flex-wrap:wrap}.appeal-row.svelte-1j425e6 button:where(.svelte-1j425e6),.appeal-row.svelte-1j425e6 p:where(.svelte-1j425e6){border:1px solid rgba(255,255,255,.1);border-radius:.4rem;padding:.35rem .6rem;color:var(--color-text);background:#ffffff0a;font-size:.72rem;margin:0}.appeal-row.svelte-1j425e6 button:where(.svelte-1j425e6):hover:not(:disabled),.verdict-summary.svelte-1j425e6:hover{background:#ffffff0d}.appeal-row.svelte-1j425e6 button:where(.svelte-1j425e6):disabled{opacity:.55;cursor:wait}.tone-pass.svelte-1j425e6,.tone-note.svelte-1j425e6{--verdict-color: #10b981}.tone-caution.svelte-1j425e6{--verdict-color: #f59e0b}.tone-veto.svelte-1j425e6{--verdict-color: #ef4444}.tone-appealed.svelte-1j425e6{--verdict-color: #818cf8}@media(max-width:900px){.verdict-summary.svelte-1j425e6{grid-template-columns:auto minmax(0,1fr) auto}.levels.svelte-1j425e6{grid-column:1 / -1;order:4;overflow-x:auto;padding-bottom:.1rem}.receipt-grid.svelte-1j425e6{grid-template-columns:1fr}}.theme-toggle.svelte-1cmi4dh{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;padding:0;border-radius:8px;background:#6366f10f;border:1px solid rgba(99,102,241,.14);color:var(--color-text);cursor:pointer;transition:background .2s ease,border-color .2s ease,color .2s ease,transform .12s ease;-webkit-tap-highlight-color:transparent}.theme-toggle.svelte-1cmi4dh:hover{background:#6366f124;border-color:#6366f14d;color:var(--color-bright)}.theme-toggle.svelte-1cmi4dh:active{transform:scale(.94)}.theme-toggle.svelte-1cmi4dh:focus-visible{outline:1px solid var(--color-synapse);outline-offset:2px}.icon-wrap.svelte-1cmi4dh{position:relative;width:18px;height:18px;display:inline-block}.icon.svelte-1cmi4dh{position:absolute;top:0;right:0;bottom:0;left:0;width:18px;height:18px;opacity:0;transform:scale(.7) rotate(-30deg);transition:opacity .2s ease,transform .2s cubic-bezier(.16,1,.3,1);pointer-events:none}.icon.active.svelte-1cmi4dh{opacity:1;transform:scale(1) rotate(0)}.theme-toggle[data-mode=dark].svelte-1cmi4dh{color:var(--color-synapse-glow, #818cf8)}.theme-toggle[data-mode=light].svelte-1cmi4dh{color:var(--color-warning, #f59e0b)}.theme-toggle[data-mode=auto].svelte-1cmi4dh{color:var(--color-dream-glow, #c084fc)}@media(prefers-reduced-motion:reduce){.theme-toggle.svelte-1cmi4dh,.icon.svelte-1cmi4dh{transition:none}}.safe-bottom.svelte-12qhfyh{padding-bottom:env(safe-area-inset-bottom,0px)}@keyframes svelte-12qhfyh-page-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.animate-page-in.svelte-12qhfyh{animation:svelte-12qhfyh-page-in .2s ease-out} +/*! tailwindcss v4.2.0 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:"JetBrains Mono", "Fira Code", "SF Mono", monospace;--color-amber-400:oklch(82.8% .189 84.429);--color-purple-400:oklch(71.4% .203 305.504);--color-purple-500:oklch(62.7% .265 303.9);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--container-2xl:42rem;--container-4xl:56rem;--container-5xl:64rem;--container-6xl:72rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-snug:1.375;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--blur-md:12px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-void:#050510;--color-abyss:#0a0a1a;--color-deep:#10102a;--color-surface:#161638;--color-elevated:#1e1e4a;--color-subtle:#2a2a5e;--color-muted:#4a4a7a;--color-dim:#7a7aaa;--color-text:#e0e0ff;--color-bright:#fff;--color-synapse:#6366f1;--color-synapse-glow:#818cf8;--color-dream:#a855f7;--color-dream-glow:#c084fc;--color-memory:#3b82f6;--color-recall:#10b981;--color-decay:#ef4444;--color-warning:#f59e0b;--color-node-pattern:#ec4899}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.end\!{inset-inline-end:var(--spacing)!important}.top-0{top:calc(var(--spacing) * 0)}.top-0\.5{top:calc(var(--spacing) * .5)}.top-1{top:calc(var(--spacing) * 1)}.top-3{top:calc(var(--spacing) * 3)}.top-4{top:calc(var(--spacing) * 4)}.top-10{top:calc(var(--spacing) * 10)}.right-0{right:calc(var(--spacing) * 0)}.right-4{right:calc(var(--spacing) * 4)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-4{bottom:calc(var(--spacing) * 4)}.-left-\[29px\]{left:-29px}.left-1\/2{left:50%}.left-4{left:calc(var(--spacing) * 4)}.left-6{left:calc(var(--spacing) * 6)}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-40{z-index:40}.z-50{z-index:50}.z-\[1\]{z-index:1}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-\[-12px\]{margin-top:-12px}.mr-1{margin-right:calc(var(--spacing) * 1)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-auto{margin-left:auto}.line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-4{-webkit-line-clamp:4;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.aspect-square{aspect-ratio:1}.h-0\.5{height:calc(var(--spacing) * .5)}.h-1{height:calc(var(--spacing) * 1)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-20{height:calc(var(--spacing) * 20)}.h-24{height:calc(var(--spacing) * 24)}.h-28{height:calc(var(--spacing) * 28)}.h-32{height:calc(var(--spacing) * 32)}.h-40{height:calc(var(--spacing) * 40)}.h-\[520px\]{height:520px}.h-\[560px\]{height:560px}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-48{max-height:calc(var(--spacing) * 48)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-72{max-height:calc(var(--spacing) * 72)}.max-h-96{max-height:calc(var(--spacing) * 96)}.max-h-\[620px\]{max-height:620px}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-40{min-height:calc(var(--spacing) * 40)}.min-h-\[240px\]{min-height:240px}.min-h-\[320px\]{min-height:320px}.min-h-\[520px\]{min-height:520px}.min-h-full{min-height:100%}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-3{width:calc(var(--spacing) * 3)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-24{width:calc(var(--spacing) * 24)}.w-32{width:calc(var(--spacing) * 32)}.w-96{width:calc(var(--spacing) * 96)}.w-\[3px\]{width:3px}.w-\[90\%\]{width:90%}.w-full{width:100%}.w-px{width:1px}.max-w-2xl{max-width:var(--container-2xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-20{max-width:calc(var(--spacing) * 20)}.max-w-\[220px\]{max-width:220px}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-xl{max-width:var(--container-xl)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-12{min-width:calc(var(--spacing) * 12)}.min-w-16{min-width:calc(var(--spacing) * 16)}.min-w-64{min-width:calc(var(--spacing) * 64)}.min-w-\[2rem\]{min-width:2rem}.min-w-\[3\.5rem\]{min-width:3.5rem}.flex-1{flex:1}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.border-separate{border-collapse:separate}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-125{--tw-scale-x:125%;--tw-scale-y:125%;--tw-scale-z:125%;scale:var(--tw-scale-x) var(--tw-scale-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-\[fadeSlide_0\.35s_ease-out_both\]{animation:.35s ease-out both fadeSlide}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-none{resize:none}.resize-y{resize:vertical}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-around{justify-content:space-around}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0{gap:calc(var(--spacing) * 0)}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-\[2px\]{gap:2px}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-y-1{row-gap:calc(var(--spacing) * 1)}.self-center{align-self:center}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.\!border-decay\/20{border-color:#ef444433!important}@supports (color:color-mix(in lab,red,red)){.\!border-decay\/20{border-color:color-mix(in oklab,var(--color-decay) 20%,transparent)!important}}.\!border-decay\/30{border-color:#ef44444d!important}@supports (color:color-mix(in lab,red,red)){.\!border-decay\/30{border-color:color-mix(in oklab,var(--color-decay) 30%,transparent)!important}}.\!border-decay\/40{border-color:#ef444466!important}@supports (color:color-mix(in lab,red,red)){.\!border-decay\/40{border-color:color-mix(in oklab,var(--color-decay) 40%,transparent)!important}}.\!border-dream\/20{border-color:#a855f733!important}@supports (color:color-mix(in lab,red,red)){.\!border-dream\/20{border-color:color-mix(in oklab,var(--color-dream) 20%,transparent)!important}}.\!border-synapse\/15{border-color:#6366f126!important}@supports (color:color-mix(in lab,red,red)){.\!border-synapse\/15{border-color:color-mix(in oklab,var(--color-synapse) 15%,transparent)!important}}.\!border-synapse\/20{border-color:#6366f133!important}@supports (color:color-mix(in lab,red,red)){.\!border-synapse\/20{border-color:color-mix(in oklab,var(--color-synapse) 20%,transparent)!important}}.\!border-synapse\/25{border-color:#6366f140!important}@supports (color:color-mix(in lab,red,red)){.\!border-synapse\/25{border-color:color-mix(in oklab,var(--color-synapse) 25%,transparent)!important}}.\!border-synapse\/30{border-color:#6366f14d!important}@supports (color:color-mix(in lab,red,red)){.\!border-synapse\/30{border-color:color-mix(in oklab,var(--color-synapse) 30%,transparent)!important}}.\!border-synapse\/40{border-color:#6366f166!important}@supports (color:color-mix(in lab,red,red)){.\!border-synapse\/40{border-color:color-mix(in oklab,var(--color-synapse) 40%,transparent)!important}}.border-\[\#A33FFF\]\/40{border-color:#a33fff66}.border-decay\/20{border-color:#ef444433}@supports (color:color-mix(in lab,red,red)){.border-decay\/20{border-color:color-mix(in oklab,var(--color-decay) 20%,transparent)}}.border-dream-glow\/40{border-color:#c084fc66}@supports (color:color-mix(in lab,red,red)){.border-dream-glow\/40{border-color:color-mix(in oklab,var(--color-dream-glow) 40%,transparent)}}.border-dream\/10{border-color:#a855f71a}@supports (color:color-mix(in lab,red,red)){.border-dream\/10{border-color:color-mix(in oklab,var(--color-dream) 10%,transparent)}}.border-dream\/20{border-color:#a855f733}@supports (color:color-mix(in lab,red,red)){.border-dream\/20{border-color:color-mix(in oklab,var(--color-dream) 20%,transparent)}}.border-dream\/30{border-color:#a855f74d}@supports (color:color-mix(in lab,red,red)){.border-dream\/30{border-color:color-mix(in oklab,var(--color-dream) 30%,transparent)}}.border-dream\/40{border-color:#a855f766}@supports (color:color-mix(in lab,red,red)){.border-dream\/40{border-color:color-mix(in oklab,var(--color-dream) 40%,transparent)}}.border-dream\/50{border-color:#a855f780}@supports (color:color-mix(in lab,red,red)){.border-dream\/50{border-color:color-mix(in oklab,var(--color-dream) 50%,transparent)}}.border-recall\/30{border-color:#10b9814d}@supports (color:color-mix(in lab,red,red)){.border-recall\/30{border-color:color-mix(in oklab,var(--color-recall) 30%,transparent)}}.border-recall\/40{border-color:#10b98166}@supports (color:color-mix(in lab,red,red)){.border-recall\/40{border-color:color-mix(in oklab,var(--color-recall) 40%,transparent)}}.border-subtle\/15{border-color:#2a2a5e26}@supports (color:color-mix(in lab,red,red)){.border-subtle\/15{border-color:color-mix(in oklab,var(--color-subtle) 15%,transparent)}}.border-subtle\/20{border-color:#2a2a5e33}@supports (color:color-mix(in lab,red,red)){.border-subtle\/20{border-color:color-mix(in oklab,var(--color-subtle) 20%,transparent)}}.border-subtle\/30{border-color:#2a2a5e4d}@supports (color:color-mix(in lab,red,red)){.border-subtle\/30{border-color:color-mix(in oklab,var(--color-subtle) 30%,transparent)}}.border-synapse{border-color:var(--color-synapse)}.border-synapse\/5{border-color:#6366f10d}@supports (color:color-mix(in lab,red,red)){.border-synapse\/5{border-color:color-mix(in oklab,var(--color-synapse) 5%,transparent)}}.border-synapse\/10{border-color:#6366f11a}@supports (color:color-mix(in lab,red,red)){.border-synapse\/10{border-color:color-mix(in oklab,var(--color-synapse) 10%,transparent)}}.border-synapse\/15{border-color:#6366f126}@supports (color:color-mix(in lab,red,red)){.border-synapse\/15{border-color:color-mix(in oklab,var(--color-synapse) 15%,transparent)}}.border-synapse\/20{border-color:#6366f133}@supports (color:color-mix(in lab,red,red)){.border-synapse\/20{border-color:color-mix(in oklab,var(--color-synapse) 20%,transparent)}}.border-synapse\/30{border-color:#6366f14d}@supports (color:color-mix(in lab,red,red)){.border-synapse\/30{border-color:color-mix(in oklab,var(--color-synapse) 30%,transparent)}}.border-synapse\/40{border-color:#6366f166}@supports (color:color-mix(in lab,red,red)){.border-synapse\/40{border-color:color-mix(in oklab,var(--color-synapse) 40%,transparent)}}.border-transparent{border-color:#0000}.border-warning\/30{border-color:#f59e0b4d}@supports (color:color-mix(in lab,red,red)){.border-warning\/30{border-color:color-mix(in oklab,var(--color-warning) 30%,transparent)}}.border-warning\/40{border-color:#f59e0b66}@supports (color:color-mix(in lab,red,red)){.border-warning\/40{border-color:color-mix(in oklab,var(--color-warning) 40%,transparent)}}.border-warning\/50{border-color:#f59e0b80}@supports (color:color-mix(in lab,red,red)){.border-warning\/50{border-color:color-mix(in oklab,var(--color-warning) 50%,transparent)}}.border-white\/5{border-color:#ffffff0d}@supports (color:color-mix(in lab,red,red)){.border-white\/5{border-color:color-mix(in oklab,var(--color-white) 5%,transparent)}}.border-t-dream{border-top-color:var(--color-dream)}.border-t-synapse{border-top-color:var(--color-synapse)}.border-t-warning{border-top-color:var(--color-warning)}.bg-\[\#A33FFF\]{background-color:#a33fff}.bg-\[\#A33FFF\]\/10{background-color:#a33fff1a}.bg-amber-400{background-color:var(--color-amber-400)}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab,red,red)){.bg-black\/40{background-color:color-mix(in oklab,var(--color-black) 40%,transparent)}}.bg-decay{background-color:var(--color-decay)}.bg-decay\/10{background-color:#ef44441a}@supports (color:color-mix(in lab,red,red)){.bg-decay\/10{background-color:color-mix(in oklab,var(--color-decay) 10%,transparent)}}.bg-decay\/20{background-color:#ef444433}@supports (color:color-mix(in lab,red,red)){.bg-decay\/20{background-color:color-mix(in oklab,var(--color-decay) 20%,transparent)}}.bg-decay\/\[0\.05\]{background-color:#ef44440d}@supports (color:color-mix(in lab,red,red)){.bg-decay\/\[0\.05\]{background-color:color-mix(in oklab,var(--color-decay) 5%,transparent)}}.bg-deep{background-color:var(--color-deep)}.bg-deep\/40{background-color:#10102a66}@supports (color:color-mix(in lab,red,red)){.bg-deep\/40{background-color:color-mix(in oklab,var(--color-deep) 40%,transparent)}}.bg-deep\/60{background-color:#10102a99}@supports (color:color-mix(in lab,red,red)){.bg-deep\/60{background-color:color-mix(in oklab,var(--color-deep) 60%,transparent)}}.bg-dream{background-color:var(--color-dream)}.bg-dream\/5{background-color:#a855f70d}@supports (color:color-mix(in lab,red,red)){.bg-dream\/5{background-color:color-mix(in oklab,var(--color-dream) 5%,transparent)}}.bg-dream\/10{background-color:#a855f71a}@supports (color:color-mix(in lab,red,red)){.bg-dream\/10{background-color:color-mix(in oklab,var(--color-dream) 10%,transparent)}}.bg-dream\/15{background-color:#a855f726}@supports (color:color-mix(in lab,red,red)){.bg-dream\/15{background-color:color-mix(in oklab,var(--color-dream) 15%,transparent)}}.bg-dream\/20{background-color:#a855f733}@supports (color:color-mix(in lab,red,red)){.bg-dream\/20{background-color:color-mix(in oklab,var(--color-dream) 20%,transparent)}}.bg-muted{background-color:var(--color-muted)}.bg-node-pattern{background-color:var(--color-node-pattern)}.bg-purple-500\/20{background-color:#ac4bff33}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\/20{background-color:color-mix(in oklab,var(--color-purple-500) 20%,transparent)}}.bg-recall{background-color:var(--color-recall)}.bg-recall\/10{background-color:#10b9811a}@supports (color:color-mix(in lab,red,red)){.bg-recall\/10{background-color:color-mix(in oklab,var(--color-recall) 10%,transparent)}}.bg-recall\/15{background-color:#10b98126}@supports (color:color-mix(in lab,red,red)){.bg-recall\/15{background-color:color-mix(in oklab,var(--color-recall) 15%,transparent)}}.bg-recall\/20{background-color:#10b98133}@supports (color:color-mix(in lab,red,red)){.bg-recall\/20{background-color:color-mix(in oklab,var(--color-recall) 20%,transparent)}}.bg-synapse{background-color:var(--color-synapse)}.bg-synapse-glow{background-color:var(--color-synapse-glow)}.bg-synapse\/10{background-color:#6366f11a}@supports (color:color-mix(in lab,red,red)){.bg-synapse\/10{background-color:color-mix(in oklab,var(--color-synapse) 10%,transparent)}}.bg-synapse\/15{background-color:#6366f126}@supports (color:color-mix(in lab,red,red)){.bg-synapse\/15{background-color:color-mix(in oklab,var(--color-synapse) 15%,transparent)}}.bg-synapse\/20{background-color:#6366f133}@supports (color:color-mix(in lab,red,red)){.bg-synapse\/20{background-color:color-mix(in oklab,var(--color-synapse) 20%,transparent)}}.bg-synapse\/25{background-color:#6366f140}@supports (color:color-mix(in lab,red,red)){.bg-synapse\/25{background-color:color-mix(in oklab,var(--color-synapse) 25%,transparent)}}.bg-synapse\/70{background-color:#6366f1b3}@supports (color:color-mix(in lab,red,red)){.bg-synapse\/70{background-color:color-mix(in oklab,var(--color-synapse) 70%,transparent)}}.bg-transparent{background-color:#0000}.bg-void{background-color:var(--color-void)}.bg-void\/60{background-color:#05051099}@supports (color:color-mix(in lab,red,red)){.bg-void\/60{background-color:color-mix(in oklab,var(--color-void) 60%,transparent)}}.bg-warning{background-color:var(--color-warning)}.bg-warning\/5{background-color:#f59e0b0d}@supports (color:color-mix(in lab,red,red)){.bg-warning\/5{background-color:color-mix(in oklab,var(--color-warning) 5%,transparent)}}.bg-warning\/20{background-color:#f59e0b33}@supports (color:color-mix(in lab,red,red)){.bg-warning\/20{background-color:color-mix(in oklab,var(--color-warning) 20%,transparent)}}.bg-white\/\[0\.02\]{background-color:#ffffff05}@supports (color:color-mix(in lab,red,red)){.bg-white\/\[0\.02\]{background-color:color-mix(in oklab,var(--color-white) 2%,transparent)}}.bg-white\/\[0\.03\]{background-color:#ffffff08}@supports (color:color-mix(in lab,red,red)){.bg-white\/\[0\.03\]{background-color:color-mix(in oklab,var(--color-white) 3%,transparent)}}.bg-white\/\[0\.04\]{background-color:#ffffff0a}@supports (color:color-mix(in lab,red,red)){.bg-white\/\[0\.04\]{background-color:color-mix(in oklab,var(--color-white) 4%,transparent)}}.bg-white\/\[0\.06\]{background-color:#ffffff0f}@supports (color:color-mix(in lab,red,red)){.bg-white\/\[0\.06\]{background-color:color-mix(in oklab,var(--color-white) 6%,transparent)}}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-dream{--tw-gradient-from:var(--color-dream);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-synapse{--tw-gradient-to:var(--color-synapse);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.p-0{padding:calc(var(--spacing) * 0)}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-10{padding:calc(var(--spacing) * 10)}.p-12{padding:calc(var(--spacing) * 12)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-10{padding-block:calc(var(--spacing) * 10)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-20{padding-block:calc(var(--spacing) * 20)}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-8{padding-top:calc(var(--spacing) * 8)}.pt-\[10vh\]{padding-top:10vh}.pr-1{padding-right:calc(var(--spacing) * 1)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-16{padding-bottom:calc(var(--spacing) * 16)}.pl-6{padding-left:calc(var(--spacing) * 6)}.pl-14{padding-left:calc(var(--spacing) * 14)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-bottom{vertical-align:bottom}.align-top{vertical-align:top}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.12em\]{--tw-tracking:.12em;letter-spacing:.12em}.tracking-\[0\.15em\]{--tw-tracking:.15em;letter-spacing:.15em}.tracking-\[0\.18em\]{--tw-tracking:.18em;letter-spacing:.18em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#E4C8FF\]{color:#e4c8ff}.text-amber-400{color:var(--color-amber-400)}.text-bright{color:var(--color-bright)}.text-decay{color:var(--color-decay)}.text-decay\/60{color:#ef444499}@supports (color:color-mix(in lab,red,red)){.text-decay\/60{color:color-mix(in oklab,var(--color-decay) 60%,transparent)}}.text-dim{color:var(--color-dim)}.text-dream{color:var(--color-dream)}.text-dream-glow{color:var(--color-dream-glow)}.text-dream\/40{color:#a855f766}@supports (color:color-mix(in lab,red,red)){.text-dream\/40{color:color-mix(in oklab,var(--color-dream) 40%,transparent)}}.text-dream\/80{color:#a855f7cc}@supports (color:color-mix(in lab,red,red)){.text-dream\/80{color:color-mix(in oklab,var(--color-dream) 80%,transparent)}}.text-memory{color:var(--color-memory)}.text-muted{color:var(--color-muted)}.text-muted\/50{color:#4a4a7a80}@supports (color:color-mix(in lab,red,red)){.text-muted\/50{color:color-mix(in oklab,var(--color-muted) 50%,transparent)}}.text-muted\/60{color:#4a4a7a99}@supports (color:color-mix(in lab,red,red)){.text-muted\/60{color:color-mix(in oklab,var(--color-muted) 60%,transparent)}}.text-node-pattern{color:var(--color-node-pattern)}.text-purple-400{color:var(--color-purple-400)}.text-recall{color:var(--color-recall)}.text-subtle{color:var(--color-subtle)}.text-synapse{color:var(--color-synapse)}.text-synapse-glow{color:var(--color-synapse-glow)}.text-text{color:var(--color-text)}.text-text\/80{color:#e0e0ffcc}@supports (color:color-mix(in lab,red,red)){.text-text\/80{color:color-mix(in oklab,var(--color-text) 80%,transparent)}}.text-warning{color:var(--color-warning)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline-offset-4{text-underline-offset:4px}.accent-synapse{accent-color:var(--color-synapse)}.accent-synapse-glow{accent-color:var(--color-synapse-glow)}.opacity-20{opacity:.2}.opacity-30{opacity:.3}.opacity-35{opacity:.35}.opacity-40{opacity:.4}.opacity-60{opacity:.6}.opacity-75{opacity:.75}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow\!{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a)!important;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)!important}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_10px_rgba\(239\,68\,68\,0\.7\)\]{--tw-shadow:0 0 10px var(--tw-shadow-color,#ef4444b3);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_12px_rgba\(99\,102\,241\,0\.15\)\]{--tw-shadow:0 0 12px var(--tw-shadow-color,#6366f126);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_12px_rgba\(99\,102\,241\,0\.18\)\]{--tw-shadow:0 0 12px var(--tw-shadow-color,#6366f12e);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_12px_rgba\(163\,63\,255\,0\.15\)\]{--tw-shadow:0 0 12px var(--tw-shadow-color,#a33fff26);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_16px_rgba\(99\,102\,241\,0\.3\)\]{--tw-shadow:0 0 16px var(--tw-shadow-color,#6366f14d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_16px_rgba\(168\,85\,247\,0\.3\)\]{--tw-shadow:0 0 16px var(--tw-shadow-color,#a855f74d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring,.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-synapse\/10{--tw-shadow-color:#6366f11a}@supports (color:color-mix(in lab,red,red)){.shadow-synapse\/10{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--color-synapse) 10%, transparent) var(--tw-shadow-alpha), transparent)}}.shadow-synapse\/20{--tw-shadow-color:#6366f133}@supports (color:color-mix(in lab,red,red)){.shadow-synapse\/20{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--color-synapse) 20%, transparent) var(--tw-shadow-alpha), transparent)}}.ring-dream-glow{--tw-ring-color:var(--color-dream-glow)}.ring-dream\/60{--tw-ring-color:#a855f799}@supports (color:color-mix(in lab,red,red)){.ring-dream\/60{--tw-ring-color:color-mix(in oklab, var(--color-dream) 60%, transparent)}}.ring-recall\/30{--tw-ring-color:#10b9814d}@supports (color:color-mix(in lab,red,red)){.ring-recall\/30{--tw-ring-color:color-mix(in oklab, var(--color-recall) 30%, transparent)}}.ring-synapse\/60{--tw-ring-color:#6366f199}@supports (color:color-mix(in lab,red,red)){.ring-synapse\/60{--tw-ring-color:color-mix(in oklab, var(--color-synapse) 60%, transparent)}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur-md{--tw-backdrop-blur:blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.duration-700{--tw-duration:.7s;transition-duration:.7s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.select-none{-webkit-user-select:none;user-select:none}.placeholder\:text-muted::placeholder{color:var(--color-muted)}@media(hover:hover){.hover\:z-10:hover{z-index:10}.hover\:scale-110:hover{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}.hover\:scale-\[1\.03\]:hover{scale:1.03}.hover\:\!border-synapse\/30:hover{border-color:#6366f14d!important}@supports (color:color-mix(in lab,red,red)){.hover\:\!border-synapse\/30:hover{border-color:color-mix(in oklab,var(--color-synapse) 30%,transparent)!important}}.hover\:border-synapse\/20:hover{border-color:#6366f133}@supports (color:color-mix(in lab,red,red)){.hover\:border-synapse\/20:hover{border-color:color-mix(in oklab,var(--color-synapse) 20%,transparent)}}.hover\:border-synapse\/30:hover{border-color:#6366f14d}@supports (color:color-mix(in lab,red,red)){.hover\:border-synapse\/30:hover{border-color:color-mix(in oklab,var(--color-synapse) 30%,transparent)}}.hover\:border-synapse\/50:hover{border-color:#6366f180}@supports (color:color-mix(in lab,red,red)){.hover\:border-synapse\/50:hover{border-color:color-mix(in oklab,var(--color-synapse) 50%,transparent)}}.hover\:bg-decay\/20:hover{background-color:#ef444433}@supports (color:color-mix(in lab,red,red)){.hover\:bg-decay\/20:hover{background-color:color-mix(in oklab,var(--color-decay) 20%,transparent)}}.hover\:bg-decay\/30:hover{background-color:#ef44444d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-decay\/30:hover{background-color:color-mix(in oklab,var(--color-decay) 30%,transparent)}}.hover\:bg-dream\/20:hover{background-color:#a855f733}@supports (color:color-mix(in lab,red,red)){.hover\:bg-dream\/20:hover{background-color:color-mix(in oklab,var(--color-dream) 20%,transparent)}}.hover\:bg-dream\/30:hover{background-color:#a855f74d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-dream\/30:hover{background-color:color-mix(in oklab,var(--color-dream) 30%,transparent)}}.hover\:bg-purple-500\/30:hover{background-color:#ac4bff4d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-purple-500\/30:hover{background-color:color-mix(in oklab,var(--color-purple-500) 30%,transparent)}}.hover\:bg-recall\/30:hover{background-color:#10b9814d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-recall\/30:hover{background-color:color-mix(in oklab,var(--color-recall) 30%,transparent)}}.hover\:bg-synapse\/30:hover{background-color:#6366f14d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-synapse\/30:hover{background-color:color-mix(in oklab,var(--color-synapse) 30%,transparent)}}.hover\:bg-warning\/30:hover{background-color:#f59e0b4d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-warning\/30:hover{background-color:color-mix(in oklab,var(--color-warning) 30%,transparent)}}.hover\:bg-white\/\[0\.02\]:hover{background-color:#ffffff05}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/\[0\.02\]:hover{background-color:color-mix(in oklab,var(--color-white) 2%,transparent)}}.hover\:bg-white\/\[0\.03\]:hover{background-color:#ffffff08}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/\[0\.03\]:hover{background-color:color-mix(in oklab,var(--color-white) 3%,transparent)}}.hover\:bg-white\/\[0\.04\]:hover{background-color:#ffffff0a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/\[0\.04\]:hover{background-color:color-mix(in oklab,var(--color-white) 4%,transparent)}}.hover\:bg-white\/\[0\.08\]:hover{background-color:#ffffff14}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/\[0\.08\]:hover{background-color:color-mix(in oklab,var(--color-white) 8%,transparent)}}.hover\:text-bright:hover{color:var(--color-bright)}.hover\:text-dim:hover{color:var(--color-dim)}.hover\:text-synapse-glow:hover{color:var(--color-synapse-glow)}.hover\:text-text:hover{color:var(--color-text)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:\!border-synapse\/40:focus{border-color:#6366f166!important}@supports (color:color-mix(in lab,red,red)){.focus\:\!border-synapse\/40:focus{border-color:color-mix(in oklab,var(--color-synapse) 40%,transparent)!important}}.focus\:border-dream\/40:focus{border-color:#a855f766}@supports (color:color-mix(in lab,red,red)){.focus\:border-dream\/40:focus{border-color:color-mix(in oklab,var(--color-dream) 40%,transparent)}}.focus\:border-synapse\/40:focus{border-color:#6366f166}@supports (color:color-mix(in lab,red,red)){.focus\:border-synapse\/40:focus{border-color:color-mix(in oklab,var(--color-synapse) 40%,transparent)}}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-synapse-glow:focus{--tw-ring-color:var(--color-synapse-glow)}.focus\:ring-synapse\/20:focus{--tw-ring-color:#6366f133}@supports (color:color-mix(in lab,red,red)){.focus\:ring-synapse\/20:focus{--tw-ring-color:color-mix(in oklab, var(--color-synapse) 20%, transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-dream-glow\/60:focus-visible{--tw-ring-color:#c084fc99}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-dream-glow\/60:focus-visible{--tw-ring-color:color-mix(in oklab, var(--color-dream-glow) 60%, transparent)}}.focus-visible\:ring-recall\/60:focus-visible{--tw-ring-color:#10b98199}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-recall\/60:focus-visible{--tw-ring-color:color-mix(in oklab, var(--color-recall) 60%, transparent)}}.focus-visible\:ring-synapse\/60:focus-visible{--tw-ring-color:#6366f199}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-synapse\/60:focus-visible{--tw-ring-color:color-mix(in oklab, var(--color-synapse) 60%, transparent)}}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:40rem){.sm\:block{display:block}.sm\:inline-flex{display:inline-flex}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}}@media(min-width:48rem){.md\:block{display:block}.md\:flex{display:flex}.md\:hidden{display:none}.md\:inline-flex{display:inline-flex}.md\:min-w-\[340px\]{min-width:340px}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.md\:grid-cols-\[1fr_auto\]{grid-template-columns:1fr auto}.md\:grid-cols-\[280px_1fr\]{grid-template-columns:280px 1fr}.md\:flex-row{flex-direction:row}.md\:pt-\[15vh\]{padding-top:15vh}.md\:pb-0{padding-bottom:calc(var(--spacing) * 0)}}@media(min-width:64rem){.lg\:block{display:block}.lg\:inline-flex{display:inline-flex}.lg\:w-56{width:calc(var(--spacing) * 56)}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-\[1fr_280px\]{grid-template-columns:1fr 280px}.lg\:grid-cols-\[1fr_340px\]{grid-template-columns:1fr 340px}.lg\:grid-cols-\[1fr_360px\]{grid-template-columns:1fr 360px}.lg\:grid-cols-\[minmax\(0\,1fr\)_340px\]{grid-template-columns:minmax(0,1fr) 340px}}.\[\&\:\:-webkit-slider-thumb\]\:h-3::-webkit-slider-thumb{height:calc(var(--spacing) * 3)}.\[\&\:\:-webkit-slider-thumb\]\:w-3::-webkit-slider-thumb{width:calc(var(--spacing) * 3)}.\[\&\:\:-webkit-slider-thumb\]\:appearance-none::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none}.\[\&\:\:-webkit-slider-thumb\]\:rounded-full::-webkit-slider-thumb{border-radius:3.40282e38px}.\[\&\:\:-webkit-slider-thumb\]\:bg-synapse-glow::-webkit-slider-thumb{background-color:var(--color-synapse-glow)}.\[\&\:\:-webkit-slider-thumb\]\:shadow-\[0_0_8px_rgba\(129\,140\,248\,0\.4\)\]::-webkit-slider-thumb{--tw-shadow:0 0 8px var(--tw-shadow-color,#818cf866);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}html{background:var(--color-void);color:var(--color-text);font-family:var(--font-mono)}body{min-height:100vh;margin:0;overflow:hidden}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--color-subtle);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--color-muted)}.glass{-webkit-backdrop-filter:blur(20px)saturate(180%);background:#16163873;border:1px solid #6366f114;box-shadow:inset 0 1px #ffffff08,0 4px 24px #0000004d}.glass-subtle{-webkit-backdrop-filter:blur(12px)saturate(150%);background:#10102a66;border:1px solid #6366f10f;box-shadow:inset 0 1px #ffffff05,0 2px 12px #0003}.glass-sidebar{-webkit-backdrop-filter:blur(24px)saturate(180%);background:#0a0a1a99;border-right:1px solid #6366f11a;box-shadow:inset -1px 0 #ffffff05,4px 0 24px #0000004d}.glass-panel{-webkit-backdrop-filter:blur(24px)saturate(180%);background:#0a0a1acc;border:1px solid #6366f11a;box-shadow:inset 0 1px #ffffff08,0 8px 32px #0006}.glow-synapse{box-shadow:0 0 20px #6366f14d,0 0 60px #6366f11a}.glow-dream{box-shadow:0 0 20px #a855f74d,0 0 60px #a855f71a}.glow-memory{box-shadow:0 0 20px #3b82f64d,0 0 60px #3b82f61a}@keyframes pulse-glow{0%,to{opacity:1}50%{opacity:.5}}.animate-pulse-glow{animation:2s ease-in-out infinite pulse-glow}@keyframes orb-float-1{0%,to{transform:translate(0)scale(1)}25%{transform:translate(60px,-40px)scale(1.1)}50%{transform:translate(-30px,-80px)scale(.95)}75%{transform:translate(-60px,-20px)scale(1.05)}}@keyframes orb-float-2{0%,to{transform:translate(0)scale(1)}25%{transform:translate(-50px,30px)scale(1.08)}50%{transform:translate(40px,60px)scale(.92)}75%{transform:translate(20px,-40px)scale(1.03)}}@keyframes orb-float-3{0%,to{transform:translate(0)scale(1)}25%{transform:translate(30px,50px)scale(1.05)}50%{transform:translate(-60px,20px)scale(.98)}75%{transform:translate(40px,-30px)scale(1.1)}}.ambient-orb{filter:blur(80px);pointer-events:none;z-index:0;opacity:.35;border-radius:50%;position:fixed}.ambient-orb-1{background:radial-gradient(circle,#a855f766,#0000 70%);width:400px;height:400px;animation:20s ease-in-out infinite orb-float-1;top:-10%;right:-5%}.ambient-orb-2{background:radial-gradient(circle,#6366f159,#0000 70%);width:350px;height:350px;animation:25s ease-in-out infinite orb-float-2;bottom:-15%;left:-5%}.ambient-orb-3{background:radial-gradient(circle,#f59e0b33,#0000 70%);width:300px;height:300px;animation:22s ease-in-out infinite orb-float-3;top:40%;left:40%}.nav-active-border{position:relative}.nav-active-border:before{content:"";background:linear-gradient(180deg,var(--color-synapse),var(--color-dream),var(--color-synapse));background-size:100% 200%;border-radius:1px;width:2px;animation:3s ease-in-out infinite gradient-shift;position:absolute;top:4px;bottom:4px;left:0}@keyframes gradient-shift{0%,to{background-position:0 0}50%{background-position:0 100%}}@keyframes float{0%,to{transform:translateY(0)translate(0)}25%{transform:translateY(-10px)translate(5px)}50%{transform:translateY(-5px)translate(-5px)}75%{transform:translateY(-15px)translate(3px)}}.retention-critical{color:var(--color-decay)}.retention-low{color:var(--color-warning)}.retention-good{color:var(--color-recall)}.retention-strong{color:var(--color-synapse)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}.toast-layer.svelte-pry2ep{position:fixed;z-index:60;pointer-events:none;display:flex;flex-direction:column;gap:.5rem;right:1.25rem;bottom:1.25rem;max-width:22rem;width:calc(100vw - 2.5rem)}@media(max-width:768px){.toast-layer.svelte-pry2ep{right:.75rem;left:.75rem;bottom:auto;top:5.25rem;max-width:none;width:auto;align-items:stretch}}.toast-item.svelte-pry2ep{pointer-events:auto;position:relative;display:flex;gap:.75rem;align-items:stretch;text-align:left;font:inherit;color:inherit;background:#0c0e16b8;backdrop-filter:blur(14px) saturate(160%);-webkit-backdrop-filter:blur(14px) saturate(160%);border:1px solid rgba(255,255,255,.06);border-radius:.75rem;padding:.75rem .9rem .75rem .5rem;overflow:hidden;box-shadow:0 10px 40px -12px #000c,0 0 22px -6px var(--toast-color);cursor:pointer;animation:svelte-pry2ep-toast-in .32s cubic-bezier(.16,1,.3,1);transform-origin:right center;transition:transform .15s ease,box-shadow .15s ease}.toast-item.svelte-pry2ep:hover{transform:translateY(-1px) scale(1.015);box-shadow:0 14px 48px -12px #000000d9,0 0 32px -4px var(--toast-color)}.toast-item.svelte-pry2ep:focus-visible{outline:1px solid var(--toast-color);outline-offset:2px}.toast-accent.svelte-pry2ep{width:3px;border-radius:2px;background:var(--toast-color);box-shadow:0 0 10px var(--toast-color);flex-shrink:0}.toast-body.svelte-pry2ep{display:flex;flex-direction:column;gap:.15rem;flex:1;min-width:0}.toast-head.svelte-pry2ep{display:flex;align-items:center;gap:.5rem}.toast-icon.svelte-pry2ep{color:var(--toast-color);font-size:.95rem;text-shadow:0 0 8px var(--toast-color);line-height:1;width:1rem;display:inline-flex;justify-content:center}.toast-title.svelte-pry2ep{color:#f5f5fa;font-size:.82rem;font-weight:600;letter-spacing:.01em}.toast-sub.svelte-pry2ep{color:#b0b6c4;font-size:.74rem;line-height:1.35;padding-left:1.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.toast-progress.svelte-pry2ep{position:absolute;left:0;bottom:0;height:2px;width:100%;background:#ffffff0a}.toast-progress-fill.svelte-pry2ep{height:100%;background:var(--toast-color);opacity:.55;transform-origin:left center;animation:svelte-pry2ep-toast-progress var(--toast-dwell) linear forwards}.toast-item.svelte-pry2ep:hover .toast-progress-fill:where(.svelte-pry2ep),.toast-item.svelte-pry2ep:focus-visible .toast-progress-fill:where(.svelte-pry2ep){animation-play-state:paused}@keyframes svelte-pry2ep-toast-in{0%{opacity:0;transform:translate(24px) scale(.98)}to{opacity:1;transform:translate(0) scale(1)}}@media(max-width:768px){.toast-item.svelte-pry2ep{transform-origin:top center;animation:svelte-pry2ep-toast-in-mobile .3s cubic-bezier(.16,1,.3,1)}}@keyframes svelte-pry2ep-toast-in-mobile{0%{opacity:0;transform:translateY(-12px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes svelte-pry2ep-toast-progress{0%{transform:scaleX(1)}to{transform:scaleX(0)}}@media(prefers-reduced-motion:reduce){.toast-item.svelte-pry2ep{animation:none}.toast-progress-fill.svelte-pry2ep{animation:none;transform:scaleX(.5)}}.strip-item.svelte-1kk3799{display:inline-flex;align-items:center;gap:.4rem;padding:0 .75rem;white-space:nowrap;flex-shrink:0}.strip-divider.svelte-1kk3799{width:1px;height:14px;background:#6366f11f;flex-shrink:0}.ambient-strip.ambient-flash.svelte-1kk3799{background:linear-gradient(90deg,#ef444414,#ef444400 70%),#0006;border-bottom-color:#ef444459;transition:background .3s ease,border-color .3s ease}@keyframes svelte-1kk3799-ping-slow{0%{transform:scale(1);opacity:.8}80%,to{transform:scale(2);opacity:0}}.animate-ping-slow{animation:svelte-1kk3799-ping-slow 2.2s cubic-bezier(0,0,.2,1) infinite}@media(prefers-reduced-motion:reduce){.ambient-strip.svelte-1kk3799 .animate-ping,.ambient-strip.svelte-1kk3799 .animate-ping-slow,.ambient-strip.svelte-1kk3799 .animate-pulse{animation:none!important}}.verdict-bar.svelte-1j425e6{border-bottom:1px solid rgba(255,255,255,.06);background:#080912b8;backdrop-filter:blur(18px) saturate(160%);-webkit-backdrop-filter:blur(18px) saturate(160%);box-shadow:0 6px 24px #0000002e}.verdict-summary.svelte-1j425e6{width:100%;min-height:2.75rem;display:grid;grid-template-columns:auto auto minmax(0,1fr) auto;align-items:center;gap:.75rem;padding:.55rem 1rem;color:var(--color-text);text-align:left;font:inherit}.sr-only.svelte-1j425e6{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.label.svelte-1j425e6,.field-label.svelte-1j425e6,.appeal-row.svelte-1j425e6>span:where(.svelte-1j425e6){color:var(--color-dim);font-size:.68rem;text-transform:uppercase;letter-spacing:0}.levels.svelte-1j425e6{display:flex;align-items:center;gap:.25rem}.levels.svelte-1j425e6 span:where(.svelte-1j425e6){border:1px solid rgba(255,255,255,.08);border-radius:.35rem;padding:.18rem .38rem;color:var(--color-muted);font-size:.64rem;line-height:1}.levels.svelte-1j425e6 span.active:where(.svelte-1j425e6){color:var(--color-bright);border-color:var(--verdict-color);background:color-mix(in srgb,var(--verdict-color) 18%,transparent);box-shadow:0 0 14px color-mix(in srgb,var(--verdict-color) 28%,transparent)}.summary-text.svelte-1j425e6{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.78rem;color:var(--color-dim)}.when.svelte-1j425e6{color:var(--color-muted);font-size:.68rem}.receipt.svelte-1j425e6{margin:0 1rem .75rem;border:1px solid rgba(255,255,255,.08);border-radius:.5rem;background:#0a0a1ac7;padding:.85rem}.receipt-grid.svelte-1j425e6{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(10rem,.8fr) minmax(0,1.1fr) minmax(0,1.1fr);gap:.85rem}.receipt.svelte-1j425e6 p:where(.svelte-1j425e6),.receipt.svelte-1j425e6 li:where(.svelte-1j425e6){margin:.25rem 0 0;color:var(--color-text);font-size:.76rem;line-height:1.45;overflow-wrap:anywhere}.receipt.svelte-1j425e6 ul:where(.svelte-1j425e6){margin:.25rem 0 0;padding-left:1rem}.appeal-row.svelte-1j425e6{display:flex;align-items:center;gap:.4rem;margin-top:.85rem;flex-wrap:wrap}.appeal-row.svelte-1j425e6 button:where(.svelte-1j425e6),.appeal-row.svelte-1j425e6 p:where(.svelte-1j425e6){border:1px solid rgba(255,255,255,.1);border-radius:.4rem;padding:.35rem .6rem;color:var(--color-text);background:#ffffff0a;font-size:.72rem;margin:0}.appeal-row.svelte-1j425e6 button:where(.svelte-1j425e6):hover:not(:disabled),.verdict-summary.svelte-1j425e6:hover{background:#ffffff0d}.appeal-row.svelte-1j425e6 button:where(.svelte-1j425e6):disabled{opacity:.55;cursor:wait}.tone-pass.svelte-1j425e6,.tone-note.svelte-1j425e6{--verdict-color: #10b981}.tone-caution.svelte-1j425e6{--verdict-color: #f59e0b}.tone-veto.svelte-1j425e6{--verdict-color: #ef4444}.tone-appealed.svelte-1j425e6{--verdict-color: #818cf8}@media(max-width:900px){.verdict-summary.svelte-1j425e6{grid-template-columns:auto minmax(0,1fr) auto}.levels.svelte-1j425e6{grid-column:1 / -1;order:4;overflow-x:auto;padding-bottom:.1rem}.receipt-grid.svelte-1j425e6{grid-template-columns:1fr}}.theme-toggle.svelte-1cmi4dh{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;padding:0;border-radius:8px;background:#6366f10f;border:1px solid rgba(99,102,241,.14);color:var(--color-text);cursor:pointer;transition:background .2s ease,border-color .2s ease,color .2s ease,transform .12s ease;-webkit-tap-highlight-color:transparent}.theme-toggle.svelte-1cmi4dh:hover{background:#6366f124;border-color:#6366f14d;color:var(--color-bright)}.theme-toggle.svelte-1cmi4dh:active{transform:scale(.94)}.theme-toggle.svelte-1cmi4dh:focus-visible{outline:1px solid var(--color-synapse);outline-offset:2px}.icon-wrap.svelte-1cmi4dh{position:relative;width:18px;height:18px;display:inline-block}.icon.svelte-1cmi4dh{position:absolute;top:0;right:0;bottom:0;left:0;width:18px;height:18px;opacity:0;transform:scale(.7) rotate(-30deg);transition:opacity .2s ease,transform .2s cubic-bezier(.16,1,.3,1);pointer-events:none}.icon.active.svelte-1cmi4dh{opacity:1;transform:scale(1) rotate(0)}.theme-toggle[data-mode=dark].svelte-1cmi4dh{color:var(--color-synapse-glow, #818cf8)}.theme-toggle[data-mode=light].svelte-1cmi4dh{color:var(--color-warning, #f59e0b)}.theme-toggle[data-mode=auto].svelte-1cmi4dh{color:var(--color-dream-glow, #c084fc)}@media(prefers-reduced-motion:reduce){.theme-toggle.svelte-1cmi4dh,.icon.svelte-1cmi4dh{transition:none}}.safe-bottom.svelte-12qhfyh{padding-bottom:env(safe-area-inset-bottom,0px)}@keyframes svelte-12qhfyh-page-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.animate-page-in.svelte-12qhfyh{animation:svelte-12qhfyh-page-in .2s ease-out} diff --git a/apps/dashboard/build/_app/immutable/assets/0.Bor8S3Zo.css.br b/apps/dashboard/build/_app/immutable/assets/0.Bor8S3Zo.css.br new file mode 100644 index 0000000000000000000000000000000000000000..ace1ff437589234eefa27803dc60b61a0f2af0b7 GIT binary patch literal 10347 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 J4!!Y4$1lz*BLM&a literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/assets/0.CN9L-NIY.css.gz b/apps/dashboard/build/_app/immutable/assets/0.Bor8S3Zo.css.gz similarity index 70% rename from apps/dashboard/build/_app/immutable/assets/0.CN9L-NIY.css.gz rename to apps/dashboard/build/_app/immutable/assets/0.Bor8S3Zo.css.gz index 9e9b96053c316175564aeb53044f70013e738823..9bfd30867ad3ea5f4eb0e4dbaad0862a2259fd13 100644 GIT binary patch delta 3575 zcmVoKYO>#)RhsN9t!a`N z6PqH`%%Vu>nRyXWGDp44k&>C2_59#GqhZgJ9yJ;Bq@>|2M} z`tH|(PB@W`y*;O?Mgj3^H#7w2V&TsM$D4b^r?JUa_TzI(sUK)ysSj0wotJC_ z_+JfdWgXRZG|N`r)y0XTI@7SqD~xt&Tol@k!F2mMo(7$WeWMTV-1$6_?)Qh`MC3;P z{L$yi;h`3*$RPV!;?!Iq=Ovm~_~jGT3c-|}p7rpLxRHNh!?hEa^ca=I^W&0|VMj^+ zJfl`gXWOS_2uk9}nI2U~CH+c4C~BA~%x(^L*->PheKa3nzHnxQ`qhU9FA_i2SoBD8wSYNAQY4Y^pp7>QT zi#2wMxq5$!kumdY!Ia$oYVK{L1~((&nb5D~eVfMzQdp;RDsI@pnbb_Wrv~z*JhHmZ z;$w2au7bqFNZ1SY3QO96XC=pNa!g7hMIc9;HpTg%geD)Mhu8)5j;Wm@*$F7{+Q=6XA*(YD`8ZOEC272UTC zMqK2IfhP2_x!s+0)Wn`iXg%wDpIXfo=)A0+j@c$}IAtNl1X)+AWRNFL>jz`jNxn|W zv|4}jVYdn3gJF}Un3-_u=9qm*#mUi>C#mEtad2njMom`t+TrJ>g5D4XS%nlnbrtkO zNkR4@DH!%D=q>pW({{tpOL_%+M@4^#isDf%g^IEd{k9LiUKM@n!@%L{!H?_g7{Azf z*VzlPS$?=wnE>xH#sCFqu_BOJ@yb1V>|%fM-FI>m)P7C~+NcfLDVMYqD|Skp+{B4% zpqjll4dF{yPXRh?fa#~MontajH|Q~qJfU~}8!nHn!RpHy>q`r3#nTl?T=BJ;l+t-bVPTdM9qAkGpB~ z4=FkB%Ds&@w*o5Okv_|yMKY;(hZsUb6w(8AABcgrtF0*bV$*QXN-qQqXA*xG#t-M< zcii4kM@To|4(Dp#k9#{GpMD+@A-`Mq1_Rj@vV-eBoNZARM|m#w*4WvVMRgYZSl*Lo zYCmq5EbUh78oYP4v0ib%p#iREobTn9F=}*X%s;M7z1!zTZ^&DJ+BM)GZtVrg5_^2o zZr`@stx4Lw{M6WI^|6i$y}EyCu(RvCB8Kyb3nXr8o!PAt!&&O9CT_{Vc>lx=Z4R3j zx}j3!^UpVM;Pn;5;nIaqqnK_j@-pjPt3g>XPF&oOBjx)|#;}dZ(Ve?dMzD^^)Us-jNrVz95nB9xgmq{iv)&q;B=P>UC%NVr{s8P%rLPuc<_HCoVjbxou9DR z_ZT+TPn>1V%I2!Q785RvTsn&^Wd>QyPUCly&x#k4;(AN|?vc}_ITc;aU`LK}f?M9# zwQTJeVtYN7yZ8ig=H$TVkKLI^zxcGC_&mgKeE*N<;kUHy0vDoREgK)X#hpRbj-iU< zF~XYxF9xev)U!t#6`g-YOP{zeyn<=x`COd72mMUcZ~96lIE=&$;f$nrfmxXNluc>WN{RHezMW4JR#M;Tm`_Z}2 z=Z&evGAUD{)c4aig#X2|l5^S=$ZtkQj?;N_(Q#{U6z7#%_{v#D>p&L%7|_N*HVs#2 z8;?1=>WYWDts;^%O-@BpEL9H-GPR(Cu*;!CsB3JiMK89(C7LBiEINAC;+jiW-lTfH zI(yrS3M+r>v=v{yv+HwDfvI~7VYgC4B}JWPt}ul%jZC$9C3vcVtyWqf_%+TqMPE&4 zsq9<4LPJL$n)u0dU?p{f$a)WojTs(>$xzWQPVu=Qn?{dL*=k&*{+HZkllD#ob&X9o zC&-&*mg-FsR<%o_uS=xpmvj;pdOyR`6soa9wn~4{eZIaay!LyAi|KU^wrAdr?)huW zKW1G-2DmiVWhwjrLH!+M-NnY4F*__v819tJ=9e$b;p>{Oe$J<|mn;grI zR^V_)XUsS%<3^{fB*^rYG=uWe-lxmV`!u9%{dYd4!L_D%AFdu`haR9Ae9s?80W zt+#*JyS8nM6&pIJ`08tmlkn|G40|G;=#~h6&5s+1Uwp#{-TNW7L-Ml=&6|P3C%GF} zM??z)@5a?9j4P@l2XbZY6P@m4d*j;K3^HF`70<8p_J#y8=Bq%Cyo0V1+$qqVxM6VB z?$t2S==LBi+I({_N7=39HjNLs0-afWf7?ikknirwWlH}Ai zf}drf^^R4|0FKFpjJ3P_|FO=Q^HA2s#=2Bjz6_OZUB%7LO*^NbH2Hg~V@MNSiQrCV)dJqGU_On+b3@b}iw9wq(`?K=i}?6XKdWx7 zS!8OdRnrlT)b(oD(4PD_7qEYM06g6PP@T#LznHr_-2-1j#m#s{6n6rIVkY@D#_kC) z<74eb(P{E&2-rZ{nXFYqFD!l~1sAr4?p2Z<`?=UYcFy%e%B-J-4Q)6Ja|+q?v$0c= z-N}b1+#(O-fS!)1p?BHsSn9ec;t(?ME?nye%XXJ6(+73!@y3^3nn!=qXKru(tUU&e zD?WR2AW+bEyLvv;T_2KQvlkQ9jZ*{gd*I+(J%K9qS(^oRt{gwplY6St|MY|}vf_iR zQ1}D=S<%+Qh-T31DF?lR+WM3iJvglz|CI5`-h-=BbQjNIQuoB@Z$%mB&j1HY_07>s z!!3EHh*)Q^GXS4G1wDU^!xl%Hd*hYMBRJhpo0E2)>n-LG@o#vin>!Tm6n46V)^-usi<%F^%AiT93Zg1WeH@m zo1i9xCpz^dV5-bvQfkv=f$#-Gtd1>=BSrBQZh5Mo*$fNH0*iOqejCET%qgi`OEWvg)#F&tZEl&LLUI!pAW0& zpP)Lh{e?2{!s{yiHJE*(U$vr5`Dcja_yj2r&D5IrWYw_hC2RSEc{vEcyo{V^dh)E@vYZkbTQoUW=vm+L-HRh*-}?#qMx>{Iudj-_V$Y-zl>bCqr0X&Wi7 z-*cRo{qhj!yX1ekaF#gFwxu(Bv{AlFPF?3&ny%uUmzC)Bw&XJ4rwYh!>XK~$|Eqzm ztfRVVX4%TSx;Rl(XNFaIJJBwUi$c5Sm+mabgPs$yCG^3aJD(@g)%`G1h}_7ZKl)rb zJg;IE8Du|89Ec0#yhQT~zgMD~{GYOeu^#>rmo03#cH)2j9ix(XG+a_L>?p}!Ueqe- zZ2Oc9K}j4G(^KfEq+clrMGZ5B*^PnOjZW;uZv6CAr7_Ez9cRW}J?YgPj-+Tnzt!G6 z#Yd9fL)G%9tQv3xEu zSFbEGW`2L;my+9G&An~Z;ASK|?)jCxZ}a#-3hQ)E#pO9TNt#Jl&_JG)2Tj*md`u45 zRgicX2|JixVM%-ItmL>&j!8+R2;^w9dMFGDQ~11w&z{1`^-&|-X3~E>S-KNqr&nc(_c2RsywzpuH{zP> zO+k~Vk!*;kH^l3D$?Kh? z(1cz#ce1mNn%E8rt!I6uQ>(cGotM?CFx%t}XCtJTAnQt%4D!Tj{T9qR$=4~FR?9i; zq5yw<3v99!lMYVZ9J3FpI60c~B$b>cj@xY9gURY%JN(>K&>Ny4tB}H{u7Z9jDabw~ z1;btiy(J$#+HUxHNpDy0sOS$-QM{L>P*L`w-}a%`tD;YR7&u%#_;H;b;};vRF?%64 z%MX_-6W}$)7@zca9v-25h ze=w$*kD(po?(!P`@ip$LpW)dj+p;bK@d_HvGwy~*pMfZzy!ey4&yg#XrW9VMNGexi zv4e@#gE|b2YE)D-;q+D1U!jhY>nmM7_16a*ulA6zA$;lTDL{t}F#XikQz*L$_Yr@6 zo#h1c20ek1C-fSB!@aOISbgteeIH?s+-2FubU$Q`#B(3YYYwX$_Wmf2M_A(CUuKN` zb^%Nozb(G|{<~#z+!L^+SZrfx=$Dv-unfP%>6u`L&GzbN3JTif1pM24?ViDM?!T1Uy}H)@}RoCr#SkI+Xz2ZPr!}zaW{?rAtlFM zxwr9BRzSr&(q|d8NGA2}5JPB)LVA1d12NEcwG{GJ>KOyVy1;T(Vb`q~@n z2>gZHjB){E&kG{E(Y^S#_MMvcyl`Nx&1H}c%*4S82jy9WHjt-SzQVvkSS?b~*{ zHA%adpBh`JKGsp8w=xZOc71;h#Bd&QH^fb?GrKTiI7@wt#4Q;Zua>x>&0*6*H&lvz z{`m$DyqRJ+T)N9?6w|FmUS_>(H7EshAalpHUO877tn4}OF*cg=sf^Aq;^9>d1^ ziLpNII3Z|(6s{Fb&|;6n7PW#jv`xap_b3{-JEMtJGp z#b6bSdiF@8qO*wnH`jjx_eIeO$FQRgwUhm%DE3HZQj$ZlD9W6a>wV==q;~w-@ER4- zndxo%k$Q}&r-*FXdiRqq>MwX6<17E-tFb(}c8D9T=1cWTF)nUe_3CDXv)|^mWfezf z=@a*5Ja}O^75~nhsJ&p%Z52;yvrlXGME~*+ifC;?ST>d<=@oy;(M|AW>B6?(!6ye897gKv}V3nSnKl&22?BZEg|{C%#Eh*bmmXpNnILYG@0PO z37YXN_IRsw%SU||j5Txl8i#ZfQ%%(8EOGKlJuytvMy!mv;iTm&Tmuj04PU`OnZ>+S+5?_s>YXWix!Uc!Uj*dn| zt;K8kwFenSYp`Mu{p+vLhv%x`zL=IGL#sWPW?KX-+-1Fau@b!}@x~-tF8(|ZRn=*g z63}C4$&jbpoAy;3erHcqHFj=Kxdlq*YrM+ID?=Cg6?=bgmw!7KWwL#@#Tr%haxs-y zCS^*L`hMDm@V{7Aa!#89`8mkQaXQZ_I&STa;=ED|UpcF29mv8T1KJqKrs3*r{e>1q^Q%(6{b+8k*PMX1P?5*)k+HlzsC8d=&R{0m3@m> zXz0j86F->_tfX!bS?@uyF~h?!87kVvDLxlu)9BGDTaAm<|B}0G(%y-nuCeLn1bLIp zQoTvSs&+~Ab%_-Hl1`#R?`K$=LN#{CRtdV#*EfHK*M6^XF}=>g_RPD{J%4Ta$E=IU z0GGzPEM@;c$lvIqbF#E8{gjg}$qPFtoAa7%z%Jgq!%tHp)Q)ERc>7CmlVjP@Y8KKP z>dQPiH6nDse)S)po>Ye=w5?1a_sSgJ6;o7l?Pin3zDZtiuWeg_>h^9?wYfpF^%i^A zwrzj0VnYWNUwv(H622XYVNb*p-4elX@Non2i*NX#dq2c>NPaA#dFfC1BzNQLh-hKp z-MISja79(*K(4HPqSKvhZ(KW@LFTKg;`w#n-jE>1d==Y{aR=0 zOlKYx20DN4ZI+hCVR>j#Hpv>tHgy*LTi}Hxx-?S1 ze=H-9vF6T`>uJYW^P9(5bLALI>dQv0{lOloO)JiaL!7_2&6D~O(r#~$7jIEP;JJ;Z z`tSyhVd+UCt9gv0Gdz|nlhzn7q{BMehtzFWH;r?llF9Atn0Aco_NclQ4*aZYHL-uc z9Y;)^Zr&RDbqnm*)3N~no2Y6(KIVlQDvehpZD}-}Z4;7iY;_nt$&unws#ee+Ac|wF zE5d^&n#(xkzHKzGdiRPKLEAlORGmN^McbQ$1|uFDjVL8pCNqXi7R)=71%5LlxpO){ z;Lp`riS6ibxTf3fHz_}3`|pM)1;2ktW!bnxf&oOq6ob;b=4hOHEx->`6^G@vu6XH; zYq2I6D9dYK7c=Aa1ucHL@gS^nnvJ<<5g*@aoLVc+>2Rf*!+h!+ zZDl;H9t_yLF-Ansx-yruUM$t0O$caXu~uj3a2&NMp=UgOpoVojS-a8gXVtAWi%c!G zYC58kx?b%X+LIsW0yYnT=k|Xesss1n7jt)~d*Dl`xEZgA;<$e(W|CiH?4AHKzQbM= zohF}#fDNRb$yzn^!s540aA9lcUM1PFpNs8d=UgwO%=%f_(1x=xr;trQ8#@)*oqTx0 zE%Go9=;??WdY9dfrLK!24j}{Y!nJ;|YTkyXa>EWa?mTNtxtK;gVU<58|U&p4kl|Ckox6bsedK9+oKGgT9bV)jL-=d{xI z%O);k`;cwO?>BM&^{2K>^9lEg9r8Z3_7=*-I!fWUX?ETw*`@V1A7DA3M4-^d*M9jAivY;t8KdKowCJ5T) t9T_q!|JMhcl^-J>22-1b8t;tjmzPXiQ)`!C&%K*>Hn8azty(lfA}Y)QTe|6234UR=G`!^&>sX6wmV?ch}a~w zH#N&XO~tuNxFLMcPv)!MqPk0*2NGeKSw0$qT3f~tnyBPBC2tOdmG=MlRdsOzK({`n z)``Ok5rCkST89a^@80_Ye3T=CR3S}Q%B9qI-+dnhKE5ncq^#2EQrec%$E?YiEUS;V z>~$L*rZM(p?W_CTP|5*rx6L0U|D$Ysz9rk&Hc5%zjw7xC`#9I~)M2V$Eqhf+PzZ`Z zscv>h@tQC};ji2786}4dO_=faybcO`P8l#}On!j2%|x7cSsD|hrK;??{jq!>`?{m{ z@2ql!!vFyyu{*}n3Q^LmK(bF^W_Uzn5C+=bZDUr02imVb37{w>7|XiII4xMd*;jxH3@r?v(uQqFb3J=_DIKY?#Fe^uHvq2}*>IH(fg?WGp`b>xc50gVrl;?x( z{5g`IzgG>3C|QEBz9CBJY&f$z9~M4Xgk(3fdR1!#ijtluP?29s7$-JQ`*>;#u~5=4 zi6oLM2Yhg=K)##7sd2%i8_*E<6kyyN9Y{ko^iqd}6!#23Vxc;TFvE1?7eYIx-axWa_$ehT*B{Nf$@xjY^?ChHuB=_u+now@4bYOj_GrN z6DXL+F=x~meL7UeqmE-ER3C$4mIoQd`oM9m!)>JNgN=QC&{qRE@u&RLnZ%o^F$N(v zjLN94`J9{B^|eaZCS!XRp(5@}#OpsG6L25gqfLv*!&8MXD2qVzmoG(15JkKfte%y4Q0MZhtJmR zwPBhJeY3WPi{jjZv+v7g`gzK*oYv#St2n~`sACwheAC0~lt*3Dh*2Xys4;6F)FbO3 zG%On*v}LwEt^gQDnE&l_>vnUnVI8l(qqIy)zf{>;*7u#W%f;n~obyD+yWTbMTw5(s zWapVKPRf%oAlmkmEC%}zs$L?zTP8Ne5dQuftJcI)Hi8z;JR&|}KlSv$LI(-F0` zJt~LIXlss2tEWEdo;-NC@t}gN{13#scemT;xZuo>$Zf(ZVU;qgBuh0%?vIY)q|8@R2Se2%Dq;5kT0ksz zgaZ{vd$6qP5WhQ-#b>OE9`kDB!f|*6SuaGvci&fP6Pa`{k!}T`BiNx1uy>-0eH<>` z`7|FQiT4f|WPn`;6?~mQKq}u?ulI(87JH+z)f~9rB$K&WKlg-T960#Y$$R^CHrUXv z3o*}H8*C4aN#GS5Hocy(-y>^9B#i?*|0uKxA7^O9UO?yJn(8e-tVr4IKO6P*qssmv zhR^Q%mdp&>y)L%jAvvYOVY)5cM@4|>0U`F*Z7os@nQHy8>GIyph#FJju>FTRVGGo( zCemT5eU~opORZ%l$X&+u6P6hG-$`rX|Nan@AZ5+ zsMeX0`VceGi2ogJF4WnEh}8*oK*4{i#@agvujex3`eya`_MUl{d7t^v`;m&tkhvKz z@7}>6g+2%<))I2))G=EcX0kRk{bl4fmKxZ8o`an!Z}!w!(;;DCnHX)|pt2_Z^~+!M z&|9s1`M>aUsy4+dJ5%L!uO6)?5}WQQ)3)kSS@-(VA~(sqMUA5ii4RQ7di7n_&2<0>ct{T=$<6xB{%cGJHw$VL#qbzN>krkFQB8h1`RvNL(M_+PSmkRKp+3j z7(3@tll_wHk;|_8ks<>$=NpfhS35ti_LetZc}L}$#NM+yhp#dco+$1;UI!vTwyBl7qAD%hunGM-~#8HELr{-?kVbO!0)W0b3kp zh-c;SPKtS?69b$MV3i`n8b;5Sx>?737S$#0Nv6%snn&$lcTWas1FaG*%j%*ZcqJ%% z!L5FLH7Di)EI|Sl6qQKw*~x`mg0t2Y+O&1?+wT$<5`|bPi}RqD@XvZ;e40lvELOpy zJ_L95-eQrs*I zZ5#_rSXMvzYjFL4@Fe7lC{f0oDkxIZGGoxJWTs_9ZAkA}l zyj&)2f<7;dYmiY6)*~s8x}+fV21)?!mC3AdHWl135(9ARTd<%f%t4yt6c9G{x3w^Gf7bZ4cmp9>pi3+?C=kD8PzE;hp0hvpK~2ma3=Tn1 zR0s9bt$T0$^;~@vQ5UaE?UQx%!w~@y-cf%$06qM`y|kY#B0A#rrXTsH@kZ25Zw^xf zW$AScJwdH;j=Z=KoKN9O<`)Cls{(trK6{*=O4pw-aLFoLtI76{KTdPQTGFAr6gS+c zU)@s??vrBy{&tO>Q8rrGJ=a^Kjg*p{%)O<#bNmDRi^{3>X0Trax8!lil6|o^ZNED?l(ogoVbr`fcccLL~Y$0 zqR*jj45cT0N&G#-{fyI80%kR)j$8DV&L1jwldYc$nGrbku(?FEUG1}X*;#_;bt-F z8ePd6JuUq`0aK1e9a$UduhFRkG25Fw%{5VH{S&r$vaDGBTLkmbKcfP>JPt9>hAhvA z{9gS=`X791zrTpc9xeQI#&6$L2;ij<@aTr~ltCR(af!i$hO=Tz5#_@S`!K>j%z_W2 z;KQhaDrKVnlaF^KQy;VLmazCjIND#Xe{$^U)q&%atvDDcZ6%%VbuGgrGEgft(^g^= z)$2xRnvTSFUU8ui+HrU#K7oq|9$uYv36Shm%4&qDL{iSYsfvW*3 z7DYU~=#UZ*r>#`Uz5+|i%EzRxtZif(x3~kOEv3^utYjDjc+6lZcz{(9hQlxd%4p#- z3M`|-_Xh&=L@*p8Ifljwh#bT=;20XGK*^!pGIJQVf)D-12~zAFh>ZhIh%9XHr5n1l zm!m}cC^Tq=)0*kcj|Z=hv}LOgk7(ug@Awcd6^D^CY_FEH<=$n^8arRufY}PR5XE+0 zv=K{3&(+o;if)afxA^mep;Ld@~2 z&?8uMlF<^2XDk_Jp@-G$wTE?H=rMqvcnslD!5ObbOHPi81^2bM#97R?6bpWqC`*hZ z<0A_@u7)W;ah~#G(O{ngv8eXhe?@AGN8l4Ew||X0v3d0Q+G2UqyU%ql;v<6qtRMs! zwTCx&0Z%GS=JsrfS}%azDk>UfVR4zisn+oHI2Ps~*SZgIJ}?f`Ut#3dS&In$)|6{| z`r?=0^005_bM}>;*+;fS-)yVAwtix9ZL_dmYglX6`QNBPm{)_*HSf80=9T)*o&vKt zzs0}kv-5cJQRv^vI;={}v6?9Tw$C9qgZ&|+PJ6`K;;kuL6? zK;dr1X(WvrLCo3owtiA~e@9~s?JcY~6zQq_242R8ohA>e)~u>*Ib?CN0487hhATdfVYjTHgEhiRX|04kR5LiT?}0 zt+6gdD*H6WYM65{2tjKC{(&wE#Sa94q#9FGBc8Mm;pAmJm#5s9i{?$F`DMEvmyhJ8 zl3bp=l%Ipj!}8Rr{645WUY>R-e-0{7mZx9JKL?d(mS%8D&fL`?&KI}QKI_DS>lk=>LHV(qNLo&5`JOEZ#@FpgL^ecxKn{kCh3#hpT zn`C(#lR`d4EMihYP%R*bZ>a)8d}0W#Jr6%%s>aj^D|Dy-aHV#J8_xFxRaD&YaF%NQ zyY5wukK>14PaY%THh`k_7BRm~N`aFV z%V#4^@~P>vOXY8IXP z1`9M{L=Bsm0w*k};bpU&NqN49^YT0XWroQ{YQ{6`H0(4f+hv#3{GbGRA}@Vf-*6H%k_hM70ig!rX=JxtpO_D7L$HJPpj~E3W*e)Oo7A_uKtN z6Aw?KH3d^TaXFY>3E10!g13WKkheb>Y=i^F4yorh4>1v=k{A2q5j3ha1kOMG@Ej{7 z-d)*nyD=G9ql1i+R7_>0oGdi;yFE`Br(B_@`-wbZoRWo}jLA%7sKp5swzamk+TC|; ziG&nWyd_aMy$N&CZSBOJO|Qc}KdFtpIFJx08=62;0F(=}4_%FJmc_mgb_Zj6<2Mv=kj>+?Oc| zRrUwDE8C`>V2)ktSTIfh=@^pTQ*T<`cWcSVsF0>>{O_`PwyTasi z7q`w{ht$D?6?5WN%%v^#MtEcGsnCVwdtUpFa&X@5GV~1Po}r`kD=hp$Y-;d)~b`zDH* z5`qAm>^FtUjN?Z&WSvK<`E_#wIY%Hzl$=oDkh_%#?p!CaX$v&>lq;VUTOX8?Ac`Q; z)Gcq|13^L`C~)s+`V{Wh(H$^~()aL|f(Ikg*uQaXgTUd&0+OL_m17G8MiCE?1b4w4 z+b}qqxS*9|J6$$~IUON~LeDrFjDzg-jTb+K!d}n|dErv93>De&v=0|!?tw}KTDl?H z+!b~3f5{+{rJHDc!y`s<;JtcwZ2@iC&ORF7m{Gf%b_@NszFQB zj|p7U`U&Ino<+w8BY@n#b=Q;*j1h20DMLJi{hFLKO-9wEbPcSCZJ*>kZkC26h1bdS zbNeW#VYhI}mShv0I|)h}vW}NcsUzLfk?2!*R;Ek7=4-z9xLn21V>nXRq&Rl)>eoZZ-qf1%-6h zM@l1=jzxAH?bpWn!-vcC;-5PS+~9CxnBqE*S&g&fh~h?39w-cJ7OG>v+fVpOaJv3` zUS~Rgq}F~F<*(<3KDYg{{~^kE@+2Xqc$|Eo*{V2_wTg8D$|OzX0>ovJpG>)4!a=~<~oMhcxviUX64QALp{qs3J@T6`zCgowF^H5Rx#h1ovV zn*Y@Jw`_7zqAeNGS6)0p4RK|7W--+cgiR>W5!rw25aou`?+9Tq&bG^R{y@IB)2FNX z#fLsvu8MiwF&X3l4wi=J?Tt)>R|8z|DO+N=Ff-S}BQ|;cZTP@s9oF`vFG+;-j$ADP z^nelbV)-#tU0%GD1#@)^Sw#*FFK$I#6q)cY^t#r~;lZbvp&nOt7VUM(84$PEpmWa${MwkC${a4l5Lx&MEh*n z9kKIPvTe^F;wSawUwjRqeLZdu#n?n^MgLDQP%nW!_`}ep|2-KzW0Ohi$6IHU9p39* zw1_!OyPX1b!@RTf*fNkN1NFoDHPwpLbzJqOG9qSq1(VFWRHmrihV*BwEo@1PD}Q=l zByc0Koy**OrIU+VK#S28w15}mD|msnm^RzGV_(Dt_ECDd&S_y)X$VLh+ zp1y%$hQT9o}{@r`Xc% zO+II1@hWnKjR>WUHMQK0J6{+1jQ{MO zAo+X|u@%xh7wMl=r-5XZvFDU*; zzUb_muvd9p=OesHWMWjU^@pl9OQse2H&(S2 z?Yb!$dtz-+rqTY@81wybc<|6Q;7ynsZbahnw+VG|U!n9G{vw8@Pm61Z`(})9VGexz zb;}m#Q`CcEsF(TODT=qc=dwQKci`stB(n*en7CDy7?u3hV~!42mSgf4v?_BtLF({- z1{b|w9H)(aH;RdI0Ss8O%6TIF$*7Q~Hyk;?u#|O*PoQQH7kC0&A@mUrOtWV^?Qk*6 zfH;A4kFvimkXpL)+Wmd0Xwa{Y_yrwB`1KT3{0aB#N7S{ufNMmOPU=N( zoQ1NM(Qv*D9_0=4%NYzcz!k&8I_wpv52FrZ49}=;W1OB6C|g(WigiK^YN+Ha z04D#~%apsI)CsTo2xTNRa067iQb!t3K}+v>cY@4Lz8N;IeSMS=!9T|vCtOj+r>U9R zM^8-OITNa0WY*<+1EN6tP*RV|Y$nMkU)@=<%}-?2859{2vx2()V&`%g>)C={p%atJ z{H9%tNxq8lR^jV)0#MPIxIRlxCb z>Lx)A-7pdT?x67nj3pCs(mY<(s_Gw1y)++VSAnd0#&>q$%TluPC9^cO0!Bh z4Gma?IrU zOe_qazNFk1srmXDL}_%fo&1dqeadw1G1$gW*BFLZ_~->r@mWN_RAKZck$@or4uiiW zt}<~Kh^1=ZC{PxnDpl)hl;dij^3(N0|LpSx_vjyF{feGZP#2!Lb7=`@>Hor5!wUV7 z*@m$sl$t?Iz%Uk(QlWea>oaoUK%kJr(%H) z_JFQ_RC+8~NR)3jh#ggrN{=>)RO4nbH19F}v7Vl46r2=r9Yf-G8U4$3lo z88W|zz^JSKeEt2|c+8LBEEytJGG^=aSoz2Iy6CICg$5P-EXTOM;M>YWEGXq$C|ak> zbH5r32-6+e>gylgtNI0jlBOho;0~`G;5Vmv$Orut4z~Wsn7^&xAmV--{3#UZ;H`1a z4cfTIAB6sztcnJ!IP(t$fEg04Qek596Jl+?*Tlkj4~p?q=1tw6ZhS&xrzm9D*6`

    ;Ec~Y*D!@u8*ko*?#!Q)l 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 o=e?"?"+new URLSearchParams(e).toString():"";return t(`/memories${o}`)},get:e=>t(`/memories/${e}`),delete:e=>t(`/memories/${e}`,{method:"DELETE"}),promote:e=>t(`/memories/${e}/promote`,{method:"POST"}),demote:e=>t(`/memories/${e}/demote`,{method:"POST"}),suppress:(e,o)=>t(`/memories/${e}/suppress`,{method:"POST",body:o?JSON.stringify({reason:o}):void 0}),unsuppress:e=>t(`/memories/${e}/unsuppress`,{method:"POST"})},search:(e,o=20)=>t(`/search?q=${encodeURIComponent(e)}&limit=${o}`),stats:()=>t("/stats"),health:()=>t("/health"),timeline:(e=7,o=200)=>t(`/timeline?days=${e}&limit=${o}`),graph:e=>{const o=e?"?"+new URLSearchParams(Object.entries(e).filter(([,i])=>i!==void 0).map(([i,s])=>[i,String(s)])).toString():"";return t(`/graph${o}`)},dream:()=>t("/dream",{method:"POST"}),explore:(e,o="associations",i,s=10)=>t("/explore",{method:"POST",body:JSON.stringify({from_id:e,action:o,to_id:i,limit:s})}),predict:()=>t("/predict",{method:"POST"}),importance:e=>t("/importance",{method:"POST",body:JSON.stringify({content:e})}),consolidate:()=>t("/consolidate",{method:"POST"}),retentionDistribution:()=>t("/retention-distribution"),intentions:(e="active")=>t(`/intentions?status=${e}`),deepReference:(e,o=20)=>t("/deep_reference",{method:"POST",body:JSON.stringify({query:e,depth:o})}),sanhedrin:{latest:()=>t("/sanhedrin/latest"),appeal:(e,o,i,s)=>t("/sanhedrin/appeal",{method:"POST",body:JSON.stringify({reason:e,note:o,claimId:i,receiptId:s})})}};export{n as a}; +const r="/api";async function t(e,o){const i=await fetch(`${r}${e}`,{headers:{"Content-Type":"application/json"},...o});if(!i.ok)throw new Error(`API ${i.status}: ${i.statusText}`);return i.json()}const n={memories:{list:e=>{const o=e?"?"+new URLSearchParams(e).toString():"";return t(`/memories${o}`)},get:e=>t(`/memories/${e}`),delete:e=>t(`/memories/${e}`,{method:"DELETE"}),promote:e=>t(`/memories/${e}/promote`,{method:"POST"}),demote:e=>t(`/memories/${e}/demote`,{method:"POST"}),suppress:(e,o)=>t(`/memories/${e}/suppress`,{method:"POST",body:o?JSON.stringify({reason:o}):void 0}),unsuppress:e=>t(`/memories/${e}/unsuppress`,{method:"POST"})},search:(e,o=20)=>t(`/search?q=${encodeURIComponent(e)}&limit=${o}`),stats:()=>t("/stats"),health:()=>t("/health"),timeline:(e=7,o=200)=>t(`/timeline?days=${e}&limit=${o}`),graph:e=>{const o=e?"?"+new URLSearchParams(Object.entries(e).filter(([,i])=>i!==void 0).map(([i,s])=>[i,String(s)])).toString():"";return t(`/graph${o}`)},dream:()=>t("/dream",{method:"POST"}),explore:(e,o="associations",i,s=10)=>t("/explore",{method:"POST",body:JSON.stringify({from_id:e,action:o,to_id:i,limit:s})}),predict:()=>t("/predict",{method:"POST"}),importance:e=>t("/importance",{method:"POST",body:JSON.stringify({content:e})}),consolidate:()=>t("/consolidate",{method:"POST"}),retentionDistribution:()=>t("/retention-distribution"),intentions:(e="active")=>t(`/intentions?status=${e}`),deepReference:(e,o=20)=>t("/deep_reference",{method:"POST",body:JSON.stringify({query:e,depth:o})}),sanhedrin:{latest:()=>t("/sanhedrin/latest"),telemetry:(e=7)=>t(`/sanhedrin/telemetry?days=${e}`),appeal:(e,o,i,s)=>t("/sanhedrin/appeal",{method:"POST",body:JSON.stringify({reason:e,note:o,claimId:i,receiptId:s})})}};export{n as a}; diff --git a/apps/dashboard/build/_app/immutable/chunks/B7CfdQuM.js.br b/apps/dashboard/build/_app/immutable/chunks/B7CfdQuM.js.br new file mode 100644 index 0000000000000000000000000000000000000000..d93874181fbfac113a243da8c24b659269520584 GIT binary patch literal 646 zcmV;10(t!#+XeuP)LN}JY}?Z5o@H`WdRXyu~xbAY%b+MUk zKZM853b+j>zn96b*=+HU=wXaS$-`$$Y0o*`vaB)n&A;Z7K$&m}r4Tp~O75$nV#33^i zf+?LKO%72xcBLADSu5K~_)RPNwp<#LM>=t#;NXCO1Cp1o4G|_P8vqrIfyv=Sptq2dFRlp^zq gM1_0p8dTk#F4dahx&~I%eKMG#LXJh%e}#N90ut>otN;K2 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/B7CfdQuM.js.gz b/apps/dashboard/build/_app/immutable/chunks/B7CfdQuM.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..fc0e3561a2ee61df289f5fffd127516bb6d9a7c9 GIT binary patch literal 774 zcmV+h1Nrt<9#v*7g#L=M^{H9J<)g0zQMn+jOML{$}-3FmA4V3cGHkKRj`=z!GiR_J=!} zP?Fx5js1y5oa9;9)o|S&>E2=q1xlcp>31Ks58ETtTx^Vs{VLAA7S-y5@;bkJfXv3k z*Hyx)ZHa{i9fp56-cUe1NYl24QCy0O?vWb@(6^JNiEg6*sMOQxC7M%f${|^QVs8}z zFIAy5wB=^P7?q))Q^PogPrn{@4!VbIuP$DzVo9>S#XJEn`~pc7x5`~0_w`E*b=pZE za?I>NvODjgiPUOsh0Hp|v+?%kW0bOXBPHM?yLPDpb3r52N8h>I!+^?6=9J3`I99kfx`ZWYa2fB80(FwGTit^nOa5^U zdPCjFp`rm$z63_d73B1UmL#QYwrv=YaSON+p`}J~$cdYgekg}`1H2s+%7V5&jhLtJ zwDiV%i+?PGZqERhZtE$Y6#~msCnyaWU}fpwi>hfRBvq0|EdyZ!(M&%51D#Y%`rHNp E02TCiY5)KL literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/D-gDZzN6.js b/apps/dashboard/build/_app/immutable/chunks/C2TQQEIa.js similarity index 65% rename from apps/dashboard/build/_app/immutable/chunks/D-gDZzN6.js rename to apps/dashboard/build/_app/immutable/chunks/C2TQQEIa.js index d17266c..d683bb6 100644 --- a/apps/dashboard/build/_app/immutable/chunks/D-gDZzN6.js +++ b/apps/dashboard/build/_app/immutable/chunks/C2TQQEIa.js @@ -1 +1 @@ -import{$ as J,bd as ee}from"./CpWkWWOo.js";import{w as ae}from"./BeMFXnHE.js";import{c as ne,H as N,N as B,r as gt,i as _t,b as L,s as C,p as x,n as ft,f as $t,g as ut,a as X,d as it,S as Nt,P as re,e as oe,h as se,o as Dt,j as q,k as ie,l as qt,m as ce,q as le,t as Kt,u as Pt,v as fe}from"./DGcYlAAw.js";class wt{constructor(a,e){this.status=a,typeof e=="string"?this.body={message:e}:e?this.body=e:this.body={message:`Error: ${a}`}}toString(){return JSON.stringify(this.body)}}class vt{constructor(a,e){this.status=a,this.location=e}}class yt extends Error{constructor(a,e,r){super(r),this.status=a,this.text=e}}const ue=/^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/;function he(t){const a=[];return{pattern:t==="/"?/^\/$/:new RegExp(`^${pe(t).map(r=>{const n=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(r);if(n)return a.push({name:n[1],matcher:n[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const o=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(r);if(o)return a.push({name:o[1],matcher:o[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!r)return;const s=r.split(/\[(.+?)\](?!\])/);return"/"+s.map((c,l)=>{if(l%2){if(c.startsWith("x+"))return ct(String.fromCharCode(parseInt(c.slice(2),16)));if(c.startsWith("u+"))return ct(String.fromCharCode(...c.slice(2).split("-").map(_=>parseInt(_,16))));const h=ue.exec(c),[,u,w,f,d]=h;return a.push({name:f,matcher:d,optional:!!u,rest:!!w,chained:w?l===1&&s[0]==="":!1}),w?"([^]*?)":u?"([^/]*)?":"([^/]+?)"}return ct(c)}).join("")}).join("")}/?$`),params:a}}function de(t){return t!==""&&!/^\([^)]+\)$/.test(t)}function pe(t){return t.slice(1).split("/").filter(de)}function me(t,a,e){const r={},n=t.slice(1),o=n.filter(i=>i!==void 0);let s=0;for(let i=0;ih).join("/"),s=0),l===void 0)if(c.rest)l="";else continue;if(!c.matcher||e[c.matcher](l)){r[c.name]=l;const h=a[i+1],u=n[i+1];h&&!h.rest&&h.optional&&u&&c.chained&&(s=0),!h&&!u&&Object.keys(r).length===o.length&&(s=0);continue}if(c.optional&&c.chained){s++;continue}return}if(!s)return r}function ct(t){return t.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}function ge({nodes:t,server_loads:a,dictionary:e,matchers:r}){const n=new Set(a);return Object.entries(e).map(([i,[c,l,h]])=>{const{pattern:u,params:w}=he(i),f={id:i,exec:d=>{const _=u.exec(d);if(_)return me(_,w,r)},errors:[1,...h||[]].map(d=>t[d]),layouts:[0,...l||[]].map(s),leaf:o(c)};return f.errors.length=f.layouts.length=Math.max(f.errors.length,f.layouts.length),f});function o(i){const c=i<0;return c&&(i=~i),[c,t[i]]}function s(i){return i===void 0?i:[n.has(i),t[i]]}}function Ft(t,a=JSON.parse){try{return a(sessionStorage[t])}catch{}}function It(t,a,e=JSON.stringify){const r=e(a);try{sessionStorage[t]=r}catch{}}function _e(t){return t.filter(a=>a!=null)}function Et(t){return t instanceof wt||t instanceof yt?t.status:500}function we(t){return t instanceof yt?t.text:"Internal Error"}const ve=new Set(["icon","shortcut icon","apple-touch-icon"]),I=Ft(Kt)??{},M=Ft(qt)??{},P={url:Pt({}),page:Pt({}),navigating:ae(null),updated:ne()};function bt(t){I[t]=C()}function ye(t,a){let e=t+1;for(;I[e];)delete I[e],e+=1;for(e=a+1;M[e];)delete M[e],e+=1}function V(t,a=!1){return a?location.replace(t.href):location.href=t.href,new Promise(()=>{})}async function Bt(){if("serviceWorker"in navigator){const t=await navigator.serviceWorker.getRegistration(L||"/");t&&await t.update()}}function Tt(){}let kt,ht,Q,U,dt,b;const Z=[],tt=[];let v=null;function pt(){var t;(t=v==null?void 0:v.fork)==null||t.then(a=>a==null?void 0:a.discard()),v=null}const G=new Map,Mt=new Set,Ee=new Set,F=new Set;let g={branch:[],error:null,url:null},Vt=!1,et=!1,Ot=!0,H=!1,K=!1,Ht=!1,St=!1,Yt,E,R,O;const at=new Set,Ct=new Map;async function Fe(t,a,e){var o,s,i,c,l;(o=globalThis.__sveltekit_1r5nume)!=null&&o.data&&globalThis.__sveltekit_1r5nume.data,document.URL!==location.href&&(location.href=location.href),b=t,await((i=(s=t.hooks).init)==null?void 0:i.call(s)),kt=ge(t),U=document.documentElement,dt=a,ht=t.nodes[0],Q=t.nodes[1],ht(),Q(),E=(c=history.state)==null?void 0:c[N],R=(l=history.state)==null?void 0:l[B],E||(E=R=Date.now(),history.replaceState({...history.state,[N]:E,[B]:R},""));const r=I[E];function n(){r&&(history.scrollRestoration="manual",scrollTo(r.x,r.y))}e?(n(),await Ce(dt,e)):(await D({type:"enter",url:gt(b.hash?Ne(new URL(location.href)):location.href),replace_state:!0}),n()),Oe()}function be(){Z.length=0,St=!1}function zt(t){tt.some(a=>a==null?void 0:a.snapshot)&&(M[t]=tt.map(a=>{var e;return(e=a==null?void 0:a.snapshot)==null?void 0:e.capture()}))}function Wt(t){var a;(a=M[t])==null||a.forEach((e,r)=>{var n,o;(o=(n=tt[r])==null?void 0:n.snapshot)==null||o.restore(e)})}function jt(){bt(E),It(Kt,I),zt(R),It(qt,M)}async function Gt(t,a,e,r){let n;a.invalidateAll&&pt(),await D({type:"goto",url:gt(t),keepfocus:a.keepFocus,noscroll:a.noScroll,replace_state:a.replaceState,state:a.state,redirect_count:e,nav_token:r,accept:()=>{a.invalidateAll&&(St=!0,n=[...Ct.keys()]),a.invalidate&&a.invalidate.forEach(Te)}}),a.invalidateAll&&J().then(J).then(()=>{Ct.forEach(({resource:o},s)=>{var i;n!=null&&n.includes(s)&&((i=o.refresh)==null||i.call(o))})})}async function ke(t){if(t.id!==(v==null?void 0:v.id)){pt();const a={};at.add(a),v={id:t.id,token:a,promise:Xt({...t,preload:a}).then(e=>(at.delete(a),e.type==="loaded"&&e.state.error&&pt(),e)),fork:null}}return v.promise}async function lt(t){var e;const a=(e=await ot(t,!1))==null?void 0:e.route;a&&await Promise.all([...a.layouts,a.leaf].filter(Boolean).map(r=>r[1]()))}async function Jt(t,a,e){var n;g=t.state;const r=document.querySelector("style[data-sveltekit]");if(r&&r.remove(),Object.assign(x,t.props.page),Yt=new b.root({target:a,props:{...t.props,stores:P,components:tt},hydrate:e,sync:!1}),await Promise.resolve(),Wt(R),e){const o={from:null,to:{params:g.params,route:{id:((n=g.route)==null?void 0:n.id)??null},url:new URL(location.href),scroll:I[E]??C()},willUnload:!1,type:"enter",complete:Promise.resolve()};F.forEach(s=>s(o))}et=!0}function nt({url:t,params:a,branch:e,status:r,error:n,route:o,form:s}){let i="never";if(L&&(t.pathname===L||t.pathname===L+"/"))i="always";else for(const f of e)(f==null?void 0:f.slash)!==void 0&&(i=f.slash);t.pathname=se(t.pathname,i),t.search=t.search;const c={type:"loaded",state:{url:t,params:a,branch:e,error:n,route:o},props:{constructors:_e(e).map(f=>f.node.component),page:At(x)}};s!==void 0&&(c.props.form=s);let l={},h=!x,u=0;for(let f=0;fi(new URL(s))))return!0;return!1}function xt(t,a){return(t==null?void 0:t.type)==="data"?t:(t==null?void 0:t.type)==="skip"?a??null:null}function xe(t,a){if(!t)return new Set(a.searchParams.keys());const e=new Set([...t.searchParams.keys(),...a.searchParams.keys()]);for(const r of e){const n=t.searchParams.getAll(r),o=a.searchParams.getAll(r);n.every(s=>o.includes(s))&&o.every(s=>n.includes(s))&&e.delete(r)}return e}function Le({error:t,url:a,route:e,params:r}){return{type:"loaded",state:{error:t,url:a,route:e,params:r,branch:[]},props:{page:At(x),constructors:[]}}}async function Xt({id:t,invalidating:a,url:e,params:r,route:n,preload:o}){if((v==null?void 0:v.id)===t)return at.delete(v.token),v.promise;const{errors:s,layouts:i,leaf:c}=n,l=[...i,c];s.forEach(m=>m==null?void 0:m().catch(()=>{})),l.forEach(m=>m==null?void 0:m[1]().catch(()=>{}));const h=g.url?t!==rt(g.url):!1,u=g.route?n.id!==g.route.id:!1,w=xe(g.url,e);let f=!1;const d=l.map(async(m,p)=>{var A;if(!m)return;const y=g.branch[p];return m[1]===(y==null?void 0:y.loader)&&!Re(f,u,h,w,(A=y.universal)==null?void 0:A.uses,r)?y:(f=!0,Rt({loader:m[1],url:e,params:r,route:n,parent:async()=>{var z;const T={};for(let j=0;j{});const _=[];for(let m=0;mPromise.resolve({}),server_data_node:xt(o)}),i={node:await Q(),loader:Q,universal:null,server:null,data:null};return nt({url:e,params:n,branch:[s,i],status:t,error:a,route:null})}catch(s){if(s instanceof vt)return Gt(new URL(s.location,location.href),{},0);throw s}}async function Ae(t){const a=t.href;if(G.has(a))return G.get(a);let e;try{const r=(async()=>{let n=await b.hooks.reroute({url:new URL(t),fetch:async(o,s)=>Se(o,s,t).promise})??t;if(typeof n=="string"){const o=new URL(t);b.hash?o.hash=n:o.pathname=n,n=o}return n})();G.set(a,r),e=await r}catch{G.delete(a);return}return e}async function ot(t,a){if(t&&!_t(t,L,b.hash)){const e=await Ae(t);if(!e)return;const r=Pe(e);for(const n of kt){const o=n.exec(r);if(o)return{id:rt(t),invalidating:a,route:n,params:oe(o),url:t}}}}function Pe(t){return ie(b.hash?t.hash.replace(/^#/,"").replace(/[?#].+/,""):t.pathname.slice(L.length))||"/"}function rt(t){return(b.hash?t.hash.replace(/^#/,""):t.pathname)+t.search}function Qt({url:t,type:a,intent:e,delta:r,event:n,scroll:o}){let s=!1;const i=Ut(g,e,t,a,o??null);r!==void 0&&(i.navigation.delta=r),n!==void 0&&(i.navigation.event=n);const c={...i.navigation,cancel:()=>{s=!0,i.reject(new Error("navigation cancelled"))}};return H||Mt.forEach(l=>l(c)),s?null:i}async function D({type:t,url:a,popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s={},redirect_count:i=0,nav_token:c={},accept:l=Tt,block:h=Tt,event:u}){var j;const w=O;O=c;const f=await ot(a,!1),d=t==="enter"?Ut(g,f,a,t):Qt({url:a,type:t,delta:e==null?void 0:e.delta,intent:f,scroll:e==null?void 0:e.scroll,event:u});if(!d){h(),O===c&&(O=w);return}const _=E,m=R;l(),H=!0,et&&d.navigation.type!=="enter"&&P.navigating.set(ft.current=d.navigation);let p=f&&await Xt(f);if(!p){if(_t(a,L,b.hash))return await V(a,o);p=await Zt(a,{id:null},await Y(new yt(404,"Not Found",`Not found: ${a.pathname}`),{url:a,params:{},route:{id:null}}),404,o)}if(a=(f==null?void 0:f.url)||a,O!==c)return d.reject(new Error("navigation aborted")),!1;if(p.type==="redirect"){if(i<20){await D({type:t,url:new URL(p.location,a),popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s,redirect_count:i+1,nav_token:c}),d.fulfil(void 0);return}p=await Lt({status:500,error:await Y(new Error("Redirect loop"),{url:a,params:{},route:{id:null}}),url:a,route:{id:null}})}else p.props.page.status>=400&&await P.updated.check()&&(await Bt(),await V(a,o));if(be(),bt(_),zt(m),p.props.page.url.pathname!==a.pathname&&(a.pathname=p.props.page.url.pathname),s=e?e.state:s,!e){const k=o?0:1,W={[N]:E+=k,[B]:R+=k,[Nt]:s};(o?history.replaceState:history.pushState).call(history,W,"",a),o||ye(E,R)}const y=f&&(v==null?void 0:v.id)===f.id?v.fork:null;v=null,p.props.page.state=s;let S;if(et){const k=(await Promise.all(Array.from(Ee,$=>$(d.navigation)))).filter($=>typeof $=="function");if(k.length>0){let $=function(){k.forEach(st=>{F.delete(st)})};k.push($),k.forEach(st=>{F.add(st)})}g=p.state,p.props.page&&(p.props.page.url=a);const W=y&&await y;W?S=W.commit():(Yt.$set(p.props),fe(p.props.page),S=(j=ee)==null?void 0:j()),Ht=!0}else await Jt(p,dt,!1);const{activeElement:A}=document;await S,await J(),await J();let T=null;if(Ot){const k=e?e.scroll:n?C():null;k?scrollTo(k.x,k.y):(T=a.hash&&document.getElementById(te(a)))?T.scrollIntoView():scrollTo(0,0)}const z=document.activeElement!==A&&document.activeElement!==document.body;!r&&!z&&$e(a,!T),Ot=!0,p.props.page&&Object.assign(x,p.props.page),H=!1,t==="popstate"&&Wt(R),d.fulfil(void 0),d.navigation.to&&(d.navigation.to.scroll=C()),F.forEach(k=>k(d.navigation)),P.navigating.set(ft.current=null)}async function Zt(t,a,e,r,n){return t.origin===Dt&&t.pathname===location.pathname&&!Vt?await Lt({status:r,error:e,url:t,route:a}):await V(t,n)}function Ie(){let t,a={element:void 0,href:void 0},e;U.addEventListener("mousemove",i=>{const c=i.target;clearTimeout(t),t=setTimeout(()=>{o(c,q.hover)},20)});function r(i){i.defaultPrevented||o(i.composedPath()[0],q.tap)}U.addEventListener("mousedown",r),U.addEventListener("touchstart",r,{passive:!0});const n=new IntersectionObserver(i=>{for(const c of i)c.isIntersecting&&(lt(new URL(c.target.href)),n.unobserve(c.target))},{threshold:0});async function o(i,c){const l=$t(i,U),h=l===a.element&&(l==null?void 0:l.href)===a.href&&c>=e;if(!l||h)return;const{url:u,external:w,download:f}=ut(l,L,b.hash);if(w||f)return;const d=X(l),_=u&&rt(g.url)===rt(u);if(!(d.reload||_))if(c<=d.preload_data){a={element:l,href:l.href},e=q.tap;const m=await ot(u,!1);if(!m)return;ke(m)}else c<=d.preload_code&&(a={element:l,href:l.href},e=c,lt(u))}function s(){n.disconnect();for(const i of U.querySelectorAll("a")){const{url:c,external:l,download:h}=ut(i,L,b.hash);if(l||h)continue;const u=X(i);u.reload||(u.preload_code===q.viewport&&n.observe(i),u.preload_code===q.eager&<(c))}}F.add(s),s()}function Y(t,a){if(t instanceof wt)return t.body;const e=Et(t),r=we(t);return b.hooks.handleError({error:t,event:a,status:e,message:r})??{message:r}}function Be(t,a={}){return t=new URL(gt(t)),t.origin!==Dt?Promise.reject(new Error("goto: invalid URL")):Gt(t,a,0)}function Te(t){if(typeof t=="function")Z.push(t);else{const{href:a}=new URL(t,location.href);Z.push(e=>e.href===a)}}function Oe(){var a;history.scrollRestoration="manual",addEventListener("beforeunload",e=>{let r=!1;if(jt(),!H){const n=Ut(g,void 0,null,"leave"),o={...n.navigation,cancel:()=>{r=!0,n.reject(new Error("navigation cancelled"))}};Mt.forEach(s=>s(o))}r?(e.preventDefault(),e.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&jt()}),(a=navigator.connection)!=null&&a.saveData||Ie(),U.addEventListener("click",async e=>{if(e.button||e.which!==1||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.defaultPrevented)return;const r=$t(e.composedPath()[0],U);if(!r)return;const{url:n,external:o,target:s,download:i}=ut(r,L,b.hash);if(!n)return;if(s==="_parent"||s==="_top"){if(window.parent!==window)return}else if(s&&s!=="_self")return;const c=X(r);if(!(r instanceof SVGAElement)&&n.protocol!==location.protocol&&!(n.protocol==="https:"||n.protocol==="http:")||i)return;const[h,u]=(b.hash?n.hash.replace(/^#/,""):n.href).split("#"),w=h===it(location);if(o||c.reload&&(!w||!u)){Qt({url:n,type:"link",event:e})?H=!0:e.preventDefault();return}if(u!==void 0&&w){const[,f]=g.url.href.split("#");if(f===u){if(e.preventDefault(),u===""||u==="top"&&r.ownerDocument.getElementById("top")===null)scrollTo({top:0});else{const d=r.ownerDocument.getElementById(decodeURIComponent(u));d&&(d.scrollIntoView(),d.focus())}return}if(K=!0,bt(E),t(n),!c.replace_state)return;K=!1}e.preventDefault(),await new Promise(f=>{requestAnimationFrame(()=>{setTimeout(f,0)}),setTimeout(f,100)}),await D({type:"link",url:n,keepfocus:c.keepfocus,noscroll:c.noscroll,replace_state:c.replace_state??n.href===location.href,event:e})}),U.addEventListener("submit",e=>{if(e.defaultPrevented)return;const r=HTMLFormElement.prototype.cloneNode.call(e.target),n=e.submitter;if(((n==null?void 0:n.formTarget)||r.target)==="_blank"||((n==null?void 0:n.formMethod)||r.method)!=="get")return;const i=new URL((n==null?void 0:n.hasAttribute("formaction"))&&(n==null?void 0:n.formAction)||r.action);if(_t(i,L,!1))return;const c=e.target,l=X(c);if(l.reload)return;e.preventDefault(),e.stopPropagation();const h=new FormData(c,n);i.search=new URLSearchParams(h).toString(),D({type:"form",url:i,keepfocus:l.keepfocus,noscroll:l.noscroll,replace_state:l.replace_state??i.href===location.href,event:e})}),addEventListener("popstate",async e=>{var r;if(!mt){if((r=e.state)!=null&&r[N]){const n=e.state[N];if(O={},n===E)return;const o=I[n],s=e.state[Nt]??{},i=new URL(e.state[re]??location.href),c=e.state[B],l=g.url?it(location)===it(g.url):!1;if(c===R&&(Ht||l)){s!==x.state&&(x.state=s),t(i),I[E]=C(),o&&scrollTo(o.x,o.y),E=n;return}const u=n-E;await D({type:"popstate",url:i,popped:{state:s,scroll:o,delta:u},accept:()=>{E=n,R=c},block:()=>{history.go(-u)},nav_token:O,event:e})}else if(!K){const n=new URL(location.href);t(n),b.hash&&location.reload()}}}),addEventListener("hashchange",()=>{K&&(K=!1,history.replaceState({...history.state,[N]:++E,[B]:R},"",location.href))});for(const e of document.querySelectorAll("link"))ve.has(e.rel)&&(e.href=e.href);addEventListener("pageshow",e=>{e.persisted&&P.navigating.set(ft.current=null)});function t(e){g.url=x.url=e,P.page.set(At(x)),P.page.notify()}}async function Ce(t,{status:a=200,error:e,node_ids:r,params:n,route:o,server_route:s,data:i,form:c}){Vt=!0;const l=new URL(location.href);let h;({params:n={},route:o={id:null}}=await ot(l,!1)||{}),h=kt.find(({id:f})=>f===o.id);let u,w=!0;try{const f=r.map(async(_,m)=>{const p=i[m];return p!=null&&p.uses&&(p.uses=je(p.uses)),Rt({loader:b.nodes[_],url:l,params:n,route:o,parent:async()=>{const y={};for(let S=0;S{const i=history.state;mt=!0,location.replace(new URL(`#${r}`,location.href)),history.replaceState(i,"",t),a&&scrollTo(o,s),mt=!1})}else{const o=document.body,s=o.getAttribute("tabindex");o.tabIndex=-1,o.focus({preventScroll:!0,focusVisible:!1}),s!==null?o.setAttribute("tabindex",s):o.removeAttribute("tabindex")}const n=getSelection();if(n&&n.type!=="None"){const o=[];for(let s=0;s{if(n.rangeCount===o.length){for(let s=0;s{o=u,s=w});return i.catch(()=>{}),{navigation:{from:{params:t.params,route:{id:((l=t.route)==null?void 0:l.id)??null},url:t.url,scroll:C()},to:e&&{params:(a==null?void 0:a.params)??null,route:{id:((h=a==null?void 0:a.route)==null?void 0:h.id)??null},url:e,scroll:n},willUnload:!a,type:r,complete:i},fulfil:o,reject:s}}function At(t){return{data:t.data,error:t.error,form:t.form,params:t.params,route:t.route,state:t.state,status:t.status,url:t.url}}function Ne(t){const a=new URL(t);return a.hash=decodeURIComponent(t.hash),a}function te(t){let a;if(b.hash){const[,,e]=t.hash.split("#",3);a=e??""}else a=t.hash.slice(1);return decodeURIComponent(a)}export{Fe as a,Be as g,P as s}; +import{$ as J,bd as ee}from"./CpWkWWOo.js";import{w as ae}from"./BeMFXnHE.js";import{c as ne,H as N,N as B,r as mt,i as _t,b as L,s as C,p as x,n as ft,f as $t,g as ut,a as X,d as it,S as Nt,P as re,e as oe,h as se,o as Dt,j as q,k as ie,l as qt,m as le,q as ce,t as Kt,u as Pt,v as fe}from"./D8UfWY0j.js";class wt{constructor(a,e){this.status=a,typeof e=="string"?this.body={message:e}:e?this.body=e:this.body={message:`Error: ${a}`}}toString(){return JSON.stringify(this.body)}}class vt{constructor(a,e){this.status=a,this.location=e}}class yt extends Error{constructor(a,e,r){super(r),this.status=a,this.text=e}}const ue=/^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/;function he(t){const a=[];return{pattern:t==="/"?/^\/$/:new RegExp(`^${pe(t).map(r=>{const n=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(r);if(n)return a.push({name:n[1],matcher:n[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const o=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(r);if(o)return a.push({name:o[1],matcher:o[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!r)return;const s=r.split(/\[(.+?)\](?!\])/);return"/"+s.map((l,c)=>{if(c%2){if(l.startsWith("x+"))return lt(String.fromCharCode(parseInt(l.slice(2),16)));if(l.startsWith("u+"))return lt(String.fromCharCode(...l.slice(2).split("-").map(_=>parseInt(_,16))));const h=ue.exec(l),[,u,w,f,d]=h;return a.push({name:f,matcher:d,optional:!!u,rest:!!w,chained:w?c===1&&s[0]==="":!1}),w?"([^]*?)":u?"([^/]*)?":"([^/]+?)"}return lt(l)}).join("")}).join("")}/?$`),params:a}}function de(t){return t!==""&&!/^\([^)]+\)$/.test(t)}function pe(t){return t.slice(1).split("/").filter(de)}function ge(t,a,e){const r={},n=t.slice(1),o=n.filter(i=>i!==void 0);let s=0;for(let i=0;ih).join("/"),s=0),c===void 0)if(l.rest)c="";else continue;if(!l.matcher||e[l.matcher](c)){r[l.name]=c;const h=a[i+1],u=n[i+1];h&&!h.rest&&h.optional&&u&&l.chained&&(s=0),!h&&!u&&Object.keys(r).length===o.length&&(s=0);continue}if(l.optional&&l.chained){s++;continue}return}if(!s)return r}function lt(t){return t.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}function me({nodes:t,server_loads:a,dictionary:e,matchers:r}){const n=new Set(a);return Object.entries(e).map(([i,[l,c,h]])=>{const{pattern:u,params:w}=he(i),f={id:i,exec:d=>{const _=u.exec(d);if(_)return ge(_,w,r)},errors:[1,...h||[]].map(d=>t[d]),layouts:[0,...c||[]].map(s),leaf:o(l)};return f.errors.length=f.layouts.length=Math.max(f.errors.length,f.layouts.length),f});function o(i){const l=i<0;return l&&(i=~i),[l,t[i]]}function s(i){return i===void 0?i:[n.has(i),t[i]]}}function Ft(t,a=JSON.parse){try{return a(sessionStorage[t])}catch{}}function It(t,a,e=JSON.stringify){const r=e(a);try{sessionStorage[t]=r}catch{}}function _e(t){return t.filter(a=>a!=null)}function Et(t){return t instanceof wt||t instanceof yt?t.status:500}function we(t){return t instanceof yt?t.text:"Internal Error"}const ve=new Set(["icon","shortcut icon","apple-touch-icon"]),I=Ft(Kt)??{},M=Ft(qt)??{},P={url:Pt({}),page:Pt({}),navigating:ae(null),updated:ne()};function bt(t){I[t]=C()}function ye(t,a){let e=t+1;for(;I[e];)delete I[e],e+=1;for(e=a+1;M[e];)delete M[e],e+=1}function V(t,a=!1){return a?location.replace(t.href):location.href=t.href,new Promise(()=>{})}async function Bt(){if("serviceWorker"in navigator){const t=await navigator.serviceWorker.getRegistration(L||"/");t&&await t.update()}}function Tt(){}let kt,ht,Q,U,dt,b;const Z=[],tt=[];let v=null;function pt(){var t;(t=v==null?void 0:v.fork)==null||t.then(a=>a==null?void 0:a.discard()),v=null}const G=new Map,Mt=new Set,Ee=new Set,F=new Set;let m={branch:[],error:null,url:null},Vt=!1,et=!1,Ot=!0,H=!1,K=!1,Ht=!1,St=!1,Yt,E,R,O;const at=new Set,Ct=new Map;async function Fe(t,a,e){var o,s,i,l,c;(o=globalThis.__sveltekit_1rrld2f)!=null&&o.data&&globalThis.__sveltekit_1rrld2f.data,document.URL!==location.href&&(location.href=location.href),b=t,await((i=(s=t.hooks).init)==null?void 0:i.call(s)),kt=me(t),U=document.documentElement,dt=a,ht=t.nodes[0],Q=t.nodes[1],ht(),Q(),E=(l=history.state)==null?void 0:l[N],R=(c=history.state)==null?void 0:c[B],E||(E=R=Date.now(),history.replaceState({...history.state,[N]:E,[B]:R},""));const r=I[E];function n(){r&&(history.scrollRestoration="manual",scrollTo(r.x,r.y))}e?(n(),await Ce(dt,e)):(await D({type:"enter",url:mt(b.hash?Ne(new URL(location.href)):location.href),replace_state:!0}),n()),Oe()}function be(){Z.length=0,St=!1}function zt(t){tt.some(a=>a==null?void 0:a.snapshot)&&(M[t]=tt.map(a=>{var e;return(e=a==null?void 0:a.snapshot)==null?void 0:e.capture()}))}function Wt(t){var a;(a=M[t])==null||a.forEach((e,r)=>{var n,o;(o=(n=tt[r])==null?void 0:n.snapshot)==null||o.restore(e)})}function jt(){bt(E),It(Kt,I),zt(R),It(qt,M)}async function Gt(t,a,e,r){let n;a.invalidateAll&&pt(),await D({type:"goto",url:mt(t),keepfocus:a.keepFocus,noscroll:a.noScroll,replace_state:a.replaceState,state:a.state,redirect_count:e,nav_token:r,accept:()=>{a.invalidateAll&&(St=!0,n=[...Ct.keys()]),a.invalidate&&a.invalidate.forEach(Te)}}),a.invalidateAll&&J().then(J).then(()=>{Ct.forEach(({resource:o},s)=>{var i;n!=null&&n.includes(s)&&((i=o.refresh)==null||i.call(o))})})}async function ke(t){if(t.id!==(v==null?void 0:v.id)){pt();const a={};at.add(a),v={id:t.id,token:a,promise:Xt({...t,preload:a}).then(e=>(at.delete(a),e.type==="loaded"&&e.state.error&&pt(),e)),fork:null}}return v.promise}async function ct(t){var e;const a=(e=await ot(t,!1))==null?void 0:e.route;a&&await Promise.all([...a.layouts,a.leaf].filter(Boolean).map(r=>r[1]()))}async function Jt(t,a,e){var n;m=t.state;const r=document.querySelector("style[data-sveltekit]");if(r&&r.remove(),Object.assign(x,t.props.page),Yt=new b.root({target:a,props:{...t.props,stores:P,components:tt},hydrate:e,sync:!1}),await Promise.resolve(),Wt(R),e){const o={from:null,to:{params:m.params,route:{id:((n=m.route)==null?void 0:n.id)??null},url:new URL(location.href),scroll:I[E]??C()},willUnload:!1,type:"enter",complete:Promise.resolve()};F.forEach(s=>s(o))}et=!0}function nt({url:t,params:a,branch:e,status:r,error:n,route:o,form:s}){let i="never";if(L&&(t.pathname===L||t.pathname===L+"/"))i="always";else for(const f of e)(f==null?void 0:f.slash)!==void 0&&(i=f.slash);t.pathname=se(t.pathname,i),t.search=t.search;const l={type:"loaded",state:{url:t,params:a,branch:e,error:n,route:o},props:{constructors:_e(e).map(f=>f.node.component),page:At(x)}};s!==void 0&&(l.props.form=s);let c={},h=!x,u=0;for(let f=0;fi(new URL(s))))return!0;return!1}function xt(t,a){return(t==null?void 0:t.type)==="data"?t:(t==null?void 0:t.type)==="skip"?a??null:null}function xe(t,a){if(!t)return new Set(a.searchParams.keys());const e=new Set([...t.searchParams.keys(),...a.searchParams.keys()]);for(const r of e){const n=t.searchParams.getAll(r),o=a.searchParams.getAll(r);n.every(s=>o.includes(s))&&o.every(s=>n.includes(s))&&e.delete(r)}return e}function Le({error:t,url:a,route:e,params:r}){return{type:"loaded",state:{error:t,url:a,route:e,params:r,branch:[]},props:{page:At(x),constructors:[]}}}async function Xt({id:t,invalidating:a,url:e,params:r,route:n,preload:o}){if((v==null?void 0:v.id)===t)return at.delete(v.token),v.promise;const{errors:s,layouts:i,leaf:l}=n,c=[...i,l];s.forEach(g=>g==null?void 0:g().catch(()=>{})),c.forEach(g=>g==null?void 0:g[1]().catch(()=>{}));const h=m.url?t!==rt(m.url):!1,u=m.route?n.id!==m.route.id:!1,w=xe(m.url,e);let f=!1;const d=c.map(async(g,p)=>{var A;if(!g)return;const y=m.branch[p];return g[1]===(y==null?void 0:y.loader)&&!Re(f,u,h,w,(A=y.universal)==null?void 0:A.uses,r)?y:(f=!0,Rt({loader:g[1],url:e,params:r,route:n,parent:async()=>{var z;const T={};for(let j=0;j{});const _=[];for(let g=0;gPromise.resolve({}),server_data_node:xt(o)}),i={node:await Q(),loader:Q,universal:null,server:null,data:null};return nt({url:e,params:n,branch:[s,i],status:t,error:a,route:null})}catch(s){if(s instanceof vt)return Gt(new URL(s.location,location.href),{},0);throw s}}async function Ae(t){const a=t.href;if(G.has(a))return G.get(a);let e;try{const r=(async()=>{let n=await b.hooks.reroute({url:new URL(t),fetch:async(o,s)=>Se(o,s,t).promise})??t;if(typeof n=="string"){const o=new URL(t);b.hash?o.hash=n:o.pathname=n,n=o}return n})();G.set(a,r),e=await r}catch{G.delete(a);return}return e}async function ot(t,a){if(t&&!_t(t,L,b.hash)){const e=await Ae(t);if(!e)return;const r=Pe(e);for(const n of kt){const o=n.exec(r);if(o)return{id:rt(t),invalidating:a,route:n,params:oe(o),url:t}}}}function Pe(t){return ie(b.hash?t.hash.replace(/^#/,"").replace(/[?#].+/,""):t.pathname.slice(L.length))||"/"}function rt(t){return(b.hash?t.hash.replace(/^#/,""):t.pathname)+t.search}function Qt({url:t,type:a,intent:e,delta:r,event:n,scroll:o}){let s=!1;const i=Ut(m,e,t,a,o??null);r!==void 0&&(i.navigation.delta=r),n!==void 0&&(i.navigation.event=n);const l={...i.navigation,cancel:()=>{s=!0,i.reject(new Error("navigation cancelled"))}};return H||Mt.forEach(c=>c(l)),s?null:i}async function D({type:t,url:a,popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s={},redirect_count:i=0,nav_token:l={},accept:c=Tt,block:h=Tt,event:u}){var j;const w=O;O=l;const f=await ot(a,!1),d=t==="enter"?Ut(m,f,a,t):Qt({url:a,type:t,delta:e==null?void 0:e.delta,intent:f,scroll:e==null?void 0:e.scroll,event:u});if(!d){h(),O===l&&(O=w);return}const _=E,g=R;c(),H=!0,et&&d.navigation.type!=="enter"&&P.navigating.set(ft.current=d.navigation);let p=f&&await Xt(f);if(!p){if(_t(a,L,b.hash))return await V(a,o);p=await Zt(a,{id:null},await Y(new yt(404,"Not Found",`Not found: ${a.pathname}`),{url:a,params:{},route:{id:null}}),404,o)}if(a=(f==null?void 0:f.url)||a,O!==l)return d.reject(new Error("navigation aborted")),!1;if(p.type==="redirect"){if(i<20){await D({type:t,url:new URL(p.location,a),popped:e,keepfocus:r,noscroll:n,replace_state:o,state:s,redirect_count:i+1,nav_token:l}),d.fulfil(void 0);return}p=await Lt({status:500,error:await Y(new Error("Redirect loop"),{url:a,params:{},route:{id:null}}),url:a,route:{id:null}})}else p.props.page.status>=400&&await P.updated.check()&&(await Bt(),await V(a,o));if(be(),bt(_),zt(g),p.props.page.url.pathname!==a.pathname&&(a.pathname=p.props.page.url.pathname),s=e?e.state:s,!e){const k=o?0:1,W={[N]:E+=k,[B]:R+=k,[Nt]:s};(o?history.replaceState:history.pushState).call(history,W,"",a),o||ye(E,R)}const y=f&&(v==null?void 0:v.id)===f.id?v.fork:null;v=null,p.props.page.state=s;let S;if(et){const k=(await Promise.all(Array.from(Ee,$=>$(d.navigation)))).filter($=>typeof $=="function");if(k.length>0){let $=function(){k.forEach(st=>{F.delete(st)})};k.push($),k.forEach(st=>{F.add(st)})}m=p.state,p.props.page&&(p.props.page.url=a);const W=y&&await y;W?S=W.commit():(Yt.$set(p.props),fe(p.props.page),S=(j=ee)==null?void 0:j()),Ht=!0}else await Jt(p,dt,!1);const{activeElement:A}=document;await S,await J(),await J();let T=null;if(Ot){const k=e?e.scroll:n?C():null;k?scrollTo(k.x,k.y):(T=a.hash&&document.getElementById(te(a)))?T.scrollIntoView():scrollTo(0,0)}const z=document.activeElement!==A&&document.activeElement!==document.body;!r&&!z&&$e(a,!T),Ot=!0,p.props.page&&Object.assign(x,p.props.page),H=!1,t==="popstate"&&Wt(R),d.fulfil(void 0),d.navigation.to&&(d.navigation.to.scroll=C()),F.forEach(k=>k(d.navigation)),P.navigating.set(ft.current=null)}async function Zt(t,a,e,r,n){return t.origin===Dt&&t.pathname===location.pathname&&!Vt?await Lt({status:r,error:e,url:t,route:a}):await V(t,n)}function Ie(){let t,a={element:void 0,href:void 0},e;U.addEventListener("mousemove",i=>{const l=i.target;clearTimeout(t),t=setTimeout(()=>{o(l,q.hover)},20)});function r(i){i.defaultPrevented||o(i.composedPath()[0],q.tap)}U.addEventListener("mousedown",r),U.addEventListener("touchstart",r,{passive:!0});const n=new IntersectionObserver(i=>{for(const l of i)l.isIntersecting&&(ct(new URL(l.target.href)),n.unobserve(l.target))},{threshold:0});async function o(i,l){const c=$t(i,U),h=c===a.element&&(c==null?void 0:c.href)===a.href&&l>=e;if(!c||h)return;const{url:u,external:w,download:f}=ut(c,L,b.hash);if(w||f)return;const d=X(c),_=u&&rt(m.url)===rt(u);if(!(d.reload||_))if(l<=d.preload_data){a={element:c,href:c.href},e=q.tap;const g=await ot(u,!1);if(!g)return;ke(g)}else l<=d.preload_code&&(a={element:c,href:c.href},e=l,ct(u))}function s(){n.disconnect();for(const i of U.querySelectorAll("a")){const{url:l,external:c,download:h}=ut(i,L,b.hash);if(c||h)continue;const u=X(i);u.reload||(u.preload_code===q.viewport&&n.observe(i),u.preload_code===q.eager&&ct(l))}}F.add(s),s()}function Y(t,a){if(t instanceof wt)return t.body;const e=Et(t),r=we(t);return b.hooks.handleError({error:t,event:a,status:e,message:r})??{message:r}}function Be(t,a={}){return t=new URL(mt(t)),t.origin!==Dt?Promise.reject(new Error("goto: invalid URL")):Gt(t,a,0)}function Te(t){if(typeof t=="function")Z.push(t);else{const{href:a}=new URL(t,location.href);Z.push(e=>e.href===a)}}function Oe(){var a;history.scrollRestoration="manual",addEventListener("beforeunload",e=>{let r=!1;if(jt(),!H){const n=Ut(m,void 0,null,"leave"),o={...n.navigation,cancel:()=>{r=!0,n.reject(new Error("navigation cancelled"))}};Mt.forEach(s=>s(o))}r?(e.preventDefault(),e.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&jt()}),(a=navigator.connection)!=null&&a.saveData||Ie(),U.addEventListener("click",async e=>{if(e.button||e.which!==1||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.defaultPrevented)return;const r=$t(e.composedPath()[0],U);if(!r)return;const{url:n,external:o,target:s,download:i}=ut(r,L,b.hash);if(!n)return;if(s==="_parent"||s==="_top"){if(window.parent!==window)return}else if(s&&s!=="_self")return;const l=X(r);if(!(r instanceof SVGAElement)&&n.protocol!==location.protocol&&!(n.protocol==="https:"||n.protocol==="http:")||i)return;const[h,u]=(b.hash?n.hash.replace(/^#/,""):n.href).split("#"),w=h===it(location);if(o||l.reload&&(!w||!u)){Qt({url:n,type:"link",event:e})?H=!0:e.preventDefault();return}if(u!==void 0&&w){const[,f]=m.url.href.split("#");if(f===u){if(e.preventDefault(),u===""||u==="top"&&r.ownerDocument.getElementById("top")===null)scrollTo({top:0});else{const d=r.ownerDocument.getElementById(decodeURIComponent(u));d&&(d.scrollIntoView(),d.focus())}return}if(K=!0,bt(E),t(n),!l.replace_state)return;K=!1}e.preventDefault(),await new Promise(f=>{requestAnimationFrame(()=>{setTimeout(f,0)}),setTimeout(f,100)}),await D({type:"link",url:n,keepfocus:l.keepfocus,noscroll:l.noscroll,replace_state:l.replace_state??n.href===location.href,event:e})}),U.addEventListener("submit",e=>{if(e.defaultPrevented)return;const r=HTMLFormElement.prototype.cloneNode.call(e.target),n=e.submitter;if(((n==null?void 0:n.formTarget)||r.target)==="_blank"||((n==null?void 0:n.formMethod)||r.method)!=="get")return;const i=new URL((n==null?void 0:n.hasAttribute("formaction"))&&(n==null?void 0:n.formAction)||r.action);if(_t(i,L,!1))return;const l=e.target,c=X(l);if(c.reload)return;e.preventDefault(),e.stopPropagation();const h=new FormData(l,n);i.search=new URLSearchParams(h).toString(),D({type:"form",url:i,keepfocus:c.keepfocus,noscroll:c.noscroll,replace_state:c.replace_state??i.href===location.href,event:e})}),addEventListener("popstate",async e=>{var r;if(!gt){if((r=e.state)!=null&&r[N]){const n=e.state[N];if(O={},n===E)return;const o=I[n],s=e.state[Nt]??{},i=new URL(e.state[re]??location.href),l=e.state[B],c=m.url?it(location)===it(m.url):!1;if(l===R&&(Ht||c)){s!==x.state&&(x.state=s),t(i),I[E]=C(),o&&scrollTo(o.x,o.y),E=n;return}const u=n-E;await D({type:"popstate",url:i,popped:{state:s,scroll:o,delta:u},accept:()=>{E=n,R=l},block:()=>{history.go(-u)},nav_token:O,event:e})}else if(!K){const n=new URL(location.href);t(n),b.hash&&location.reload()}}}),addEventListener("hashchange",()=>{K&&(K=!1,history.replaceState({...history.state,[N]:++E,[B]:R},"",location.href))});for(const e of document.querySelectorAll("link"))ve.has(e.rel)&&(e.href=e.href);addEventListener("pageshow",e=>{e.persisted&&P.navigating.set(ft.current=null)});function t(e){m.url=x.url=e,P.page.set(At(x)),P.page.notify()}}async function Ce(t,{status:a=200,error:e,node_ids:r,params:n,route:o,server_route:s,data:i,form:l}){Vt=!0;const c=new URL(location.href);let h;({params:n={},route:o={id:null}}=await ot(c,!1)||{}),h=kt.find(({id:f})=>f===o.id);let u,w=!0;try{const f=r.map(async(_,g)=>{const p=i[g];return p!=null&&p.uses&&(p.uses=je(p.uses)),Rt({loader:b.nodes[_],url:c,params:n,route:o,parent:async()=>{const y={};for(let S=0;S{const i=history.state;gt=!0,location.replace(new URL(`#${r}`,location.href)),history.replaceState(i,"",t),a&&scrollTo(o,s),gt=!1})}else{const o=document.body,s=o.getAttribute("tabindex");o.tabIndex=-1,o.focus({preventScroll:!0,focusVisible:!1}),s!==null?o.setAttribute("tabindex",s):o.removeAttribute("tabindex")}const n=getSelection();if(n&&n.type!=="None"){const o=[];for(let s=0;s{if(n.rangeCount===o.length){for(let s=0;s{o=u,s=w});return i.catch(()=>{}),{navigation:{from:{params:t.params,route:{id:((c=t.route)==null?void 0:c.id)??null},url:t.url,scroll:C()},to:e&&{params:(a==null?void 0:a.params)??null,route:{id:((h=a==null?void 0:a.route)==null?void 0:h.id)??null},url:e,scroll:n},willUnload:!a,type:r,complete:i},fulfil:o,reject:s}}function At(t){return{data:t.data,error:t.error,form:t.form,params:t.params,route:t.route,state:t.state,status:t.status,url:t.url}}function Ne(t){const a=new URL(t);return a.hash=decodeURIComponent(t.hash),a}function te(t){let a;if(b.hash){const[,,e]=t.hash.split("#",3);a=e??""}else a=t.hash.slice(1);return decodeURIComponent(a)}export{Fe as a,Be as g,P as s}; diff --git a/apps/dashboard/build/_app/immutable/chunks/C2TQQEIa.js.br b/apps/dashboard/build/_app/immutable/chunks/C2TQQEIa.js.br new file mode 100644 index 0000000000000000000000000000000000000000..dfd5c89cf47482d037583ee6fe2617042579a839 GIT binary patch literal 7642 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 Q_5bVt05T){XW>%-0FMYe4*&oF literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/D-gDZzN6.js.br b/apps/dashboard/build/_app/immutable/chunks/D-gDZzN6.js.br deleted file mode 100644 index 64ff75497e0b12ba79d1489131493d32119fb630..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7644 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 diff --git a/apps/dashboard/build/_app/immutable/chunks/D-gDZzN6.js.gz b/apps/dashboard/build/_app/immutable/chunks/D-gDZzN6.js.gz deleted file mode 100644 index 466d96047fdc64515d8e0aa85610b450aaec9c36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8427 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 N^}q3IMTp^3005-EQYQca diff --git a/apps/dashboard/build/_app/immutable/chunks/DGcYlAAw.js b/apps/dashboard/build/_app/immutable/chunks/D8UfWY0j.js similarity index 88% rename from apps/dashboard/build/_app/immutable/chunks/DGcYlAAw.js rename to apps/dashboard/build/_app/immutable/chunks/D8UfWY0j.js index cd5566d..8fe3a65 100644 --- a/apps/dashboard/build/_app/immutable/chunks/DGcYlAAw.js +++ b/apps/dashboard/build/_app/immutable/chunks/D8UfWY0j.js @@ -1 +1 @@ -var x=t=>{throw TypeError(t)};var B=(t,e,n)=>e.has(t)||x("Cannot "+n);var a=(t,e,n)=>(B(t,e,"read from private field"),n?n.call(t):e.get(t)),c=(t,e,n)=>e.has(t)?x("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,n);import{o as I}from"./GG5zm9kr.js";import{s as u,g as f,h as d}from"./CpWkWWOo.js";import{w as G}from"./BeMFXnHE.js";new URL("sveltekit-internal://");function ae(t,e){return t==="/"||e==="ignore"?t:e==="never"?t.endsWith("/")?t.slice(0,-1):t:e==="always"&&!t.endsWith("/")?t+"/":t}function oe(t){return t.split("%25").map(decodeURI).join("%25")}function ie(t){for(const e in t)t[e]=decodeURIComponent(t[e]);return t}function le({href:t}){return t.split("#")[0]}function W(...t){let e=5381;for(const n of t)if(typeof n=="string"){let r=n.length;for(;r;)e=e*33^n.charCodeAt(--r)}else if(ArrayBuffer.isView(n)){const r=new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let s=r.length;for(;s;)e=e*33^r[--s]}else throw new TypeError("value must be a string or TypedArray");return(e>>>0).toString(36)}new TextEncoder;new TextDecoder;function X(t){const e=atob(t),n=new Uint8Array(e.length);for(let r=0;r((t instanceof Request?t.method:(e==null?void 0:e.method)||"GET")!=="GET"&&b.delete(U(t)),z(t,e));const b=new Map;function ce(t,e){const n=U(t,e),r=document.querySelector(n);if(r!=null&&r.textContent){r.remove();let{body:s,...l}=JSON.parse(r.textContent);const o=r.getAttribute("data-ttl");return o&&b.set(n,{body:s,init:l,ttl:1e3*Number(o)}),r.getAttribute("data-b64")!==null&&(s=X(s)),Promise.resolve(new Response(s,l))}return window.fetch(t,e)}function ue(t,e,n){if(b.size>0){const r=U(t,n),s=b.get(r);if(s){if(performance.now()o)}function s(o){n=!1,e.set(o)}function l(o){let i;return e.subscribe(h=>{(i===void 0||n&&h!==i)&&o(i=h)})}return{notify:r,set:s,subscribe:l}}const D={v:()=>{}};function Re(){const{set:t,subscribe:e}=G(!1);let n;async function r(){clearTimeout(n);try{const s=await fetch(`${M}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!s.ok)return!1;const o=(await s.json()).version!==F;return o&&(t(!0),D.v(),clearTimeout(n)),o}catch{return!1}}return{subscribe:e,check:r}}function Q(t,e,n){return t.origin!==Y||!t.pathname.startsWith(e)?!0:n?t.pathname!==location.pathname:!1}function Se(t){}const H=new Set(["load","prerender","csr","ssr","trailingSlash","config"]);[...H];const Z=new Set([...H]);[...Z];let E,O,T;const ee=I.toString().includes("$$")||/function \w+\(\) \{\}/.test(I.toString());var _,m,w,p,v,y,A,R,P,S,V,k,j;ee?(E={data:{},form:null,error:null,params:{},route:{id:null},state:{},status:-1,url:new URL("https://example.com")},O={current:null},T={current:!1}):(E=new(P=class{constructor(){c(this,_,u({}));c(this,m,u(null));c(this,w,u(null));c(this,p,u({}));c(this,v,u({id:null}));c(this,y,u({}));c(this,A,u(-1));c(this,R,u(new URL("https://example.com")))}get data(){return f(a(this,_))}set data(e){d(a(this,_),e)}get form(){return f(a(this,m))}set form(e){d(a(this,m),e)}get error(){return f(a(this,w))}set error(e){d(a(this,w),e)}get params(){return f(a(this,p))}set params(e){d(a(this,p),e)}get route(){return f(a(this,v))}set route(e){d(a(this,v),e)}get state(){return f(a(this,y))}set state(e){d(a(this,y),e)}get status(){return f(a(this,A))}set status(e){d(a(this,A),e)}get url(){return f(a(this,R))}set url(e){d(a(this,R),e)}},_=new WeakMap,m=new WeakMap,w=new WeakMap,p=new WeakMap,v=new WeakMap,y=new WeakMap,A=new WeakMap,R=new WeakMap,P),O=new(V=class{constructor(){c(this,S,u(null))}get current(){return f(a(this,S))}set current(e){d(a(this,S),e)}},S=new WeakMap,V),T=new(j=class{constructor(){c(this,k,u(!1))}get current(){return f(a(this,k))}set current(e){d(a(this,k),e)}},k=new WeakMap,j),D.v=()=>T.current=!0);function Ue(t){Object.assign(E,t)}export{be as H,_e as N,ge as P,he as S,ye as a,J as b,Re as c,le as d,ie as e,pe as f,ve as g,ae as h,Q as i,N as j,oe as k,fe as l,ue as m,O as n,Y as o,E as p,ce as q,me as r,we as s,de as t,Ae as u,Ue as v,Se as w}; +var x=t=>{throw TypeError(t)};var B=(t,e,n)=>e.has(t)||x("Cannot "+n);var a=(t,e,n)=>(B(t,e,"read from private field"),n?n.call(t):e.get(t)),c=(t,e,n)=>e.has(t)?x("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,n);import{o as I}from"./GG5zm9kr.js";import{s as u,g as f,h as d}from"./CpWkWWOo.js";import{w as G}from"./BeMFXnHE.js";new URL("sveltekit-internal://");function ae(t,e){return t==="/"||e==="ignore"?t:e==="never"?t.endsWith("/")?t.slice(0,-1):t:e==="always"&&!t.endsWith("/")?t+"/":t}function oe(t){return t.split("%25").map(decodeURI).join("%25")}function ie(t){for(const e in t)t[e]=decodeURIComponent(t[e]);return t}function le({href:t}){return t.split("#")[0]}function W(...t){let e=5381;for(const n of t)if(typeof n=="string"){let r=n.length;for(;r;)e=e*33^n.charCodeAt(--r)}else if(ArrayBuffer.isView(n)){const r=new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let s=r.length;for(;s;)e=e*33^r[--s]}else throw new TypeError("value must be a string or TypedArray");return(e>>>0).toString(36)}new TextEncoder;new TextDecoder;function X(t){const e=atob(t),n=new Uint8Array(e.length);for(let r=0;r((t instanceof Request?t.method:(e==null?void 0:e.method)||"GET")!=="GET"&&b.delete(U(t)),z(t,e));const b=new Map;function ce(t,e){const n=U(t,e),r=document.querySelector(n);if(r!=null&&r.textContent){r.remove();let{body:s,...l}=JSON.parse(r.textContent);const o=r.getAttribute("data-ttl");return o&&b.set(n,{body:s,init:l,ttl:1e3*Number(o)}),r.getAttribute("data-b64")!==null&&(s=X(s)),Promise.resolve(new Response(s,l))}return window.fetch(t,e)}function ue(t,e,n){if(b.size>0){const r=U(t,n),s=b.get(r);if(s){if(performance.now()o)}function s(o){n=!1,e.set(o)}function l(o){let i;return e.subscribe(h=>{(i===void 0||n&&h!==i)&&o(i=h)})}return{notify:r,set:s,subscribe:l}}const D={v:()=>{}};function Re(){const{set:t,subscribe:e}=G(!1);let n;async function r(){clearTimeout(n);try{const s=await fetch(`${M}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!s.ok)return!1;const o=(await s.json()).version!==F;return o&&(t(!0),D.v(),clearTimeout(n)),o}catch{return!1}}return{subscribe:e,check:r}}function Q(t,e,n){return t.origin!==Y||!t.pathname.startsWith(e)?!0:n?t.pathname!==location.pathname:!1}function Se(t){}const H=new Set(["load","prerender","csr","ssr","trailingSlash","config"]);[...H];const Z=new Set([...H]);[...Z];let E,O,T;const ee=I.toString().includes("$$")||/function \w+\(\) \{\}/.test(I.toString());var _,w,m,p,v,y,A,R,P,S,V,k,j;ee?(E={data:{},form:null,error:null,params:{},route:{id:null},state:{},status:-1,url:new URL("https://example.com")},O={current:null},T={current:!1}):(E=new(P=class{constructor(){c(this,_,u({}));c(this,w,u(null));c(this,m,u(null));c(this,p,u({}));c(this,v,u({id:null}));c(this,y,u({}));c(this,A,u(-1));c(this,R,u(new URL("https://example.com")))}get data(){return f(a(this,_))}set data(e){d(a(this,_),e)}get form(){return f(a(this,w))}set form(e){d(a(this,w),e)}get error(){return f(a(this,m))}set error(e){d(a(this,m),e)}get params(){return f(a(this,p))}set params(e){d(a(this,p),e)}get route(){return f(a(this,v))}set route(e){d(a(this,v),e)}get state(){return f(a(this,y))}set state(e){d(a(this,y),e)}get status(){return f(a(this,A))}set status(e){d(a(this,A),e)}get url(){return f(a(this,R))}set url(e){d(a(this,R),e)}},_=new WeakMap,w=new WeakMap,m=new WeakMap,p=new WeakMap,v=new WeakMap,y=new WeakMap,A=new WeakMap,R=new WeakMap,P),O=new(V=class{constructor(){c(this,S,u(null))}get current(){return f(a(this,S))}set current(e){d(a(this,S),e)}},S=new WeakMap,V),T=new(j=class{constructor(){c(this,k,u(!1))}get current(){return f(a(this,k))}set current(e){d(a(this,k),e)}},k=new WeakMap,j),D.v=()=>T.current=!0);function Ue(t){Object.assign(E,t)}export{be as H,_e as N,ge as P,he as S,ye as a,J as b,Re as c,le as d,ie as e,pe as f,ve as g,ae as h,Q as i,N as j,oe as k,fe as l,ue as m,O as n,Y as o,E as p,ce as q,we as r,me as s,de as t,Ae as u,Ue as v,Se as w}; diff --git a/apps/dashboard/build/_app/immutable/chunks/D8UfWY0j.js.br b/apps/dashboard/build/_app/immutable/chunks/D8UfWY0j.js.br new file mode 100644 index 0000000000000000000000000000000000000000..8a34f5722d0e531c996e31da471ed79193e4f250 GIT binary patch literal 2609 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 TD0E~~pK~*GLBhsX6=eGd^~w_U literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/D8UfWY0j.js.gz b/apps/dashboard/build/_app/immutable/chunks/D8UfWY0j.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..62beff4715669bc654b407e96b01bffc52058cd4 GIT binary patch literal 2952 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 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/chunks/DGcYlAAw.js.br b/apps/dashboard/build/_app/immutable/chunks/DGcYlAAw.js.br deleted file mode 100644 index 986afe9f7fd3f3fbf542cdde288dfa5b62a981dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2609 zcmV-13eNQ#h#4Rp2jzA$2N-tK?*EfPlBE7@>UZDE$tYe%+NGHPyFA3Hos>?%JPfgr zi1chi!0`3u($m$up{eYD6JU*Nb&Kx-mbn8Y152HIC?fwiS5_|MZVMb$;p!{QrYuRR zy3PN8CU0jJUPId#ILO`=woI71+LULtQrTS|5vDCWOFGXC4fObXiAh(bFG6pLTR)-9pMJ*?!@z#CU)TvI{h%bEG8>6hS(LE&sPK%ISs!QQP|xC1AvUZqo#5u%eKr{S0h zl4~M5h5tY9isyN#NdykSKcD;w#%UNKH`I5g8_cIY(&2Ii;mB94E$ssI`Hf@USQzeq zfAT8p^k<^CRR)_#T~{kZDoXmkK{l?07HF?L6&UlVl%`l6?NV?4lK2O;No7s1WoJ3M zM)*cA_ME=I%VsSxlN;-TSw??#T{EPBYVScZYOo~Qo((pVnm~>^!IN21YJ}J;QdqCo z4>b)W&F{}yhS`cw+?568>oI8H4pezJYY2t$I)~k=AM| zO{GG1^dd=#ZR;wgncR=rr0sV}SweJDd`)ifJWr&xBu?Xr>XE1KBxOBEB$8Myv+zt1 zvI><)kcYk`d{DSg;sQJqJc#fAskXMJR>VRDP%F3UB!956PR?85tU@%^bnn_V9I@~d}!5Sl-UMsUc zDIke&m^`Y!{dkmoB6vz`pw|ep7bpCPrZeogf-3tNm3dnaO!Orw8QHcmp^_)h^RiF&RKrjtj}2O3o1-jQI>|f z;$yIR=vBCzd6SRPtHd%#o(@9`2;Usvh+~4@PaK^5l#2>j zDZg&$rF#ZgKOug$XNoUTMT@7p9d7n?JZ`(&)mAmn<)iESiL>Xv)u4WROvoc7LA1E} zpVYQ!$;p_J4OcoD3oAz+r-Wm+!s@AVCVo(wt8`R*br6<7e=rb$Q+KqaDo5FZ zCOCMUMbto%+Y{OLK?B0_-Es5ggi)A9wkhe8X}GQ7bf1K*-fL>v0vD{o91)A$= z#Q?NEfT&z;bS~1gsxJjQ%DANANgI`~T^K5l^hO`{Hw)UCU_l~l^xP(bLw4z~OdzB# z1=+wF;T!p{YfrEK%LAjVUUDj8Dz@Z0!7%s4C*v^I4d2#=U75E#NW9uz{i>tit;FJ% zrk9#t)|taz=LlPR?k&sA{bkYAxYXQJRIrH-L2MF_uoPa!e>N+hsiYeDD(CAE%2XGA zRo6jy?B;Vp@us6?4v0=O_?loNE=X_(H=rNLRY7K3#+w+m>&PWdYeo~Aib|s`dzJF8 zT`t1P%$FJYW{ug2jf!=&XQhPHt$5*ncl8Al25B?~Y8z~eKm%x*V=EahMN*Tl9EB^~ zii9R80(cauc7+XVl)`{?dFhW*w&ms(t;O{-wLNDy0jh$fOL7sMT_f;p;l##9U;3{?Q#X~ z6*QNk^IVL}Lwc)NLB3_{W>&At0J{vcPKM2=P~E>_+3KTW%anNpk!O;vvw|4`hKGCfKYOD|=rv0i9}e%(0uc@&E^ z5<7KS7l7&11iyhMxk_=^UN6j>~OYzTD1d~){>yXU7g)6!wq`twfE9#xN3#hk7 zo$L`BRw%?R@Cn=sqLLAFva*#2+GVLIkUo)mjPimy(}0rVbRloB&v&&_&LWYR0z~Tt z8w_fuu6HodvHln+x-g8)BQV4KUCz12y#OLSY+5S<+#U`keBDpKYa>WG^x6FBO5EHs^Mo*p-KF zCD3qlme8`jFm@fN1gp17Syg-135>nn%PBdx{zn#6{Tc=ZlBlD*v?XeQG^w2mU~G)F zacOLgo5ri=g*dMkV|`nXm>zS-s@3Lls6`w}&1G9;jGDLNIt^p}o}C|^6`aO)-ZnSR z<-1Z5*0kQc>hr|V8re(oMtak$9<0%`7TpDvan-wSr*RAqh!^!UX8Hw%9?=E~M~5)w z3KC8cJ3XV+fm+X5>NAp{;Bp(3obAJRltVZt-|K=!P;tH+E_oQP*bQr@?%@a3PS-TL TA=8mfeZkGpB@r82Rgmo;K{gN4 diff --git a/apps/dashboard/build/_app/immutable/chunks/DGcYlAAw.js.gz b/apps/dashboard/build/_app/immutable/chunks/DGcYlAAw.js.gz deleted file mode 100644 index 2fd77b7ed6c435c37b2c54b466cf8cecbd3bfc62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2953 zcmV;43wHD$iwFP!000026O|cjSKB!D`~C{!VRP(3IM7b#%sOK@lrrsfTj&tzV`v5x zTS*L#@R+&4)JeJ0 z6gFbwd|>o$$n+r#fQP+O;gxXHAf4wz>OweFIlq@EtQ+)SzI^s|{;xY3+$y)mP>8W0 zQ(PuwhD%c8ALk$LK72S6UHlbdysR;vv$wx}Dc zfa=3uWogX3J+iy+hZQc(R&=f0UT^Cg^c`42T{a>J5TO+yP`Jr-az&Nw&)&iz4sUCSn8UNMtw z0-}8@%@3}BwKr;!KX^e9z^xgB`=V!0f7u_j0)R>r5Fnj+8iF0ZIT%D~newS?No2%> zjPa?S8M1*K_$*>SK7INZMD2{qV-WgCd%L^RFIlEQqltGUC0##XOeRbQsd}HXmB)R* zuvY>@bU8Tr7lY^VU~Etce5^G)n@k`etIZp8vp+ydR3tYfQH><>YIj$S?DaNv@rpKm z-6hQykRJ=Ue#{)|SPdN^4N_v{aBE9@?BL*F&kwX18Z__e&wgnbvM>6CqnG5M-oIdW z-hp74h{vq}@+sABEBH;}*9=L5O3+B?2RtCS~V z6-=0pXM^s>6cDUHp6(WabN2UwDGj+WXL=@*(1R@Ci!3`_iZpTdpdeTPls5O}$%X50 zK}_IBuQv`72EsD$($uK0<_3RYMHw3<-_pD_MqH(A6>QO^*%BEgB3{fP!~>8;u7|)h z)?f&%K@(4I8F_j=8E7!^v4DEOG4BG&=3>b_6A#5$B@pOR|))RgSN<7AI z{PR!7URHijMISu{hI$8uFI5cWS0V!i&`{@0L7IcSie$cDRx)%QXpGe+@`6lXOuNJdjF|1l zG@dco37)NY(}~?DF0rvO3Q`_ti-akUZw3vvFu?TvIzBfv4A7iJ1!zux&_ofGj7RlG zC0o61&{W0fM#VDC^_8)9+cFFtOGfs5A+u<^Fd<n;FWr>r?c9jpWBhTB8rkNPi>|&Ox z;QG3;=JmdO#vwiZO&4zmW2%^cc0d9>Xg(54oQEKG5l1| z*B5kp3ZtRtA{A6P)^zbh4%0zkriX?Ut}Q!xi{sd4=~+R|tp<(ai?QOzs!gxW?vve> zEyZ+mR@{l9*=`l~iE=};Xt`i+XnnA?H!x>VRx7BftPOa7 zPz^8DK|Mr0aa@rI~#h(8Kd$doink}IO}7rt1Aax(NsHj z{=3;O-j@Aqn&*8e{|XD!trGl(6xA>lf{*ERPD6;&W@I%hWCYjXJGTQWOEU{^sX*NM zP4Lw30?*#8%oU#R2i28exZgT215bNfdp>y)EIpq*Py~{oDugxnCKfy9As|b97s^h= z{888brcc^31$Tdfnusk;&p0+42so+jPZKbLZNb2O*g^rlso?cl2tqXX3{7NKj(ufX z%Me2A$~8%BiUqVzuq>KU;a_F`YDv=!=FwpWTIVY4_t_UZ&og+Ti@EEUG zDjWK8VP3wF9G-?blw6aASCsguw);8kkz0GR`sO5mK(oYstxbEpet>oa``!I^e~yg5 zt0TNqp$R%@)@C4dCLXOs2e7KaFg_(M0H;Z$L`OVAIj<-UxJx;2D2?MDAzf9Z7T%>@ zHMG{#j}Ye-afQ&O&KqhI9gh$%D`E@p(k>fX6G@NIt}9v#@6xU}Xcv!3ebgadY)XC9 zP(#2zLV8}2BD70)ZsJ8?z8bNi|ZGUcS7I^!M>QE*75gD<-CHYE3T*T;KlVFJcn@| zlC@bWd5z1MoSSV-GP5QmH7g@Iv%lpp%{nF2tTXZlE-5+1<(3F@dIv9aTr;vT>zth7 z!pSFG1UbPaC$RzkP3C5mWMx(upv|hu5wrhAxHRjM49&VK2mkmF0X~GEi5UO@6G)1( diff --git a/apps/dashboard/build/_app/immutable/entry/app.BIXcLtMB.js.br b/apps/dashboard/build/_app/immutable/entry/app.BIXcLtMB.js.br deleted file mode 100644 index 682afec036b3f1276fb19020596574942cc1c5aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3574 zcmV;=neRJ=hB(P>-$0m?UhxNXQQir$2B#zWe5d z*>-E0-bj)+EF&bDZ7oa9USFD6(_KJmoPHel(!R^T^dtzGD~*DKD2TO@>Yp|B@Bebc zF8EVBj@n_?>{|8(G13M?;gO|($Za(3?v(a;LFWhBWSjdvOWh`pvAf&e+d{RNMSjpA zf?cp!y8cgRdExN{0IDXfpMunMPN(Yh=g-KVkxpxTyOO=&1%mTQb8GP^89HlZ+T}EHGb~< zdfhZEysyHjtetxy=v8y9Q$DWF%;z@on{DUmEjEpK76x5bK&lclLPl3?f=g4M`9-$* z@SY$dhKo%okFEXj-ZuN_)vg)@wvp7U5<6Be<1CEwZ;k6zKPneg0^2kuemL5+Go;GD z!UBNVrV2vF{Bn^^=+^e8y?;%kh4>Q2RzvE?wbat|m-5Sfnz4ViQynEMY0p@gKZT+l zX*Y$?#E^XTFPQJrj5=T9zFxoxfSNJw9TSs0R}Q+xbnsHX;&Zbxw-}F(jbvUGSO03t zJO8rz#J()Wd~!sC&~NAN?WI-$=JiqvON=MSW(>Y=rQKpYJH#~j3=fRY20A8jX$^a3 z>!sQ@^gUUD7%slQch2M0^dF$xBto6W;`ag4S9@u7-W5OG1T==5d*dDi+L1;G_a-4+ z=$p$=(82^#%Zzv}+C!WS$ecMDS9LGk)7&q0NJ`s{Er?MhqQA-U7oWV*!U(BnZ`wXy z>=={8ZgQ{#ox8K9EaUJcI*^f!tE4&O`^{jyaG4wbicZA>0rlY$(#Sk;Yj>11+z* z7nQ%p;(s~fZ{E!9xBwHipgBU9{tYrS0pS{_(!Uzaq<{bl(VRR07*7SEpj&i&1>#Z#Rrldebd{!sSGajRT)tRN}BU&^bI zy}uNQFyhALWb~8jdUf9NWJoc-$OJtOuE5v_7*X${o&HVf2u}zG_Rf?=xzcRoTzjZN zZ#C!$p6L#tgXFP713&WsZEIhyMi}u=QDvkAl=p3N74F}jJ9#ie?VWciw2$BNI;-C- zaR3C--G7QY?ETOi1yNr8=h6-mCE>Ct)dXK{GXMKfVSJii(HsgEW#RUn>8%`&z`H0u zAr6%%0EwxKHD_=Vb4IqFSatoMdV<~kk3BzCJU+O`Zv!;Nw*w0UvOEBsOH^8F0nJT>Smd8$xgQ?5ewesB^7FEsA=wFu6*qzY(kh@U4m-BHhC z9~$1YL7i$b*ur)ha_Gl{HI?O&xAr*p%^@Y`T4#Tq z*fxIh;m<;p%W&IBjLMHFS3S~+!A<3(9*k2qOiVib7nmy7YzFHB&+7+kCYLt-yaxRN{3@L>^_(VXP?|&@A2K>-R`$2w z>~-%2W%5DCpaHfrd{%Mf))Xtw0tFu(ad@fjuG0T){wqYF{F>LDyOu6#<>p-Eeuhjv z#2v89{1%V*yMx*9eWB)*;D*J3=U4%@)pY$%X8Qz5LSW zhw?*ZwXo8CE_HPZOyKNd@$DBoCD#GIaq+kj2GwQL*04yK>?Iu*5l-i!jsG~>bXzvE zu=?&nL#_^i5a#+eDzdY8uaQN!ToBF}n`(6>+P!m(RXU#1(dk$JDo<$TmQ`-+=8P zX97A?eIHXZ0@+=7QvE)3EklyCP{LnG_{atZTVRNI{4tk}^lzXx0i4z;>#%mh>gv9r z)Jlqy`RT`nyd~fZO1tx2HshYgR5;lKaBOPBGJ4d#FENq1gENIO0}?16YGahf$c+)X zcIa5p8e$kD=R4Zohu;$ly>`ltTbb2CYe`d&FK3FJ(;;nz+xMl~n=b zS`T0A;Qllvw|&@UZ8aD0nM;wX9$hA*(HqgVZ&20=dAUCxNck@BZP|3=0~?X)_l~V+ zf!K*l45x-|w|?)5HF2U(TPO3yU2MWv@)DHYSl4az?=z|@mstUn$+B^~`V>%A09T^Ix1kx2)j zk(hc3{%pk|X6eHD$29O-94ddO#hb7bBt4uqUDN8aUmsoA;P+@)C-RmL@stb=kWclC z_5Wq}n>nGywnUQm=RoYOU_bs(`I1Q5o%X$^;<9%iUYOB2`bjm$77s9s{s%G41`@Td z?eCS?t^=U&V%^bpL*QJ!OPq@Aa;(gLXW~N9vqHv=$y+?hx;~}=pFmUr zM7Ml3AqfcYZ0)N28z1xR$$&K7R;IkRTZVWSOV9X}v6vHo>*Bx2o&?sydpFhOGG0FB zhGd!h17)DU8G8wX(PU|5%eJ+RApk%SBor*z&@dPXBnlHN=yu#m6^+T;AE394qOL|D z$2EE}g2NvDusPk*C1++J+lgniYz)6Hd^3aJ;eY_B{c?S_F2^&&_9p#uh*V3EPPI+( zb{Hwwb%CH6&J?tKgIT7Fpe@5~gx#tyU4Cc=tK3VKXCX@l@BwC@!>IMFiyh5CrI#Cw zec=%TqRpA)y5!OfRP`Jd&zSa`5pd{?O&eX0T3*&6Nqv5^3|>u2vdg zn0HT>HM3;f?1O8)H>;DnxZDi14HZmnGCS{m5?)x~ug}p%@Mbu;ieyGV>7KY<3%WGl z4A+W2+{TvXaFH#HxyOLn2j-Ht`E$A62f^&#wMmh=H|Mk7x4{ettjcPps!iqdgDzFN ze*VC!cz-YzzMS6H?H?W7y|t$~sGLC<2j z-7Vp6v3bu&CoCE|0y<$aVt*tY><2N{bY=tt7I6Ds(%FJy7p7Esw2my7Vu{X($6D=3qn<4qdL=@aMS#-=`fIK~XU}~%;A><(Ii%Zpl1X1H9l1CR2&X-#(l3P;m-D+7j13zX`r_*;B?Q}dNY|t>)6^D3w21qPj z@wD#eC;r!;WKH|-2NsRL7qo+$_p_t-*1Pr+%LE5ZJMmxR?*|{o>y~qTo`oMBRX@C) z*C-1=3?E(}9BWy<{&8O3jb7vT$K_@Yeq=tn`}>0|{9^yH__O=tcMktuaPx6#^>X~Y zZ*(`VKXUqSREFNA>(otCiE1{Wjy%h-1povkotJ&NnVk9yK#ghlI}+ zwZqdN-TPm~A3HW(F!+&X;zM^*7(`k@80>BSvfYfgGOPWGNX~xRmJXjEmq3n zf)zJ62M_mW=UH4^TIn&mHOw&1uG!KK52MRw!zyRjY-@+XYvlGCVMfRu?LH~(|GKOc zvdDI{gM;_N&fQTzXB4p4%XMeyzLhiBibd_USiRo9C}r(cENKVK_HOPvt?Wn{^xU;8 zy-qdD0t_9zScRL))=iEFFz20JzWH_aBa5%9{k&|Q+D9KRIecJJ`{nK9^f<`j+thyA z7Q49K+Rm*4Q~1Zd)=$>Tt=iHW?#Hjwdn?Dqwsznpm8*x=eRc#CYXs(tQ{Kw@H0bs8 zXR?3sdY9z^h8kz~UG#1W9@?s^>bs5xIa_h`UF*qdtMxznMkM{zBYk(o>?jyWx5JP& zqbP`!NFCR4^p~zggb@mhnPwX?419k6ROCa$_X8%$|4UUq&z;Rve(|mxQNxnDQQ%2o zx*yvI+V(B+Ap0Q0B;cbVJCblLchKU^)Iutt=Be&Rg8EIj=PKW(2^r~eFnQ*9nv5J_+hgPe+iONbY+HbTA3H+#V)0Q%B5Y3>Nw9q<44VcUqdmXam?tXW4Bs>2VLM1Myru-+b13Hb@D#-t zmBNHTfQW8#h~|rj$y5iY9^^>Ql>w8PTn#=l7p_H}Os81iti=hR+D&(Xaph_D%71aG-=Kst8g?_vrw5 zgdnJQn4*Bs^U0$(me>FMU0u1{te(D%g5mTm!p zdY36Jl{gy2ogGAai>xbaMFdbkP9mz9!~~uaeU~Z;F(D!0go0X+C`%%LJpOv(n3zl* zPbED-2}WX>WV(>@B>K*%Z-K7Z$i&JuN=yc6jH#nI32CGN6g28npVcCwX&M`=0UTwZ>FvTcJE}8fZ44)uLUO znj)9tJX9H`(D^k6STSUKYlWKf@0U+O6D)vG2w;E+6O?xuJSg03>1_UZtkxe=4H5;A z4y_0h>)t)94VVgmsddPR84;j_>?%4$coRH}4&f@QIRsS5!0I(z%zMP~SrouCZ};{< z{}DBVKE=gpkFdz_<8Bane49fm3xF|5uB<5vM1=74y?)?WQlXZbMqT63Z{JL9eccXX z2D>2$I`mCYE?E29wt0|e4yfzRTg`l7IWr4}Z!jp>TB^d$kU>$nW^0n|VaCNtzW6-HTLc?ukl zuX&ha8G*5G%|E5Q-Z5SF0xNN87*RJcESbD9eUh&*FHa4Gi|<0^7<$l%kA~iaQydVc`8|RW(*Uo%4ll0iM5ceCg&pDo9Ci- z2bCwNz6luv*fS$11lC9sumo{@6*)b}*JT+1oP&h4AXDN7k+Tbd5@O1O4Mzyg2t!cz zq3yVq(o{*P&P7t{%8GJDIvDp&tnr(eaL=6>DguafS;XTNa+4pVnDu3zG&%}m6vv;x z?|e*;;t;?iS~|SBk-&fwD(`RfbNHF7NlYc4SkT}Zf)i3?d{tIUaWn<7k%=c0cb0## zn$kjJh;#Iq3>@DI2Abu>p}|aBATm_4W@r}e8i~uUBfhCnOBLs~c%16Q5s{1;e74;f zxZT8Nr*1=22%S45$I<{L6Csl4F6j z`xH{@1|HKu88nh5BXW!l*XdJT#^Y$jpqoMs1_m>A8Hy|baSzhvFo+#gVofrhAtiw~ z)Fqd8SxqX`!2}_1P1k`A?Bh%+Nc=|?zzxunUBeR}uvIPm4}fv2@4CUDCfSZv|(?J!l16H!0CcBFpfXJY!;brecx}0RwsM4lCt?O7_v=xbyPS zJH?x&0p>85etyb{&wG}H_+(s$Avkr}JE%4hRR=(Vg_i!FDr#Qpr&3##@rizf)mo^Z z!BlM@u;Mmd2l7HAS$a8{*( zuEzwysQDRKSVD}1Mr3&L{1{iF0K<6*(_uvYn$jf?Y;y8A<185rcsff3ikaS+O7yl| zqGBr1D_{NtR==V|KT?U_K%yh^C?tA>?h=Wde^8=6`It&{!CCTAq6_2+P6&c2*d`PQ z&ZJDRX%@QTio)K${sVLFt$xlxcriNApVQG3{RQ77HN-~p z&Xf~kD;~a&=y5e67q{e@ZyyG1AJ57FDV`uM&ged$(&UVa9j2pP31^5%qLODoKTc2K zR6k(KBU4F0^(UkkaH`_foAT8?ChRYZ_n*pBffPvzHs=bdl1;Kjw#g1D0n=0E7DlJ!&^pUCu2Lb8@CBq z2`FxpasiE3Dz8X+@iK4;<#Lg0Zss$>UBE5MCFDZT1s2Myl3u(!Tt>Q*AziM{{1x4? zIHS&8r@Xl$3yW8d%UIaT#f;GWR0|Lp`qqcg&9R|_Z2BFUWYEBSSid0 zq99rli9zUh2PGA3fYK|)RWrfj-Rd$9N=sEeCv~|rGdAQZU<1=qK}5l-{4Cz+F5{=1 zRbO8 z^;O9&UX?E+x1A#=l1piBGep0dOED<;%5JuJ{l0{gYT-*0r~J$_P+eISi#Pep7$|+k zKygBs?=rj!Se5$X*8{Y9d#qS!HQLKL9X4$k>;W=%S zRF_3ooA^-qwTVOZk^Eh*J(b%;{;n8dsD3w0hL`_N-~+ru;D9k3!waX#upIspD2DOs z;y4^*q3j0uW(J;wu45XE;@H;W7<~`jAfhm^y*SXN)B@yj&#P^Fh zSj-IijQSIvK}`#T9`%CA;jDq~7KTEDF&c?g8C8h4hK}FEv5XpG)24VQf}jVCXr z0+(uZ@{Nm1A{qq=qc!o`2>|>;5S7SpUXPicUWMTud=u;rDpFDqO&_E58WC5i{6ax_ ziU@1tD?ey8i<;oqZ8*hv^dCS+{Rz5+>T5;Pq5LZr7(QlCQCneZ9lQxYALxjWOgMQE zW%dxo;Pm`aII$58fj9oqgP)Ek{LwaI8??&1LGT)<->rD~W*BD${E>$(iFrQ?-~jIP ZZcL*-jXL;RJ092n_!qPosohg50064nxvT&H diff --git a/apps/dashboard/build/_app/immutable/entry/app.BIXcLtMB.js b/apps/dashboard/build/_app/immutable/entry/app.Bv9rD2TH.js similarity index 79% rename from apps/dashboard/build/_app/immutable/entry/app.BIXcLtMB.js rename to apps/dashboard/build/_app/immutable/entry/app.Bv9rD2TH.js index 319e17d..da09974 100644 --- a/apps/dashboard/build/_app/immutable/entry/app.BIXcLtMB.js +++ b/apps/dashboard/build/_app/immutable/entry/app.Bv9rD2TH.js @@ -1,2 +1,2 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../nodes/0.BSxKGxRx.js","../chunks/Bzak7iHL.js","../chunks/GG5zm9kr.js","../chunks/CpWkWWOo.js","../chunks/BlVfL1ME.js","../chunks/CHOnp4oo.js","../chunks/B4yTwGkE.js","../chunks/DdEqwvdI.js","../chunks/CGEBXrjl.js","../chunks/CJCPY1OL.js","../chunks/A7po6GxK.js","../chunks/aVbAZ-t7.js","../chunks/BKuqSeVd.js","../chunks/sZcqyNBA.js","../chunks/CJsMJEun.js","../chunks/C6HuKgyx.js","../chunks/BeMFXnHE.js","../chunks/D-gDZzN6.js","../chunks/DGcYlAAw.js","../chunks/MAY1QfFZ.js","../chunks/BUoSzNdg.js","../chunks/Cx-f-Pzo.js","../chunks/D4ymNiig.js","../chunks/CcUbQ_Wl.js","../chunks/554JRhq6.js","../assets/0.CN9L-NIY.css","../nodes/1.CJFfVX1H.js","../nodes/2.D-vKwnTC.js","../nodes/3.mK8D6pz1.js","../nodes/4.DPhwyLUO.js","../chunks/V6gjw5Ec.js","../nodes/5.C0AYWqwr.js","../chunks/BnXDGOmJ.js","../assets/5.DQ_AfUnN.css","../nodes/6.BD0AetaD.js","../chunks/C4h_mRt2.js","../assets/6.BSSBWVKL.css","../nodes/7.2YrTacps.js","../assets/7.CCrNEDd3.css","../nodes/8.CokrlgDp.js","../nodes/9.Vu2AXN40.js","../assets/9.BBx09UGv.css","../nodes/10.CjP_ylq3.js","../nodes/11.k15P8M2H.js","../nodes/12.BthmSU_R.js","../nodes/13.C0fh4g_5.js","../assets/13.Bjd0S47S.css","../nodes/14.DUh3SXOF.js","../nodes/15.QNRJhGzj.js","../assets/15.ChjqzJHo.css","../nodes/16.QhdtMP78.js","../assets/16.BnHgRQtR.css","../nodes/17.DlzXJVdF.js","../nodes/18.Bmu4OWRV.js","../nodes/19.Baocji37.js","../nodes/20.CJQuAMkU.js","../assets/20.DKhUrxcR.css"])))=>i.map(i=>d[i]); -var Q=r=>{throw TypeError(r)};var X=(r,t,e)=>t.has(r)||Q("Cannot "+e);var l=(r,t,e)=>(X(r,t,"read from private field"),e?e.call(r):t.get(r)),H=(r,t,e)=>t.has(r)?Q("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(r):t.set(r,e),W=(r,t,e,n)=>(X(r,t,"write to private field"),n?n.call(r,e):t.set(r,e),e);import{N as Z,ab as ut,b as _t,E as ct,ac as lt,ae as dt,T as ft,R as $,ax as vt,U as ht,h as U,L as pt,g as h,bc as Et,G as gt,I as Pt,p as Rt,aA as yt,aB as Ot,$ as At,f as L,e as Tt,a as bt,s as z,d as Lt,r as It,u as x,t as Dt}from"../chunks/CpWkWWOo.js";import{h as Vt,m as wt,u as kt,s as xt}from"../chunks/BlVfL1ME.js";import"../chunks/Bzak7iHL.js";import{o as St}from"../chunks/GG5zm9kr.js";import{i as B}from"../chunks/B4yTwGkE.js";import{a as g,c as V,f as et,t as jt}from"../chunks/CHOnp4oo.js";import{B as Ct}from"../chunks/DdEqwvdI.js";import{b as S}from"../chunks/CJsMJEun.js";import{p as N}from"../chunks/V6gjw5Ec.js";function j(r,t,e){var n;Z&&(n=ht,ut());var i=new Ct(r);_t(()=>{var c=t()??null;if(Z){var s=lt(n),a=s===vt,m=c!==null;if(a!==m){var R=dt();ft(R),i.anchor=R,$(!1),i.ensure(c,c&&(u=>e(u,c))),$(!0);return}}i.ensure(c,c&&(u=>e(u,c)))},ct)}function Bt(r){return class extends Nt{constructor(t){super({component:r,...t})}}}var P,d;class Nt{constructor(t){H(this,P);H(this,d);var c;var e=new Map,n=(s,a)=>{var m=Pt(a,!1,!1);return e.set(s,m),m};const i=new Proxy({...t.props||{},$$events:{}},{get(s,a){return h(e.get(a)??n(a,Reflect.get(s,a)))},has(s,a){return a===pt?!0:(h(e.get(a)??n(a,Reflect.get(s,a))),Reflect.has(s,a))},set(s,a,m){return U(e.get(a)??n(a,m),m),Reflect.set(s,a,m)}});W(this,d,(t.hydrate?Vt:wt)(t.component,{target:t.target,anchor:t.anchor,props:i,context:t.context,intro:t.intro??!1,recover:t.recover,transformError:t.transformError})),(!((c=t==null?void 0:t.props)!=null&&c.$$host)||t.sync===!1)&&Et(),W(this,P,i.$$events);for(const s of Object.keys(l(this,d)))s==="$set"||s==="$destroy"||s==="$on"||gt(this,s,{get(){return l(this,d)[s]},set(a){l(this,d)[s]=a},enumerable:!0});l(this,d).$set=s=>{Object.assign(i,s)},l(this,d).$destroy=()=>{kt(l(this,d))}}$set(t){l(this,d).$set(t)}$on(t,e){l(this,P)[t]=l(this,P)[t]||[];const n=(...i)=>e.call(this,...i);return l(this,P)[t].push(n),()=>{l(this,P)[t]=l(this,P)[t].filter(i=>i!==n)}}$destroy(){l(this,d).$destroy()}}P=new WeakMap,d=new WeakMap;const Ut="modulepreload",qt=function(r,t){return new URL(r,t).href},tt={},o=function(t,e,n){let i=Promise.resolve();if(e&&e.length>0){let s=function(u){return Promise.all(u.map(p=>Promise.resolve(p).then(y=>({status:"fulfilled",value:y}),y=>({status:"rejected",reason:y}))))};const a=document.getElementsByTagName("link"),m=document.querySelector("meta[property=csp-nonce]"),R=(m==null?void 0:m.nonce)||(m==null?void 0:m.getAttribute("nonce"));i=s(e.map(u=>{if(u=qt(u,n),u in tt)return;tt[u]=!0;const p=u.endsWith(".css"),y=p?'[rel="stylesheet"]':"";if(!!n)for(let O=a.length-1;O>=0;O--){const _=a[O];if(_.href===u&&(!p||_.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${u}"]${y}`))return;const E=document.createElement("link");if(E.rel=p?"stylesheet":Ut,p||(E.as="script"),E.crossOrigin="",E.href=u,R&&E.setAttribute("nonce",R),document.head.appendChild(E),p)return new Promise((O,_)=>{E.addEventListener("load",O),E.addEventListener("error",()=>_(new Error(`Unable to preload CSS for ${u}`)))})}))}function c(s){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=s,window.dispatchEvent(a),!a.defaultPrevented)throw s}return i.then(s=>{for(const a of s||[])a.status==="rejected"&&c(a.reason);return t().catch(c)})},ae={};var Ft=et('

    '),Gt=et(" ",1);function Yt(r,t){Rt(t,!0);let e=N(t,"components",23,()=>[]),n=N(t,"data_0",3,null),i=N(t,"data_1",3,null),c=N(t,"data_2",3,null);yt(()=>t.stores.page.set(t.page)),Ot(()=>{t.stores,t.page,t.constructors,e(),t.form,n(),i(),c(),t.stores.page.notify()});let s=z(!1),a=z(!1),m=z(null);St(()=>{const _=t.stores.page.subscribe(()=>{h(s)&&(U(a,!0),At().then(()=>{U(m,document.title||"untitled page",!0)}))});return U(s,!0),_});const R=x(()=>t.constructors[2]);var u=Gt(),p=L(u);{var y=_=>{const A=x(()=>t.constructors[0]);var T=V(),w=L(T);j(w,()=>h(A),(b,I)=>{S(I(b,{get data(){return n()},get form(){return t.form},get params(){return t.page.params},children:(f,Wt)=>{var K=V(),at=L(K);{var st=D=>{const q=x(()=>t.constructors[1]);var k=V(),F=L(k);j(F,()=>h(q),(G,Y)=>{S(Y(G,{get data(){return i()},get form(){return t.form},get params(){return t.page.params},children:(v,zt)=>{var M=V(),nt=L(M);j(nt,()=>h(R),(it,mt)=>{S(mt(it,{get data(){return c()},get form(){return t.form},get params(){return t.page.params}}),C=>e()[2]=C,()=>{var C;return(C=e())==null?void 0:C[2]})}),g(v,M)},$$slots:{default:!0}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),g(D,k)},ot=D=>{const q=x(()=>t.constructors[1]);var k=V(),F=L(k);j(F,()=>h(q),(G,Y)=>{S(Y(G,{get data(){return i()},get form(){return t.form},get params(){return t.page.params}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),g(D,k)};B(at,D=>{t.constructors[2]?D(st):D(ot,!1)})}g(f,K)},$$slots:{default:!0}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),g(_,T)},J=_=>{const A=x(()=>t.constructors[0]);var T=V(),w=L(T);j(w,()=>h(A),(b,I)=>{S(I(b,{get data(){return n()},get form(){return t.form},get params(){return t.page.params}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),g(_,T)};B(p,_=>{t.constructors[1]?_(y):_(J,!1)})}var E=Tt(p,2);{var O=_=>{var A=Ft(),T=Lt(A);{var w=b=>{var I=jt();Dt(()=>xt(I,h(m))),g(b,I)};B(T,b=>{h(a)&&b(w)})}It(A),g(_,A)};B(E,_=>{h(s)&&_(O)})}g(r,u),bt()}const se=Bt(Yt),oe=[()=>o(()=>import("../nodes/0.BSxKGxRx.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]),import.meta.url),()=>o(()=>import("../nodes/1.CJFfVX1H.js"),__vite__mapDeps([26,1,20,3,4,5,18,2,16,17]),import.meta.url),()=>o(()=>import("../nodes/2.D-vKwnTC.js"),__vite__mapDeps([27,1,3,5,9,7]),import.meta.url),()=>o(()=>import("../nodes/3.mK8D6pz1.js"),__vite__mapDeps([28,1,20,3,2,17,16,18]),import.meta.url),()=>o(()=>import("../nodes/4.DPhwyLUO.js"),__vite__mapDeps([29,1,2,3,4,5,6,7,10,13,24,19,16,8,30,15,23]),import.meta.url),()=>o(()=>import("../nodes/5.C0AYWqwr.js"),__vite__mapDeps([31,1,3,4,5,6,7,8,11,12,21,32,10,30,15,16,33]),import.meta.url),()=>o(()=>import("../nodes/6.BD0AetaD.js"),__vite__mapDeps([34,1,3,4,5,6,7,8,35,10,11,12,24,21,30,15,16,18,2,36]),import.meta.url),()=>o(()=>import("../nodes/7.2YrTacps.js"),__vite__mapDeps([37,1,2,3,4,5,6,7,8,10,13,11,12,21,23,38]),import.meta.url),()=>o(()=>import("../nodes/8.CokrlgDp.js"),__vite__mapDeps([39,1,3,4,5,6,7,8,10,11,12,21,13,24]),import.meta.url),()=>o(()=>import("../nodes/9.Vu2AXN40.js"),__vite__mapDeps([40,1,20,3,4,5,6,7,8,21,12,15,16,19,23,10,11,30,41]),import.meta.url),()=>o(()=>import("../nodes/10.CjP_ylq3.js"),__vite__mapDeps([42,1,2,3,4,5,6,7,8,10,11,12,21,13,32,15,16,18,14,30,23,20,24,19]),import.meta.url),()=>o(()=>import("../nodes/11.k15P8M2H.js"),__vite__mapDeps([43,1,2,3,4,5,6,7,8,21,12,13,17,16,18,24,23,10,30,15]),import.meta.url),()=>o(()=>import("../nodes/12.BthmSU_R.js"),__vite__mapDeps([44,1,2,3,4,5,6,7,8,11,12,24]),import.meta.url),()=>o(()=>import("../nodes/13.C0fh4g_5.js"),__vite__mapDeps([45,1,2,3,4,5,6,7,8,10,11,12,21,13,32,24,23,46]),import.meta.url),()=>o(()=>import("../nodes/14.DUh3SXOF.js"),__vite__mapDeps([47,1,2,3,4,5,6,7,8,10,11,12,21]),import.meta.url),()=>o(()=>import("../nodes/15.QNRJhGzj.js"),__vite__mapDeps([48,1,2,3,4,5,6,7,8,35,10,21,12,13,14,24,11,30,15,16,23,49]),import.meta.url),()=>o(()=>import("../nodes/16.QhdtMP78.js"),__vite__mapDeps([50,1,2,3,4,5,6,7,8,11,12,24,10,21,30,15,16,23,51]),import.meta.url),()=>o(()=>import("../nodes/17.DlzXJVdF.js"),__vite__mapDeps([52,1,2,3,4,5,6,7,8,11,12,21,15,16,24,19,22,23]),import.meta.url),()=>o(()=>import("../nodes/18.Bmu4OWRV.js"),__vite__mapDeps([53,1,2,3,4,5,6,7,8,21,12,24]),import.meta.url),()=>o(()=>import("../nodes/19.Baocji37.js"),__vite__mapDeps([54,1,2,3,4,5,6,7,8,21,12,32,24,23]),import.meta.url),()=>o(()=>import("../nodes/20.CJQuAMkU.js"),__vite__mapDeps([55,1,2,3,4,5,6,7,8,35,10,11,12,21,13,32,14,18,16,56]),import.meta.url)],ne=[],ie={"/":[3],"/(app)/activation":[4,[2]],"/(app)/contradictions":[5,[2]],"/(app)/dreams":[6,[2]],"/(app)/duplicates":[7,[2]],"/(app)/explore":[8,[2]],"/(app)/feed":[9,[2]],"/(app)/graph":[10,[2]],"/(app)/importance":[11,[2]],"/(app)/intentions":[12,[2]],"/(app)/memories":[13,[2]],"/(app)/patterns":[14,[2]],"/(app)/reasoning":[15,[2]],"/(app)/schedule":[16,[2]],"/(app)/settings":[17,[2]],"/(app)/stats":[18,[2]],"/(app)/timeline":[19,[2]],"/waitlist":[20]},rt={handleError:(({error:r})=>{console.error(r)}),reroute:(()=>{}),transport:{}},Ht=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.decode])),me=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.encode])),ue=!1,_e=(r,t)=>Ht[r](t);export{_e as decode,Ht as decoders,ie as dictionary,me as encoders,ue as hash,rt as hooks,ae as matchers,oe as nodes,se as root,ne as server_loads}; +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../nodes/0.j0CpgSFp.js","../chunks/Bzak7iHL.js","../chunks/GG5zm9kr.js","../chunks/CpWkWWOo.js","../chunks/BlVfL1ME.js","../chunks/CHOnp4oo.js","../chunks/B4yTwGkE.js","../chunks/DdEqwvdI.js","../chunks/CGEBXrjl.js","../chunks/CJCPY1OL.js","../chunks/A7po6GxK.js","../chunks/aVbAZ-t7.js","../chunks/BKuqSeVd.js","../chunks/sZcqyNBA.js","../chunks/CJsMJEun.js","../chunks/C6HuKgyx.js","../chunks/BeMFXnHE.js","../chunks/C2TQQEIa.js","../chunks/D8UfWY0j.js","../chunks/MAY1QfFZ.js","../chunks/BUoSzNdg.js","../chunks/Cx-f-Pzo.js","../chunks/D4ymNiig.js","../chunks/CcUbQ_Wl.js","../chunks/B7CfdQuM.js","../assets/0.Bor8S3Zo.css","../nodes/1.DEUqmURt.js","../nodes/2.D-vKwnTC.js","../nodes/3.Bu_uPddU.js","../nodes/4.DYVet_v-.js","../chunks/V6gjw5Ec.js","../nodes/5.C0AYWqwr.js","../chunks/BnXDGOmJ.js","../assets/5.DQ_AfUnN.css","../nodes/6.54m-BxV_.js","../chunks/C4h_mRt2.js","../assets/6.BSSBWVKL.css","../nodes/7.2YrTacps.js","../assets/7.CCrNEDd3.css","../nodes/8.DGKslLJe.js","../nodes/9.Vu2AXN40.js","../assets/9.BBx09UGv.css","../nodes/10.CACwABbv.js","../nodes/11.B_W3XFQr.js","../nodes/12.DxkSrFsy.js","../nodes/13.CD5qzYsO.js","../assets/13.Bjd0S47S.css","../nodes/14.DUh3SXOF.js","../nodes/15.CyCv1LGV.js","../assets/15.ChjqzJHo.css","../nodes/16.Cth-SSqa.js","../assets/16.BnHgRQtR.css","../nodes/17.k6k7874Y.js","../nodes/18.C60Wuzj2.js","../nodes/19.BIUSI5ln.js","../nodes/20.DebghJca.js","../assets/20.DKhUrxcR.css"])))=>i.map(i=>d[i]); +var Q=r=>{throw TypeError(r)};var X=(r,t,e)=>t.has(r)||Q("Cannot "+e);var l=(r,t,e)=>(X(r,t,"read from private field"),e?e.call(r):t.get(r)),H=(r,t,e)=>t.has(r)?Q("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(r):t.set(r,e),W=(r,t,e,n)=>(X(r,t,"write to private field"),n?n.call(r,e):t.set(r,e),e);import{N as Z,ab as ut,b as _t,E as ct,ac as lt,ae as dt,T as ft,R as $,ax as vt,U as ht,h as U,L as pt,g as h,bc as Et,G as gt,I as Pt,p as Rt,aA as yt,aB as Ot,$ as At,f as L,e as Tt,a as bt,s as z,d as Lt,r as It,u as x,t as Dt}from"../chunks/CpWkWWOo.js";import{h as Vt,m as wt,u as kt,s as xt}from"../chunks/BlVfL1ME.js";import"../chunks/Bzak7iHL.js";import{o as St}from"../chunks/GG5zm9kr.js";import{i as B}from"../chunks/B4yTwGkE.js";import{a as g,c as V,f as et,t as jt}from"../chunks/CHOnp4oo.js";import{B as Ct}from"../chunks/DdEqwvdI.js";import{b as S}from"../chunks/CJsMJEun.js";import{p as N}from"../chunks/V6gjw5Ec.js";function j(r,t,e){var n;Z&&(n=ht,ut());var i=new Ct(r);_t(()=>{var c=t()??null;if(Z){var s=lt(n),a=s===vt,m=c!==null;if(a!==m){var R=dt();ft(R),i.anchor=R,$(!1),i.ensure(c,c&&(u=>e(u,c))),$(!0);return}}i.ensure(c,c&&(u=>e(u,c)))},ct)}function Bt(r){return class extends Nt{constructor(t){super({component:r,...t})}}}var P,d;class Nt{constructor(t){H(this,P);H(this,d);var c;var e=new Map,n=(s,a)=>{var m=Pt(a,!1,!1);return e.set(s,m),m};const i=new Proxy({...t.props||{},$$events:{}},{get(s,a){return h(e.get(a)??n(a,Reflect.get(s,a)))},has(s,a){return a===pt?!0:(h(e.get(a)??n(a,Reflect.get(s,a))),Reflect.has(s,a))},set(s,a,m){return U(e.get(a)??n(a,m),m),Reflect.set(s,a,m)}});W(this,d,(t.hydrate?Vt:wt)(t.component,{target:t.target,anchor:t.anchor,props:i,context:t.context,intro:t.intro??!1,recover:t.recover,transformError:t.transformError})),(!((c=t==null?void 0:t.props)!=null&&c.$$host)||t.sync===!1)&&Et(),W(this,P,i.$$events);for(const s of Object.keys(l(this,d)))s==="$set"||s==="$destroy"||s==="$on"||gt(this,s,{get(){return l(this,d)[s]},set(a){l(this,d)[s]=a},enumerable:!0});l(this,d).$set=s=>{Object.assign(i,s)},l(this,d).$destroy=()=>{kt(l(this,d))}}$set(t){l(this,d).$set(t)}$on(t,e){l(this,P)[t]=l(this,P)[t]||[];const n=(...i)=>e.call(this,...i);return l(this,P)[t].push(n),()=>{l(this,P)[t]=l(this,P)[t].filter(i=>i!==n)}}$destroy(){l(this,d).$destroy()}}P=new WeakMap,d=new WeakMap;const Ut="modulepreload",qt=function(r,t){return new URL(r,t).href},tt={},o=function(t,e,n){let i=Promise.resolve();if(e&&e.length>0){let s=function(u){return Promise.all(u.map(p=>Promise.resolve(p).then(y=>({status:"fulfilled",value:y}),y=>({status:"rejected",reason:y}))))};const a=document.getElementsByTagName("link"),m=document.querySelector("meta[property=csp-nonce]"),R=(m==null?void 0:m.nonce)||(m==null?void 0:m.getAttribute("nonce"));i=s(e.map(u=>{if(u=qt(u,n),u in tt)return;tt[u]=!0;const p=u.endsWith(".css"),y=p?'[rel="stylesheet"]':"";if(!!n)for(let O=a.length-1;O>=0;O--){const _=a[O];if(_.href===u&&(!p||_.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${u}"]${y}`))return;const E=document.createElement("link");if(E.rel=p?"stylesheet":Ut,p||(E.as="script"),E.crossOrigin="",E.href=u,R&&E.setAttribute("nonce",R),document.head.appendChild(E),p)return new Promise((O,_)=>{E.addEventListener("load",O),E.addEventListener("error",()=>_(new Error(`Unable to preload CSS for ${u}`)))})}))}function c(s){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=s,window.dispatchEvent(a),!a.defaultPrevented)throw s}return i.then(s=>{for(const a of s||[])a.status==="rejected"&&c(a.reason);return t().catch(c)})},ae={};var Ft=et('
    '),Gt=et(" ",1);function Yt(r,t){Rt(t,!0);let e=N(t,"components",23,()=>[]),n=N(t,"data_0",3,null),i=N(t,"data_1",3,null),c=N(t,"data_2",3,null);yt(()=>t.stores.page.set(t.page)),Ot(()=>{t.stores,t.page,t.constructors,e(),t.form,n(),i(),c(),t.stores.page.notify()});let s=z(!1),a=z(!1),m=z(null);St(()=>{const _=t.stores.page.subscribe(()=>{h(s)&&(U(a,!0),At().then(()=>{U(m,document.title||"untitled page",!0)}))});return U(s,!0),_});const R=x(()=>t.constructors[2]);var u=Gt(),p=L(u);{var y=_=>{const A=x(()=>t.constructors[0]);var T=V(),w=L(T);j(w,()=>h(A),(b,I)=>{S(I(b,{get data(){return n()},get form(){return t.form},get params(){return t.page.params},children:(f,Wt)=>{var K=V(),at=L(K);{var st=D=>{const q=x(()=>t.constructors[1]);var k=V(),F=L(k);j(F,()=>h(q),(G,Y)=>{S(Y(G,{get data(){return i()},get form(){return t.form},get params(){return t.page.params},children:(v,zt)=>{var M=V(),nt=L(M);j(nt,()=>h(R),(it,mt)=>{S(mt(it,{get data(){return c()},get form(){return t.form},get params(){return t.page.params}}),C=>e()[2]=C,()=>{var C;return(C=e())==null?void 0:C[2]})}),g(v,M)},$$slots:{default:!0}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),g(D,k)},ot=D=>{const q=x(()=>t.constructors[1]);var k=V(),F=L(k);j(F,()=>h(q),(G,Y)=>{S(Y(G,{get data(){return i()},get form(){return t.form},get params(){return t.page.params}}),v=>e()[1]=v,()=>{var v;return(v=e())==null?void 0:v[1]})}),g(D,k)};B(at,D=>{t.constructors[2]?D(st):D(ot,!1)})}g(f,K)},$$slots:{default:!0}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),g(_,T)},J=_=>{const A=x(()=>t.constructors[0]);var T=V(),w=L(T);j(w,()=>h(A),(b,I)=>{S(I(b,{get data(){return n()},get form(){return t.form},get params(){return t.page.params}}),f=>e()[0]=f,()=>{var f;return(f=e())==null?void 0:f[0]})}),g(_,T)};B(p,_=>{t.constructors[1]?_(y):_(J,!1)})}var E=Tt(p,2);{var O=_=>{var A=Ft(),T=Lt(A);{var w=b=>{var I=jt();Dt(()=>xt(I,h(m))),g(b,I)};B(T,b=>{h(a)&&b(w)})}It(A),g(_,A)};B(E,_=>{h(s)&&_(O)})}g(r,u),bt()}const se=Bt(Yt),oe=[()=>o(()=>import("../nodes/0.j0CpgSFp.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]),import.meta.url),()=>o(()=>import("../nodes/1.DEUqmURt.js"),__vite__mapDeps([26,1,20,3,4,5,18,2,16,17]),import.meta.url),()=>o(()=>import("../nodes/2.D-vKwnTC.js"),__vite__mapDeps([27,1,3,5,9,7]),import.meta.url),()=>o(()=>import("../nodes/3.Bu_uPddU.js"),__vite__mapDeps([28,1,20,3,2,17,16,18]),import.meta.url),()=>o(()=>import("../nodes/4.DYVet_v-.js"),__vite__mapDeps([29,1,2,3,4,5,6,7,10,13,24,19,16,8,30,15,23]),import.meta.url),()=>o(()=>import("../nodes/5.C0AYWqwr.js"),__vite__mapDeps([31,1,3,4,5,6,7,8,11,12,21,32,10,30,15,16,33]),import.meta.url),()=>o(()=>import("../nodes/6.54m-BxV_.js"),__vite__mapDeps([34,1,3,4,5,6,7,8,35,10,11,12,24,21,30,15,16,18,2,36]),import.meta.url),()=>o(()=>import("../nodes/7.2YrTacps.js"),__vite__mapDeps([37,1,2,3,4,5,6,7,8,10,13,11,12,21,23,38]),import.meta.url),()=>o(()=>import("../nodes/8.DGKslLJe.js"),__vite__mapDeps([39,1,3,4,5,6,7,8,10,11,12,21,13,24]),import.meta.url),()=>o(()=>import("../nodes/9.Vu2AXN40.js"),__vite__mapDeps([40,1,20,3,4,5,6,7,8,21,12,15,16,19,23,10,11,30,41]),import.meta.url),()=>o(()=>import("../nodes/10.CACwABbv.js"),__vite__mapDeps([42,1,2,3,4,5,6,7,8,10,11,12,21,13,32,15,16,18,14,30,23,20,24,19]),import.meta.url),()=>o(()=>import("../nodes/11.B_W3XFQr.js"),__vite__mapDeps([43,1,2,3,4,5,6,7,8,21,12,13,17,16,18,24,23,10,30,15]),import.meta.url),()=>o(()=>import("../nodes/12.DxkSrFsy.js"),__vite__mapDeps([44,1,2,3,4,5,6,7,8,11,12,24]),import.meta.url),()=>o(()=>import("../nodes/13.CD5qzYsO.js"),__vite__mapDeps([45,1,2,3,4,5,6,7,8,10,11,12,21,13,32,24,23,46]),import.meta.url),()=>o(()=>import("../nodes/14.DUh3SXOF.js"),__vite__mapDeps([47,1,2,3,4,5,6,7,8,10,11,12,21]),import.meta.url),()=>o(()=>import("../nodes/15.CyCv1LGV.js"),__vite__mapDeps([48,1,2,3,4,5,6,7,8,35,10,21,12,13,14,24,11,30,15,16,23,49]),import.meta.url),()=>o(()=>import("../nodes/16.Cth-SSqa.js"),__vite__mapDeps([50,1,2,3,4,5,6,7,8,11,12,24,10,21,30,15,16,23,51]),import.meta.url),()=>o(()=>import("../nodes/17.k6k7874Y.js"),__vite__mapDeps([52,1,2,3,4,5,6,7,8,11,12,21,15,16,24,19,22,23]),import.meta.url),()=>o(()=>import("../nodes/18.C60Wuzj2.js"),__vite__mapDeps([53,1,2,3,4,5,6,7,8,21,12,24]),import.meta.url),()=>o(()=>import("../nodes/19.BIUSI5ln.js"),__vite__mapDeps([54,1,2,3,4,5,6,7,8,21,12,32,24,23]),import.meta.url),()=>o(()=>import("../nodes/20.DebghJca.js"),__vite__mapDeps([55,1,2,3,4,5,6,7,8,35,10,11,12,21,13,32,14,18,16,56]),import.meta.url)],ne=[],ie={"/":[3],"/(app)/activation":[4,[2]],"/(app)/contradictions":[5,[2]],"/(app)/dreams":[6,[2]],"/(app)/duplicates":[7,[2]],"/(app)/explore":[8,[2]],"/(app)/feed":[9,[2]],"/(app)/graph":[10,[2]],"/(app)/importance":[11,[2]],"/(app)/intentions":[12,[2]],"/(app)/memories":[13,[2]],"/(app)/patterns":[14,[2]],"/(app)/reasoning":[15,[2]],"/(app)/schedule":[16,[2]],"/(app)/settings":[17,[2]],"/(app)/stats":[18,[2]],"/(app)/timeline":[19,[2]],"/waitlist":[20]},rt={handleError:(({error:r})=>{console.error(r)}),reroute:(()=>{}),transport:{}},Ht=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.decode])),me=Object.fromEntries(Object.entries(rt.transport).map(([r,t])=>[r,t.encode])),ue=!1,_e=(r,t)=>Ht[r](t);export{_e as decode,Ht as decoders,ie as dictionary,me as encoders,ue as hash,rt as hooks,ae as matchers,oe as nodes,se as root,ne as server_loads}; diff --git a/apps/dashboard/build/_app/immutable/entry/app.Bv9rD2TH.js.br b/apps/dashboard/build/_app/immutable/entry/app.Bv9rD2TH.js.br new file mode 100644 index 0000000000000000000000000000000000000000..3a1c082afb8001ea1db59c0ac6323def3d27d818 GIT binary patch literal 3598 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 aA4W7B(6Ei4wWCSpkADHL)4W_$DgXciKH1Fx literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/entry/start.Bnkotnxp.js b/apps/dashboard/build/_app/immutable/entry/start.Bnkotnxp.js deleted file mode 100644 index 6cca906..0000000 --- a/apps/dashboard/build/_app/immutable/entry/start.Bnkotnxp.js +++ /dev/null @@ -1 +0,0 @@ -import{a as r}from"../chunks/D-gDZzN6.js";import{w as t}from"../chunks/DGcYlAAw.js";export{t as load_css,r as start}; diff --git a/apps/dashboard/build/_app/immutable/entry/start.Bnkotnxp.js.br b/apps/dashboard/build/_app/immutable/entry/start.Bnkotnxp.js.br deleted file mode 100644 index 8a9d8578d90762c564c2564763fc126427d25cad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmV-y0F(b4bpQw~4(x`{?~rj+byVkso>a1SPOHqYEXp$K`++FK--}4O?4&|jS_U~~ zrHvMwPR_3;<-0&HQY3 OpxIl60Vg<6l12xAdoINQ diff --git a/apps/dashboard/build/_app/immutable/entry/start.Bnkotnxp.js.gz b/apps/dashboard/build/_app/immutable/entry/start.Bnkotnxp.js.gz deleted file mode 100644 index 70f2eaad12ee1ccdb779d62c8fae0e32c45a3ac0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107 zcmb2|=3oE;CgIa(bWiAOt@I1=&5?5vOTwL=`hK McrV+WR|d2L0JHEZ3IG5A literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/0.BSxKGxRx.js b/apps/dashboard/build/_app/immutable/nodes/0.BSxKGxRx.js deleted file mode 100644 index 1753ddd..0000000 --- a/apps/dashboard/build/_app/immutable/nodes/0.BSxKGxRx.js +++ /dev/null @@ -1,86 +0,0 @@ -import"../chunks/Bzak7iHL.js";import{o as Xe}from"../chunks/GG5zm9kr.js";import{f as ce,e as s,d as a,r as t,t as B,p as Ke,n as _e,g as e,a as He,s as ie,c as ht,h as k,u as G}from"../chunks/CpWkWWOo.js";import{s as h,d as Ge,a as J,e as Pe}from"../chunks/BlVfL1ME.js";import{i as q}from"../chunks/B4yTwGkE.js";import{e as Se,i as Fe}from"../chunks/CGEBXrjl.js";import{c as Ze,a as u,f as x,t as et}from"../chunks/CHOnp4oo.js";import{s as tt}from"../chunks/CJCPY1OL.js";import{s as ke,r as gt}from"../chunks/A7po6GxK.js";import{s as U}from"../chunks/aVbAZ-t7.js";import{b as bt}from"../chunks/sZcqyNBA.js";import{b as xt}from"../chunks/CJsMJEun.js";import{a as se,s as Ve}from"../chunks/C6HuKgyx.js";import{s as _t,g as at}from"../chunks/D-gDZzN6.js";import{b as he}from"../chunks/DGcYlAAw.js";import{s as lt,m as ot,a as dt,e as kt,w as st,u as yt,i as wt,f as $t}from"../chunks/MAY1QfFZ.js";import{i as At}from"../chunks/BUoSzNdg.js";import{s as ct}from"../chunks/Cx-f-Pzo.js";import{t as Te}from"../chunks/D4ymNiig.js";import{a as Oe}from"../chunks/554JRhq6.js";import{d as Ct,w as vt,g as pt}from"../chunks/BeMFXnHE.js";const Mt=()=>{const r=_t;return{page:{subscribe:r.page.subscribe},navigating:{subscribe:r.navigating.subscribe},updated:r.updated}},Et={subscribe(r){return Mt().page.subscribe(r)}};var Tt=x('
    ');function St(r){const i=()=>se(lt,"$suppressedCount",o),[o,n]=Ve();var g=Ze(),C=ce(g);{var y=N=>{var $=Tt(),w=s(a($),2),p=a(w);t(w),t($),B(()=>h(p,`Actively forgetting ${i()??""} ${i()===1?"memory":"memories"}`)),u(N,$)};q(C,N=>{i()>0&&N(y)})}u(r,g),n()}var jt=x(''),Dt=x('
    ');function It(r,i){Ke(i,!1);const o=()=>se(Te,"$toasts",n),[n,g]=Ve(),C={DreamCompleted:"✦",ConsolidationCompleted:"◉",ConnectionDiscovered:"⟷",MemoryPromoted:"↑",MemoryDemoted:"↓",MemorySuppressed:"◬",MemoryUnsuppressed:"◉",Rac1CascadeSwept:"✺",MemoryDeleted:"✕",HookVerdictRecorded:"⚑"};function y(p){return C[p]??"◆"}function N(p){Te.dismiss(p.id)}function $(p,d){(p.key==="Enter"||p.key===" ")&&(p.preventDefault(),Te.dismiss(d.id))}At();var w=Dt();Se(w,5,o,p=>p.id,(p,d)=>{var M=jt(),R=s(a(M),2),V=a(R),Y=a(V),ee=a(Y,!0);t(Y);var Q=s(Y,2),re=a(Q,!0);t(Q),t(V);var v=s(V,2),m=a(v,!0);t(v),t(R),_e(2),t(M),B(A=>{ke(M,"aria-label",`${e(d).title??""}: ${e(d).body??""}. Click to dismiss.`),ct(M,`--toast-color: ${e(d).color??""}; --toast-dwell: ${e(d).dwellMs??""}ms;`),h(ee,A),h(re,e(d).title),h(m,e(d).body)},[()=>y(e(d).type)]),J("click",M,()=>N(e(d))),J("keydown",M,A=>$(A,e(d))),Pe("mouseenter",M,()=>Te.pauseDwell(e(d).id,e(d).dwellMs)),Pe("mouseleave",M,()=>Te.resumeDwell(e(d).id)),Pe("focus",M,()=>Te.pauseDwell(e(d).id,e(d).dwellMs)),Pe("blur",M,()=>Te.resumeDwell(e(d).id)),u(p,M)}),t(w),u(r,w),He(),g()}Ge(["click","keydown"]);function Ne(r){const i=r.data;if(!i||typeof i!="object")return null;const o=i.timestamp??i.at??i.occurred_at;if(o==null)return null;if(typeof o=="number")return Number.isFinite(o)?o>1e12?o:o*1e3:null;if(typeof o!="string")return null;const n=Date.parse(o);return Number.isFinite(n)?n:null}const Qe=10,ut=3e4,Ft=Qe*ut;function Nt(r,i){const o=i-Ft,n=new Array(Qe).fill(0);for(const C of r){if(C.type==="Heartbeat")continue;const y=Ne(C);if(y===null||yi)continue;const N=Math.min(Qe-1,Math.floor((y-o)/ut));n[N]+=1}const g=Math.max(1,...n);return n.map(C=>({count:C,ratio:C/g}))}function Lt(r,i){const o=i-864e5;for(const n of r){if(n.type!=="DreamCompleted")continue;return(Ne(n)??i)>=o?n:null}return null}function Bt(r){if(!r||!r.data)return null;const i=r.data,o=typeof i.insights_generated=="number"?i.insights_generated:typeof i.insightsGenerated=="number"?i.insightsGenerated:null;return o!==null&&Number.isFinite(o)?o:null}function Rt(r,i){let o=null,n=null;for(const N of r)if(!o&&N.type==="DreamStarted"&&(o=N),!n&&N.type==="DreamCompleted"&&(n=N),o&&n)break;if(!o)return!1;const g=Ne(o)??i,C=i-300*1e3;return g=n}return!1}var Ot=x(' at risk',1),Kt=x('0 at risk',1),Ht=x(' at risk',1),Gt=x(' intentions',1),Wt=x('— intentions'),qt=x('· insights',1),zt=x(' Last dream: ',1),Yt=x('No recent dream'),Qt=x('
    '),Ut=x('
    DREAMING...
    ',1),Xt=x(''),Zt=x('
    memories · avg retention
    ');function Jt(r,i){Ke(i,!0);const o=()=>se(dt,"$avgRetention",C),n=()=>se(kt,"$eventFeed",C),g=()=>se(ot,"$memoryCount",C),[C,y]=Ve(),N=G(()=>Math.round((o()??0)*100)),$=G(()=>(o()??0)>=.5);let w=ie(null);async function p(){try{const l=await Oe.retentionDistribution();if(Array.isArray(l.endangered)&&l.endangered.length>0){k(w,l.endangered.length,!0);return}const c=l.distribution??[];let j=0;for(const _ of c){const D=/^(\d+)/.exec(_.range);if(!D)continue;const F=Number.parseInt(D[1],10);Number.isFinite(F)&&F<30&&(j+=_.count??0)}k(w,j,!0)}catch{k(w,null)}}let d=ie(null);async function M(){var l;try{const c=await Oe.intentions("active");k(d,c.total??((l=c.intentions)==null?void 0:l.length)??0,!0)}catch{k(d,null)}}let R=ie(ht(Date.now()));const V=G(()=>{const l=n(),c=Lt(l,e(R)),j=c?Ne(c)??e(R):null,_=j!==null?e(R)-j:null;return{isDreaming:Rt(l,e(R)),recent:c,recentMsAgo:_,insights:Bt(c)}}),Y=G(()=>Nt(n(),e(R))),ee=G(()=>Pt(n(),e(R)));Xe(()=>{p(),M();const l=setInterval(()=>{k(R,Date.now(),!0)},1e3),c=setInterval(()=>{p(),M()},6e4);return()=>{clearInterval(l),clearInterval(c)}});var Q=Zt();let re;var v=a(Q),m=a(v),A=a(m);let ye;var Ae=s(A,2);let je;t(m);var ve=s(m,2),T=a(ve,!0);t(ve);var E=s(ve,6);let b;var X=a(E);t(E),_e(2),t(v);var W=s(v,4),K=a(W);{var le=l=>{var c=Ot(),j=ce(c),_=a(j,!0);t(j),_e(2),B(()=>h(_,e(w))),u(l,c)},S=l=>{var c=Kt();_e(2),u(l,c)},I=l=>{var c=Ht();_e(2),u(l,c)};q(K,l=>{e(w)!==null&&e(w)>0?l(le):e(w)===0?l(S,1):l(I,!1)})}t(W);var f=s(W,4),O=a(f);{var z=l=>{var c=Gt(),j=ce(c);let _;var D=s(j,2);let F;var H=a(D,!0);t(D),_e(2),B(()=>{_=U(j,1,"inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,_,{"bg-node-pattern":e(d)>5,"animate-ping-slow":e(d)>5,"bg-muted":e(d)<=5}),F=U(D,1,"tabular-nums svelte-1kk3799",null,F,{"text-node-pattern":e(d)>5,"text-text":e(d)>0&&e(d)<=5,"text-muted":e(d)===0}),h(H,e(d))}),u(l,c)},pe=l=>{var c=Wt();u(l,c)};q(O,l=>{e(d)!==null?l(z):l(pe,!1)})}t(f);var te=s(f,4),oe=a(te);{var ue=l=>{var c=zt(),j=s(ce(c),4),_=a(j,!0);t(j);var D=s(j,2);{var F=H=>{var ne=qt(),Me=s(ce(ne),2),we=a(Me,!0);t(Me),_e(2),B(()=>h(we,e(V).insights)),u(H,ne)};q(D,H=>{e(V).insights!==null&&H(F)})}B(H=>h(_,H),[()=>Vt(e(V).recentMsAgo)]),u(l,c)},ae=l=>{var c=Yt();u(l,c)};q(oe,l=>{e(V).recent&&e(V).recentMsAgo!==null?l(ue):l(ae,!1)})}t(te);var de=s(te,4),me=s(a(de),2);Se(me,21,()=>e(Y),Fe,(l,c)=>{var j=Qt();B(_=>ct(j,`height: ${_??""}%; opacity: ${e(c).count===0?.18:.5+e(c).ratio*.5};`),[()=>Math.max(10,e(c).ratio*100)]),u(l,j)}),t(me),t(de);var Ce=s(de,2);{var Be=l=>{var c=Ut();_e(2),u(l,c)};q(Ce,l=>{e(V).isDreaming&&l(Be)})}var De=s(Ce,4);{var Re=l=>{var c=Xt();u(l,c)};q(De,l=>{e(ee)&&l(Re)})}t(Q),B(()=>{re=U(Q,1,"ambient-strip relative flex h-9 w-full items-center gap-0 overflow-hidden border-b border-synapse/15 bg-black/40 px-3 text-[11px] text-dim backdrop-blur-md svelte-1kk3799",null,re,{"ambient-flash":e(ee)}),ye=U(A,1,"absolute inline-flex h-full w-full animate-ping rounded-full opacity-75 svelte-1kk3799",null,ye,{"bg-recall":e($),"bg-warning":!e($)}),je=U(Ae,1,"relative inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,je,{"bg-recall":e($),"bg-warning":!e($)}),h(T,g()),b=U(E,1,"svelte-1kk3799",null,b,{"text-recall":e($),"text-warning":!e($)}),h(X,`${e(N)??""}%`)}),u(r,Q),He(),y()}var ea=x(" "),ta=x('
  • '),aa=x(' ',1),sa=x('

    Appeal recorded.

    '),ra=x('

    No appealable veto in this receipt.

    '),na=x('
    Claim

    Verdict

    Precedent
      Fix

      Appeal
      '),ia=x('
      ');function la(r,i){Ke(i,!0);const o=["PASS","NOTE","CAUTION","VETO","APPEALED"];let n=ie(null),g=ie(""),C=ie(!1),y=ie(null),N=ie(null),$=G(()=>{var v;return((v=e(n))==null?void 0:v.verdictBar)??(e(g)?"CAUTION":"NOTE")}),w=G(()=>{var v,m;return((v=e(n))==null?void 0:v.claims.find(A=>A.decision==="veto"))??((m=e(n))==null?void 0:m.claims.find(A=>A.decision==="appealed"))??null}),p=G(()=>{var v;return e(w)??((v=e(n))==null?void 0:v.claims[0])??null}),d=G(()=>!!e(n)||!!e(g));Xe(()=>{M();const v=window.setInterval(M,4e3);return()=>window.clearInterval(v)});async function M(){var v;try{const m=await Oe.sanhedrin.latest();k(n,m.receipt,!0),k(g,""),((v=m.receipt)==null?void 0:v.verdictBar)==="VETO"&&m.receipt.id!==e(N)&&(k(C,!0),k(N,m.receipt.id,!0))}catch(m){k(g,m instanceof Error?m.message:String(m),!0)}}async function R(v){var m;if(!(!e(w)||((m=e(n))==null?void 0:m.verdictBar)!=="VETO")){k(y,v,!0);try{const A=await Oe.sanhedrin.appeal(v,void 0,e(w).id,e(n).id);k(n,A.receipt,!0),k(C,!0),k(g,"")}catch(A){k(g,A instanceof Error?A.message:String(A),!0)}finally{k(y,null)}}}function V(v){if(!v)return"";const m=new Date(v);return Number.isNaN(m.getTime())?"":m.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function Y(v){var m;return(m=v==null?void 0:v.precedent)!=null&&m.length?v.precedent.map(A=>A.summary??A.command??"Precedent recorded.").slice(0,3):["No precedent attached."]}var ee=Ze(),Q=ce(ee);{var re=v=>{var m=ia(),A=a(m),ye=s(a(A),2);Se(ye,21,()=>o,Fe,(S,I)=>{var f=ea();let O;var z=a(f,!0);t(f),B(()=>{ke(f,"aria-current",e(I)===e($)?"true":void 0),O=U(f,1,"svelte-1j425e6",null,O,{active:e(I)===e($)}),h(z,e(I))}),u(S,f)}),t(ye);var Ae=s(ye,2),je=a(Ae);t(Ae);var ve=s(Ae,2),T=a(ve);{var E=S=>{var I=et();B(()=>h(I,e(g))),u(S,I)},b=S=>{var I=et();B(()=>h(I,e(n).summary)),u(S,I)};q(T,S=>{e(g)?S(E):e(n)&&S(b,1)})}t(ve);var X=s(ve,2),W=a(X,!0);t(X),t(A);var K=s(A,2);{var le=S=>{var I=na(),f=a(I),O=a(f),z=s(a(O),2),pe=a(z,!0);t(z),t(O);var te=s(O,2),oe=s(a(te),2),ue=a(oe);t(oe),t(te);var ae=s(te,2),de=s(a(ae),2);Se(de,21,()=>Y(e(p)),Fe,(_,D)=>{var F=ta(),H=a(F,!0);t(F),B(()=>h(H,e(D))),u(_,F)}),t(de),t(ae);var me=s(ae,2),Ce=s(a(me),2),Be=a(Ce,!0);t(Ce),t(me),t(f);var De=s(f,2),Re=s(a(De),2);{var l=_=>{var D=aa(),F=ce(D),H=a(F,!0);t(F);var ne=s(F,2),Me=a(ne,!0);t(ne);var we=s(ne,2),We=a(we,!0);t(we),B((L,P,fe)=>{F.disabled=L,h(H,e(y)==="stale"?"Saving":"Stale"),ne.disabled=P,h(Me,e(y)==="wrong"?"Saving":"Wrong"),we.disabled=fe,h(We,e(y)==="too_strict"?"Saving":"Too strict")},[()=>!!e(y),()=>!!e(y),()=>!!e(y)]),J("click",F,()=>R("stale")),J("click",ne,()=>R("wrong")),J("click",we,()=>R("too_strict")),u(_,D)},c=_=>{var D=sa();u(_,D)},j=_=>{var D=ra();u(_,D)};q(Re,_=>{e(w)&&e(n).verdictBar==="VETO"?_(l):e(n).verdictBar==="APPEALED"?_(c,1):_(j,!1)})}t(De),t(I),B(()=>{var _,D,F,H;h(pe,((_=e(p))==null?void 0:_.text)??e(n).draftPreview),h(ue,`${((D=e(p))==null?void 0:D.decision)??e(n).overall??""} · ${((F=e(p))==null?void 0:F.evidence_state)??e($)??""}`),h(Be,((H=e(p))==null?void 0:H.fix)||"No change required.")}),u(S,I)};q(K,S=>{e(C)&&e(n)&&S(le)})}t(m),B((S,I)=>{U(m,1,S,"svelte-1j425e6"),ke(A,"aria-expanded",e(C)),h(je,`Current verdict: ${e($)??""}`),h(W,I)},[()=>`verdict-bar tone-${e($).toLowerCase()}`,()=>{var S;return V((S=e(n))==null?void 0:S.createdAt)}]),J("click",A,()=>k(C,!e(C))),u(v,m)};q(Q,v=>{e(d)&&v(re)})}u(r,ee),He()}Ge(["click"]);const mt="vestige.theme",rt="vestige-theme-light",Le=vt("dark"),Ue=vt(!0),nt=Ct([Le,Ue],([r,i])=>r==="auto"?i?"dark":"light":r);function oa(r){return r==="dark"||r==="light"||r==="auto"}function da(r){if(oa(r)){Le.set(r);try{localStorage.setItem(mt,r)}catch{}}}function Ye(){const r=pt(Le);da(r==="dark"?"light":r==="light"?"auto":"dark")}function ca(){if(document.getElementById(rt))return;const r=document.createElement("style");r.id=rt,r.textContent=` -/* Vestige light-mode overrides — injected by theme.ts. - * Activated by [data-theme='light'] on . - * Tokens mirror the real names used in app.css so the cascade stays clean. */ -[data-theme='light'] { - /* Core surface palette (slate scale) */ - --color-void: #f8fafc; /* slate-50 — page background */ - --color-abyss: #f1f5f9; /* slate-100 */ - --color-deep: #e2e8f0; /* slate-200 */ - --color-surface: #f1f5f9; /* slate-100 */ - --color-elevated: #e2e8f0; /* slate-200 */ - --color-subtle: #cbd5e1; /* slate-300 */ - --color-muted: #94a3b8; /* slate-400 */ - --color-dim: #475569; /* slate-600 */ - --color-text: #0f172a; /* slate-900 */ - --color-bright: #020617; /* slate-950 */ -} - -/* Baseline body/html wiring — app.css sets these against the dark - * tokens; we just let the variables do the work. Reassert for clarity. */ -[data-theme='light'] html, -html[data-theme='light'] { - background: var(--color-void); - color: var(--color-text); -} - -/* Glass surfaces — recompose on a light canvas. The original alphas - * are tuned for dark; invert-and-tint for light so panels still read - * as elevated instead of vanishing. */ -[data-theme='light'] .glass { - background: rgba(255, 255, 255, 0.65); - border: 1px solid rgba(99, 102, 241, 0.12); - box-shadow: - inset 0 1px 0 0 rgba(255, 255, 255, 0.6), - 0 4px 24px rgba(15, 23, 42, 0.08); -} -[data-theme='light'] .glass-subtle { - background: rgba(255, 255, 255, 0.55); - border: 1px solid rgba(99, 102, 241, 0.1); - box-shadow: - inset 0 1px 0 0 rgba(255, 255, 255, 0.5), - 0 2px 12px rgba(15, 23, 42, 0.06); -} -[data-theme='light'] .glass-sidebar { - background: rgba(248, 250, 252, 0.82); - border-right: 1px solid rgba(99, 102, 241, 0.14); - box-shadow: - inset -1px 0 0 0 rgba(255, 255, 255, 0.4), - 4px 0 24px rgba(15, 23, 42, 0.08); -} -[data-theme='light'] .glass-panel { - background: rgba(255, 255, 255, 0.75); - border: 1px solid rgba(99, 102, 241, 0.14); - box-shadow: - inset 0 1px 0 0 rgba(255, 255, 255, 0.5), - 0 8px 32px rgba(15, 23, 42, 0.1); -} - -/* Halve glow intensity — neon accents stay recognizable without - * washing out on slate-50. */ -[data-theme='light'] .glow-synapse { - box-shadow: 0 0 10px rgba(99, 102, 241, 0.15), 0 0 30px rgba(99, 102, 241, 0.05); -} -[data-theme='light'] .glow-dream { - box-shadow: 0 0 10px rgba(168, 85, 247, 0.15), 0 0 30px rgba(168, 85, 247, 0.05); -} -[data-theme='light'] .glow-memory { - box-shadow: 0 0 10px rgba(59, 130, 246, 0.15), 0 0 30px rgba(59, 130, 246, 0.05); -} - -/* Ambient orbs are gorgeous on black and blinding on white. Tame them. */ -[data-theme='light'] .ambient-orb { - opacity: 0.18; - filter: blur(100px); -} - -/* Scrollbar recolor for the lighter surface. */ -[data-theme='light'] ::-webkit-scrollbar-thumb { - background: #cbd5e1; -} -[data-theme='light'] ::-webkit-scrollbar-thumb:hover { - background: #94a3b8; -} -`,document.head.appendChild(r)}function it(r){document.documentElement.dataset.theme=r}let ge=null,$e=null,be=null,xe=null;function va(){ge&&$e&&ge.removeEventListener("change",$e),xe==null||xe(),be==null||be(),ge=null,$e=null,xe=null,be=null,ca();let r="dark";try{const i=localStorage.getItem(mt);(i==="dark"||i==="light"||i==="auto")&&(r=i)}catch{}return Le.set(r),ge=window.matchMedia("(prefers-color-scheme: dark)"),Ue.set(ge.matches),$e=i=>Ue.set(i.matches),ge.addEventListener("change",$e),it(pt(nt)),xe=nt.subscribe(it),be=Le.subscribe(()=>{}),()=>{ge&&$e&&ge.removeEventListener("change",$e),ge=null,$e=null,xe==null||xe(),be==null||be(),xe=null,be=null}}var pa=x('');function ua(r){const i=()=>se(Le,"$theme",o),[o,n]=Ve(),g={dark:"Dark",light:"Light",auto:"Auto (system)"},C={dark:"light",light:"auto",auto:"dark"};let y=G(i),N=G(()=>C[e(y)]),$=G(()=>`Toggle theme: ${g[e(y)]} (click for ${g[e(N)]})`);var w=pa(),p=a(w),d=a(p);let M;var R=s(d,2);let V;var Y=s(R,2);let ee;t(p),t(w),B(()=>{ke(w,"aria-label",e($)),ke(w,"title",e($)),ke(w,"data-mode",e(y)),M=U(d,0,"icon svelte-1cmi4dh",null,M,{active:e(y)==="dark"}),V=U(R,0,"icon svelte-1cmi4dh",null,V,{active:e(y)==="light"}),ee=U(Y,0,"icon svelte-1cmi4dh",null,ee,{active:e(y)==="auto"})}),J("click",w,function(...Q){Ye==null||Ye.apply(this,Q)}),u(r,w),n()}Ge(["click"]);var ma=x('
      '),fa=x('
      '),ha=x(''),ga=x(' '),ba=x('
      ',1),xa=x(''),_a=x('
      No matches
      '),ka=x('
      esc
      '),ya=x(" ",1);function Ga(r,i){Ke(i,!0);const o=()=>se(Et,"$page",$),n=()=>se(wt,"$isConnected",$),g=()=>se(ot,"$memoryCount",$),C=()=>se(dt,"$avgRetention",$),y=()=>se(yt,"$uptimeSeconds",$),N=()=>se(lt,"$suppressedCount",$),[$,w]=Ve();let p=ie(!1),d=ie(""),M=ie(void 0),R=G(()=>o().url.pathname.startsWith(he)?o().url.pathname.slice(he.length)||"/":o().url.pathname),V=G(()=>e(R)==="/waitlist"||e(R).startsWith("/waitlist/"));Xe(()=>{e(V)||st.connect();const T=va();function E(b){if(e(V))return;if((b.metaKey||b.ctrlKey)&&b.key==="k"){b.preventDefault(),k(p,!e(p)),k(d,""),e(p)&&requestAnimationFrame(()=>{var K;return(K=e(M))==null?void 0:K.focus()});return}if(b.key==="Escape"&&e(p)){k(p,!1);return}if(b.target instanceof HTMLInputElement||b.target instanceof HTMLTextAreaElement)return;if(b.key==="/"){b.preventDefault();const K=document.querySelector('input[type="text"]');K==null||K.focus();return}const W={g:"/graph",m:"/memories",t:"/timeline",f:"/feed",e:"/explore",i:"/intentions",s:"/stats",r:"/reasoning",a:"/activation",d:"/dreams",c:"/schedule",p:"/importance",u:"/duplicates",x:"/contradictions",n:"/patterns"}[b.key.toLowerCase()];W&&!b.metaKey&&!b.ctrlKey&&!b.altKey&&(b.preventDefault(),at(`${he}${W}`))}return window.addEventListener("keydown",E),()=>{st.disconnect(),window.removeEventListener("keydown",E),T()}});const Y=[{href:"/graph",label:"Graph",icon:"◎",shortcut:"G"},{href:"/reasoning",label:"Reasoning",icon:"✦",shortcut:"R"},{href:"/memories",label:"Memories",icon:"◈",shortcut:"M"},{href:"/timeline",label:"Timeline",icon:"◷",shortcut:"T"},{href:"/feed",label:"Feed",icon:"◉",shortcut:"F"},{href:"/explore",label:"Explore",icon:"◬",shortcut:"E"},{href:"/activation",label:"Activation",icon:"◈",shortcut:"A"},{href:"/dreams",label:"Dreams",icon:"✧",shortcut:"D"},{href:"/schedule",label:"Schedule",icon:"◷",shortcut:"C"},{href:"/importance",label:"Importance",icon:"◎",shortcut:"P"},{href:"/duplicates",label:"Duplicates",icon:"◉",shortcut:"U"},{href:"/contradictions",label:"Contradictions",icon:"⚠",shortcut:"X"},{href:"/patterns",label:"Patterns",icon:"▦",shortcut:"N"},{href:"/intentions",label:"Intentions",icon:"◇",shortcut:"I"},{href:"/stats",label:"Stats",icon:"◫",shortcut:"S"},{href:"/settings",label:"Settings",icon:"⚙",shortcut:","}],ee=Y.slice(0,5);function Q(T,E){const b=E.startsWith(he)?E.slice(he.length)||"/":E;return T==="/graph"?b==="/"||b==="/graph":b.startsWith(T)}let re=G(()=>e(d)?Y.filter(T=>T.label.toLowerCase().includes(e(d).toLowerCase())):Y);function v(T){k(p,!1),k(d,""),at(`${he}${T}`)}var m=ya(),A=ce(m);{var ye=T=>{var E=Ze(),b=ce(E);tt(b,()=>i.children),u(T,E)},Ae=T=>{var E=ba(),b=s(ce(E),6),X=a(b),W=a(X),K=s(W,2);Se(K,21,()=>Y,Fe,(L,P)=>{const fe=G(()=>Q(e(P).href,o().url.pathname));var Z=ma(),Ee=a(Z),qe=a(Ee,!0);t(Ee);var Ie=s(Ee,2),ze=a(Ie,!0);t(Ie);var Je=s(Ie,2),ft=a(Je,!0);t(Je),t(Z),B(()=>{ke(Z,"href",`${he??""}${e(P).href??""}`),U(Z,1,`flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all duration-200 text-sm - ${e(fe)?"bg-synapse/15 text-synapse-glow border border-synapse/30 shadow-[0_0_12px_rgba(99,102,241,0.15)] nav-active-border":"text-dim hover:text-text hover:bg-white/[0.03] border border-transparent"}`),h(qe,e(P).icon),h(ze,e(P).label),h(ft,e(P).shortcut)}),u(L,Z)}),t(K);var le=s(K,2),S=a(le);t(le);var I=s(le,2),f=a(I),O=a(f),z=s(O,2),pe=a(z,!0);t(z);var te=s(z,2),oe=a(te);ua(oe),t(te),t(f);var ue=s(f,2),ae=a(ue),de=a(ae);t(ae);var me=s(ae,2),Ce=a(me);t(me);var Be=s(me,2);{var De=L=>{var P=fa(),fe=a(P);t(P),B(Z=>h(fe,`up ${Z??""}`),[()=>$t(y())]),u(L,P)};q(Be,L=>{y()>0&&L(De)})}t(ue);var Re=s(ue,2);{var l=L=>{var P=ha(),fe=a(P);St(fe),t(P),u(L,P)};q(Re,L=>{N()>0&&L(l)})}t(I),t(X);var c=s(X,2),j=a(c);Jt(j,{});var _=s(j,2);la(_,{});var D=s(_,2),F=a(D);tt(F,()=>i.children),t(D),t(c);var H=s(c,2),ne=a(H),Me=a(ne);Se(Me,17,()=>ee,Fe,(L,P)=>{const fe=G(()=>Q(e(P).href,o().url.pathname));var Z=ga(),Ee=a(Z),qe=a(Ee,!0);t(Ee);var Ie=s(Ee,2),ze=a(Ie,!0);t(Ie),t(Z),B(()=>{ke(Z,"href",`${he??""}${e(P).href??""}`),U(Z,1,`flex flex-col items-center gap-0.5 px-3 py-2 rounded-lg transition-all min-w-[3.5rem] - ${e(fe)?"text-synapse-glow":"text-muted"}`),h(qe,e(P).icon),h(ze,e(P).label)}),u(L,Z)});var we=s(Me,2);t(ne),t(H),t(b);var We=s(b,2);It(We,{}),B(L=>{ke(W,"href",`${he??""}/graph`),U(O,1,`w-2 h-2 rounded-full ${n()?"bg-recall animate-pulse-glow":"bg-decay"}`),h(pe,n()?"Connected":"Offline"),h(de,`${g()??""} memories`),h(Ce,`${L??""}% retention`)},[()=>(C()*100).toFixed(0)]),J("click",S,()=>{k(p,!0),k(d,""),requestAnimationFrame(()=>{var L;return(L=e(M))==null?void 0:L.focus()})}),J("click",we,()=>{k(p,!0),k(d,""),requestAnimationFrame(()=>{var L;return(L=e(M))==null?void 0:L.focus()})}),u(T,E)};q(A,T=>{e(V)?T(ye):T(Ae,!1)})}var je=s(A,2);{var ve=T=>{var E=ka(),b=a(E),X=a(b),W=s(a(X),2);gt(W),xt(W,f=>k(M,f),()=>e(M)),_e(2),t(X);var K=s(X,2),le=a(K);Se(le,17,()=>e(re),Fe,(f,O)=>{var z=xa(),pe=a(z),te=a(pe,!0);t(pe);var oe=s(pe,2),ue=a(oe,!0);t(oe);var ae=s(oe,2),de=a(ae,!0);t(ae),t(z),B(()=>{h(te,e(O).icon),h(ue,e(O).label),h(de,e(O).shortcut)}),J("click",z,()=>v(e(O).href)),u(f,z)});var S=s(le,2);{var I=f=>{var O=_a();u(f,O)};q(S,f=>{e(re).length===0&&f(I)})}t(K),t(b),t(E),J("keydown",E,f=>{f.key==="Escape"&&k(p,!1)}),J("click",E,f=>{f.target===f.currentTarget&&k(p,!1)}),J("keydown",W,f=>{f.key==="Enter"&&e(re).length>0&&v(e(re)[0].href)}),bt(W,()=>e(d),f=>k(d,f)),u(T,E)};q(je,T=>{e(p)&&!e(V)&&T(ve)})}u(r,m),He(),w()}Ge(["click","keydown"]);export{Ga as component}; diff --git a/apps/dashboard/build/_app/immutable/nodes/0.BSxKGxRx.js.br b/apps/dashboard/build/_app/immutable/nodes/0.BSxKGxRx.js.br deleted file mode 100644 index 91dae85c22fe054d71781ce4958e9107cebe375a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9644 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 diff --git a/apps/dashboard/build/_app/immutable/nodes/0.BSxKGxRx.js.gz b/apps/dashboard/build/_app/immutable/nodes/0.BSxKGxRx.js.gz deleted file mode 100644 index 524ab3b4cbb4f45c412a3343451d28da4008fd0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10974 zcmV<4Dk0S$iwFP!000026V-j$a^pyn;B(biAkk_SP#vU5>c~tgkuoMFrBtaaCFQBr zC_x}dLc+lUKvI;FX7e<=W4ktHV|(=O*qH4;%|7gy?PHtm<9teg$+~+4fZ(Oftm+<{ zu0sR^?jG(Q9v%@M;XyCxMRBT^%PUT|AKoM@FYfG{$KKvS`8v@zJ$ic|X?CK$=i_!9 z1q$fPm+N=I)0Qct!;e>-h4^{JSqDEkv+-k(vjjgq z&K&&grmTyfH>{5zFQ<8E_TJsRdv_eEJP?7dsQaa)`;*}4WJZV={@eCJ^>9Ze;34SG zGmvYe^Wn>z2}mM(#u;Jk&Jb_D+R6tItSbw?Z{MoguJy9QM|tS@F_Y z(4U$oAF9U(GoUwI=)W_A(s%7}J-fr}_esB%II-8_^|*{B z<-B0bLVMtK?9>Z8lW;}33f=FycFJ9NFQ3L^wv$=~rV*R>qHf^IFsG`6x8w2Vz>c-^ z)Vei(c;*l4drC#cDOF!g66nh-(q94b=lt0ptnOIAsUI{3LTGH?JVxA;k z6lz8T-zD%=tJK!Dv;AFDf3Aucb00K1;2O!=1>uJ9|Afrf{Ur6;Bl#83lb#)B_;xFa z{C>(cFZ8{Tmn0d|%usyTp%*~AlzPx`Q>s(+qeVU2@zPQ0@j6tof^|ICCaTI=ovcc5 zypV2A?AZ#4Jw>t|g=s0^uGbGlgIxS(XRY~!(6kA>AI!~mKXg)5>RE~=B`n(`Gf%hy zPD5YHRL|We@RRB+GTBAM!b|HdH%zj!j`a~9S<`a3(J?pgv20`=L07@2CF>kalnt%K zu#F{?)lAm2Y-4C{rtpWQSoXreD!WFHeQG$U5HNvu6nA)vT|-;C_Y8AuOV`KZ(Xy=S zmL8zljP$yA0Q=F$pG=eWjU%>XjyHccnhbdW_~(`7%&EYs3^kq_1&i|jNCJO{d+ z?I(G=sy%BTdKUA{`&ZoX*rTc`2a_o4Wak_@8C9IKz;f9zonNUr>eKT#EAwxrdR*-4>}`1J34`ZE)wv6^Y>Zd zHqXocb5?ei_k1M%&sp)CFqwD(b)MQzwP`1g?eeoB@1@A+|0_u6y#H67?M2beTOPZf zlb&)12N-{F>EdWIAEQJkaFH^SZ2G6;9beLshw zZ-)uN1j#1Q>l&Q127bn{#>#oZf`H`=nPYZ=-D6}35OB-prOAFWbO(6^%VPNYh+doY z0vZ-)3it|iuw*ote0RbPJ&5`V7el>7g?8@QP`Hg8idvv4Ri;%`pW6ejpn~!DgGpQo z-j1Ap^39dB{C@mJ@_jJ0Lm0vs4VyTQ!N(r@i4F{AFS&7%X(w04rQ(N;Y^V4)a%k4(UfC&< zi!2LqCh(zH)&OtyuphLbAu@;~`dapqT`vT;YDDH%^t{TewXLWg{aEFz^=TTwWs=4) zFPO(=Xl=v94D=o+NNaOJEupy;65+8xd(EwCh4oWwm9Meg)OyW-?5B$Iq!Z6IQQA#e zXoY;JHR9MF8Lzon#<9nMt_c$tLjX24;1{$G%s0u3(f90eJ5F2N1|NuWN0+~| zs#401#IbLUDl3=EVXmJL3VTM=dTxM>FwLtsS&YL=y}8mEn~HBen9;wb1x-}ZZsX6N9|<#_V+NUpv&hPfyX=LD z*XgFoRfmT>#${Duja&0x*Jn^)K8TsW6(%dW0(+&VgemA8Q?E~ocPiBjY69irJ2W$- zRw(#LC>V7R0nyyBNXKU>SQls*hPTK%GTEbW2Bc^P016QZ$b@DK-rbN#h@?UvRW~!c zIU;ViJeZSsrPWFWJ7y+e=UH>>QMDd!6|MNJQ-4$`qL-Wqi_~T#ymp?(ZFNVHsNB)>W|<+JK15X+t}q7SoDwfo7c9VVAowdDjL!jm)V=o2RwB zmHK|dXLTsXH#Oi~$pX%`)u(LZ3I10pKQ=GFt_5epr}Ib9x4=C#fY<3@d}S)E%03p_ zESBM*nxN%j&v&8@%>U3#23~6W$z(+9%iZie0xT_ydV+>vb~1pOX9x7djQ_dTKO%| zee`AaivHg6Bj@JVv-@oh#F6%y&1p0PMvkP%MY-@U=3jy&hY{`*iqT#j7#*(_wKCDXzINEf%=HonST?=6Kl7i706iZFC9=u+yB-76Qp-zNN3*&6w z`KC84yQMYhoH#f;+_Ai<;ne7>HIeD#(Jb*&b-_eR%iBhc=l?Vj&#%nH^IhCD1FvwJ z^*)_7O<2Us*Ejf@6t&A?^@r~|*}Dke3Hz3NZSeM@$wqQN;K+JO`((5_rIFAuBHS3O zm_Jr471Lx(5+W;pZk5-~O$;UsEe{sw7@6C&VG8MJxj;R`yieniT*Ug8J+!@4JH{}i zlwjLK+iCUj*`TF11-;5%B7$Fj8Ct~-X(%+8m({Ojp9Z1l74!ba7_vF9NQYvXE2C77 zE_%#|{~<&JSxj&CMIbWllN8k$-E;Fnr5V;7k!=+8RWjt5xd0 zR4tmo1b?o|-zoCf1<5g98b(9IG&5sdJ!qT-G2fOzY@_~2+;YHr-7&o@Aaf{ypY=F9!HC|`LvQ7LeXoaCkI~G0z;n|r&<`pVHz-O=bmDhVSuQz`- zUNHnfqIoD4zdWyOfws9>$1j#;;ny=*%+!5jA9q^E<~T)Jka8R3dx!EJ1Ltii-txEi1 zQlSx-8qLwM(I#mXs_t{twO!~sm0rX}6{H*$7;xIuc1any3m$M*tJ0PwH$H&9aYnUE zj;^iO$k7Yq%6jgA%GswbN2zgd_=+}!f4iB5SHym?V~VkrdUCn?q+VYC9hK5X)Q{!$ zF>WAV&pLrz+L=lg+Z7(c>H^O2#P{`hJ~zkeEZieU1Ir7SVzd&D*uTarSQv5PLBYyx-^c2gOmdGyI}UNj zxc&%>fT3$*h$BZ|AGDiW=k-_D*)`5_uij)WsCx&io=dQmx#LNSR5XX?dvUzuNF0#+ z?I+=LWA<8}4j9R!ZrrwR4Sh1qp+onuDOTls`8rYZbiGzv=NlA`@jZ-c+4dLD%FV%* z=dHAVWju;%CW7PMBJf79$88^%=yVXN{A{I%g2rD!JBl=$Fzpts<}r|o;qA2RCA8Z2 zdTB-}w5P+W5;T zQ&K)+Dg+kF$dVCYbg#n#7zUHn4jnu+wG+otycLuKo+Owab4Ew@0F;6(<0;usK_eu5 zKmj}B5w_ds&kLF7#fr(sewtFSRog~EW00TUD{Vj&J^hIHJLRNI(RZBtdT z6ulutZ_J9`m=?VuL1?umEkz$q!j7_H87ATne;6CD4^4Z7^}jV&GfOxBm2k* z${n7bdjU-Ppa<)qr8GK-U<%2xP%?3G$?m&RKd$RFnA&%|RA(Z7Ulfd$<9;8Cc99kx zSc7SE>Sbdtw1rsF1~LM1H|cJy?NP*s58- z&|%({Q`77;wVf_PU5e=~7g;E;F^0plr~oXd2GS)2mS-DTj13ngxSVZdtJzV$nvG~F zd&c%NU(&X?Eu(hFn<8#x8*Lc}Xy+@p8xDoy*tIV-Lf*`j*&_s0*!OAnFak zD{BBb#)vh*F}oL`-?~DAru%n9R7~>ESX-=fM{4jU}zSeEVv1=ZQFpipT+pt9kuYW$T&i6+)0vm zNb*<-Cmkb5BrGBo(VjjcM5Mlmf(Thi#FilufN=$eorgr++=xEFINCEsROE_nXQs4k zrN}3S5O*aryF~;EV`kez-B)Z^w5&^&+p=;IgrUltqVhnn`vTc*X2Gc@FM=O3Y_=`J zW&nCB5Vr-_LX*~&WN_QEk-=T;MBCGhZp!Fb0%bLdkJ(0;)fq|_hxk4e&4>WQ3}DDf z(gSwF+8hg+BdE}g?RE-| zf8g;U`nEpDScYM2&qLkLXMh# zC8fMThWF;7?!gT77G@$i_&8nMQiL((=e`%y_%v1>-7D$nno`^7i49^DGY&MrjIBsmUvs+2lG%ag~syUWb>{E)TfQ;-aWTMX2#Q}%1OJ-cag6tBwB=ffWumaigwggsP7o_U3vV@ClCC{3W z2=?=5dKL)s3sEbkO|C7o6o`a*f535#0FN{;^>I>mmPRpUZNu6j<$)2TEY5an)fwRj zP*9$7-b;-G@UuuhXJ;#Cz2Is~FjSW+DX2N%A&@UOa{2*I%3#X4<8yp`G1_;HI5p+O zb2F(louKWcA9V`;=xDTrK7vFRB4VxozI z%b0D%U9C0Js71?ZQvP21QKLgZwtRDenH-|UtsjWi50@GU^Q@Z&{&Rvqk8XIFXn}`Q zZ#tY3V`MM1VGgeK@#vu!V$iPaV1{W#5RS-L1Yd8D5)Id9VOjfe<@>qS-GBcb2-J*X zfbYj`+u>RdJbapR%}8)TrX@JjHj%)0C6Ost!d_F?e$#%^w%g98CjS9Cgi%_rkP%3N}wruv?=fK@!#Wdi&|-G=*xVG6C*#-UDb}<4@X^*$Qh@;8Kz)`U|OZpHrJm z*6;xJR_Y^hr{%8m>gE(Pt5e{#iwMw9*X-5SlNnLhrbYDv0A72%zP^#`MFHQK0!P~f z_)5F_xMt64=IIo8D;Aqozp2zJ8`a0tygywh@bUL(Ll7sf#OUliJY3#TK=0 zZgf0N(CiYf*&Q2Ki)4h@LD7IyGT=>^K8ZuKxZ1$?0~`!s@{(w-u-ai1-;}jeZYK$k zQ_Pabh*j*Rqs7LHJhAWb?;_hS%&(4B8ma}Go8NyYGe6Z=G>~sf9lXS#S=KW|-^OKJ z(2GD`j6@0_0DUeT*hyJC2T3B(F|LI*+wXPl1hrs8_e%RAbXSxMb+ZW_7hFbKg2Awq zdZCb55QBaUVQ_TB@F7FbRM9WN-mgSf%56kj_9ePO@ui99ssB(wom{N#1O}xI& zwBk>tys?go5nF0?t=hZQC@EV&KYhxyYNZCiYgGiU)&%fvNt{)#fB)Tgz#24ig-|Q- z?}BPf2Cx-v4WMfHM_i_X0IN(}t07F~2{pt6BFWD9b&{=rlVrbCuyrX|4WRIrkhy|w zd|5CUOmKoTSF*JySX~AG5WOe0Lb8(V;$M<)ZIOVbOuj`Du91Xm1obPLj%@tvTJG^T zwcOgTZMr7_wYs3`s=062v;6_rC?|oAtR>*9$U}r2Jp)~tkt?IT~gg-K4uhOcD&!1Qw_Tq$7~kg&>vn2OAA)7P%b{)?3{G z<9vcTTYJ2q-f568*DG@`9;|pBrCG&Jv9__G;%N|BF}7xw#1O@;g#2{}?`etp2{sI! zC7^_a7L154HCd<)yI#t{=fh--W_b@ZTXuW^sG|`10TJNx2^eeJgY^h<~6!W72iUtZgri{e#)V&y;7S~>{mxjD`n}(+>$UJpH=H&}A+`ot|FJD&4 zrCh!mL*C@}On?xF-1TfjH+nH|^Ek=ou?}jnPSX*S)|Z41{16gPOq9*Dp34_rQ4TP+ z>pq}5Xh&Gng|O-(y`;(|US3M7JWwz8qLunsM4!H?iRLuI15Gy7L}LoD_r84mLoCYE zsM9I#45~VTx8_c#A>qwLrD1IM=70@48U}=3M7Ne+p`jE0(>1(a!P3JhT(ms*O3?I$Py4F8I$Kn8S&Ti1w+`@@3{?k@jZ6U^~qN=E^9sx@fDk@$puxQ5J& z*NXhrnpPXs=%WIkYvre_8vgOCNN*1@3?@s1gyliM!ue$GS(KSl74F3p4V+b^SoZb=7o&6XXhI}oeNi!3J1M( z-w_aF&7f!^O#wvd5tN#rvYVWGxXB@Ip<^z5^u!2sNU!nsCO13t{g#S8K+$Pd#PJk< zPu{~*Z2k==?_9!2D+P3+oHD5$%eObh%H z%9ovot>ounMJnlfMH89AQ5dPmf^0m6)h#jnF3!w3=y>L=bcbSI#d+&HXnnkKGqk6hN74gBtZraifkAGF+LCVUg*T;& zHW{MGI00(*!}qbS;$iGHyjOL7@#*c#7v(A`v9vI(=O^yPS3E?HYv+{TDD`5*t&e}DCLF10C6@k~!G=IfEvv6gY3&YHCbR2&X% zRhu;MMJkrs%nmw#t+|1kRY$2*Bz?c)apy=fm*!-fW^z<$5+*1p$Bnh=G-LHZFSr}{ z9@t(uWz$nWO6;Md9LR>b%+<_XCKG={Wp7du zB8L%EJ7n-CpK9IAkP|j8OdIVMSu7Nv;0=7!189##8+0$JkK&hg{6dV$DF;4ix{@^e@}ABmgs0Xc$|gg)g3L1$!;J)4fh6vmr1szR%-^jf-~ zwI20T%Jiaz^~&6?Ica|!E|xGYLB1a0Yq8`xX-{Q9ATrEyKlaNQ@4&MkW$KK{J1^}T zU2bm8zNhoWU7p>T@cFa8qSvRvaDgoTV*GWeRwpNms{DT);GF& z-~T6{6JpmLh(wMKbV`ZvKU4#_2i8u@2vYy zU0;E`X&xgTZXC8bhuJh1Y0^jkZB0R?M z2$Cid<$W?6zS`n&6m>QizSDXRKpn)wGx2?lHuaDu{pJZOPG^0D?DxRnF?~d5x9}aW zMZpE4BkK*JOy>V5`uKvBIeA?0a`WBt@}t}o=~>z$J==atkH#EJv{U2L(tVeYm+s%; zPc>xwF>(uLcBdr2)O$y6c|h-R@m71;ftbXcyZxaepBr=shiI)2*2R4{=Ix@zC}daH zUy5%S1jCE%{|?%r3+i+F(1tJdG0U)&=8%}DMTx}5d-@CPQw6&)4T*f17i2a62Nm~F z!7U6);-2RP8SWoc+;at2n4QEEmk(t)f2-o`Dmb};O0=EaU?t{1tC%|qrfQ=SxuF!z zm9(MYXErTyx8>JNyZ>9o+g9)j`2tNIsS zD^tGsmSO!L73)mJ5MN^_EKX+#HKLeezj?Yi@lgi_;3mx%K?KOma=S(y|vi ze&6MZ{FMXsooUuTC=v~zifjA1eJPC%< zUk=zwag|g%Q_*V>`ot__`?Hzpme>IJXa!j74rY;jG}+Jixszp+?8tPJeM~pmp>&fw z1lZ32_9ehi2(V88?Gylh$^d?%6o!xL7S2beBSZ9q8C~&18F*w~@|hj7e*r@a>g05B; z`~uh0rwmUq;UOmR3tU=g4@zQJrzD8zb^Tl70;`u(JSdAYnUL@^rrUr9u^&_Zn*2^3 z0t?!yD9C!Z*cdusA4LMxE76QTHsdR7#WQF`pAxhD%m(0p=Fc6RSTyO`MaZMBAGg~ylg9ThC8Bk*ADzpl?1bB-cL(COo#K++Pg&ZP(KN($oG_yAVx-Wh zOy&rlF?sc1Pv(=0;rt8B@q=tRelTx2eo!pO$8*vO|D2V{`2u)}20NE=j;(V{Nv@w` zwy{VVq&va*ME>qTonYLE2?kzJSWGQ2PxU>esdn%tKXwa$!N)(pF%DVVly{E-d--jK z?~6QP@Kng#5S%>b)9#1L4J+9;jOMpmC z4vwP(rQvI#19l~tS z1byU8b%NmxRs?hayj_;3ozAIb3M;SU-Bca4vw(4>f?XVwP!mvcQMnY_04goCmTWpM z%*JIxPnpGDb7`^|4|{}`yS#jk3F$IJF_3p?4IlW0Em$Mt@5;WU-=L+Gmk@*+Z+`#( M0c3Y|UYmLV0MEgV&;S4c diff --git a/apps/dashboard/build/_app/immutable/nodes/0.j0CpgSFp.js b/apps/dashboard/build/_app/immutable/nodes/0.j0CpgSFp.js new file mode 100644 index 0000000..c8a2beb --- /dev/null +++ b/apps/dashboard/build/_app/immutable/nodes/0.j0CpgSFp.js @@ -0,0 +1,86 @@ +import"../chunks/Bzak7iHL.js";import{o as Xe}from"../chunks/GG5zm9kr.js";import{f as le,e as s,d as a,r as t,t as I,p as We,n as fe,g as e,a as qe,s as ne,c as ht,h,u as q}from"../chunks/CpWkWWOo.js";import{s as m,d as ze,a as re,e as Ge}from"../chunks/BlVfL1ME.js";import{i as G}from"../chunks/B4yTwGkE.js";import{e as Ie,i as Ve}from"../chunks/CGEBXrjl.js";import{c as Ze,a as v,f as g,t as et}from"../chunks/CHOnp4oo.js";import{s as tt}from"../chunks/CJCPY1OL.js";import{s as we,r as gt}from"../chunks/A7po6GxK.js";import{s as te}from"../chunks/aVbAZ-t7.js";import{b as bt}from"../chunks/sZcqyNBA.js";import{b as xt}from"../chunks/CJsMJEun.js";import{a as oe,s as He}from"../chunks/C6HuKgyx.js";import{s as kt,g as at}from"../chunks/C2TQQEIa.js";import{b as xe}from"../chunks/D8UfWY0j.js";import{s as lt,m as ot,a as dt,e as _t,w as st,u as yt,i as wt,f as $t}from"../chunks/MAY1QfFZ.js";import{i as At}from"../chunks/BUoSzNdg.js";import{s as ct}from"../chunks/Cx-f-Pzo.js";import{t as De}from"../chunks/D4ymNiig.js";import{a as Ke}from"../chunks/B7CfdQuM.js";import{d as Ct,w as vt,g as pt}from"../chunks/BeMFXnHE.js";const Mt=()=>{const n=kt;return{page:{subscribe:n.page.subscribe},navigating:{subscribe:n.navigating.subscribe},updated:n.updated}},Tt={subscribe(n){return Mt().page.subscribe(n)}};var Et=g('
      ');function St(n){const l=()=>oe(lt,"$suppressedCount",o),[o,i]=He();var x=Ze(),T=le(x);{var y=N=>{var C=Et(),$=s(a(C),2),p=a($);t($),t(C),I(()=>m(p,`Actively forgetting ${l()??""} ${l()===1?"memory":"memories"}`)),v(N,C)};G(T,N=>{l()>0&&N(y)})}v(n,x),i()}var jt=g(''),Dt=g('
      ');function It(n,l){We(l,!1);const o=()=>oe(De,"$toasts",i),[i,x]=He(),T={DreamCompleted:"✦",ConsolidationCompleted:"◉",ConnectionDiscovered:"⟷",MemoryPromoted:"↑",MemoryDemoted:"↓",MemorySuppressed:"◬",MemoryUnsuppressed:"◉",Rac1CascadeSwept:"✺",MemoryDeleted:"✕",HookVerdictRecorded:"⚑"};function y(p){return T[p]??"◆"}function N(p){De.dismiss(p.id)}function C(p,c){(p.key==="Enter"||p.key===" ")&&(p.preventDefault(),De.dismiss(c.id))}At();var $=Dt();Ie($,5,o,p=>p.id,(p,c)=>{var E=jt(),L=s(a(E),2),V=a(L),Z=a(V),z=a(Z,!0);t(Z);var ae=s(Z,2),de=a(ae,!0);t(ae),t(V);var u=s(V,2),f=a(u,!0);t(u),t(L),fe(2),t(E),I(M=>{we(E,"aria-label",`${e(c).title??""}: ${e(c).body??""}. Click to dismiss.`),ct(E,`--toast-color: ${e(c).color??""}; --toast-dwell: ${e(c).dwellMs??""}ms;`),m(z,M),m(de,e(c).title),m(f,e(c).body)},[()=>y(e(c).type)]),re("click",E,()=>N(e(c))),re("keydown",E,M=>C(M,e(c))),Ge("mouseenter",E,()=>De.pauseDwell(e(c).id,e(c).dwellMs)),Ge("mouseleave",E,()=>De.resumeDwell(e(c).id)),Ge("focus",E,()=>De.pauseDwell(e(c).id,e(c).dwellMs)),Ge("blur",E,()=>De.resumeDwell(e(c).id)),v(p,E)}),t($),v(n,$),qe(),x()}ze(["click","keydown"]);function Be(n){const l=n.data;if(!l||typeof l!="object")return null;const o=l.timestamp??l.at??l.occurred_at;if(o==null)return null;if(typeof o=="number")return Number.isFinite(o)?o>1e12?o:o*1e3:null;if(typeof o!="string")return null;const i=Date.parse(o);return Number.isFinite(i)?i:null}const Qe=10,ut=3e4,Ft=Qe*ut;function Nt(n,l){const o=l-Ft,i=new Array(Qe).fill(0);for(const T of n){if(T.type==="Heartbeat")continue;const y=Be(T);if(y===null||yl)continue;const N=Math.min(Qe-1,Math.floor((y-o)/ut));i[N]+=1}const x=Math.max(1,...i);return i.map(T=>({count:T,ratio:T/x}))}function Lt(n,l){const o=l-864e5;for(const i of n){if(i.type!=="DreamCompleted")continue;return(Be(i)??l)>=o?i:null}return null}function Vt(n){if(!n||!n.data)return null;const l=n.data,o=typeof l.insights_generated=="number"?l.insights_generated:typeof l.insightsGenerated=="number"?l.insightsGenerated:null;return o!==null&&Number.isFinite(o)?o:null}function Bt(n,l){let o=null,i=null;for(const N of n)if(!o&&N.type==="DreamStarted"&&(o=N),!i&&N.type==="DreamCompleted"&&(i=N),o&&i)break;if(!o)return!1;const x=Be(o)??l,T=l-300*1e3;return x=i}return!1}var Pt=g(' at risk',1),Kt=g('0 at risk',1),Ht=g(' at risk',1),Gt=g(' intentions',1),Wt=g('— intentions'),qt=g('· insights',1),zt=g(' Last dream: ',1),Yt=g('No recent dream'),Qt=g('
      '),Ut=g('telemetry unavailable'),Xt=g('· fail-open',1),Zt=g(' vetoes · appeals ',1),Jt=g('
      DREAMING...
      ',1),ea=g(''),ta=g('
      memories · avg retention
      ');function aa(n,l){We(l,!0);const o=()=>oe(dt,"$avgRetention",T),i=()=>oe(_t,"$eventFeed",T),x=()=>oe(ot,"$memoryCount",T),[T,y]=He(),N=q(()=>Math.round((o()??0)*100)),C=q(()=>(o()??0)>=.5);let $=ne(null);async function p(){try{const r=await Ke.retentionDistribution();if(Array.isArray(r.endangered)&&r.endangered.length>0){h($,r.endangered.length,!0);return}const d=r.distribution??[];let A=0;for(const R of d){const b=/^(\d+)/.exec(R.range);if(!b)continue;const w=Number.parseInt(b[1],10);Number.isFinite(w)&&w<30&&(A+=R.count??0)}h($,A,!0)}catch{h($,null)}}let c=ne(null);async function E(){var r;try{const d=await Ke.intentions("active");h(c,d.total??((r=d.intentions)==null?void 0:r.length)??0,!0)}catch{h(c,null)}}let L=ne(ht(Date.now()));const V=q(()=>{const r=i(),d=Lt(r,e(L)),A=d?Be(d)??e(L):null,R=A!==null?e(L)-A:null;return{isDreaming:Bt(r,e(L)),recent:d,recentMsAgo:R,insights:Vt(d)}}),Z=q(()=>Nt(i(),e(L)));let z=ne(null),ae=ne(!1);async function de(){try{h(z,await Ke.sanhedrin.telemetry(7),!0),h(ae,!1)}catch{h(z,null),h(ae,!0)}}const u=q(()=>Ot(i(),e(L)));Xe(()=>{p(),E(),de();const r=setInterval(()=>{h(L,Date.now(),!0)},1e3),d=setInterval(()=>{p(),E(),de()},6e4);return()=>{clearInterval(r),clearInterval(d)}});var f=ta();let M;var he=a(f),ge=a(he),Fe=a(ge);let $e;var j=s(Fe,2);let D;t(ge);var k=s(ge,2),se=a(k,!0);t(k);var Y=s(k,6);let P;var pe=a(Y);t(Y),fe(2),t(he);var S=s(he,4),F=a(S);{var _=r=>{var d=Pt(),A=le(d),R=a(A,!0);t(A),fe(2),I(()=>m(R,e($))),v(r,d)},K=r=>{var d=Kt();fe(2),v(r,d)},X=r=>{var d=Ht();fe(2),v(r,d)};G(F,r=>{e($)!==null&&e($)>0?r(_):e($)===0?r(K,1):r(X,!1)})}t(S);var ce=s(S,4),ue=a(ce);{var me=r=>{var d=Gt(),A=le(d);let R;var b=s(A,2);let w;var O=a(b,!0);t(b),fe(2),I(()=>{R=te(A,1,"inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,R,{"bg-node-pattern":e(c)>5,"animate-ping-slow":e(c)>5,"bg-muted":e(c)<=5}),w=te(b,1,"tabular-nums svelte-1kk3799",null,w,{"text-node-pattern":e(c)>5,"text-text":e(c)>0&&e(c)<=5,"text-muted":e(c)===0}),m(O,e(c))}),v(r,d)},be=r=>{var d=Wt();v(r,d)};G(ue,r=>{e(c)!==null?r(me):r(be,!1)})}t(ce);var J=s(ce,4),Ae=a(J);{var Ce=r=>{var d=zt(),A=s(le(d),4),R=a(A,!0);t(A);var b=s(A,2);{var w=O=>{var H=qt(),W=s(le(H),2),ee=a(W,!0);t(W),fe(2),I(()=>m(ee,e(V).insights)),v(O,H)};G(b,O=>{e(V).insights!==null&&O(w)})}I(O=>m(R,O),[()=>Rt(e(V).recentMsAgo)]),v(r,d)},Ne=r=>{var d=Yt();v(r,d)};G(Ae,r=>{e(V).recent&&e(V).recentMsAgo!==null?r(Ce):r(Ne,!1)})}t(J);var Te=s(J,4),Ee=s(a(Te),2);Ie(Ee,21,()=>e(Z),Ve,(r,d)=>{var A=Qt();I(R=>ct(A,`height: ${R??""}%; opacity: ${e(d).count===0?.18:.5+e(d).ratio*.5};`),[()=>Math.max(10,e(d).ratio*100)]),v(r,A)}),t(Ee),t(Te);var Se=s(Te,4),Oe=s(a(Se),2);{var je=r=>{var d=Ut();v(r,d)},Le=r=>{var d=Zt(),A=le(d),R=a(A,!0);t(A);var b=s(A,6),w=a(b,!0);t(b);var O=s(b,4);{var H=W=>{var ee=Xt(),ie=s(le(ee),2),Pe=a(ie,!0);t(ie),fe(2),I(()=>m(Pe,e(z).failOpen)),v(W,ee)};G(O,W=>{var ee;(ee=e(z))!=null&&ee.failOpen&&W(H)})}I(()=>{var W,ee,ie;m(R,((ee=(W=e(z))==null?void 0:W.byVerdict)==null?void 0:ee.VETO)??"—"),m(w,((ie=e(z))==null?void 0:ie.appeals)??"—")}),v(r,d)};G(Oe,r=>{e(ae)?r(je):r(Le,!1)})}t(Se);var B=s(Se,2);{var Q=r=>{var d=Jt();fe(2),v(r,d)};G(B,r=>{e(V).isDreaming&&r(Q)})}var U=s(B,4);{var ve=r=>{var d=ea();v(r,d)};G(U,r=>{e(u)&&r(ve)})}t(f),I(()=>{M=te(f,1,"ambient-strip relative flex h-9 w-full items-center gap-0 overflow-hidden border-b border-synapse/15 bg-black/40 px-3 text-[11px] text-dim backdrop-blur-md svelte-1kk3799",null,M,{"ambient-flash":e(u)}),$e=te(Fe,1,"absolute inline-flex h-full w-full animate-ping rounded-full opacity-75 svelte-1kk3799",null,$e,{"bg-recall":e(C),"bg-warning":!e(C)}),D=te(j,1,"relative inline-flex h-2 w-2 rounded-full svelte-1kk3799",null,D,{"bg-recall":e(C),"bg-warning":!e(C)}),m(se,x()),P=te(Y,1,"svelte-1kk3799",null,P,{"text-recall":e(C),"text-warning":!e(C)}),m(pe,`${e(N)??""}%`)}),v(n,f),qe(),y()}var sa=g(" "),ra=g('
    • '),na=g(' ',1),ia=g('

      Appeal recorded.

      '),la=g('

      No appealable veto in this receipt.

      '),oa=g('
      Claim

      Verdict

      Precedent
        Fix

        Appeal
        '),da=g('
        ');function ca(n,l){We(l,!0);const o=["PASS","NOTE","CAUTION","VETO","APPEALED"];let i=ne(null),x=ne(""),T=ne(!1),y=ne(null),N=ne(null),C=q(()=>{var u;return((u=e(i))==null?void 0:u.verdictBar)??(e(x)?"CAUTION":"NOTE")}),$=q(()=>{var u,f;return((u=e(i))==null?void 0:u.claims.find(M=>M.decision==="veto"))??((f=e(i))==null?void 0:f.claims.find(M=>M.decision==="appealed"))??null}),p=q(()=>{var u;return e($)??((u=e(i))==null?void 0:u.claims[0])??null}),c=q(()=>!!e(i)||!!e(x));Xe(()=>{E();const u=window.setInterval(E,4e3);return()=>window.clearInterval(u)});async function E(){var u;try{const f=await Ke.sanhedrin.latest();h(i,f.receipt,!0),h(x,""),((u=f.receipt)==null?void 0:u.verdictBar)==="VETO"&&f.receipt.id!==e(N)&&(h(T,!0),h(N,f.receipt.id,!0))}catch(f){h(x,f instanceof Error?f.message:String(f),!0)}}async function L(u){var f;if(!(!e($)||((f=e(i))==null?void 0:f.verdictBar)!=="VETO")){h(y,u,!0);try{const M=await Ke.sanhedrin.appeal(u,void 0,e($).id,e(i).id);h(i,M.receipt,!0),h(T,!0),h(x,"")}catch(M){h(x,M instanceof Error?M.message:String(M),!0)}finally{h(y,null)}}}function V(u){if(!u)return"";const f=new Date(u);return Number.isNaN(f.getTime())?"":f.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function Z(u){var f;return(f=u==null?void 0:u.precedent)!=null&&f.length?u.precedent.map(M=>M.summary??M.command??"Precedent recorded.").slice(0,3):["No precedent attached."]}var z=Ze(),ae=le(z);{var de=u=>{var f=da(),M=a(f),he=s(a(M),2);Ie(he,21,()=>o,Ve,(S,F)=>{var _=sa();let K;var X=a(_,!0);t(_),I(()=>{we(_,"aria-current",e(F)===e(C)?"true":void 0),K=te(_,1,"svelte-1j425e6",null,K,{active:e(F)===e(C)}),m(X,e(F))}),v(S,_)}),t(he);var ge=s(he,2),Fe=a(ge);t(ge);var $e=s(ge,2),j=a($e);{var D=S=>{var F=et();I(()=>m(F,e(x))),v(S,F)},k=S=>{var F=et();I(()=>m(F,e(i).summary)),v(S,F)};G(j,S=>{e(x)?S(D):e(i)&&S(k,1)})}t($e);var se=s($e,2),Y=a(se,!0);t(se),t(M);var P=s(M,2);{var pe=S=>{var F=oa(),_=a(F),K=a(_),X=s(a(K),2),ce=a(X,!0);t(X),t(K);var ue=s(K,2),me=s(a(ue),2),be=a(me);t(me),t(ue);var J=s(ue,2),Ae=s(a(J),2);Ie(Ae,21,()=>Z(e(p)),Ve,(B,Q)=>{var U=ra(),ve=a(U,!0);t(U),I(()=>m(ve,e(Q))),v(B,U)}),t(Ae),t(J);var Ce=s(J,2),Ne=s(a(Ce),2),Te=a(Ne,!0);t(Ne),t(Ce),t(_);var Ee=s(_,2),Se=s(a(Ee),2);{var Oe=B=>{var Q=na(),U=le(Q),ve=a(U,!0);t(U);var r=s(U,2),d=a(r,!0);t(r);var A=s(r,2),R=a(A,!0);t(A),I((b,w,O)=>{U.disabled=b,m(ve,e(y)==="stale"?"Saving":"Stale"),r.disabled=w,m(d,e(y)==="wrong"?"Saving":"Wrong"),A.disabled=O,m(R,e(y)==="too_strict"?"Saving":"Too strict")},[()=>!!e(y),()=>!!e(y),()=>!!e(y)]),re("click",U,()=>L("stale")),re("click",r,()=>L("wrong")),re("click",A,()=>L("too_strict")),v(B,Q)},je=B=>{var Q=ia();v(B,Q)},Le=B=>{var Q=la();v(B,Q)};G(Se,B=>{e($)&&e(i).verdictBar==="VETO"?B(Oe):e(i).verdictBar==="APPEALED"?B(je,1):B(Le,!1)})}t(Ee),t(F),I(()=>{var B,Q,U,ve;m(ce,((B=e(p))==null?void 0:B.text)??e(i).draftPreview),m(be,`${((Q=e(p))==null?void 0:Q.decision)??e(i).overall??""} · ${((U=e(p))==null?void 0:U.evidence_state)??e(C)??""}`),m(Te,((ve=e(p))==null?void 0:ve.fix)||"No change required.")}),v(S,F)};G(P,S=>{e(T)&&e(i)&&S(pe)})}t(f),I((S,F)=>{te(f,1,S,"svelte-1j425e6"),we(M,"aria-expanded",e(T)),m(Fe,`Current verdict: ${e(C)??""}`),m(Y,F)},[()=>`verdict-bar tone-${e(C).toLowerCase()}`,()=>{var S;return V((S=e(i))==null?void 0:S.createdAt)}]),re("click",M,()=>h(T,!e(T))),v(u,f)};G(ae,u=>{e(c)&&u(de)})}v(n,z),qe()}ze(["click"]);const mt="vestige.theme",rt="vestige-theme-light",Re=vt("dark"),Ue=vt(!0),nt=Ct([Re,Ue],([n,l])=>n==="auto"?l?"dark":"light":n);function va(n){return n==="dark"||n==="light"||n==="auto"}function pa(n){if(va(n)){Re.set(n);try{localStorage.setItem(mt,n)}catch{}}}function Ye(){const n=pt(Re);pa(n==="dark"?"light":n==="light"?"auto":"dark")}function ua(){if(document.getElementById(rt))return;const n=document.createElement("style");n.id=rt,n.textContent=` +/* Vestige light-mode overrides — injected by theme.ts. + * Activated by [data-theme='light'] on . + * Tokens mirror the real names used in app.css so the cascade stays clean. */ +[data-theme='light'] { + /* Core surface palette (slate scale) */ + --color-void: #f8fafc; /* slate-50 — page background */ + --color-abyss: #f1f5f9; /* slate-100 */ + --color-deep: #e2e8f0; /* slate-200 */ + --color-surface: #f1f5f9; /* slate-100 */ + --color-elevated: #e2e8f0; /* slate-200 */ + --color-subtle: #cbd5e1; /* slate-300 */ + --color-muted: #94a3b8; /* slate-400 */ + --color-dim: #475569; /* slate-600 */ + --color-text: #0f172a; /* slate-900 */ + --color-bright: #020617; /* slate-950 */ +} + +/* Baseline body/html wiring — app.css sets these against the dark + * tokens; we just let the variables do the work. Reassert for clarity. */ +[data-theme='light'] html, +html[data-theme='light'] { + background: var(--color-void); + color: var(--color-text); +} + +/* Glass surfaces — recompose on a light canvas. The original alphas + * are tuned for dark; invert-and-tint for light so panels still read + * as elevated instead of vanishing. */ +[data-theme='light'] .glass { + background: rgba(255, 255, 255, 0.65); + border: 1px solid rgba(99, 102, 241, 0.12); + box-shadow: + inset 0 1px 0 0 rgba(255, 255, 255, 0.6), + 0 4px 24px rgba(15, 23, 42, 0.08); +} +[data-theme='light'] .glass-subtle { + background: rgba(255, 255, 255, 0.55); + border: 1px solid rgba(99, 102, 241, 0.1); + box-shadow: + inset 0 1px 0 0 rgba(255, 255, 255, 0.5), + 0 2px 12px rgba(15, 23, 42, 0.06); +} +[data-theme='light'] .glass-sidebar { + background: rgba(248, 250, 252, 0.82); + border-right: 1px solid rgba(99, 102, 241, 0.14); + box-shadow: + inset -1px 0 0 0 rgba(255, 255, 255, 0.4), + 4px 0 24px rgba(15, 23, 42, 0.08); +} +[data-theme='light'] .glass-panel { + background: rgba(255, 255, 255, 0.75); + border: 1px solid rgba(99, 102, 241, 0.14); + box-shadow: + inset 0 1px 0 0 rgba(255, 255, 255, 0.5), + 0 8px 32px rgba(15, 23, 42, 0.1); +} + +/* Halve glow intensity — neon accents stay recognizable without + * washing out on slate-50. */ +[data-theme='light'] .glow-synapse { + box-shadow: 0 0 10px rgba(99, 102, 241, 0.15), 0 0 30px rgba(99, 102, 241, 0.05); +} +[data-theme='light'] .glow-dream { + box-shadow: 0 0 10px rgba(168, 85, 247, 0.15), 0 0 30px rgba(168, 85, 247, 0.05); +} +[data-theme='light'] .glow-memory { + box-shadow: 0 0 10px rgba(59, 130, 246, 0.15), 0 0 30px rgba(59, 130, 246, 0.05); +} + +/* Ambient orbs are gorgeous on black and blinding on white. Tame them. */ +[data-theme='light'] .ambient-orb { + opacity: 0.18; + filter: blur(100px); +} + +/* Scrollbar recolor for the lighter surface. */ +[data-theme='light'] ::-webkit-scrollbar-thumb { + background: #cbd5e1; +} +[data-theme='light'] ::-webkit-scrollbar-thumb:hover { + background: #94a3b8; +} +`,document.head.appendChild(n)}function it(n){document.documentElement.dataset.theme=n}let ke=null,Me=null,_e=null,ye=null;function ma(){ke&&Me&&ke.removeEventListener("change",Me),ye==null||ye(),_e==null||_e(),ke=null,Me=null,ye=null,_e=null,ua();let n="dark";try{const l=localStorage.getItem(mt);(l==="dark"||l==="light"||l==="auto")&&(n=l)}catch{}return Re.set(n),ke=window.matchMedia("(prefers-color-scheme: dark)"),Ue.set(ke.matches),Me=l=>Ue.set(l.matches),ke.addEventListener("change",Me),it(pt(nt)),ye=nt.subscribe(it),_e=Re.subscribe(()=>{}),()=>{ke&&Me&&ke.removeEventListener("change",Me),ke=null,Me=null,ye==null||ye(),_e==null||_e(),ye=null,_e=null}}var fa=g('');function ha(n){const l=()=>oe(Re,"$theme",o),[o,i]=He(),x={dark:"Dark",light:"Light",auto:"Auto (system)"},T={dark:"light",light:"auto",auto:"dark"};let y=q(l),N=q(()=>T[e(y)]),C=q(()=>`Toggle theme: ${x[e(y)]} (click for ${x[e(N)]})`);var $=fa(),p=a($),c=a(p);let E;var L=s(c,2);let V;var Z=s(L,2);let z;t(p),t($),I(()=>{we($,"aria-label",e(C)),we($,"title",e(C)),we($,"data-mode",e(y)),E=te(c,0,"icon svelte-1cmi4dh",null,E,{active:e(y)==="dark"}),V=te(L,0,"icon svelte-1cmi4dh",null,V,{active:e(y)==="light"}),z=te(Z,0,"icon svelte-1cmi4dh",null,z,{active:e(y)==="auto"})}),re("click",$,function(...ae){Ye==null||Ye.apply(this,ae)}),v(n,$),i()}ze(["click"]);var ga=g(' '),ba=g('
        '),xa=g(''),ka=g(' '),_a=g('
        ',1),ya=g(''),wa=g('
        No matches
        '),$a=g('
        esc
        '),Aa=g(" ",1);function za(n,l){We(l,!0);const o=()=>oe(Tt,"$page",C),i=()=>oe(wt,"$isConnected",C),x=()=>oe(ot,"$memoryCount",C),T=()=>oe(dt,"$avgRetention",C),y=()=>oe(yt,"$uptimeSeconds",C),N=()=>oe(lt,"$suppressedCount",C),[C,$]=He();let p=ne(!1),c=ne(""),E=ne(void 0),L=q(()=>o().url.pathname.startsWith(xe)?o().url.pathname.slice(xe.length)||"/":o().url.pathname),V=q(()=>e(L)==="/waitlist"||e(L).startsWith("/waitlist/"));Xe(()=>{e(V)||st.connect();const j=ma();function D(k){if(e(V))return;if((k.metaKey||k.ctrlKey)&&k.key==="k"){k.preventDefault(),h(p,!e(p)),h(c,""),e(p)&&requestAnimationFrame(()=>{var P;return(P=e(E))==null?void 0:P.focus()});return}if(k.key==="Escape"&&e(p)){h(p,!1);return}if(k.target instanceof HTMLInputElement||k.target instanceof HTMLTextAreaElement)return;if(k.key==="/"){k.preventDefault();const P=document.querySelector('input[type="text"]');P==null||P.focus();return}const Y={g:"/graph",m:"/memories",t:"/timeline",f:"/feed",e:"/explore",i:"/intentions",s:"/stats",r:"/reasoning",a:"/activation",d:"/dreams",c:"/schedule",p:"/importance",u:"/duplicates",x:"/contradictions",n:"/patterns"}[k.key.toLowerCase()];Y&&!k.metaKey&&!k.ctrlKey&&!k.altKey&&(k.preventDefault(),at(`${xe}${Y}`))}return window.addEventListener("keydown",D),()=>{st.disconnect(),window.removeEventListener("keydown",D),j()}});const Z=[{href:"/graph",label:"Graph",icon:"◎",shortcut:"G"},{href:"/reasoning",label:"Reasoning",icon:"✦",shortcut:"R"},{href:"/memories",label:"Memories",icon:"◈",shortcut:"M"},{href:"/timeline",label:"Timeline",icon:"◷",shortcut:"T"},{href:"/feed",label:"Feed",icon:"◉",shortcut:"F"},{href:"/explore",label:"Explore",icon:"◬",shortcut:"E"},{href:"/activation",label:"Activation",icon:"◈",shortcut:"A"},{href:"/dreams",label:"Dreams",icon:"✧",shortcut:"D"},{href:"/schedule",label:"Schedule",icon:"◷",shortcut:"C"},{href:"/importance",label:"Importance",icon:"◎",shortcut:"P"},{href:"/duplicates",label:"Duplicates",icon:"◉",shortcut:"U"},{href:"/contradictions",label:"Contradictions",icon:"⚠",shortcut:"X"},{href:"/patterns",label:"Patterns",icon:"▦",shortcut:"N"},{href:"/intentions",label:"Intentions",icon:"◇",shortcut:"I"},{href:"/stats",label:"Stats",icon:"◫",shortcut:"S"},{href:"/settings",label:"Settings",icon:"⚙",shortcut:","}],z=Z.slice(0,5);function ae(j,D){const k=D.startsWith(xe)?D.slice(xe.length)||"/":D;return j==="/graph"?k==="/"||k==="/graph":k.startsWith(j)}let de=q(()=>e(c)?Z.filter(j=>j.label.toLowerCase().includes(e(c).toLowerCase())):Z);function u(j){h(p,!1),h(c,""),at(`${xe}${j}`)}var f=Aa(),M=le(f);{var he=j=>{var D=Ze(),k=le(D);tt(k,()=>l.children),v(j,D)},ge=j=>{var D=_a(),k=s(le(D),6),se=a(k),Y=a(se),P=s(Y,2);Ie(P,21,()=>Z,Ve,(b,w)=>{const O=q(()=>ae(e(w).href,o().url.pathname));var H=ga(),W=a(H),ee=a(W,!0);t(W);var ie=s(W,2),Pe=a(ie,!0);t(ie);var Je=s(ie,2),ft=a(Je,!0);t(Je),t(H),I(()=>{we(H,"href",`${xe??""}${e(w).href??""}`),te(H,1,`flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all duration-200 text-sm + ${e(O)?"bg-synapse/15 text-synapse-glow border border-synapse/30 shadow-[0_0_12px_rgba(99,102,241,0.15)] nav-active-border":"text-dim hover:text-text hover:bg-white/[0.03] border border-transparent"}`),m(ee,e(w).icon),m(Pe,e(w).label),m(ft,e(w).shortcut)}),v(b,H)}),t(P);var pe=s(P,2),S=a(pe);t(pe);var F=s(pe,2),_=a(F),K=a(_),X=s(K,2),ce=a(X,!0);t(X);var ue=s(X,2),me=a(ue);ha(me),t(ue),t(_);var be=s(_,2),J=a(be),Ae=a(J);t(J);var Ce=s(J,2),Ne=a(Ce);t(Ce);var Te=s(Ce,2);{var Ee=b=>{var w=ba(),O=a(w);t(w),I(H=>m(O,`up ${H??""}`),[()=>$t(y())]),v(b,w)};G(Te,b=>{y()>0&&b(Ee)})}t(be);var Se=s(be,2);{var Oe=b=>{var w=xa(),O=a(w);St(O),t(w),v(b,w)};G(Se,b=>{N()>0&&b(Oe)})}t(F),t(se);var je=s(se,2),Le=a(je);aa(Le,{});var B=s(Le,2);ca(B,{});var Q=s(B,2),U=a(Q);tt(U,()=>l.children),t(Q),t(je);var ve=s(je,2),r=a(ve),d=a(r);Ie(d,17,()=>z,Ve,(b,w)=>{const O=q(()=>ae(e(w).href,o().url.pathname));var H=ka(),W=a(H),ee=a(W,!0);t(W);var ie=s(W,2),Pe=a(ie,!0);t(ie),t(H),I(()=>{we(H,"href",`${xe??""}${e(w).href??""}`),te(H,1,`flex flex-col items-center gap-0.5 px-3 py-2 rounded-lg transition-all min-w-[3.5rem] + ${e(O)?"text-synapse-glow":"text-muted"}`),m(ee,e(w).icon),m(Pe,e(w).label)}),v(b,H)});var A=s(d,2);t(r),t(ve),t(k);var R=s(k,2);It(R,{}),I(b=>{we(Y,"href",`${xe??""}/graph`),te(K,1,`w-2 h-2 rounded-full ${i()?"bg-recall animate-pulse-glow":"bg-decay"}`),m(ce,i()?"Connected":"Offline"),m(Ae,`${x()??""} memories`),m(Ne,`${b??""}% retention`)},[()=>(T()*100).toFixed(0)]),re("click",S,()=>{h(p,!0),h(c,""),requestAnimationFrame(()=>{var b;return(b=e(E))==null?void 0:b.focus()})}),re("click",A,()=>{h(p,!0),h(c,""),requestAnimationFrame(()=>{var b;return(b=e(E))==null?void 0:b.focus()})}),v(j,D)};G(M,j=>{e(V)?j(he):j(ge,!1)})}var Fe=s(M,2);{var $e=j=>{var D=$a(),k=a(D),se=a(k),Y=s(a(se),2);gt(Y),xt(Y,_=>h(E,_),()=>e(E)),fe(2),t(se);var P=s(se,2),pe=a(P);Ie(pe,17,()=>e(de),Ve,(_,K)=>{var X=ya(),ce=a(X),ue=a(ce,!0);t(ce);var me=s(ce,2),be=a(me,!0);t(me);var J=s(me,2),Ae=a(J,!0);t(J),t(X),I(()=>{m(ue,e(K).icon),m(be,e(K).label),m(Ae,e(K).shortcut)}),re("click",X,()=>u(e(K).href)),v(_,X)});var S=s(pe,2);{var F=_=>{var K=wa();v(_,K)};G(S,_=>{e(de).length===0&&_(F)})}t(P),t(k),t(D),re("keydown",D,_=>{_.key==="Escape"&&h(p,!1)}),re("click",D,_=>{_.target===_.currentTarget&&h(p,!1)}),re("keydown",Y,_=>{_.key==="Enter"&&e(de).length>0&&u(e(de)[0].href)}),bt(Y,()=>e(c),_=>h(c,_)),v(j,D)};G(Fe,j=>{e(p)&&!e(V)&&j($e)})}v(n,f),qe(),$()}ze(["click","keydown"]);export{za as component}; diff --git a/apps/dashboard/build/_app/immutable/nodes/0.j0CpgSFp.js.br b/apps/dashboard/build/_app/immutable/nodes/0.j0CpgSFp.js.br new file mode 100644 index 0000000000000000000000000000000000000000..17966bc969a99f799631b3afd5143d57b8ba9267 GIT binary patch literal 9928 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 G2Y&&ZI6^c4 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/0.j0CpgSFp.js.gz b/apps/dashboard/build/_app/immutable/nodes/0.j0CpgSFp.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..6d56e43be141c057bbb9fff167dd455dec965b8a GIT binary patch literal 11290 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 diff --git a/apps/dashboard/build/_app/immutable/nodes/1.CJFfVX1H.js.gz b/apps/dashboard/build/_app/immutable/nodes/1.CJFfVX1H.js.gz deleted file mode 100644 index a10aac2f9637fbacf920009cfdde2d5d62f216e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 383 zcmV-_0f7D=iwFP!000026J?OiPQx$|gzr3ssW{lul2U{~BDe@j1qXf(2r9TB<2Z>) zVq3OTsz!Nt;-IUxhNKB(25FE4e2@}YkToPh9M~WlM3ArlnG3TjR;w31%yfY?qweK<`Z#-9 z4#~dJX4m~_6#ej`%$e4sajXC2-97&(Z*G1^Llh(OIJ^7YKA-m_*UEYHO`A-3B&^jI zlg0{PTZO8qFSHOm=b5kF(A-tpHZG#tB+QE>;<@0(K2y@~c+D(Y(jz>%%4c(QHSJFm zZe~7#8Hv+caWAz(3!H)?O@z(kX$u z^Vr^F1WJqvoi_myvB4bVep~_u*MJ3;yU!6yRb7_XYb_IWaw(!pIL9(US^}GHrmpQ8 dlU8i{g)YKEx$d^Bgz{~C@CON

        ",1);function C(f,n){g(n,!1),h();var t=E(),r=d(t),c=s(r,!0);o(r);var a=_(r,2),u=s(a,!0);o(a),l(()=>{var e;p(c,i.status),p(u,(e=i.error)==null?void 0:e.message)}),x(f,t),v()}export{C as component}; +import"../chunks/Bzak7iHL.js";import{i as h}from"../chunks/BUoSzNdg.js";import{p as g,f as d,t as l,a as v,d as s,r as o,e as _}from"../chunks/CpWkWWOo.js";import{s as p}from"../chunks/BlVfL1ME.js";import{a as x,f as $}from"../chunks/CHOnp4oo.js";import{p as m}from"../chunks/D8UfWY0j.js";import{s as k}from"../chunks/C2TQQEIa.js";const b={get error(){return m.error},get status(){return m.status}};k.updated.check;const i=b;var E=$("

        ",1);function C(f,n){g(n,!1),h();var t=E(),r=d(t),c=s(r,!0);o(r);var a=_(r,2),u=s(a,!0);o(a),l(()=>{var e;p(c,i.status),p(u,(e=i.error)==null?void 0:e.message)}),x(f,t),v()}export{C as component}; diff --git a/apps/dashboard/build/_app/immutable/nodes/1.DEUqmURt.js.br b/apps/dashboard/build/_app/immutable/nodes/1.DEUqmURt.js.br new file mode 100644 index 0000000000000000000000000000000000000000..894d776fd98e6b6f5ad04f29edebf33e145dd7dc GIT binary patch literal 340 zcmV-a0jvHSi2`7Z!nS$yk!2b#7D*CE5)I9(e`$333@GiS$?!RSHm#-89X#?EK`=(Q zsUSEOK`8nEZ@xD`u4rPJJ;yt8VDl)OBs7W{d}XpBEU z=ew^(0rg$(P9wEvicd!lxQA%miz@2vK8p+Cl!rNt0wDqegaiU10k}}21uC%gzWV#U zx>QK^hDVtXJ5A4P3NjhFfsNc<9q;B+96GQV8lBp;zEcr_PQ1D?{ykKTxAq#JyG3s>db##_AJz?a0AB?A% m4lTJl?5eZFerM`r@>tiwFP!000026J=0cOT#b}efL+yv4;dM-6n!!mkG{+f***^;nT?4w2f_( zkfdW+`rmE3J(Tq&C){&#&dC*}R>qBjU=n4O%kY0QzFSFNG zU)cp6j_Kop_0zl5*GdiQmgmaH+jX+}nf?w+t in i?Bc(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var kt=(i,t,e)=>zc(i,typeof t!="symbol"?t+"":t,e);import"../chunks/Bzak7iHL.js";import{o as jl,a as Zl}from"../chunks/GG5zm9kr.js";import{s as me,c as va,h as zt,g as B,p as ys,aB as kc,a as Es,d as yt,e as bt,n as Hc,r as xt,t as Ke,u as Gn,f as Kl,j as Vc}from"../chunks/CpWkWWOo.js";import{s as fe,d as $l,a as Fe}from"../chunks/BlVfL1ME.js";import{i as kn}from"../chunks/B4yTwGkE.js";import{e as _s,i as hr}from"../chunks/CGEBXrjl.js";import{a as _e,f as Se,c as Gc}from"../chunks/CHOnp4oo.js";import{s as ve,r as xa}from"../chunks/A7po6GxK.js";import{s as Us}from"../chunks/aVbAZ-t7.js";import{s as Sr}from"../chunks/Cx-f-Pzo.js";import{b as Ma}from"../chunks/sZcqyNBA.js";import{b as Jl}from"../chunks/BnXDGOmJ.js";import{s as Wc,a as Xc}from"../chunks/C6HuKgyx.js";import{b as Do}from"../chunks/DGcYlAAw.js";import{b as Yc}from"../chunks/CJsMJEun.js";import{p as vs}from"../chunks/V6gjw5Ec.js";import{N as Sa}from"../chunks/CcUbQ_Wl.js";import{i as qc}from"../chunks/BUoSzNdg.js";import{a as gi}from"../chunks/554JRhq6.js";import{e as jc}from"../chunks/MAY1QfFZ.js";/** +var Bc=Object.defineProperty;var zc=(i,t,e)=>t in i?Bc(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var kt=(i,t,e)=>zc(i,typeof t!="symbol"?t+"":t,e);import"../chunks/Bzak7iHL.js";import{o as jl,a as Zl}from"../chunks/GG5zm9kr.js";import{s as me,c as va,h as zt,g as B,p as ys,aB as kc,a as Es,d as yt,e as bt,n as Hc,r as xt,t as Ke,u as Gn,f as Kl,j as Vc}from"../chunks/CpWkWWOo.js";import{s as fe,d as $l,a as Fe}from"../chunks/BlVfL1ME.js";import{i as kn}from"../chunks/B4yTwGkE.js";import{e as _s,i as hr}from"../chunks/CGEBXrjl.js";import{a as _e,f as Se,c as Gc}from"../chunks/CHOnp4oo.js";import{s as ve,r as xa}from"../chunks/A7po6GxK.js";import{s as Us}from"../chunks/aVbAZ-t7.js";import{s as Sr}from"../chunks/Cx-f-Pzo.js";import{b as Ma}from"../chunks/sZcqyNBA.js";import{b as Jl}from"../chunks/BnXDGOmJ.js";import{s as Wc,a as Xc}from"../chunks/C6HuKgyx.js";import{b as Do}from"../chunks/D8UfWY0j.js";import{b as Yc}from"../chunks/CJsMJEun.js";import{p as vs}from"../chunks/V6gjw5Ec.js";import{N as Sa}from"../chunks/CcUbQ_Wl.js";import{i as qc}from"../chunks/BUoSzNdg.js";import{a as gi}from"../chunks/B7CfdQuM.js";import{e as jc}from"../chunks/MAY1QfFZ.js";/** * @license * Copyright 2010-2024 Three.js Authors * SPDX-License-Identifier: MIT diff --git a/apps/dashboard/build/_app/immutable/nodes/10.CACwABbv.js.br b/apps/dashboard/build/_app/immutable/nodes/10.CACwABbv.js.br new file mode 100644 index 0000000000000000000000000000000000000000..ddad2ebbe25ae6b28ff72eb7803988aa6ed949cd GIT binary patch literal 124073 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

        S5 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

        h)Q_WJg&Tfk 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

        D$SaLt;VYOByYwyQq@6vt z9aKbo!UmtEU~^oNU~d!VyUUts03kP#^zWt! z6i?r%713%9u4n`BY10KYjUW0I9oxs5Y4u7m#m*x;;9blxgnh}R8D$G}wjdg;9m48v z0BaBgUs(w{N&a369XG^{5@=|Pvq7OvP4lgd$M)*O;`If#pzP`={%4bE!P&m7QR6I} zB89cZb+ss$XlhG7AxWLS)}9A4H^p?LMyE#90Eoy*X;ux2NO^a&D|L`-MWA*>d6YXU zN*tozh{l@PXjd-GUeMS-%xvaotwPTO-vW>E_ip-z|1)fy*Yi-j3bMSVeo>DnP_6#i z=h7rt8K6Z>L7_=z2Lm|6dpPTLzRh8=tMylgsLdOMmDE`3UFUk_gqE|h|6%{o=Rs_b zAgqHc?18v@n?fx;&Be_4Cr@KLeU-JWXhJ)C5}ubRfEBHD;S1}y7mSL~i&&>n|DyQ8w?~DTB`ICLsO%3!CJaQ@p&l|Vv0qxtx64Cxev63jj%e1p3P{> zA>`qd*~aZU2<1pjhlO@NV893Ym&(4n&hrbHi5kF@&k{n6YK-)TV^?FIg7)cWlECeN zc0z~yWCuMJwVVK=sq+hFf8eBlnMf`}=(X8xd!S0gli>AHQxhtrye-R8MOmx~Hx0YU zwY~GhCw7#A2?u)p1Qr)y)^8OqOyBzuUtUUrDcpL1knEQEhCKa13Hdpl_X-Ui%UX%r zm~l-yKkIj1a_D4nA(Ed=M?#8n_KNbvZ6n|3WD1;|@MMP&c(I);-^xy~u2AA}nr07w zz)xVl+#mWRaS(l8NX@Cv5J-#n`_^*6OVO>H@swia&b8nw60sk#Zpu^b)@8R)dbXZB z(Cg%GDzN6SAY6q%2GRnb>Y_+KpE(}|?Wsg_`*))hY+ejgWFE({J23S!hno`FY=SM>52 z1C)24xt4-{D6K=jNv;cfuUGB?r6HxgZsOf@Rc$mWuvi{iV2_~y$jGl8nU(6L=2D$y z#*0_ok_jb(9>6#^0i!fQ0M>f3eEB{}fW%eR^`ozFVDvKu+|t5tuvxo+3G5`lj_QpQ zCcaWk?)D@$<|4z1;4My!Zf*HlS0GG(knSF;Xa>nd7iVRiKL?-hRI*2B#BadKUl`VO z8}=UZ*Q8(kH~K=Gk8$Q92S`DbX73?}r5%IR_S<)k_{)h?zW$8sh5;ao&oEtw5CE5- z{QP6C9slO#dF>J@N&H{$7+Wa-YLz1FwR=4Snl6Rsu|!C!iHzYTmHcNd%B*C0J=JO# zg4uPzBZWMu@8Y1^lE7)0>9IhyPGW&5;rEkKYX7?4UsfAN8N~I>i0?6KlxsvHn<;B= zTUKB&?D2R3hG9Hu{%f$%pa9(6ob)}tUYU|D#uwRRHEuv%9E`mWn zp|zCxw*O-ZRJ5^hKQE&dmm^0rCP=2Q_=Z{h}X)6!0)Z`;~U*K9UvhD5K`u_QH@ zbw;T98~_KE6d(A~EYEfST%JKoaewWh7C%9LYpV0BBiTfeKEFEEx~v!KPU0CS8;QwhgI<@Q05gI_)MOMnh>nco@k? z6rXvOSM(+xXFRMb649zUDBheXC9Rm7u!PCHqe*gYiCd{z!25lH?C|+y{w&~%AHi(Z z#;kmk@bI@{<&RK?LKg`N1&6!1x?4c1-_WxY6P=H0jE0$&+9EcgO}SQu79(81?yUNo z%4*S44;%asQLcc%UeJ2q8p^*j*Jh3|k8gXuX-BN!;FjsAFUVvE;r*2>Qm3ZM7V(!0 z2b*5Pjcb3LznYT;)7|VE~{tMsEOQ$~{p3&^5v}lxW{@B2TY5ost`8=LmsBY)~16l=!Z)k|2 z@%wT1tNOr?|8d{0!x}HRu~%u`WaLsfcMCa0_NpFO{|LWjPvhPe z@0y45q#8?e-4=cIEBtl_mQt442!vpUD`Oj$6)P}YKaoKo(K}pg^Q&*AAtX}u6yKfE zc@xd$U4MzrloG0pQ{^qN8ZCdpD&r*tF|HD7yEX2crS0u2`$RZl^H1XNW!8m8>95V* zc`&F(3c&34H2fRwUx0E=1CMn6n!M$^C|mKfsli5;HO9a4R!^9$4nn?n1mkW5Lw316 zDi7HA{8LsD?@E|SpOb7IaC(aOa+2G*qPaBbRT}x~zr}N8DBaCD)T|pDY;3r(i*^42 zubi_sDMiO03kLxJe;thfGwB_*UYsw|x>mT&4mLa7?8V%FIE<{(0U&6de2{@SSes^Z zO*jXb%!db`&lQ1~ow??ARFGGg%;GuBx5LiaR#OwYcXR{jA{V0m1BGpfBMwlZoiR|p zfpi-PiAEP=Ty+qdQYx}De}t97T$~dop>brUvJ(hO zZLYHQ_J+bWT`3{(Xb6yV^E(j5qa8W;iF&))ESO%UY*Urt8bsK-832uqaHaQja0889 zZT z;)LJC<`fjpr_EAe+Li>cuTG?+PP2sLm=k%qtg0aBAuDA{i{wBu$qOIaT?1-h@Ob_a zD&7QrLf(i90s*sgWB#A!SpsN=Lz)QtSz8dp8h;#U#fpL)(l)D9au{ST z&S6+h4;sd}4k_bea@LnPQfjIaG2QvGW+F3Rgm%uQ#e30>+Ro@qCRh2?!q6uX;Cg$I zZP(>wE}2s!Pw{m%uelaLI4EV3U0x#bJf%>6&}10?oKJ^Do8H*$eJB3B{jb|V=N63o z&V4wgfelqUXUsU7uO34y8>459^-SW$>2sVOVSj!%{*VG}r~^0smNgcLjb7}9#m~oX z$IJ@CzZ=j5^1jZwP{|N{Zm`%^vZ4bbB)A1GWhOg9HgFkh(lq?u(-tey`Sc5n?|nE?8Sc_f)-uVjoua*5I=8%lx= z<3$c(W`$;Etf3<=0w{#Jm$v2v%y2n<$&J8mPJszAU@FX&;8f+*yQ&4P&nl@C01siC z_?C(0vT1u8pfbA>mgOYp^lj6NQx8O!))BWw=E!VC|L3}o5l!@@$9-1RHo@6OK zwftllifHIr%px%UR}LyMafXa()7x^Xuu8GtZUkm(B3H(8vfxXS=tDpDX9lV(2gr5iL1Alk0?jEK3 zSUYdlu5pF>Y{1LHk6ip9I{ya#esQFUYaRXT-2VOf^54Z(-u^nf@57JVf9l-TGe61r zeVY$Y=G%%(=&3DSo`Sbpeac=4=0H;!wY=y5+eF!iM2x3L_{w;o-*a%qJn?VjKavb} zco<|K2jX&BlndtgSyWt>{v%u`g|4RtY#6oYgZc3j{QM`?a=-H<-X)!X`}V+(?1}Em zKpj7Obhnbx|JvE#dGVt^SIeU@c8MN*xALWO&TrVk8OS;=qnoz?JU@!0 z1t4iBNHBf_P}o7)d5e|0bd_%{=cb+z$-M(cc7-g~>$0s8B`$n-VH+@Ad6$dSJR8=p z+tpFO_&wdv)eY$1 z$~w{+R!LFV>9SDueviS3!wFmZ9!DbJRES^<0#oB5?(_%Y4GsW=Dd=*QSM%~GZC(x{ zD!vD8RekzAYu~CtkPocOLO=~JddU`NeLctV?4O#yq+@WKV-k`!#V-lIjF!ZM-Fq-9 zi8bN#Vs4WE_x%+QBKNMEY%y_EAJz1<3TU!%J&T_F0ZDI%9ReeWOt<~{8;Y~DQ!Nby zKLz+i8}Mb5KGtR)vOEpZ{X1mV9OWP0y9yF#ZpFnPa5`9}2KL0QNX-rAz2QUL&4pTN zy`61KUfC+c9tDRvNv-SVBtXWoTOzZl^&VP*h}l>7`5(vH03AHmsT>j1&pANFKC1lE zPqIgI!NTzJ19Yq`A)#-b`M;53srKX_TA#ANMF5{@!~RcpAPIaGTyKPg7@b{h8WZ~+ zzG83r^3F*KSIbcM4fKG};a(TAe|4f>`iB{UaFert5v|NtTizQ8>^;bWFA$2PcJ_>? zl;L-X&2PT6Ch_%($k!&@)f(O>&5?aey6_0AaQa;0J2`*vnGZq7dl~Hgdf}iB^ofL! zx1Z0pXyKwrtS+g5*6`$esSc@uJ5KQ@#m(fpeKQ{kCZgt@is>uzhNeh{jT}0cULbL3 zxGdXtm834{Wk+oLKZjnMv3qP~eclH&%pqt)S{nWWh-yBuNl9I!*!I=gKUgWcb7Yhv zhh|ff(*2?meH6aqYK!IYW@Kwf^=x3TG?UlO!xkT{^H<(5A2sFw$Vt$xazc~^D}7+# zBDWpGIQ{pLR?&>ndRHR;KE`A?186f%*Xmhs7sO}>ug#ijQX77~3Mx>eJqJS( zm91!7NMI0bgSA>c^p5zAI9tkYxYUlyHQaI!<=V4FQaf-pzVvgahQST?^mCX}2=(TF zHH_PVPHWNGJf5L7azpF9pq{UWCEiRZF$t5u+OG4v3 zaG85N^_mh2d0;jX624=e)*ZhofrvX;PM`5$tPuSHiJpy1&Q_)pLar8yd0_oD4^#{K z(g{3%_wV7`O?PW#nWAjv>P#vC?AKRDr!yQ2+A)SMsLg{2XEUTK8M}#pJ8pXs^=kCI zeK#8I%qQfIOd$>g?9md7qh=FZ2#gy%`)4}iw~CTbKGML1yhb9+_R?^Dz{3M(C@xhk zIiEL)*tP!-OAP@mPf>|y>af(I(`xo)4jhe9)ZRl+*}LGX=q+yTVSjrBTKgIt@y4?7olE9_4|MBU%h|w(chUDtL(1@VaolVk zeH`uW*WIl(jQGKHyH@A%Ilm$sCJ3UqEAmP_t^-;J>s>$gpY~1q|M$T%eyK|p_0<$! z{!V7|F~K++CJyX_mgwSOlP7oq{3b%4bZ}TG88_5U^^uUbA|%94$A$vt5@`!TR*h(u zW4Nw2$!@UMB-vLNI|(<%OA}~)d&FkUfWgX%k_971BtAuMs2)5fUq;Y1vWY1U4{)rF?pYD|9qed<__VUNqB+|` zoWiv6Ay85gn&P6oKz%C`{;dk28rnM~`jqUHKkS%{-)jyTgc!-su;mHZ#^6bD=>!Hs z(c{w?j7lGEV*IE15%{hCIcs6oSLmt1?I} z6-86$=c7Z7gDKtB(X-c5JK{AsdTv1(Mm!V46c@VlkcN?Uqj&bGqxqIF%46TX&viy? z42xrcum#D4T^46>`6fo+KSndnJ+)9w`beRP-d{A%F2A0I`R#ij$CCFu8Y^J(X1be5 zJ=SL+bBhIYyg#vOC7nW^NJGoVch%)~cJ!M8IED1Va(7mB;7XNQ<>aP7FcXdI9sn!I z!G3_3K;b0ItH?urI_seh{aAbSy0}aw60C(IrxF%y_ZgLd&36`nROJ-zjn&^Et-#L8 z1J`B{a>*<&GP73ez|Is9?fFF`?DA_UR&aK-hmJ`mVsAq4;*Dnsg@c0cpUVp@wxl8v zmf5J%1!X%2&RsBXtIL(hj1w;Gjt$)6lx_EB_U$>2l+49*ivL{i6s-Qw{vs*ZUyxu= z=pw&dR{wbL&wa_k8xte`vg9ls?lo=RX!+ykjSZsLUCt^=dl6!K?~;MCIy4_^KQ{@z zq8;;4$WfksCPkn6#z2G@qoP|c-}sg4yl#o`9A)A@&cP!%sXv>?tvRl{fJ{UBFmPs-`j1UX>+LEIcLmiy$pkgVA~Ll(utp}LS4L~LYuez zAk12|gO{lxs=-O2!hJtuKjg2z`3U1R_WGb&?!wY;L=sVlfA!qUcFK0jOj^xGqNm-k zfa9T=fLr3~)840~!@o~TXBvC=cKpIltO8oorC>_^y&b+SD0rdAZp|UW6Jg3aOe>@e zOH&yxvZz!dh0h3>JVkR+QL5wxc|!pAX4B%K=N#McLQoZK3O1j(7|$9nelP4zUDb!f_YY#JA9h1P_*0p-j4aH1YyrK zg|rt52B|Z~@5Dl{)7MaLjY^+IGL#oMbG52m58A8bTEB!23u4o(^G0~+tUdqgTXm7v zb#;z`YSw$(OXL!1f(3m4t!$QJY)Q$8Vi`=JxQJ94;3J|(pEkEh<{k(D@{}#aO>EdI z=}faH^QQLev`z1BYYXDek<(Xu$%Bdtf*wcJ8l{@e%G3-HG-FEXiJ~;)YoQ`u?J16{ zeHn?w@@Hu*64XpHGDw_y;4&qRt_@C=iBj=-_mI(_h^%^F?piBtRkQ0##5hj!4%gW+Na4G>X+;{}W^il@(#_!CKur~zZ$H8s zx*|5UyodomOtd5N=&~08r5|2mZjF^??-vTgK?Kk8(W4oIGK(e-c%Hj~IT91K8AKo! z8;|3`BImb;$H+WEa^j}ME`4mU?X2c!J<-$Q zS78&(>_VU-jB8_Z^X-=CYivt^lDnaL@4POXC-|<^D(Q`BIdOL;bk(NmR*k0c6Zs-! zceTy%8?t4XO$6h>8RA3t(Q4b1yXVG6B|>jlG9>b@T$(7Vc$1EF8qxmo8mMnAV>x;O zo__h*yt#%Iaa>Z8XJGs#Ra$*+1C-SVPmY0JU~POVhkusWf@>>Ki!(IFg1_j#$i3O) z#j$=XY}aN}?XTXWa$X!lV;FzLGQIt30uG~KZ+EYvKNtycN+Z6m^0iG`3+YQ24K8mEx@Esof-8j4PKC!OY`A)Bnm2<1dS z6^X#$seZ)A*R-6I6IhfgswN|jkN+w$k371NytrBA&4J^$Lb1DdKvm5ZkE&}HM%|Q> zQnW-ixxqAJx)MaGVv>|KFcx-3f~D`bwO(pv++?U0yHI5^cRlER>}Skz^|7)@WjCq4j7swACW~in{wV(T{NIeC(K|d8Dg$wi@*WWYf+jQisJ= zgrU;vYgKo1X0BYE2*;vB35g-m~XP$Qev^z_t- z4uOYc(Y-Jpk<6oLJIZAwfunn`b7%aRa<;J@R=u+xVSn0PgMa@DY~_m#DXraLv;f>f z4n|ABt!fS}0@yKVSg%1?k#37Nt0h?-!Vvx}hLWbj!{1e#;dKyG zg&O6?B84(!vB;cxfK=R^r_tcAbm^i$sFn_#lw$Y`FHE7lOpRiv*J}=#*hCojD~$jt z`-Nl?-G5FtwGCl^r*kw|2}SedHKu@r6KRSYYUno{;Fa|69A7-2B?J;k+PJq^?z-H| ztFzQtXRMAFeCB#6yt*JzInmJ6T0ZODId_=&b(5i*K1}@*#rI%hDK3NN5_eI@M$%!5 zQLq*gZ#+q0RNpy_9F)UaP4?JiDi09KJg!hx|7PX+@h&QdTDPvFfd@&ocHl3gqwuH7 zddP7@UsRJeZK5SIMal04t-$46{X3}c%jED)bxVp`aD&qPZ2*ju!@x!xMI3s)5xjo8qP?qL@!8+q zt5-6L$XsH6!lIN@z6cDkrz~&~YXSwAN>At~4tq(%d3{*HmA7h&AY(&uAY;kFMJmq6 zoX~MmeTPZ=(Gp^MS+OjyrdP#PRCzDgt-hU|t-P$VEU(I|+{{LxP=OWmdnP4EsR^@o z7y2#AMpoNyGdQ*r(ne!O!Q$SZd<^@ubzgymhupl8jDD`4Zk%2!ma`@|y7rNnKWDUQLk7Pc320Lpr*dDEia%lQ zvzH_~*v<1&ft?Q~xzK(oXqa|o5m6={i_B%2^RXOeoC$HT)(7Cl0}X`2ZpGBJiLW_n zGm?eRe;u&8Yg|IEj`u}M%MD7&w~4f%#y=rX1+#13C0|GS4u2f_VAVhfEgfH%B8-96vwj#M0_%TQ;bj2(blh;mcUmG&YFrTxBh|FO#nYnGKf z{RkFA45dz<9>j{iBA02J&QbK`t4w8La>}deRdJP!)C?daw!X0iEB>YmJs43WRFVb| zkQaFpD;+rVJA$|B)1e&lYJn+6m$&F6ce$U2bcLqxqAJ38xrqg(xYQJBOs-kNvpYLv z_DB#MSs-x`ofBuxc*9^#awlkezv1?80}(Mzp`v)V@f*^6PdF4llEs82WMfjB-%6Jm zvGx<4B|J`-HW+X%vDE=e>PpLRpc<6A@F5OStxD&Tp4nO|qXuzlPqZ=Fut+CpNP9W~ zX0Sd|?R z9|2&w*&>ocVFr3`(L;?+rku^FIygMIB zehsN?zqAMh&ZCT^_{;1NSHTQmcwz$Rf!kWsMbU zmlHyeD7P8Lc_X_1L*()a>f~xt zy6qh5AKww0)jtlOp5THTv8BLq6^*?syGF=mf#+lAcq>8gLC#e{|4g|Q&PjK^evrmSziSIk-|v(+_5;^~{%z{Ac=b{0D_6ybJv4|Ss>4Q&gkZDAXysjFBzzme zGAHqCLwI&G+B<=%m0_L*kl=YFGsT@_qFO0Kers;OE76UFbg3grgYj>^gXmyR(Fch% zPQLJ~fb0R-0~bbs;f}`CpHg0)>O-h=ztR-BV;?$Fm5Gr!ih^?U?#uPpkgtonee=5T z@skIctlEdN1VSTMAAav+LG8AvS4z(Wv^Ob?&6V$|R}r>&wwa7!e8P&~JA^ ztp`49Rm2ri#N_iDw%|zmr$kXu;r`Y;B=TcgZY{<1TnV8{9v#?!i&0ldG z*)*k$k+0?9kYd)Q*O>%Ce|hGAkHRSLd#ls+c6jZMI=fXP-O#?t)0oSDi&rjOhwQjE z#?q5xnoia0Y@m9nQBlYM$v`*Z+*Fj-@<@M^gvREv?2VU`6V(WrnK}$H4ko&=BOg#% z`J+&R2MGB?__00b`?d8{v@k>|0f-TQfM9J5Upnk&N~hOd!|{GSc9?ZiJ`DXACFG~o zojW*KMhgnNAJ%dqj7)udG84*EoQ-D>Nr#NjF?TCG7T*dF*1(!RTk#76#Z?!XFWRif zPdX;fn#6pfdDUu(2xN|l?Kbr}-5xlH0wD>5;ike3oA9ytR%$kAMBufIKg|&0X%>gR z#faMlyEPe)oWxNgn_!?A@f;nssnKJv&AgR4B)f$C>PA&xEKf^oplorj2kJCfT4mLG zek}`1d?cJKzY7p)nHf|`pTc+1Hm$_+sG&11PF)D4R*FF2yoM=plJujY{ER_yL1(x@ z17W60l}Z00c}j0d>!H(!#P=^7kupZlpHT1Sc1(l0uacqTpSJb@K{2^+qn_h3_QPcK z=}<1RbPS55HI*g5stdRwiyU9bp?ekb$(SLyJA65<81N2s%XE>ksh1atYxOtq-%q>% z)}M-yLeu(UKj_$FVkE$~E-(zl8M3qEEJU&UJ`^#1>W5!A-kO_C`~J8dcR9VN%JsCX z`-A24detW9THXr96Xn_h!ER76lL{E%NM4n&UjFH|`C2E%V;_mV@D`dQ-}R}YV%-Ow z3IvGlpO%?28HI-|QAZi_72@%5DB_IeDKDDC`iv^xwL~;a%W7Kg;TP{3ILw;jNm9+D zRT7;#gh_x6RpI}hRL)|Gj>};Uvm-yC{GGFU-wAwi3$mG?DJY0aB1-(+f_MCeLz_k9 zG$QUqA%*cgw&#UC-4ZKT3=s;74}3XG8^x}fw`j!m_>B{|0Wu{%^38IjxQ|n1jSeK{ zw;bgie>`&On|j}+F23>WqFiz?6?wLxr}={se0LI-ni2%D#iILGOEEb_4GSS~Vt|sf zWGjFdiXl1Ynmi_jr!JA%`X1@x+9pYHx$v(q`FZ%pCpJ__L%sEulkHQ~n#FNwWN_ah z(Qv*fFQV`8ECy0`qOry83J*Gne0G)ZSQph~QWQY=|IE}%TjQQXwjMhK&Gh6GEsZRZ z)Qi_XNcVDYBJXXqApB?R=;}y~w?(pfo0nEwql8qfUr9n64uM&pdo$xHA=rkR&DP$R zGecLg1_%jF;UXbk0Uchw^#?TfFd+;hTj`?I3Zr|})N1prOFMa7mxaz`5j1$grf%2` zRLv66N&zaLbKFI|d(Yptl6MKKiT>gb-lKDw(2we}! zWI%;Y3pG|~MMQ^l5W=_JWNOVHPNsS=DR*=lVi3<((LyV7f_hF+s3^rKGfxnMN^@3-Rfh>Dx*xUY>XHMeQ2inHUwAWPQUTy1AKj?3i58z@{TOU;U9PD ziwyqzxWL7&DVt=HX{G*{g3hyXST2^%){=lS83NKjSj^5p`Q$R0tJ&97dkdFrIzH;N z>A1H8%8#{lAr5mXOfi_=uU_cbyG5aL1g}_%+o4$JJvDD;Fz@$(WP21h8$hdl0ZLc- zU0a??qejNJ&~8d5Hy!c>#icCHR%Uw%Evk*3lp@fJC-qt-?m-a`Mb<7e|_~ zojA-gOpkwWqcQ}?>>0%|%E@=FuZ{9`&W_a@Y%xhU)BHlxrpecB5qw%npT=7-RAhnP zUh)DEeQz(x-4?B9i`473 zfU>E=TJEn~pZ(60)yctuO$p1vX!;Xe!LfHEB97o}>Lg#j>q_~DYjY))xcHRRFsU9! zBqFe~_u=8=?}9Da6#t_f=Xnd-5C4V}dKo>A|G~ujkVGeZo^c+(A4dRQKb|aRkIwv{ z0$ftM?fCb#Ra~*~HkgT8;XO)Kr`o+l(UVdw#R()8$l-EO6a4QmlXSJrU$1v0iclx| zW`8^PP1UY^4o@9Jx;TViGLZxl7Az7(w1SfQ9yp>y)!2AYM#+AjFXu98o##H$*V-adC|?4^&^x3t+COQZ$_OchbP@5SNYrL2_u zh17|dR5^wO-5n_wxj@wU(wTSZranQt(FM{81)`}YU=nS>*WHYIYW-xv(M*2J5}?Ep zs-gwCLqLjWJfT!;G+n`x?v3uMT$j}ELt5D1D<=wz=&Zo)kW_ielSrF#c2067t&$uw zlT3~vjsX-1ICo%t{_XgwjRP(vIffT5s!3NoCF$|6hfhiEI4Dx~41d7*fZmhAH1S%L zk&O#w1cX1X>}_cx#DU?A%%gyQ-`!Rpe;w2%*vhoXqF3wk zOgcsC4-;T&&f&?jlakjrID?d#1S?f+0%f;i7B~ieU^giw9khS?t=K2SDu&!P#9_FW zZtmJYB+j$hNTqa^>CC(|o8@d~QJUAB!x{VRCgg?>lg$O?PCR^w%ug4hQ+xBfwIh)Wo?LUC*z5qcJ0JZiq_3p4!xiBh=FF` z>?*RJB?Rt4^HZz3EGpR>%8bJ0;SyFJt#-9e=PMZ;r#1Z|*{KQ?s`C?BNC+4J4zm;$FMrchL`4+5dS$$v5bT#oc2-8;L*x4Mw@RhQX02j*2_h+*&WX{_{ zSRJ)z6OT%!!3ce=7qpcyxl(p3@<)#CBo)8&7DuP<=wM~C9mQtS<8ktH=C>-^B_i(V zK-kf96>9^!B0I}^OWC*<%kkff zklm~rTlrLoPG^r{xj2a(5gb`M>{xj(7^`QoxEu0|!N6p92XrB)op_%@P&kzSm|1C< z*(icVF)UXQjN{_dSj(ti3lE7dU8z^wiW!RCJh=}-!|;lW$#6hb0pwOlnNSrYtIttT zdToQy@&&B>5etS%ftVY^Qgteh0~Qx3D!UbDb@{G>OB`Sr?3IA_dKClVU{Wxh1TySZ znF$77H8V1w!TQfkO% zb#Ooy-u3fWkx0h$!}b;~MSwSMU#BZ1$=@nL)y-|l;3B$T;1OE||EuDG1oDfFt=-)1 z54;mq{62|)aOWkBeapm~_->H6O_}t|R@d>8NcPgSh|In1S-8C4$W>LZ+lt{CDvOcok>w(O(*UHZ?lzsOLAXG}TD@T3xX$ z-spz9IN~k87Sw&rx^a6^N4&(u&A}MA@&jZsEJP z?M_}lalNv&^gM!X% zT9~DhsBFu=(w1dqb3JU}=|%=FdQ%Wd~T>ZlV^ZAY+Y?rkO(v+pDK7CYFXX4f9# z`>kDH*V}x;x!AsZhYIJcFK%QWolXz*~CG;&mw-5vr)JjvYru?4OW5pHCMNr7r|MRp4-%rkR%@WFJ6jL_N zvg!6M2KW_)7S{ulTcD7OJSnj@VQfz5h$>Y>3pOPx%dos=VMAWCJeAF<+f{B+J6m}x z>hagyTW~!OKLY5;f8a*gMxK1Ev_4==M z=og*lI;h*y?t5I{M_&Vws8B^ouXkh;2XlS}&vKX$9mo9m2Z;H#vc1aP9P2Ftl&((r znd2q7muuL~pE%V;O;T99>u3Lea@{(P9Zg&2RZO@>^XillEK{A#R&#KmR4NIp30BSs zoq4xwz3uj8aX$nvQ>B;1kD!3hQA@nL%O$Jz1#?X>w+fMRVwV&55*4TutuQfcn3y_q zmpw7;EeXs?<+{-KGd=;%EnW{*JK{Ab9N%Ip1s+uhQ|e>lkWitKTt;RUZ!KoI2`i`? zgmUq^b%^V65SmZ^Gs_TNoOc$(pFxq0D8Dyor@IXdp&3k|le-OUZGZ|6Lab>O8g=

        Bp!Jx~(nVUwMX2~!kP&T2 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

        `);function Ft(Be,Ee){ct(Ee,!0);let q,G=p(""),j=p(""),I=p("solo"),J=p("sync"),x=p(""),H=p(""),y=p("idle"),_=p(""),S=p(""),T=p(!1),C=p(mt([{role:"bot",content:"Ask me about installing Vestige, whether heavy models are required, Solo vs Team Pro, sync, pricing, or what happens after you join the June list."}]));const Fe=[{value:"Local",label:"SQLite memory, no hosted memory service"},{value:"MCP",label:"Claude Code, Cursor, Cline, Codex, Goose"},{value:"June",label:"Pro sync, backup, team memory early access"}],De=[{name:"Solo Pro",accent:"#22c55e",copy:"Multi-device sync, encrypted backups, managed updates, and a cleaner memory dashboard for developers living inside AI coding agents."},{name:"Team Pro",accent:"#06b6d4",copy:"Shared project memory, admin review, audit trails, PostgreSQL-backed deployments, and async support for engineering teams."}],Oe=["Private by default","Sync without lock-in","Team memory controls","Bot-assisted support"],ze=[{label:"Install",prompt:"How do I install Vestige and connect it to Claude Code?"},{label:"No 20GB?",prompt:"Do I need the Sanhedrin model or 20GB of RAM?"},{label:"Solo vs Team",prompt:"Should I choose Solo Pro or Team Pro?"},{label:"Sync",prompt:"How will Pro sync and backups work?"},{label:"Pricing",prompt:"How much will Vestige Pro cost?"},{label:"Human help",prompt:"When does a human get involved?"}];it(()=>{const t=q.getContext("2d");if(!t)return;const e=t;let r=0,i=0,m=0;const d=Array.from({length:62},(b,w)=>({x:Math.random(),y:Math.random(),vx:(Math.random()-.5)*16e-5,vy:(Math.random()-.5)*16e-5,phase:Math.random()*Math.PI*2,kind:w%5}));function M(){const b=Math.min(window.devicePixelRatio||1,2);i=window.innerWidth,m=window.innerHeight,q.width=Math.floor(i*b),q.height=Math.floor(m*b),q.style.width=`${i}px`,q.style.height=`${m}px`,e.setTransform(b,0,0,b,0,0)}function Me(b){e.clearRect(0,0,i,m);const w=e.createLinearGradient(0,0,i,m);w.addColorStop(0,"#07100f"),w.addColorStop(.45,"#0b1221"),w.addColorStop(1,"#15100a"),e.fillStyle=w,e.fillRect(0,0,i,m),e.strokeStyle="rgba(148, 163, 184, 0.08)",e.lineWidth=1;for(let n=0;n.96)&&(n.vx*=-1),(n.y<.06||n.y>.94)&&(n.vy*=-1);for(let n=0;n{cancelAnimationFrame(r),window.removeEventListener("resize",M)}});function Ne(){const t=["## Vestige Pro waitlist","",`Plan: ${a(I)}`,`Priority: ${a(J)}`,a(x).trim()?`Use case: ${a(x).trim()}`:"Use case:","","Please do not include private email addresses in this public issue."].join(` `);return`https://github.com/samvallad33/vestige/issues/new?title=${encodeURIComponent("Vestige Pro waitlist")}&body=${encodeURIComponent(t)}`}async function Ye(t){if(t.preventDefault(),c(y,"submitting"),c(_,""),a(H).trim()){c(y,"success"),c(_,"You are on the list.");return}if(!a(j).includes("@")){c(y,"error"),c(_,"Enter an email so the early-access invite can reach you.");return}a(G).trim(),a(j).trim(),a(I),a(J),a(x).trim(),new Date().toISOString();{c(y,"success"),c(_,"Email capture is ready for an endpoint. Opening the GitHub waitlist fallback with your email omitted."),window.open(Ne(),"_blank","noopener,noreferrer");return}}function Ke(t){const e=t.toLowerCase();return/(install|setup|onboard|claude|cursor|cline|codex|connect)/.test(e)?["Start with the open-source install:","1. `npm install -g vestige-mcp-server@latest`","2. Claude Code: `claude mcp add vestige vestige-mcp -s user`","3. Codex: `codex mcp add vestige -- vestige-mcp`","Then test it by asking your agent to remember a preference, opening a fresh session, and asking for that preference back."].join(` diff --git a/apps/dashboard/build/_app/immutable/nodes/20.DebghJca.js.br b/apps/dashboard/build/_app/immutable/nodes/20.DebghJca.js.br new file mode 100644 index 0000000000000000000000000000000000000000..cc2dc08b25f5b1aac8fe5ddb7cfbb96e85ba7cd0 GIT binary patch literal 5511 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 JCm3r)+yHuFv8@0A literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/20.DebghJca.js.gz b/apps/dashboard/build/_app/immutable/nodes/20.DebghJca.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..6c1b8e82e36d78302c9d835985b028ffa852f502 GIT binary patch literal 6455 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 RFxmRY{{e?cRny=>0030gzLfv~ literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/3.mK8D6pz1.js b/apps/dashboard/build/_app/immutable/nodes/3.Bu_uPddU.js similarity index 56% rename from apps/dashboard/build/_app/immutable/nodes/3.mK8D6pz1.js rename to apps/dashboard/build/_app/immutable/nodes/3.Bu_uPddU.js index 28965de..3cca1e6 100644 --- a/apps/dashboard/build/_app/immutable/nodes/3.mK8D6pz1.js +++ b/apps/dashboard/build/_app/immutable/nodes/3.Bu_uPddU.js @@ -1 +1 @@ -import"../chunks/Bzak7iHL.js";import{i as p}from"../chunks/BUoSzNdg.js";import{o as r}from"../chunks/GG5zm9kr.js";import{p as t,a}from"../chunks/CpWkWWOo.js";import{g as m}from"../chunks/D-gDZzN6.js";function g(i,o){t(o,!1),r(()=>m("/graph",{replaceState:!0})),p(),a()}export{g as component}; +import"../chunks/Bzak7iHL.js";import{i as p}from"../chunks/BUoSzNdg.js";import{o as r}from"../chunks/GG5zm9kr.js";import{p as t,a}from"../chunks/CpWkWWOo.js";import{g as m}from"../chunks/C2TQQEIa.js";function g(i,o){t(o,!1),r(()=>m("/graph",{replaceState:!0})),p(),a()}export{g as component}; diff --git a/apps/dashboard/build/_app/immutable/nodes/3.Bu_uPddU.js.br b/apps/dashboard/build/_app/immutable/nodes/3.Bu_uPddU.js.br new file mode 100644 index 0000000000000000000000000000000000000000..ca7f12cac7edc5108dfb541364cb935705dd5ab5 GIT binary patch literal 164 zcmV;V09*eXBmp30aZZ1uwyNYrs0ReM+4-3!mRT6r7I<4ESsLIg{~r0>#&CI_QWVjO zym!~6TCH(%U}|1%nKD{W*`KSbM@B-+6pHaE`yX+bq>uGVue=0{b(P(&lNtlfg?;qP z43(Ar(|*631!*@xoA1YCb6}#rcL|iTg_#dlnQma&1;EMF08;ztUZk9DJv)Z_8`AYZ SV%Y{PGk|{~&J^>I|4{*`tWg;N literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/3.Bu_uPddU.js.gz b/apps/dashboard/build/_app/immutable/nodes/3.Bu_uPddU.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..09e598a395f59283bca63ba2e82fbdc362712b91 GIT binary patch literal 197 zcmV;$06PC4iwFP!000026J^ao3xY5hfZ=<;LOpFTw1S9|Iuv0+6k_3d*wkg)H|B&; z{O_fg#Ln*nFBb~5aa`9+@=6w^x2tKfmE!CzP#8BQLsxOahD4~;j zEQ4TCi&deAQgzZ0I<|Wi7jb-rq0Krg{^a}?hKCdFWm?I^aFAApI04)k1jL?Uq7lNI ztw4^KX{vIEG@7XwO;}{8VQYKZVoVgmgd*Is_ivZL_br(;tv~qy-fPkrB>?~c6MtHf literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/3.mK8D6pz1.js.br b/apps/dashboard/build/_app/immutable/nodes/3.mK8D6pz1.js.br deleted file mode 100644 index 840c5ed9ce2d6e1e2301267de55de990d59e264d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmV;W09yYWBmp30aZZ1uwyN}mr-3t|yt!Kwje|@r= TVO%r;7b(CQ7iNli$ZU`U3Gqku diff --git a/apps/dashboard/build/_app/immutable/nodes/3.mK8D6pz1.js.gz b/apps/dashboard/build/_app/immutable/nodes/3.mK8D6pz1.js.gz deleted file mode 100644 index 3482e9c2dbfb793264218c55ac114fa53b182b71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 198 zcmV;%06G63iwFP!000026J5*WxHVZ1%ZKqt0e&d07igW AS^xk5 diff --git a/apps/dashboard/build/_app/immutable/nodes/4.DPhwyLUO.js.br b/apps/dashboard/build/_app/immutable/nodes/4.DPhwyLUO.js.br deleted file mode 100644 index 715e2abd6662c90c4ac6f2c5543d7d6028c5d80a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4437 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 b2f{h-ns&VK)pugyqegR3mc^NN5H0o(n%Sov diff --git a/apps/dashboard/build/_app/immutable/nodes/4.DPhwyLUO.js.gz b/apps/dashboard/build/_app/immutable/nodes/4.DPhwyLUO.js.gz deleted file mode 100644 index 6cf01ba109d5b61fbf7512c0615bc0a91767d7f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4976 zcmV-$6OZg4iwFP!000026U{o=a@$Cf&)Z)Cp*?CqDnbAy$~Guaq1&=8$vSMe?NG=d zP$VJZG7gcH#EAKVdD@7H*r$Ekr~Rt_lFh6t93-V~&%;KHqgw#7vhuF1tSov#93`2o zX=~0P4~Oa6?!7&H>AiWc-KKKeW1|m|WT(=I5*weVblOXzpf=^`sC6H_9wzlEF`}MO zlHzlRIQZ~^!Y;ntQ9|)KAuc{*lHub$>EnZv9zG5z$?@q@lCU|P`z0j<1|}gsf(2pr z;?Kj+pULWyH1ZFR-Amv~Iwbj~q zdolR2Sx03q8ZMxo?0hlKdxu{aPTuahfy=q=Kvmi+6h-Pf(1mQ3EW595{7dnJ=IY8e|k ziK+F9>{DxlyaPb9-OEEK^P*6?rAn$kBs9yDaOpG;x-`+e^w0~v3`ZUx(=AKi*3ER~ z0>mn2eXPxr7H4gz9qWpkOGY(g=dbz1blWhS)s!0;AU%?kF*&t#^}*{Y3o~<=nS+EX zr~K_&nCHYgqbp<5wE)tK62+&PbZP1B%dNb9xw@)8aI{0~boFvAUpcX}f%f5erP=Ok zah?v8hq0NiGN==!%AvY)LMCR9LsBnfkf}Nq7U)(&|0sn#b<(Es&kL%d#v3T%x^f3Gt*-4};_@W3`gyp1JoaNuFWX<0k0&5qKw6NpAI4_G!Uq z2Q^^qb2DFkSBtz)LTQ26+kQ{YbbF6}ORu-LyVUH~aNpDnl!6qRPs4sT0J;nDk{5x( zKgUwklej`-K<}yDgxbS4ernkyrc0J3?*NlK8yQ{3FzU)G%+0(or|rV+W6iZQ8>itU zAbF~#QJy&T#&ee}In5F;?91Szog}d*U^DhqPPNQV`ZNQqRGp`KV%3MWp66#YQMy(~ zu;^MPVYPiCR0etV<>g$&b}55dlZRA9&01*ZT0-w=l2S#T-r0$CPOXS4zil~Q;`meo z_P!;DQAlM8xJJWT?h$~-$aBHyvZ1x)&ej^A*!fK*p9Lx33+Z1^Zk8a#ckI}blPC{e zq=^uu_`9H((Qzi>pN1VegDA1&z;j(6WaRSxN_DFDdhiLhZKU2kFg6VF*|P)BpI9B? zfA#Stc<-YyUxhH~U0-s1J54Ql)ad2DFAeyk>qpK|mh8l{8@}D8K##{PM2TdVaV*_= zX>R-8J^KPyF72hAEiS3#xt3hWDNAEZZnX5j$@UJCCuk5|3xQDVmf z&so4;D~YdhO`p_Qc#jnY*2dcuDxPvz2C140*GcQc&k54k4uBL_V&-+QJ546x)uM0SO(2LeSiNZrGn8 zpuMa}tj&rK03O0i#eZwCMqtTQ_0J2jN1VWpLzZ;4jg>-feTFZYxm70Xbo>>ZupR3LXb zH&Rk;7X?eRN!~(9$K>3#cA&CRfTT)}YVTLI_m7rN&Mc%sLdu_Cp%AJJpoAnN4!Kbu zKCW7Z;Nw{ziEnikwFCPGRd!Xek#zL!4c*j9U^%M_+rbk%bfZ8~8(K?U@k!shd2*ob zDpv%{8>(EX^T_8RDNk z>m!s+FaM^LWu!_HYC$O&kUq(T>Byei&NQeo4s2(jDEq{t5Dub5OsSR7ZyvpFr*wH) zc_VgeuE_qPBKz}->}$mAs5SMB1@%-i6f#sE;5e8%;PaDK z)(iqNFR7c@qYp{chYXiO$fTLw@6%+T`u4=UM^RMLOYDHA2fiJr)HU^~ssdwI*%gtp ztCCMx0l#7Xg@Ge6aKsAZAp_THZ$*8;Wf9I6a~>9RNUW&GeG5)Ko>o~#ZNq`aSC^MV zp)(No>X!4NAVRUiTAXE8NJnr;&y)}<`B?F+jtAl7~)&L(C_*(5fT%^^I3$>b|R3jnPpBN4{w*m>(g`H!0*@1$Z`g6Ev zfLm=S4#gd%JfVH!pOqUZ0E*biEVj4wywFvAtK)-h!6M=8x**OoSTn1n&DIsHA*VQM zqQt_SH&&*NR~1JaH{eBG31=1x@nCp@!xI>u%nyr0>BHDCGt8^_n2>SPydje&q)K)! z`e1#9BNEA|HBn;a17v|7RWeG9mu%N(yWWHnW(%+=PI0Vrn9_dFZ5$~Mk)5$jV44at z5)POMz(fEN@y*wR0E#sshQt>-@BsKZ=pE#D3!-I|33gk_bu=RvHWHj|~*b0d)+N6d;oVGASVAW`WZza0#Y^0W8FVoQP^tLX*-9+PEaBwu)G{VR);)+X1FQLa1Um){38Wpu5gM^}wk z0$v&X^@4Qdosv+puTIIgQd?Gx6eZ$@zFh;Rz6Yk$$%d}3%76U*e`K>7yhg_jp)g{O z`$UG!aW(5H{$9rYSl=5oA4pDl4eiixitH>9t=mrv}_F6#jl+D9V z04ft0iyi`$V4hDf&nGDPh_6{5{W^gL6GvMw21-J61BKwQ5T0EdH93WkYFqvs23Vlk zQm=WY@Yr?*$%~YW_(ORLf;|K|eyC1B;}UY`(a~-M%6!))U3&2VxZB&ZJcZY>c>T^- zX-a_lWzkH6gWm7TZ(FW+SM)7`OM=yl5lN{gg^Ux6zb4fBf?wa8&f}I?`4=Ga&`?dr=VQ*=(x> zYLcxrJaFP9{`WV?{{OG~NKhU%MvcIg;&Eg13AA<4PJ}~aT}Rc{LAC$-@8?wGEV~K1 z6R{1sQ#CcEp6&V6MJ?xNj#EA}$TRA)w%CFt612qke+x@AOH2IofBywboJPPUa|Y=5 zfCf=A`3X~;Mj4yng;F-4QXl&+oD5B+tu(g7nc4V<*$+oLnsk*+BwOkxk?qptm;Ye@ zpg03)lt}5w13D6T2D<}NfGwUZl150Kaf9rOoz$L}P%v~VMWayAU`M!gA!5J7UjA?C zr+@qle)?>CY;D2`q_#eP!dI7+x@c{*jRdykMog)lfIYjAo$PLOM+usqhIZGdGjF5_!1$}M+KYVO3sY&?4&t`-KI&z8DjBa| zwxmD){-5<`d&(Gyn6V-7ARKw35#d!G;3V6RKoAhl4l~b@sN1J0kzDH76O^z!k#z0# zx&&?&+Z#*ZcsN5sIZX0lO-pVP#i<0f6hwlq=`BsVGq?!?|4r{4Z6g zrxM-=O@#RP5oRpsxG2Vxu@Bi0aKYMMKt<$pC(VXX;i`2JBTrfx(hc`iK;Zxsh-G{t z610e=C*u;RdLeA&5?+*XsI(+ z7go^#66e}CFzx!a#Mh}bw_FXqzL?7;C6;Qy(@IS$vx+V59W%-^yzgq@rJDfF@z~ID zVTY;5!k`OF939`l3j-`@*1$sDJj@A^4Mrfed=V) z(sR)R8@e;>Ldjc@wjHE6V-aR(7Lo7EjRSMQQ+vk3nqliIEwdt1qw_=wA+iqRP!Pn$ zXg+~EBU~-z)-vymooDwRtesKx9^QrxJl6#~&u>NsiyxQL7-9r(Y9>C#%h#~M4-KZo zN{6=0FJm~zrE(9fnn;uE$!nP%MV9dE7s3FvExdLk4mCGTxluIlmuG?Nv(}_hGU{L|Ij4~=ur#1wEBh~Je3fhTaFo-66Z zfMfcxrHpw0beluXQNak##*1TU*{4V9EC2yaaWUI`KgZ_#F~4Ite|!`_2{~V~qR5^r!m2m9sY)(*@BIuvu+M%;E?9fq!P5rB1@oT`JA0a8M;MqK zBuSKP+gd==)b3OBlKln+P=z-aeK_rTq3!#V2j+T1olbF)|KN9&U--kJ){@aKn$a7lh)Q6#3@ zwV%?cmBj~Wak~ihk@Xd#q5Mq^`hHOVwGQ4BU09v3%7v=7UF9vI%3F2S;CEi)cRA*W zRF$83JS{IPuvfc^W~#U5e=INmP>R+jrIwv3D*3>g&=maGthJ=^OUT&L(e8Rd~9lFi2n(&stbjjeaeFFJd=tOLxu!9naCy7UkQeL!Br3-U$qza$<=%pB~ z|LUMV{&s%6KDf)mj(2Gj)}|$peG8&B8EVz$n{Ppk-f(8ZV4QK3hpY!ixvqR7>CEwAfm&FdvTb-5BMXQtfl3hqp zVKTH$qNJ1?0GFrWd#@Fxu!V*NCLv)KE`MYg_SuGBd{Y^b0+tex+n6fykWSoa6w2fl z*(Dl$LpGETSSxgS`2}`skMQb;ckOc((Oe~ms)iGAU~?bJL!M*KDNg#FgtiGmmk=rEhMfB8S65(`3uF8~0^tCMR0 diff --git a/apps/dashboard/build/_app/immutable/nodes/4.DPhwyLUO.js b/apps/dashboard/build/_app/immutable/nodes/4.DYVet_v-.js similarity index 99% rename from apps/dashboard/build/_app/immutable/nodes/4.DPhwyLUO.js rename to apps/dashboard/build/_app/immutable/nodes/4.DYVet_v-.js index eb053c8..f4d960a 100644 --- a/apps/dashboard/build/_app/immutable/nodes/4.DPhwyLUO.js +++ b/apps/dashboard/build/_app/immutable/nodes/4.DYVet_v-.js @@ -1,4 +1,4 @@ -import"../chunks/Bzak7iHL.js";import{o as we,a as Ne}from"../chunks/GG5zm9kr.js";import{p as Me,s as A,c as le,aB as ve,e as y,d as p,t as L,g as e,f as Ee,u as de,r as v,a as Se,h as d,n as me}from"../chunks/CpWkWWOo.js";import{s as K,d as Ie,a as xe}from"../chunks/BlVfL1ME.js";import{i as ue}from"../chunks/B4yTwGkE.js";import{a as E,c as Fe,b as oe,f as X}from"../chunks/CHOnp4oo.js";import{s as o,r as ge}from"../chunks/A7po6GxK.js";import{b as Ge,a as Pe}from"../chunks/sZcqyNBA.js";import{a as he}from"../chunks/554JRhq6.js";import{e as ke}from"../chunks/MAY1QfFZ.js";import{e as fe,i as ye}from"../chunks/CGEBXrjl.js";import{p as W}from"../chunks/V6gjw5Ec.js";import{N as Ce}from"../chunks/CcUbQ_Wl.js";const Re=.93,Te=.05,be="#8B95A5",Le="#818cf8",Oe=140,pe=8,De=4,Ke=12;function je(s){return!Number.isFinite(s)||s<=0?0:s*Re}function Ue(s){return Number.isFinite(s)?s>=Te:!1}function Ae(s){return!Number.isFinite(s)||stypeof b=="string");M.length!==0&&u.push({source_id:N.source_id,target_ids:M})}return u.reverse()}var Qe=oe(''),We=oe(''),Xe=oe(' '),Je=oe(''),Ze=oe('');function $e(s,f){Me(f,!0);let u=W(f,"width",3,900),x=W(f,"height",3,560),N=W(f,"source",3,null),M=W(f,"neighbours",19,()=>[]),b=W(f,"liveBurstKey",3,0),S=W(f,"liveBurst",3,null);const F=22,J=14;let B=A(le([])),G=A(le([])),T=A(le([])),U=0,O=null,ne=null,Z=0;function $(n,t,c,_){U+=1;const i=U,l=b()>0&&e(B).length>0?40:0,m=c+(Math.random()-.5)*l,g=_+(Math.random()-.5)*l;d(T,[...e(T),{burstId:i,x:m,y:g,radius:F,opacity:.75},{burstId:i,x:m,y:g,radius:F,opacity:.5}],!0);const V={id:`${n.id}::${i}`,label:n.label,nodeType:"source",x:m,y:g,activation:1,isSource:!0,sourceBurstId:i},H=[],k=[],C=U*.37%(Math.PI*2),re=qe(m,g,t.length,C);t.forEach((D,ie)=>{const se=re[ie];se&&(H.push({id:`${D.id}::${i}`,label:D.label,nodeType:D.nodeType,x:se.x,y:se.y,activation:Ye(ie,t.length),isSource:!1,sourceBurstId:i}),k.push({burstId:i,sourceNodeId:V.id,targetNodeId:`${D.id}::${i}`,drawProgress:0,staggerDelay:ze(ie),framesElapsed:0}))}),d(B,[...e(B),V,...H],!0),d(G,[...e(G),...k],!0)}function q(){let n=[];for(const i of e(B)){const l=je(i.activation);Ue(l)&&n.push({...i,activation:l})}d(B,n,!0);const t=new Set(n.map(i=>i.id));let c=[];for(const i of e(G)){if(!t.has(i.sourceNodeId)||!t.has(i.targetNodeId))continue;const l=i.framesElapsed+1;let m=i.drawProgress;l>=i.staggerDelay&&(m=Math.min(1,m+1/15)),c.push({...i,framesElapsed:l,drawProgress:m})}d(G,c,!0);let _=[];for(const i of e(T)){const l=i.radius+6,m=i.opacity*.96;m<.02||l>Math.max(u(),x())||_.push({...i,radius:l,opacity:m})}d(T,_,!0),O=requestAnimationFrame(q)}function Y(){d(B,[],!0),d(G,[],!0),d(T,[],!0)}ve(()=>{if(!N())return;const n=N().id;n!==ne&&(ne=n,Y(),$(N(),M(),u()/2,x()/2))}),ve(()=>{if(!S()||b()===0||b()===Z)return;Z=b();const n=(Math.random()-.5)*120,t=(Math.random()-.5)*120;$(S().source,S().neighbours,u()/2+n,x()/2+t)}),we(()=>{O=requestAnimationFrame(q)}),Ne(()=>{O!==null&&cancelAnimationFrame(O)});function ce(n,t){return Ve(n,t)}function ee(n){const t=e(B).find(l=>l.id===n.sourceNodeId),c=e(B).find(l=>l.id===n.targetNodeId);if(!t||!c)return null;const _=t.x+(c.x-t.x)*n.drawProgress,i=t.y+(c.y-t.y)*n.drawProgress;return{x1:t.x,y1:t.y,x2:_,y2:i}}var P=Ze(),te=y(p(P));fe(te,17,()=>e(T),ye,(n,t)=>{var c=Qe();L(()=>{o(c,"cx",e(t).x),o(c,"cy",e(t).y),o(c,"r",e(t).radius),o(c,"opacity",e(t).opacity)}),E(n,c)});var j=y(te);fe(j,17,()=>e(G),ye,(n,t)=>{const c=de(()=>ee(e(t)));var _=Fe(),i=Ee(_);{var l=m=>{var g=We();L(()=>{o(g,"x1",e(c).x1),o(g,"y1",e(c).y1),o(g,"x2",e(c).x2),o(g,"y2",e(c).y2),o(g,"opacity",.35*e(t).drawProgress)}),E(m,g)};ue(i,m=>{e(c)&&m(l)})}E(n,_)});var z=y(j);fe(z,17,()=>e(B),n=>n.id,(n,t)=>{const c=de(()=>ce(e(t).nodeType,e(t).isSource)),_=de(()=>e(t).isSource?F*(.7+.3*e(t).activation):J*(.5+.8*e(t).activation));var i=Je(),l=p(i),m=y(l),g=y(m),V=y(g);{var H=k=>{var C=Xe(),re=p(C,!0);v(C),L(D=>{o(C,"x",e(t).x),o(C,"y",e(t).y+e(_)+18),o(C,"opacity",.9*e(t).activation),K(re,D)},[()=>e(t).label.length>40?e(t).label.slice(0,40)+"…":e(t).label]),E(k,C)};ue(V,k=>{e(t).isSource&&e(t).label&&k(H)})}v(i),L(k=>{o(i,"opacity",k),o(l,"cx",e(t).x),o(l,"cy",e(t).y),o(l,"r",e(_)*1.9),o(l,"fill",e(c)),o(l,"opacity",.18*e(t).activation),o(m,"cx",e(t).x),o(m,"cy",e(t).y),o(m,"r",e(_)),o(m,"fill",e(c)),o(g,"cx",e(t).x-e(_)*.3),o(g,"cy",e(t).y-e(_)*.3),o(g,"r",e(_)*.35),o(g,"opacity",.35*e(t).activation)},[()=>Math.min(1,e(t).activation*1.25)]),E(n,i)}),v(P),L(()=>{o(P,"width",u()),o(P,"height",x()),o(P,"viewBox",`0 0 ${u()??""} ${x()??""}`)}),E(s,P),Se()}var et=X('

        Computing activation...

        '),tt=X('

        Activation failed

        '),rt=X(`

        No matching memory

        Nothing in the graph matches . Try a broader +import"../chunks/Bzak7iHL.js";import{o as we,a as Ne}from"../chunks/GG5zm9kr.js";import{p as Me,s as A,c as le,aB as ve,e as y,d as p,t as L,g as e,f as Ee,u as de,r as v,a as Se,h as d,n as me}from"../chunks/CpWkWWOo.js";import{s as K,d as Ie,a as xe}from"../chunks/BlVfL1ME.js";import{i as ue}from"../chunks/B4yTwGkE.js";import{a as E,c as Fe,b as oe,f as X}from"../chunks/CHOnp4oo.js";import{s as o,r as ge}from"../chunks/A7po6GxK.js";import{b as Ge,a as Pe}from"../chunks/sZcqyNBA.js";import{a as he}from"../chunks/B7CfdQuM.js";import{e as ke}from"../chunks/MAY1QfFZ.js";import{e as fe,i as ye}from"../chunks/CGEBXrjl.js";import{p as W}from"../chunks/V6gjw5Ec.js";import{N as Ce}from"../chunks/CcUbQ_Wl.js";const Re=.93,Te=.05,be="#8B95A5",Le="#818cf8",Oe=140,pe=8,De=4,Ke=12;function je(s){return!Number.isFinite(s)||s<=0?0:s*Re}function Ue(s){return Number.isFinite(s)?s>=Te:!1}function Ae(s){return!Number.isFinite(s)||stypeof b=="string");M.length!==0&&u.push({source_id:N.source_id,target_ids:M})}return u.reverse()}var Qe=oe(''),We=oe(''),Xe=oe(' '),Je=oe(''),Ze=oe('');function $e(s,f){Me(f,!0);let u=W(f,"width",3,900),x=W(f,"height",3,560),N=W(f,"source",3,null),M=W(f,"neighbours",19,()=>[]),b=W(f,"liveBurstKey",3,0),S=W(f,"liveBurst",3,null);const F=22,J=14;let B=A(le([])),G=A(le([])),T=A(le([])),U=0,O=null,ne=null,Z=0;function $(n,t,c,_){U+=1;const i=U,l=b()>0&&e(B).length>0?40:0,m=c+(Math.random()-.5)*l,g=_+(Math.random()-.5)*l;d(T,[...e(T),{burstId:i,x:m,y:g,radius:F,opacity:.75},{burstId:i,x:m,y:g,radius:F,opacity:.5}],!0);const V={id:`${n.id}::${i}`,label:n.label,nodeType:"source",x:m,y:g,activation:1,isSource:!0,sourceBurstId:i},H=[],k=[],C=U*.37%(Math.PI*2),re=qe(m,g,t.length,C);t.forEach((D,ie)=>{const se=re[ie];se&&(H.push({id:`${D.id}::${i}`,label:D.label,nodeType:D.nodeType,x:se.x,y:se.y,activation:Ye(ie,t.length),isSource:!1,sourceBurstId:i}),k.push({burstId:i,sourceNodeId:V.id,targetNodeId:`${D.id}::${i}`,drawProgress:0,staggerDelay:ze(ie),framesElapsed:0}))}),d(B,[...e(B),V,...H],!0),d(G,[...e(G),...k],!0)}function q(){let n=[];for(const i of e(B)){const l=je(i.activation);Ue(l)&&n.push({...i,activation:l})}d(B,n,!0);const t=new Set(n.map(i=>i.id));let c=[];for(const i of e(G)){if(!t.has(i.sourceNodeId)||!t.has(i.targetNodeId))continue;const l=i.framesElapsed+1;let m=i.drawProgress;l>=i.staggerDelay&&(m=Math.min(1,m+1/15)),c.push({...i,framesElapsed:l,drawProgress:m})}d(G,c,!0);let _=[];for(const i of e(T)){const l=i.radius+6,m=i.opacity*.96;m<.02||l>Math.max(u(),x())||_.push({...i,radius:l,opacity:m})}d(T,_,!0),O=requestAnimationFrame(q)}function Y(){d(B,[],!0),d(G,[],!0),d(T,[],!0)}ve(()=>{if(!N())return;const n=N().id;n!==ne&&(ne=n,Y(),$(N(),M(),u()/2,x()/2))}),ve(()=>{if(!S()||b()===0||b()===Z)return;Z=b();const n=(Math.random()-.5)*120,t=(Math.random()-.5)*120;$(S().source,S().neighbours,u()/2+n,x()/2+t)}),we(()=>{O=requestAnimationFrame(q)}),Ne(()=>{O!==null&&cancelAnimationFrame(O)});function ce(n,t){return Ve(n,t)}function ee(n){const t=e(B).find(l=>l.id===n.sourceNodeId),c=e(B).find(l=>l.id===n.targetNodeId);if(!t||!c)return null;const _=t.x+(c.x-t.x)*n.drawProgress,i=t.y+(c.y-t.y)*n.drawProgress;return{x1:t.x,y1:t.y,x2:_,y2:i}}var P=Ze(),te=y(p(P));fe(te,17,()=>e(T),ye,(n,t)=>{var c=Qe();L(()=>{o(c,"cx",e(t).x),o(c,"cy",e(t).y),o(c,"r",e(t).radius),o(c,"opacity",e(t).opacity)}),E(n,c)});var j=y(te);fe(j,17,()=>e(G),ye,(n,t)=>{const c=de(()=>ee(e(t)));var _=Fe(),i=Ee(_);{var l=m=>{var g=We();L(()=>{o(g,"x1",e(c).x1),o(g,"y1",e(c).y1),o(g,"x2",e(c).x2),o(g,"y2",e(c).y2),o(g,"opacity",.35*e(t).drawProgress)}),E(m,g)};ue(i,m=>{e(c)&&m(l)})}E(n,_)});var z=y(j);fe(z,17,()=>e(B),n=>n.id,(n,t)=>{const c=de(()=>ce(e(t).nodeType,e(t).isSource)),_=de(()=>e(t).isSource?F*(.7+.3*e(t).activation):J*(.5+.8*e(t).activation));var i=Je(),l=p(i),m=y(l),g=y(m),V=y(g);{var H=k=>{var C=Xe(),re=p(C,!0);v(C),L(D=>{o(C,"x",e(t).x),o(C,"y",e(t).y+e(_)+18),o(C,"opacity",.9*e(t).activation),K(re,D)},[()=>e(t).label.length>40?e(t).label.slice(0,40)+"…":e(t).label]),E(k,C)};ue(V,k=>{e(t).isSource&&e(t).label&&k(H)})}v(i),L(k=>{o(i,"opacity",k),o(l,"cx",e(t).x),o(l,"cy",e(t).y),o(l,"r",e(_)*1.9),o(l,"fill",e(c)),o(l,"opacity",.18*e(t).activation),o(m,"cx",e(t).x),o(m,"cy",e(t).y),o(m,"r",e(_)),o(m,"fill",e(c)),o(g,"cx",e(t).x-e(_)*.3),o(g,"cy",e(t).y-e(_)*.3),o(g,"r",e(_)*.35),o(g,"opacity",.35*e(t).activation)},[()=>Math.min(1,e(t).activation*1.25)]),E(n,i)}),v(P),L(()=>{o(P,"width",u()),o(P,"height",x()),o(P,"viewBox",`0 0 ${u()??""} ${x()??""}`)}),E(s,P),Se()}var et=X('

        Computing activation...

        '),tt=X('

        Activation failed

        '),rt=X(`

        No matching memory

        Nothing in the graph matches . Try a broader query or switch on live mode to watch the engine fire its own bursts.

        `),it=X(`

        Waiting for activation

        Seed a burst with the search bar above, or enable live mode to overlay bursts from the cognitive engine as they happen.

        `),st=X('
        Seed

        '),at=X(`

        Spreading Activation

        Collins & Loftus 1975 — activation spreads from a seed memory to diff --git a/apps/dashboard/build/_app/immutable/nodes/4.DYVet_v-.js.br b/apps/dashboard/build/_app/immutable/nodes/4.DYVet_v-.js.br new file mode 100644 index 0000000000000000000000000000000000000000..48a22efb5df1a6e401bed6f822d6924c94975f1b GIT binary patch literal 4439 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 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/4.DYVet_v-.js.gz b/apps/dashboard/build/_app/immutable/nodes/4.DYVet_v-.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..7edd3c0a04d27cae3e389c57ac4b3e2fad04e196 GIT binary patch literal 4975 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 literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/6.BD0AetaD.js b/apps/dashboard/build/_app/immutable/nodes/6.54m-BxV_.js similarity index 99% rename from apps/dashboard/build/_app/immutable/nodes/6.BD0AetaD.js rename to apps/dashboard/build/_app/immutable/nodes/6.54m-BxV_.js index 8d4e000..77162f8 100644 --- a/apps/dashboard/build/_app/immutable/nodes/6.BD0AetaD.js +++ b/apps/dashboard/build/_app/immutable/nodes/6.54m-BxV_.js @@ -1,4 +1,4 @@ -import"../chunks/Bzak7iHL.js";import{p as qe,d as a,r as t,e as i,g as e,f as he,u as b,t as R,a as Se,n as X,h as de,s as be,W as Ge,aG as Ae}from"../chunks/CpWkWWOo.js";import{s as x,d as Ye,a as pe}from"../chunks/BlVfL1ME.js";import{c as Fe,a as m,f as _,b as Ve,t as Ie}from"../chunks/CHOnp4oo.js";import{i as j}from"../chunks/B4yTwGkE.js";import{e as ge}from"../chunks/CGEBXrjl.js";import{h as We}from"../chunks/C4h_mRt2.js";import{s as A,r as Be,a as Xe}from"../chunks/A7po6GxK.js";import{s as _e}from"../chunks/aVbAZ-t7.js";import{a as ze}from"../chunks/554JRhq6.js";import{s as ae}from"../chunks/Cx-f-Pzo.js";import{p as Ue}from"../chunks/V6gjw5Ec.js";import{b as Je}from"../chunks/DGcYlAAw.js";const Te=5,je=["Replay","Cross-reference","Strengthen","Prune","Transfer"];function Oe(v){if(!Number.isFinite(v))return 1;const n=Math.floor(v);return n<1?1:n>Te?Te:n}const Ke=.3,Qe=.7;function Ze(v){const n=ye(v);return n>Qe?"high":n1?1:v}function $e(v){return v==null||!Number.isFinite(v)||v<0?"0ms":v<1e3?`${Math.round(v)}ms`:`${(v/1e3).toFixed(2)}s`}function et(v){const n=ye(v);return`${Math.round(n*100)}%`}function tt(v,n=""){return`${n}/memories/${v}`}function st(v,n=2){return!v||v.length===0?[]:v.slice(0,Math.max(0,n))}function at(v,n=2){return v?Math.max(0,v.length-n):0}function rt(v){return v?v.length>8?v.slice(0,8):v:""}var nt=_('

        Episodic hippocampus
        Semantic cortex
        ',1),it=Ve(''),vt=_('
        '),lt=_(''),ot=_('Replaying memories'),ct=_('New connections found: '),dt=_('Strengthened: '),ut=_('Compressed: '),ft=_('Connections persisted: Insights: ',1),mt=_('
        ');function pt(v,n){qe(n,!0);const N=[{num:1,name:"Replay",color:"#818cf8",desc:"Hippocampal replay: tagged memories surface for consolidation."},{num:2,name:"Cross-reference",color:"#a855f7",desc:"Semantic proximity check — new edges discovered across memories."},{num:3,name:"Strengthen",color:"#c084fc",desc:"Co-activated memories strengthen; FSRS stability grows."},{num:4,name:"Prune",color:"#ef4444",desc:"Low-retention redundant memories compressed or released."},{num:5,name:"Transfer",color:"#10b981",desc:"Episodic → semantic consolidation (hippocampus → cortex)."}];let l=b(()=>Oe(n.stage)),f=b(()=>N[e(l)-1]),q=b(()=>{if(!n.dreamResult)return 8;const s=n.dreamResult.memoriesReplayed??8;return Math.max(6,Math.min(12,s))}),re=b(()=>{var r;if(!n.dreamResult)return 5;const s=((r=n.dreamResult.stats)==null?void 0:r.newConnectionsFound)??5;return Math.max(3,Math.min(e(q),s))}),z=b(()=>{var r;if(!n.dreamResult)return Math.ceil(e(q)*.5);const s=((r=n.dreamResult.stats)==null?void 0:r.memoriesStrengthened)??Math.ceil(e(q)*.5);return Math.max(1,Math.min(e(q),s))}),ne=b(()=>{var r;if(!n.dreamResult)return Math.ceil(e(q)*.25);const s=((r=n.dreamResult.stats)==null?void 0:r.memoriesCompressed)??Math.ceil(e(q)*.25);return Math.max(1,Math.min(Math.floor(e(q)/2),s))});function C(s,r=0){const d=Math.sin((s+1)*9301+49297+r*233)*233280;return d-Math.floor(d)}let U=b(()=>{const s=[],r=Math.ceil(Math.sqrt(e(q))),d=Math.ceil(e(q)/r);for(let c=0;c{const s=[],r=e(U).length;for(let d=0;d{var r=nt();X(4),m(s,r)};j(le,s=>{e(l)===5&&s(oe)})}var ee=i(le,2);ge(ee,23,()=>e(L),(s,r)=>s.a+"-"+s.b+"-"+r,(s,r,d)=>{const c=b(()=>e(U)[e(r).a]),p=b(()=>e(U)[e(r).b]);var u=Fe(),k=he(u);{var w=g=>{const M=b(()=>I(e(c))),h=b(()=>F(e(c))),V=b(()=>I(e(p))),ke=b(()=>F(e(p)));var E=it();R(()=>{A(E,"x1",e(M)),A(E,"y1",e(h)),A(E,"x2",e(V)),A(E,"y2",e(ke)),A(E,"stroke",e(f).color),A(E,"stroke-width",e(l)===2?.25:e(l)===3?.35:.2),A(E,"stroke-opacity",e(l)<2?0:e(l)===4?.25:e(l)===5?.15:.6),A(E,"stroke-dasharray",e(l)===2?"1.2 0.8":"none"),ae(E,`--edge-delay: ${e(d)*80}ms`)}),m(g,E)};j(k,g=>{e(c)&&e(p)&&g(w)})}m(s,u)}),t(ee);var S=i(ee,2);ge(S,17,()=>e(U),s=>s.id,(s,r)=>{var d=vt();let c;R((p,u,k,w,g)=>{c=_e(d,1,"memory-card svelte-1cq1ntk",null,c,{"is-pulsing":e(l)===3&&e(r).strengthened,"is-pruning":e(l)===4&&e(r).pruned,"is-transferring":e(l)===5,"semantic-side":e(l)===5&&e(r).transferIsSemantic}),ae(d,` +import"../chunks/Bzak7iHL.js";import{p as qe,d as a,r as t,e as i,g as e,f as he,u as b,t as R,a as Se,n as X,h as de,s as be,W as Ge,aG as Ae}from"../chunks/CpWkWWOo.js";import{s as x,d as Ye,a as pe}from"../chunks/BlVfL1ME.js";import{c as Fe,a as m,f as _,b as Ve,t as Ie}from"../chunks/CHOnp4oo.js";import{i as j}from"../chunks/B4yTwGkE.js";import{e as ge}from"../chunks/CGEBXrjl.js";import{h as We}from"../chunks/C4h_mRt2.js";import{s as A,r as Be,a as Xe}from"../chunks/A7po6GxK.js";import{s as _e}from"../chunks/aVbAZ-t7.js";import{a as ze}from"../chunks/B7CfdQuM.js";import{s as ae}from"../chunks/Cx-f-Pzo.js";import{p as Ue}from"../chunks/V6gjw5Ec.js";import{b as Je}from"../chunks/D8UfWY0j.js";const Te=5,je=["Replay","Cross-reference","Strengthen","Prune","Transfer"];function Oe(v){if(!Number.isFinite(v))return 1;const n=Math.floor(v);return n<1?1:n>Te?Te:n}const Ke=.3,Qe=.7;function Ze(v){const n=ye(v);return n>Qe?"high":n1?1:v}function $e(v){return v==null||!Number.isFinite(v)||v<0?"0ms":v<1e3?`${Math.round(v)}ms`:`${(v/1e3).toFixed(2)}s`}function et(v){const n=ye(v);return`${Math.round(n*100)}%`}function tt(v,n=""){return`${n}/memories/${v}`}function st(v,n=2){return!v||v.length===0?[]:v.slice(0,Math.max(0,n))}function at(v,n=2){return v?Math.max(0,v.length-n):0}function rt(v){return v?v.length>8?v.slice(0,8):v:""}var nt=_('
        Episodic hippocampus
        Semantic cortex
        ',1),it=Ve(''),vt=_('
        '),lt=_(''),ot=_('Replaying memories'),ct=_('New connections found: '),dt=_('Strengthened: '),ut=_('Compressed: '),ft=_('Connections persisted: Insights: ',1),mt=_('
        ');function pt(v,n){qe(n,!0);const N=[{num:1,name:"Replay",color:"#818cf8",desc:"Hippocampal replay: tagged memories surface for consolidation."},{num:2,name:"Cross-reference",color:"#a855f7",desc:"Semantic proximity check — new edges discovered across memories."},{num:3,name:"Strengthen",color:"#c084fc",desc:"Co-activated memories strengthen; FSRS stability grows."},{num:4,name:"Prune",color:"#ef4444",desc:"Low-retention redundant memories compressed or released."},{num:5,name:"Transfer",color:"#10b981",desc:"Episodic → semantic consolidation (hippocampus → cortex)."}];let l=b(()=>Oe(n.stage)),f=b(()=>N[e(l)-1]),q=b(()=>{if(!n.dreamResult)return 8;const s=n.dreamResult.memoriesReplayed??8;return Math.max(6,Math.min(12,s))}),re=b(()=>{var r;if(!n.dreamResult)return 5;const s=((r=n.dreamResult.stats)==null?void 0:r.newConnectionsFound)??5;return Math.max(3,Math.min(e(q),s))}),z=b(()=>{var r;if(!n.dreamResult)return Math.ceil(e(q)*.5);const s=((r=n.dreamResult.stats)==null?void 0:r.memoriesStrengthened)??Math.ceil(e(q)*.5);return Math.max(1,Math.min(e(q),s))}),ne=b(()=>{var r;if(!n.dreamResult)return Math.ceil(e(q)*.25);const s=((r=n.dreamResult.stats)==null?void 0:r.memoriesCompressed)??Math.ceil(e(q)*.25);return Math.max(1,Math.min(Math.floor(e(q)/2),s))});function C(s,r=0){const d=Math.sin((s+1)*9301+49297+r*233)*233280;return d-Math.floor(d)}let U=b(()=>{const s=[],r=Math.ceil(Math.sqrt(e(q))),d=Math.ceil(e(q)/r);for(let c=0;c{const s=[],r=e(U).length;for(let d=0;d{var r=nt();X(4),m(s,r)};j(le,s=>{e(l)===5&&s(oe)})}var ee=i(le,2);ge(ee,23,()=>e(L),(s,r)=>s.a+"-"+s.b+"-"+r,(s,r,d)=>{const c=b(()=>e(U)[e(r).a]),p=b(()=>e(U)[e(r).b]);var u=Fe(),k=he(u);{var w=g=>{const M=b(()=>I(e(c))),h=b(()=>F(e(c))),V=b(()=>I(e(p))),ke=b(()=>F(e(p)));var E=it();R(()=>{A(E,"x1",e(M)),A(E,"y1",e(h)),A(E,"x2",e(V)),A(E,"y2",e(ke)),A(E,"stroke",e(f).color),A(E,"stroke-width",e(l)===2?.25:e(l)===3?.35:.2),A(E,"stroke-opacity",e(l)<2?0:e(l)===4?.25:e(l)===5?.15:.6),A(E,"stroke-dasharray",e(l)===2?"1.2 0.8":"none"),ae(E,`--edge-delay: ${e(d)*80}ms`)}),m(g,E)};j(k,g=>{e(c)&&e(p)&&g(w)})}m(s,u)}),t(ee);var S=i(ee,2);ge(S,17,()=>e(U),s=>s.id,(s,r)=>{var d=vt();let c;R((p,u,k,w,g)=>{c=_e(d,1,"memory-card svelte-1cq1ntk",null,c,{"is-pulsing":e(l)===3&&e(r).strengthened,"is-pruning":e(l)===4&&e(r).pruned,"is-transferring":e(l)===5,"semantic-side":e(l)===5&&e(r).transferIsSemantic}),ae(d,` left: ${p??""}%; top: ${u??""}%; opacity: ${k??""}; diff --git a/apps/dashboard/build/_app/immutable/nodes/6.54m-BxV_.js.br b/apps/dashboard/build/_app/immutable/nodes/6.54m-BxV_.js.br new file mode 100644 index 0000000000000000000000000000000000000000..0dc56f06fbcc54e4cf5c8f4de515303ebfbe198e GIT binary patch literal 5620 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 Ol-O)e?w~0BpWXo-ogZKT literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/6.54m-BxV_.js.gz b/apps/dashboard/build/_app/immutable/nodes/6.54m-BxV_.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..9a8e1e669443783fb9d2c2cf858079039e6f6b5f GIT binary patch literal 6334 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 Tei4@4?gJ$bo0mH%O7H9)Sm*+? diff --git a/apps/dashboard/build/_app/immutable/nodes/6.BD0AetaD.js.gz b/apps/dashboard/build/_app/immutable/nodes/6.BD0AetaD.js.gz deleted file mode 100644 index b1295da2122839f763decab437564110920843bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6335 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 BOIrW{ diff --git a/apps/dashboard/build/_app/immutable/nodes/8.CokrlgDp.js.br b/apps/dashboard/build/_app/immutable/nodes/8.CokrlgDp.js.br deleted file mode 100644 index 87e1326543b67dbb29444ac8c2387906b9d2e1ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3017 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 N?tkeSwP?~M005}3wtoNs diff --git a/apps/dashboard/build/_app/immutable/nodes/8.CokrlgDp.js b/apps/dashboard/build/_app/immutable/nodes/8.DGKslLJe.js similarity index 99% rename from apps/dashboard/build/_app/immutable/nodes/8.CokrlgDp.js rename to apps/dashboard/build/_app/immutable/nodes/8.DGKslLJe.js index 33dba0f..d57b207 100644 --- a/apps/dashboard/build/_app/immutable/nodes/8.CokrlgDp.js +++ b/apps/dashboard/build/_app/immutable/nodes/8.DGKslLJe.js @@ -1,4 +1,4 @@ -import"../chunks/Bzak7iHL.js";import{p as ze,s as I,c as Ae,g as e,a as Pe,d as r,e as a,h as b,r as t,i as Qe,t as y,f as ge,u as se,j as qe}from"../chunks/CpWkWWOo.js";import{d as Be,a as q,s as o}from"../chunks/BlVfL1ME.js";import{a as c,f as m,c as De}from"../chunks/CHOnp4oo.js";import{i as k}from"../chunks/B4yTwGkE.js";import{e as ie,i as ne}from"../chunks/CGEBXrjl.js";import{r as ye}from"../chunks/A7po6GxK.js";import{s as oe}from"../chunks/aVbAZ-t7.js";import{s as Ke}from"../chunks/Cx-f-Pzo.js";import{b as de}from"../chunks/sZcqyNBA.js";import{a as X}from"../chunks/554JRhq6.js";var Re=m(''),Ue=m('
        Source

        '),Ve=m('
        Target

        '),Ge=m(`
        Target Memory
        '),Ue=m('
        Source

        '),Ve=m('
        Target

        '),Ge=m(`
        Target Memory
        `,1),He=m('

        '),Je=m(' '),Le=m(" "),We=m(" "),Xe=m(" "),Ye=m(' '),Ze=m('

        '),et=m('

        '),tt=m('

        No connections found for this query.

        '),rt=m('
        '),at=m('
        '),st=m('
        '),it=m(`

        Explore Connections

        Source Memory

        Importance Scorer

        4-channel neuroscience scoring: novelty, arousal, reward, attention

        `);function ft(he,we){ze(we,!0);let V=I(""),G=I(""),F=I(null),C=I(null),B=I(Ae([])),$=I("associations"),O=I(!1),H=I(""),D=I(null);const le={associations:{icon:"◎",desc:"Spreading activation — find related memories via graph traversal"},chains:{icon:"⟿",desc:"Build reasoning path from source to target memory"},bridges:{icon:"⬡",desc:"Find connecting memories between two concepts"}};async function ve(){if(e(V).trim()){b(O,!0);try{const s=await X.search(e(V),1);s.results.length>0&&(b(F,s.results[0],!0),await Y())}catch{}finally{b(O,!1)}}}async function pe(){if(e(G).trim()){b(O,!0);try{const s=await X.search(e(G),1);s.results.length>0&&(b(C,s.results[0],!0),e(F)&&await Y())}catch{}finally{b(O,!1)}}}async function Y(){if(e(F)){b(O,!0);try{const s=(e($)==="chains"||e($)==="bridges")&&e(C)?e(C).id:void 0,i=await X.explore(e(F).id,e($),s);b(B,i.results||i.nodes||i.chain||i.bridges||[],!0)}catch{b(B,[],!0)}finally{b(O,!1)}}}async function ke(){e(H).trim()&&b(D,await X.importance(e(H)),!0)}function Se(s){b($,s,!0),e(F)&&Y()}var Z=it(),ee=a(r(Z),2);ie(ee,20,()=>["associations","chains","bridges"],ne,(s,i)=>{var d=Re(),_=r(d),h=r(_,!0);t(_);var f=a(_,2),p=r(f,!0);t(f);var n=a(f,2),g=r(n,!0);t(n),t(d),y(w=>{oe(d,1,`flex flex-col items-center gap-1 p-3 rounded-xl text-sm transition diff --git a/apps/dashboard/build/_app/immutable/nodes/8.DGKslLJe.js.br b/apps/dashboard/build/_app/immutable/nodes/8.DGKslLJe.js.br new file mode 100644 index 0000000000000000000000000000000000000000..94fe0cd3cf28f4bec210c7bcd35f575f282e2131 GIT binary patch literal 3012 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 GJ@{`HYSM%N literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/immutable/nodes/8.DGKslLJe.js.gz b/apps/dashboard/build/_app/immutable/nodes/8.DGKslLJe.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..57e055d17a0df59a3cd1f3b0ee6bfb9697be84d4 GIT binary patch literal 3485 zcmV;O4Px>iiwFP!000026U|!NZrex_ect&BhRArxou(|=&SYRk4s1tu65k`oPHY%9 zMYhD2DUuaIFnb*j3W3F}8; z%=JoT+40igHd)@fw{M@b*ZY-TqSu*_K170tME!i3m5qjI;wtn%IF z)`z&~mzN0tjAo{8K99nmc87cAsdB3`Q|+_%=7q(d&rIE$1u(Qa*75zs?%Fujotc_k zIG;v`TbnZ;{4nE)=i43kBs~x_@9bE6M;m?PhZpUX^Dx+WkwkW&Ili4F4V}{=w}!sH zp}knf=P;JVoiN~5pSmpVFPb7WT-K`5@JbWk`zfcc{OZtv)3{jqVp(DM!6fe`D3{%3 znj&je>*7}}4%5J;E&$V>w8Pk?v6YMhJ4)#CN>$$|FPbs0CR$xT9BBQvRnyWaqOoHq zRO7Mj+_Io+4Va6#T45SH^u;ph1B}sx&ZIB(;fL5k1Ro{C9iI-ht{qt`TAy3B$}?@g zCv@rXDeskBg2v@1c;)QdyyC{x?tj@QV%k@Ea|@WEVYhQ?>)M9BPfMRec_p z6SZa5*CyC2ccvZCei)DDP*_1LP$*DyHwczl5T#t>qliicx)%9>%L{#QWJ7OJJ9a#P z5Nq56KTGR(bt#3 zJ2Ibhu1@YEW9QTk3guJW%ve_1mlxgv@?6(y8IiuR!vZ(2DP`VhFP?1NkeW$e&*W37 zFd@{RbGppQAs-IZfc0%ottj;&T_AfP_P_n>A9;qzJjmJlR@y7G3!H+v0Jf^r!Ckw` z_F51Rlf?mfi^ZkKO42s>X*n<=7hoTK5CXZm$cxn? zUK0#1$E<8%VEv?d@Hf-jNqrwZlym&qoSL4cc?p3EXD>}S>x{CWBDE4PX2Gph#gYX6 z*K>kQT`!sxmFIFDo-rB{!Pmw`UyMjhU
        nS zWW%YNkUz1-uvKTFfs3fxDc%bHx=!PFHX50YKiX;(*MkL{$l8tBqhvwDkuCg|mZSJv zCNhU|r_k_O-_Dj}=sFe>S!LlHasRUe;8M$hV8^0HPdDsSm8FejU9%j|h7|DOI-JH~ z;xLL@63_zIfORc^{rh}GG#i|f*gnx>I{t+=?+Gk zq(~?Z6!56?lDX*rOU6H4k@&dt?7k(mpK8Pf#Hdzq1cn5002%qcT;h1$DPq~2fB z91CLPRGn@tZp?Zo4MZW-I^6Im8Bp`#o*Dy6o>a}c54V-G#v4P2R&rO3J1_3Ef`tiuVOKtDwr59KB64-5qBI`r5& zacSbL>#Yd3=K?!58}QzVdD?Hk{8Q^dEF2PxSG)ZUea-Ef2*VHOvRrF{p87R(Q<%hG{;ujUy2g9*-WR*OG=kuo>4r zR1$Fri1~2esV5a6cIxw_;?tnZy^ZS9lF>GHNG`anUZFA~6?_E!W5?!>_b>)`+P*)M z=4$46Je~p<<=}R|5!~+Qz-`ZhqsET8wDdb5e#{W=EPw{0r)Hzk&?O=C$H(k}3aSo< zsj+Ro#E%Md*Y84T3aW(VyHW?NFai?@DjpsydoL2qQn|F$CNs=wJmBS=#{4=DR~)OHpaJv7Y)V@ zct{(z5gQjKSuyJj^iZ-=C5GA9xSY&wlDUxNuDc=uB}PIR%zi+fZsQ%`CD)DEa82UD za4jQZT$|$6WCx60gC!DytfOQdDGNZ>L0K1MfszGqyFgtdV*oZnYPh6EZi-tMG;Xua zD|9_@rc56dcuTRfu}{9$(&V+X*=KM^;IE2EneGS0?#n=nnk4 zg<2%y1>t5u0S5x&nq%}ErP8w;V~l|XsSG!#7;o|xJng`w5jEb*sXHiti(KF+0VP~1 z8KQ)vlDdfXDQzSw?5yz~!|n>zOlTGqP%(6+0uRJ4$~qwPzJdaI{5||&NCIO(?vZRE zuxKFNDAE#B?-Uwm>C&605BD!$>iYP5DDH2%EDuS`YhSY_)TuDDOb6meQhLoTuWO^mWDFyF~6zikQhK0+XmR+_hUDm~@6&Zsb zyf!l*)z#ir_C#6s1R#w>*a9i(f+Ubpi)6-##{=bZY5u;ED(lV08Co9-b4?MjJy1DR z(HP3r2Z$bJEs!0UWD|y#n$nU}PGL$5ryPUq6a}Yf{s2FkB48(^Cj+)ePB1!~L=@U` zz>YCsz0U+}`||(iH#Zv9yGzB?J^gLL_Q91Yus=*d?i1&ekr$Z5Q{DO6-#2>qexcLE|+_yCV95i2eY=*TwL4F>-;3obbnh+{mjmb~h!b zKudokicLfU2$WY+PPvgKu+mHJVHlwL0jlpx?xbM9t4^Jitkjg-woGxVG|7LFQ6(ZoSBWwrPPh zUxGk;InZqc+AfmusEqXEmuXeJ-<%=WcFFqWG=y*@AaI~FWY(rCzM1mlTseXkTASoR zHV5fcrr)F6F#S}wE*w~Xf2QqVLsicDPATg-WPM!;0JKXYf%(XM8NuBFl#URHIS2T)Qv~EtR!4a+ zU=3)eWVv}|R@57k1Pi8mo|6Q{A#~Z$HBzj|<=-MdA0MlxG=AMku=0tn_v@RSa-ZuJ zr?xlu)V9&dP%fKUxjbt3AUYKYF5Wr~*#TntoG6}ZQ=jmbu!r?t-uGJ#>4F0j?_rz8 zuiBM5++*C3Jle?#495!Xu>{%!pvSnAeUSA~(366!-VrEuF%%iO>K*R!6d89eI)W3@ z!Xp!!`h9HbJ^5y6;stxruv>6X(%du_w-M`EwW|KbQ?~J-2v17&HcNl07jN|RbtP19 zxTH|LLdiw)otKov)B#h_W!g38H6pBNM6lTd52eCG5ws5Ip8)+64e_1Q2yQo-i?TO|!$cg-uDMb9 zsk8@t+a%=j=hT}gHD|Rdw>t5!l=+Qj>OGve@8JJGkawCc$&I!)&zhj9wfE*&FB&&@ z#t#X(7CS%4()^W3^Fvj|uEmw(VzS?Qi&K;7e(Nslx8AD8;mpK&ZQ~3s=jDEDhmt!g zW)-tk LtHv20(j@=@;XlFE literal 0 HcmV?d00001 diff --git a/apps/dashboard/build/_app/version.json b/apps/dashboard/build/_app/version.json index a0b8a69..d87c2dc 100644 --- a/apps/dashboard/build/_app/version.json +++ b/apps/dashboard/build/_app/version.json @@ -1 +1 @@ -{"version":"2.1.22"} \ No newline at end of file +{"version":"2.1.23"} \ No newline at end of file diff --git a/apps/dashboard/build/_app/version.json.br b/apps/dashboard/build/_app/version.json.br index 7ee1248..94cb2d3 100644 --- a/apps/dashboard/build/_app/version.json.br +++ b/apps/dashboard/build/_app/version.json.br @@ -1 +1 @@ - {"version":"2.1.22"} \ No newline at end of file + {"version":"2.1.23"} \ No newline at end of file diff --git a/apps/dashboard/build/_app/version.json.gz b/apps/dashboard/build/_app/version.json.gz index 9667dd0a5c88d811afedca6ce9dd19bac860a992..f6da5732e268147b5b1f521bb6b8796d6272b2c0 100644 GIT binary patch delta 17 YcmdPUm>|Owwu+VE!(x#V5e5bZ04i1lJpcdz delta 17 YcmdPUm>|Oww2GDC_{nRfA`A=+04{k1`2YX_ diff --git a/apps/dashboard/build/index.html b/apps/dashboard/build/index.html index ce5c054..4d5765f 100644 --- a/apps/dashboard/build/index.html +++ b/apps/dashboard/build/index.html @@ -11,13 +11,13 @@ - - + + - + - + @@ -33,7 +33,7 @@

        @BK2%`^?Oi!^QVGwawl# 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%0D`G<+Pc0p{0IP(m|{ptokisOitK9>gKBvWrP*P# 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