ThatAIguyA world of ideas

THE CONSCIOUSNESS ATLAS
Read. Experiment. Follow the evidence.

ConsciousnessLearn · Explore · Joseph Anady

Janady13/missionmatch / internal/modules/ai/vectorguard.go

Source identity, revision, and recovered contents.

GitHub sourceSource text recovered

Source identity

FieldRecorded value
Source typeGitHub source
Original recordJanady13/missionmatch / internal/modules/ai/vectorguard.go
DateNot specified in source
RepositoryJanady13/missionmatch
Revision720d47fae476b0d38477ae4401697d372b1ea2bc
Branchfeature/opportunity-to-outcome
Path or archive memberinternal/modules/ai/vectorguard.go
Original SHA-256df22ccb362dc75299cf24979063aa76b1201c179108c3a6bdb27a2864eb9e1b6
Git blob SHA475cf2a0667af179763b93324790beb26025926b
Reading-copy SHA-256df22ccb362dc75299cf24979063aa76b1201c179108c3a6bdb27a2864eb9e1b6

Original source ↗

Every recorded occurrence

These 2 records contain identical original source bytes. Their paths and revisions remain part of the archive.

Original recordBranch or archiveRevision / identifierOriginal location
Janady13/missionmatch / internal/modules/ai/vectorguard.gofeature/opportunity-to-outcome720d47fae476b0d38477ae4401697d372b1ea2bcOpen original
Janady13/missionmatch / internal/modules/ai/vectorguard.gofeature/aioe-upgrade2178e7298d0e5d9af83afa12402fd587f0ba6ed8Open original

Recovered source transcript

package ai import ( "context" "errors" "fmt" "math" "sync" "sync/atomic" "github.com/jackc/pgx/v5/pgxpool" "github.com/pgvector/pgvector-go" "github.com/missionworkforce/missionmatch/internal/platform/embeddings" "github.com/missionworkforce/missionmatch/internal/platform/inference" "github.com/missionworkforce/missionmatch/internal/platform/tenant" ) // ErrVectorModelMismatch means the stored vectors were not produced by the configured embed model (or // the vector columns are the wrong width, or the store is not backfilled). Mixing embed models silently // mis ranks every retrieval with no error, so the brain MUST refuse to serve until the store is re // embedded with the configured model. The handler maps this to a typed 503 vector_model_mismatch. var ErrVectorModelMismatch = errors.New("ai: stored vectors were not produced by the configured embed model") // vectorMatchTolerance is the minimum cosine between a stored skill vector and a fresh embedding of the // same skill name by the configured model. The same text under the same model, normalized, lands at // cosine ~1.0; a DIFFERENT model (the all-minilm to bge corruption mode) lands far lower (the synonym // and unrelated calibration showed a different meaning, never mind a different model, sits at 0.4 to // 0.9), so 0.98 cleanly separates same model from a model swap while tolerating float drift. const vectorMatchTolerance = 0.98 // VectorGate is the enforced re embed gate. It holds the boot time verdict on whether the stored vectors // were produced by the configured embed model, and /ai/query consults it before serving. A genuine model // mismatch closes the gate permanently (until a re embed and restart); a transient failure at boot (the // plane was briefly unreachable) leaves the gate to self heal on the first query after the plane recovers, // so a momentary outage does not dark the brain forever. The rest of the API never consults this gate. // The verdict is held PER ORGANIZATION, which matters once tenants have their own databases. Each tenant // database carries its own vectors and is backfilled independently, so "verified" is a property of a // store, not of the process. A single shared verdict would let the first tenant that happened to be // backfilled correctly open the gate for a tenant whose store is stale, half re embedded, or on the old // model, which is exactly the silent mis ranking this gate exists to prevent. In shared mode every // request resolves to the same empty key, so there is one verdict and the behaviour is unchanged. type VectorGate struct { mu sync.Mutex states map[string]*gateState verify func(ctx context.Context) error } // gateState is one store's verdict. ok is atomic so the hot path after verification takes no lock. type gateState struct { ok atomic.Bool mismatch bool // a permanent negative verdict was reached for this store reason string // the last failure detail, for the log and the 503 message } // NewVectorGate builds a gate over a verification closure. A nil closure means no verifier is configured // (the dev or test posture); such a gate is always open, so existing call sites that do not wire the // check keep serving. func NewVectorGate(verify func(ctx context.Context) error) *VectorGate { return &VectorGate{verify: verify, states: map[string]*gateState{}} } // stateFor returns the verdict holder for the caller's organization, creating it on first sight. An // unresolved organization uses the empty key, which is the shared mode case and also the boot self check. func (g *VectorGate) stateFor(ctx context.Context) *gateState { key, _ := tenant.OrgFromContext(ctx) g.mu.Lock() defer g.mu.Unlock() if g.states == nil { g.states = map[string]*gateState{} } s, ok := g.states[key] if !ok { s = &gateState{} g.states[key] = s } return s } // Check returns nil when the brain may serve THIS caller's store, or a typed error when it may not: // ErrVectorModelMismatch (a model mismatch or wrong width or unbackfilled store, a permanent closed gate // for that store) or an inference.ErrPlaneUnavailable wrap (the check could not reach the plane yet, // retried on the next call). func (g *VectorGate) Check(ctx context.Context) error { s := g.stateFor(ctx) if s.ok.Load() { return nil } g.mu.Lock() defer g.mu.Unlock() if s.ok.Load() { return nil } if s.mismatch { return fmt.Errorf("%w: %s", ErrVectorModelMismatch, s.reason) } if g.verify == nil { s.ok.Store(true) return nil } err := g.verify(ctx) if err == nil { s.ok.Store(true) return nil } if errors.Is(err, ErrVectorModelMismatch) { s.mismatch = true s.reason = err.Error() return err } // Transient (the plane was unreachable for the re embed): stay unverified and surface a plane outage, // so the caller gets a typed 503 and the gate retries on the next query rather than darkening forever. s.reason = err.Error() return fmt.Errorf("%w: stored vector model not yet verified: %v", inference.ErrPlaneUnavailable, err) } // VerifyVectorModel is the boot self check. It asserts the vector column dimension for skills and // candidates and confirms the stored skill vectors were produced by the configured embed model, by re // embedding a sample of stored skill NAMES (the embedded text for a skill is its name, so it is // re embeddable; a candidate's resume text is CUI and is never re embedded here, its column dimension is // checked through the catalog instead). The skills table is global and shares the one backfill model with // candidates, so a match here proves the configured model is the store's model. func VerifyVectorModel(ctx context.Context, db *tenant.DB, client *inference.Client, dim int) error { if db == nil { return errors.New("ai: vector model check needs a database") } if client == nil { return errors.New("ai: vector model check needs an inference client") } // Acquire rather than reading the DB's own pool directly. Under per tenant routing the routing DB has no pool of // its own and the vectors being verified live in the CALLER'S tenant database, so the check has to run // against the same store the retrieval will read. In shared mode this is a no op wrapper over the one // pool. At boot there is no organization in context, so this fails as a TRANSIENT error, which is // already the designed path: the gate stays unverified and self heals on the first real query, where an // organization does exist. leaf, release, err := db.Acquire(ctx) if err != nil { return fmt.Errorf("ai: vector model check needs a tenant database: %w", err) } defer release() if leaf.Pool == nil { return errors.New("ai: vector model check needs a database") } pool := leaf.Pool // Dimension contract through the catalog (the app role sees no candidate rows without a tenant, and // the column type carries the width), so a wrong width column is caught without reading any PII. if err := assertVectorColumnDim(ctx, pool, "candidates", "resume_embedding", dim); err != nil { return err } if err := assertVectorColumnDim(ctx, pool, "skills", "embedding", dim); err != nil { return err } // Model match on the global skills table. Re embed the SAME text the backfill embedded (the skill // name with its category), via the shared embeddings.SkillEmbedText, or a categorized skill would // look like a model mismatch when only the text differs. var texts []string var stored [][]float32 rows, err := pool.Query(ctx, "SELECT name, COALESCE(category,''), embedding FROM skills WHERE embedding IS NOT NULL ORDER BY id LIMIT 5") if err != nil { return fmt.Errorf("ai: sample stored skill vectors: %w", err) } defer rows.Close() for rows.Next() { var name, category string var v pgvector.Vector if err := rows.Scan(&name, &category, &v); err != nil { return err } texts = append(texts, embeddings.SkillEmbedText(name, category)) stored = append(stored, v.Slice()) } if err := rows.Err(); err != nil { return err } if len(texts) == 0 { return fmt.Errorf("%w: no backfilled skill embeddings to verify against (run the bge backfill before serving the brain)", ErrVectorModelMismatch) } res, err := client.Embed(ctx, texts) if err != nil { // Could not reach the plane to re embed: a transient condition, not a proven mismatch. return fmt.Errorf("ai: re embed for the vector model check: %w", err) } return vectorsMatchModel(texts, stored, res.Embeddings, dim) } // vectorsMatchModel is the pure comparison core (no DB, no plane), so the match and mismatch decision is // unit testable. Every stored vector must be dim wide and cosine close to the fresh embedding of its name. func vectorsMatchModel(names []string, stored, fresh [][]float32, dim int) error { if len(fresh) != len(stored) { return fmt.Errorf("ai: re embed returned %d vectors for %d stored", len(fresh), len(stored)) } for i := range stored { if len(stored[i]) != dim { return fmt.Errorf("%w: stored skill %q vector width %d, expected %d", ErrVectorModelMismatch, names[i], len(stored[i]), dim) } if len(fresh[i]) != dim { return fmt.Errorf("ai: fresh embedding width %d, expected %d (plane or config error)", len(fresh[i]), dim) } c := cosineSim(stored[i], fresh[i]) if c < vectorMatchTolerance { return fmt.Errorf("%w: stored vector for skill %q matches the configured model at cosine %.4f, below tolerance %.2f (the store was embedded by a different model, re embed before serving)", ErrVectorModelMismatch, names[i], c, vectorMatchTolerance) } } return nil } // assertVectorColumnDim reads the pgvector column dimension from the catalog (pgvector stores the // dimension directly in atttypmod, with no offset) and asserts it equals dim. func assertVectorColumnDim(ctx context.Context, pool *pgxpool.Pool, table, column string, dim int) error { var typmod int err := pool.QueryRow(ctx, `SELECT a.atttypmod FROM pg_attribute a JOIN pg_class c ON c.oid = a.attrelid JOIN pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = 'public' AND c.relname = $1 AND a.attname = $2 AND NOT a.attisdropped`, table, column).Scan(&typmod) if err != nil { return fmt.Errorf("ai: read %s.%s vector dimension: %w", table, column, err) } if typmod != dim { return fmt.Errorf("%w: column %s.%s is vector(%d), expected vector(%d)", ErrVectorModelMismatch, table, column, typmod, dim) } return nil } // cosineSim computes the true cosine (it divides by both norms), so it is correct whether or not the // stored vector was normalized at backfill. func cosineSim(a, b []float32) float64 { var dot, na, nb float64 for i := range a { dot += float64(a[i]) * float64(b[i]) na += float64(a[i]) * float64(a[i]) nb += float64(b[i]) * float64(b[i]) } if na == 0 || nb == 0 { return 0 } return dot / (math.Sqrt(na) * math.Sqrt(nb)) }

Search equations, builds, manuscript text, and recovered sources.