arborist/aborist/search/base.py
russell@unturf.com 01a4390693
verify: layered strategies + entity policies, rename VISUAL → UNGROUNDED
- aborist/qa/verify.py: three strategies tried in sequence. quote uses
  sequential pairing (1st & 2nd `"`, 3rd & 4th, ...) which eliminates
  the phantom inter-pair captures regex pairing produced on adjacent
  quote pairs like `"title" prose "quote"`. span checks bullet/sentence
  lines verbatim. entity matches multi-word proper nouns; gated by
  policy ∈ {strict, hybrid, drop, proximity}. Default proximity
  promotes to STRICT only when N=3 verified entities cluster within
  W=300 chars in source — separates structural grounding (cast list,
  infobox) from incidental mention (scattered plot summary).

- aborist/store.py: schema CHECK now `('STRICT','HYBRID','UNGROUNDED')`.
  Migration helper rebuilds legacy `('STRICT','HYBRID','VISUAL')`
  tables via temp-table copy, translating VISUAL → UNGROUNDED in the
  SELECT. Idempotent — DDL inspection skips the rebuild on already-
  migrated DBs.

- aborist/cli.py: new `aborist reclassify` re-runs the verifier
  against existing live records under the current entity policy; no
  LLM calls. --compare runs all four policies side-by-side, --dry-run
  reports transitions without writing. Cold-source records skipped.
  One providence_reclassify audit event per changed row.

- AuditMode.UNGROUNDED replaces VISUAL across search backend, FTS5,
  test fixtures, CLAUDE.md. The substrate (Merkle-AGI) name was
  about FOR-style visualization; in the RAG layer the semantic is
  "no recoverable grounding," so the label now says that.

DEFAULT_QUERY_POLICY gains entity_policy + entity_proximity_n +
entity_proximity_window so any tuning folds into governance_policy_hash
and invalidates cache cleanly.
2026-04-28 16:58:31 -04:00

52 lines
1.6 KiB
Python

"""Search backend ABC + Hit dataclass with explicit audit mode.
Every search hit carries an `audit_mode` so callers never overclaim. Aborist
adapts the Merkle-AGI v7 audit-mode trichotomy to the RAG layer:
- STRICT — Merkle-verified evidence: every claim cited verbatim against
the source-content tree.
- HYBRID — partial / mixed evidence: some claims source-grounded, others
emerged from training. Cache or search hit is partially trusted.
- UNGROUNDED — no recoverable proof of grounding. Keyword (FTS5) hits land
here by default; LLM answers fall here when no double-quoted
span, sentence, or proper-noun phrase verifies against context.
Substrate name was VISUAL (no formal guarantees attached); we
renamed to UNGROUNDED so the RAG semantic is explicit.
"""
from __future__ import annotations
import enum
import sqlite3
from abc import ABC, abstractmethod
from dataclasses import dataclass
class AuditMode(str, enum.Enum):
STRICT = "STRICT"
HYBRID = "HYBRID"
UNGROUNDED = "UNGROUNDED"
@dataclass(frozen=True)
class Hit:
document_root: str
document_uri: str
chunk_idx: int
snippet: str
score: float
audit_mode: AuditMode
title: str | None = None
class SearchBackend(ABC):
"""A search hook over the chunk store."""
name: str
audit_mode: AuditMode # default mode this backend reports
def __init__(self, conn: sqlite3.Connection):
self.conn = conn
@abstractmethod
def search(self, query: str, limit: int = 20) -> list[Hit]:
...