Source code for cadrumo.application.corpus_search.models
"""Typed records for the on-host corpus-search grounding surface.Every record is a strict, frozen pydantic v2 model. The surface neverexposes a bare ``dict`` for a chunk, a search hit, or a citationresolution: the console grounds an operator against verbatim legal text,so the provenance carried alongside each result (corpus_ref, sourcepath, document id, permalink) is contract, not decoration.See Also: :func:`~application.corpus_search.runtime.search_corpus` Runtime service that returns :class:`~application.corpus_search.models.RetrievalResponse`.Notes: External adapters may project this response while preserving its typed retrieval provenance."""from__future__importannotationsfromenumimportStrEnumfromtypingimportAnnotatedfrompydanticimportBaseModel,Field,NonNegativeInt,StringConstraints,model_validatorfrom...core.errors.hierarchyimportpydantic_validation_boundaryfrom...core.modelsimportSTRICT_FROZEN_CONFIGas_STRICT_FROZEN_Text=Annotated[str,StringConstraints(strip_whitespace=True,min_length=1)]
[docs]classRetrievalMode(StrEnum):"""How a retrieval response was produced. ``CITATION`` — the query was an exact citation id, short-circuited to the structured lookup; ``LEXICAL_ONLY`` — the ranked FTS5 lexical search over the bundled corpus. These are the only two shapes the product ships: the shipped retrieval surface loads no model and computes no vectors. """CITATION="citation"LEXICAL_ONLY="lexical_only"
[docs]classCorpusChunk(BaseModel):"""One retrievable prose chunk extracted from the bundled corpus. A chunk is a paragraph-bounded slice of a single extracted unit (an article or disposition). ``chunk_id`` is deterministic given the same corpus, so a rebuilt index re-mints byte-identical ids and a chunk id held across a rebuild still resolves. """model_config=_STRICT_FROZENchunk_id:_Textcorpus_ref:_Textsource_path:_Textdoc_title:_Textsection:str|None=Noneanchor:str|None=Noneordinal:NonNegativeInttext:_Text
[docs]classCorpusDocument(BaseModel):"""Metadata for one extracted corpus source file in the lexical index."""model_config=_STRICT_FROZENcorpus_ref:_Textsource_path:_Texttitle:_Textchunk_count:NonNegativeInt
[docs]classLexicalSearchHit(BaseModel):"""One ranked lexical-search result over the FTS5 index."""model_config=_STRICT_FROZENchunk_id:_Textcorpus_ref:_Textdoc_title:_Textsection:str|None=Noneanchor:str|None=Nonerank:NonNegativeIntscore:floattext:_Text
[docs]classCitationResolution(BaseModel):"""A citation id resolved to catalogue metadata plus verbatim text. The metadata is projected from the registry legal catalogue (the single citation authority); ``verbatim_text`` is read from the bundled extracted corpus the citation's ``corpus_ref`` points at. """model_config=_STRICT_FROZENcitation_id:_Textdocument_id:_Textkind:_Textcorpus_ref:_Textpermalink:_Textarticle:str|None=Nonesection:str|None=Noneanchor:str|None=Noneverbatim_text:_Text
[docs]classCorpusIndexBuildResult(BaseModel):"""Summary of one lexical-index build."""model_config=_STRICT_FROZENdatabase_path:_Textdocument_count:NonNegativeIntchunk_count:NonNegativeInt
[docs]classRetrievalHit(BaseModel):"""One ranked lexical-retrieval result over the corpus. ``text`` is the verbatim chunk prose (the snippet source); ``corpus_ref`` grounds it in the bundled source (and is the ``cadrumo://corpus/{ref}`` key that resolves the full verbatim text). ``score`` is the FTS5 BM25 relevance, sign-flipped so a larger value is a better match; ``lexical_rank`` is the hit's zero-based position in the lexical ranking. """model_config=_STRICT_FROZENchunk_id:_Textcorpus_ref:_Textdoc_title:_Texttext:_Textscore:float=Field(ge=0.0)rank:NonNegativeIntlexical_rank:int|None=None
[docs]classRetrievalResponse(BaseModel):"""The typed result of one corpus retrieval. ``mode`` records how the response was produced (citation short-circuit or ranked lexical search). ``citation`` carries the resolved citation when ``mode`` is ``CITATION``; otherwise ``hits`` carries the ranked results. """model_config=_STRICT_FROZENquery:_Textmode:RetrievalModehits:tuple[RetrievalHit,...]=()citation:CitationResolution|None=None@model_validator(mode="after")@pydantic_validation_boundarydef_mode_and_result_agree(self)->RetrievalResponse:ifself.modeisRetrievalMode.CITATION:ifself.citationisNone:raiseValueError("a CITATION response must carry a citation")ifself.hits:raiseValueError("a CITATION response must not carry lexical hits")elifself.citationisnotNone:raiseValueError("a LEXICAL_ONLY response must not carry a citation")returnself