qfa.domain.models#

Domain models for the feedback analysis backend.

All models are immutable (frozen) Pydantic models per ADR-001.

Classes

AggregateSummaryResultModel(*, title, ...)

The result of summarizing multiple feedback records as a single aggregate.

AnalysisRequestModel(*, feedback_records[, ...])

A request to analyze one or more feedback records.

AnalysisResultModel(*, result[, ...])

The result of a feedback analysis.

AssignedCodeModel(*[, coding_level_1_id, ...])

A single leaf code assigned to a feedback record with its hierarchical path.

AuthKeyInfo(*, key_id, name, tenant_id, ...)

Metadata for an API key returned by the auth orchestrator.

CodedFeedbackRecordModel(*, ...)

Coding output for one feedback record.

CodingAssignmentRequestModel(*, ...[, ...])

A request to assign hierarchical codes to a single feedback record.

CodingAssignmentResultModel(*, ...)

The result of assigning codes to multiple feedback records.

CodingFramework(*, root_codes)

A tree of coding nodes defining the full hierarchical coding framework.

CodingNode(*, id, name, children)

A node in a hierarchical coding framework.

FeedbackRecordMetadataModel(*[, created, ...])

Metadata associated with a feedback record.

FeedbackRecordModel(*, id, content, ...)

A single feedback record submitted for analysis.

FeedbackRecordSummaryModel(*, id, title, summary)

Summary output for a single feedback record.

KeyCreationResponse(*, key_id, api_key)

Response model for API key creation.

LLMResponse(*, structured, model, ...)

Raw response from an LLM provider.

SensitivityAnalysisRequestModel(*, ...)

A request to analyze a single feedback record for sensitivity.

SensitivityAnalysisResultModel(*, ...)

The result of analyzing feedback records for sensitivity.

SensitivityAnalysisResultModelList(*, results)

The result of analyzing feedback records for sensitivity.

SingleSummaryRequestModel(*, ...)

A request to summarize a single feedback record.

SummaryRequestModel(*, feedback_records[, ...])

A request to summarize multiple feedback records (bulk path).

SummaryResultModel(*, feedback_record_summaries)

The result of summarizing multiple feedback records individually.

TenantApiKey(*, key_id, name[, key, ...])

An API key associated with a tenant.

TenantInfo(*, tenant_id, name, allows_superusers)

Tenant information returned by the auth orchestrator.

class qfa.domain.models.FeedbackRecordMetadataModel(*, created: str = '', coding_level_1: str | None = None, coding_level_2: str | None = None, coding_level_3: str | None = None)[source]#

Bases: BaseModel

Metadata associated with a feedback record.

Named fields (created, coding_level_1, coding_level_2, coding_level_3) match the EspoCRM pipeline convention (see scripts/espo_crm/). Only these fields are accepted; any other key is rejected rather than silently dropped, matching the API-level ApiFeedbackRecordMetadata (qfa.api.schemas), which enforces the same restriction at the HTTP boundary. Test/benchmark fixtures that carry richer metadata (e.g. fixtures/analyze_corpus.yaml’s theme, language, codes) must project down to these four fields before constructing a FeedbackRecordModel.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'extra': 'forbid', 'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

created: str#
coding_level_1: str | None#
coding_level_2: str | None#
coding_level_3: str | None#
class qfa.domain.models.FeedbackRecordModel(*, id: str, content: ~typing.Annotated[str, ~annotated_types.MinLen(min_length=1), ~annotated_types.MaxLen(max_length=100000)], metadata: ~qfa.domain.models.FeedbackRecordMetadataModel = <factory>, url_id: str = '')[source]#

Bases: BaseModel

A single feedback record submitted for analysis.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

id: str#
content: str#
metadata: FeedbackRecordMetadataModel#
url_id: str#
class qfa.domain.models.CodingNode(*, id: str, name: str, children: list[CodingNode] = <factory>)[source]#

Bases: BaseModel

A node in a hierarchical coding framework.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

id: str#
name: str#
children: list[CodingNode]#
class qfa.domain.models.CodingFramework(*, root_codes: Annotated[list[CodingNode], MinLen(min_length=1)])[source]#

Bases: BaseModel

A tree of coding nodes defining the full hierarchical coding framework.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

root_codes: list[CodingNode]#
class qfa.domain.models.AnalysisRequestModel(*, feedback_records: Annotated[tuple[FeedbackRecordModel, ...], MinLen(min_length=1)], output_language: str | None = None, prompt: Annotated[str, MinLen(min_length=1), MaxLen(max_length=4000)], tenant_id: str, mode: Literal['single_pass', 'hierarchical'] = 'single_pass', period: Literal['day', 'week', 'month'] | None = None, espo_feedback_base_url: str | None = None)[source]#

Bases: BaseModel

A request to analyze one or more feedback records.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

feedback_records: tuple[FeedbackRecordModel, ...]#
prompt: str#
output_language: str | None#
tenant_id: str#
mode: Literal['single_pass', 'hierarchical']#
period: Literal['day', 'week', 'month'] | None#
espo_feedback_base_url: str | None#
class qfa.domain.models.AnalysisResultModel(*, result: str, quality_score: Annotated[float | None, Ge(ge=0.0), Le(le=1.0)] = None, uncertainty_explanation: str = '', confidence: Annotated[float | None, Ge(ge=0.0), Le(le=1.0)] = None, coding_trends: CodingTrendTable | None = None)[source]#

Bases: BaseModel

The result of a feedback analysis.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

result: str#
quality_score: float | None#
uncertainty_explanation: str#
confidence: float | None#
class qfa.domain.models.SummaryRequestModel(*, feedback_records: Annotated[tuple[FeedbackRecordModel, ...], MinLen(min_length=1)], output_language: str | None = None, prompt: Annotated[str | None, MaxLen(max_length=4000)] = None, tenant_id: str, espo_feedback_base_url: str | None = None)[source]#

Bases: BaseModel

A request to summarize multiple feedback records (bulk path).

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

feedback_records: tuple[FeedbackRecordModel, ...]#
output_language: str | None#
prompt: str | None#
tenant_id: str#
espo_feedback_base_url: str | None#
class qfa.domain.models.SingleSummaryRequestModel(*, feedback_record: FeedbackRecordModel, tenant_id: str)[source]#

Bases: BaseModel

A request to summarize a single feedback record.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

feedback_record: FeedbackRecordModel#
tenant_id: str#
class qfa.domain.models.FeedbackRecordSummaryModel(*, id: str, title: str, summary: str, quality_score: Annotated[float | None, Ge(ge=0.0), Le(le=1.0)] = None)[source]#

Bases: BaseModel

Summary output for a single feedback record.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

id: str#
title: str#
summary: str#
quality_score: float | None#
class qfa.domain.models.SummaryResultModel(*, feedback_record_summaries: tuple[FeedbackRecordSummaryModel, ...])[source]#

Bases: BaseModel

The result of summarizing multiple feedback records individually.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

feedback_record_summaries: tuple[FeedbackRecordSummaryModel, ...]#
class qfa.domain.models.AggregateSummaryResultModel(*, title: str, summary: str, quality_score: float)[source]#

Bases: BaseModel

The result of summarizing multiple feedback records as a single aggregate.

# TODO come up with nice solution for non-mutable quality-score, so this can be a frozen class.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

title: str#
summary: str#
quality_score: float#
model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qfa.domain.models.CodingAssignmentRequestModel(*, feedback_record: FeedbackRecordModel, coding_levels: CodingFramework, max_codes: Annotated[int, Ge(ge=1), Le(le=50)], confidence_threshold: Annotated[float | None, Ge(ge=0.0), Le(le=1.0)] = None, tenant_id: str)[source]#

Bases: BaseModel

A request to assign hierarchical codes to a single feedback record.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

feedback_record: FeedbackRecordModel#
coding_levels: CodingFramework#
max_codes: int#
confidence_threshold: float | None#
tenant_id: str#
class qfa.domain.models.AssignedCodeModel(*, coding_level_1_id: str | None = None, coding_level_1_name: str | None = None, coding_level_2_id: str | None = None, coding_level_2_name: str | None = None, coding_level_3_id: str | None = None, coding_level_3_name: str | None = None, confidence_level_1: float | None = None, confidence_level_2: float | None = None, confidence_level_3: float | None = None, confidence_aggregate: float | None = None, explanation: str)[source]#

Bases: BaseModel

A single leaf code assigned to a feedback record with its hierarchical path.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

coding_level_1_id: str | None#
coding_level_1_name: str | None#
coding_level_2_id: str | None#
coding_level_2_name: str | None#
coding_level_3_id: str | None#
coding_level_3_name: str | None#
confidence_level_1: float | None#
confidence_level_2: float | None#
confidence_level_3: float | None#
confidence_aggregate: float | None#
explanation: str#
class qfa.domain.models.CodedFeedbackRecordModel(*, feedback_record_id: str, assigned_codes: tuple[AssignedCodeModel, ...])[source]#

Bases: BaseModel

Coding output for one feedback record.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

feedback_record_id: str#
assigned_codes: tuple[AssignedCodeModel, ...]#
class qfa.domain.models.CodingAssignmentResultModel(*, coded_feedback_records: tuple[CodedFeedbackRecordModel, ...])[source]#

Bases: BaseModel

The result of assigning codes to multiple feedback records.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

coded_feedback_records: tuple[CodedFeedbackRecordModel, ...]#
class qfa.domain.models.SensitivityAnalysisRequestModel(*, feedback_record: FeedbackRecordModel, tenant_id: str)[source]#

Bases: BaseModel

A request to analyze a single feedback record for sensitivity.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

feedback_record: FeedbackRecordModel#
tenant_id: str#
class qfa.domain.models.SensitivityAnalysisResultModel(*, feedback_record_id: str, sensitivity_types: tuple[SensitivityType, ...], explanation: str)[source]#

Bases: BaseModel

The result of analyzing feedback records for sensitivity.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

feedback_record_id: str#
sensitivity_types: tuple[SensitivityType, ...]#
explanation: str#
property is_sensitive: bool#

Convenience property indicating whether any sensitivity types were detected.

class qfa.domain.models.SensitivityAnalysisResultModelList(*, results: tuple[SensitivityAnalysisResultModel, ...])[source]#

Bases: BaseModel

The result of analyzing feedback records for sensitivity.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

results: tuple[SensitivityAnalysisResultModel, ...]#
class qfa.domain.models.LLMResponse(*, structured: T_Response, model: str, prompt_tokens: int, completion_tokens: int, cost: float)[source]#

Bases: BaseModel, Generic[T_Response]

Raw response from an LLM provider.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

structured: T_Response#
model: str#
prompt_tokens: int#
completion_tokens: int#
cost: float#
class qfa.domain.models.TenantApiKey(*, key_id: str, name: str, key: SecretStr | None = None, hashed_key: SecretStr, tenant_id: str, is_superuser: bool = False)[source]#

Bases: BaseModel

An API key associated with a tenant.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

key_id: str#
name: str#
key: SecretStr | None#
hashed_key: SecretStr#
tenant_id: str#
is_superuser: bool#
static hash_key(key: str) str[source]#

Return a stable scrypt-derived hex digest for an API key.

matches_key(provided_key: str) bool[source]#

Check whether provided_key matches this stored API key hash.

class qfa.domain.models.KeyCreationResponse(*, key_id: str, api_key: str)[source]#

Bases: BaseModel

Response model for API key creation.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

key_id: str#
api_key: str#
model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qfa.domain.models.AuthKeyInfo(*, key_id: str, name: str, tenant_id: str, is_superuser: bool)[source]#

Bases: BaseModel

Metadata for an API key returned by the auth orchestrator.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

key_id: str#
name: str#
tenant_id: str#
is_superuser: bool#
model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class qfa.domain.models.TenantInfo(*, tenant_id: str, name: str, allows_superusers: bool)[source]#

Bases: BaseModel

Tenant information returned by the auth orchestrator.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

tenant_id: str#
name: str#
model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

allows_superusers: bool#