judgevet.domain

Status: draft.

judgevet.domain

Domain layer - pure types and business logic.

Examples:

from judgevet.domain import Noul, Choice, Score
from judgevet.domain.answers import NoulAnswer, ChoiceAnswer, ScoreAnswer

# Create a yes/no question
noul = Noul(
    instructions="Is this a valid question?",
    criteria={"true": "It is valid", "false": "It is not valid"},
)

# Create a choice question
choice = Choice(
    criteria={"a": "Option A", "b": "Option B"},
    instructions="Choose one:",
)

# Create a score question
score = Score(
    criteria=["Poor", "Fair", "Good", "Excellent"],
    instructions="Rate the response:",
)

# Answer a question
answer = NoulAnswer(noul=0.75)
assert 0.0 <= answer.noul <= 1.0
See Also

Attributes:

Name Type Description
Answer type

Union type of all answer types.

Choice type

Question type for multiple choice.

ChoiceAnswer type

Answer type for multiple choice.

JevAuthError type

401/403 authentication errors.

JevError type

Base exception for all Jev errors.

JevRateLimitError type

429 rate limit errors.

JevRequestError type

4xx client request errors.

JevResponseError type

2xx with unparseable body.

JevServiceError type

5xx or transport errors.

Noul type

Question type for yes/no.

NoulAnswer type

Answer type for yes/no.

Question type

Base question type.

Score type

Question type for numeric rating.

ScoreAnswer type

Answer type for numeric rating.

SystemOneResponse type

API response container.

Usage type

API usage tracking.

Answer = NoulAnswer | ChoiceAnswer | ScoreAnswer module-attribute

Union type for all possible answers.

Question = Noul | Choice | Score module-attribute

A question object.

Choice

A question that selects between named alternatives.

See: https://docs.typesafe.ai/primitives/choice

Attributes:

Name Type Description
criteria Mapping[str, str | dict | Sequence | None]

Labels mapped to descriptions.

instructions str | dict | Sequence | None

The question to ask.

Examples:

question = Choice(
    criteria={"a": "Option A", "b": "Option B"},
    instructions="Choose one:",
)
assert len(question.criteria) == 2
See Also

__init__(criteria, instructions=None)

Initialize a Choice question.

Parameters:

Name Type Description Default
criteria Mapping[str, str | dict[str, Any] | Sequence[Any] | None]

Labels mapped to descriptions, or None for undescribed labels.

required
instructions str | dict[str, Any] | Sequence[Any] | None

The question to ask.

None

__repr__()

Return a string representation of the Choice.

ChoiceAnswer dataclass

A selected choice with probabilities and confidence.

See: https://docs.typesafe.ai/primitives/choice

This frozen dataclass validates values in __post_init__. Confidence and probabilities must be finite, numeric and within [0.0, 1.0], excluding booleans. Probabilities must sum to 1.0 and contain the selected choice.

Attributes:

Name Type Description
choice str

The name of the choice with highest probability.

confidence float

Confidence in the selected choice, from 0 to 1.

probabilities dict[str, float]

Probability of each choice, keyed by choice name.

Examples:

answer = ChoiceAnswer(
    choice="yes",
    confidence=0.8,
    probabilities={"yes": 0.8, "no": 0.2},
)
assert answer.choice in answer.probabilities
See Also

__post_init__()

Validate choice, confidence, and probabilities.

Ensures confidence is finite in [0.0, 1.0], all probability values are finite in [0.0, 1.0], probabilities sum to 1.0, and choice is a key.

Raises:

Type Description
TypeError

If confidence or any probability is nonnumeric or a boolean.

ValueError

If a numeric value is nonfinite or outside [0.0, 1.0]. Also raised if probabilities do not sum to 1.0 or choice is missing from probabilities.

JevAuthError

Bases: JevError

Authentication error - 401 or 403.

Raised when the API key is missing, invalid, or lacks the necessary permissions to access the requested resource.

Attributes:

Name Type Description
args tuple

Standard exception arguments containing the message.

status_code int

Always 401 or 403.

Examples:

error = JevAuthError("Unauthorized", 401)
assert error.retryable is False

retryable property

Return True if the error is retryable.

Returns:

Type Description
bool

False for auth errors (401, 403).

__init__(message, status_code)

Initialize the auth error.

Parameters:

Name Type Description Default
message str

The error message.

required
status_code int

The HTTP status code (401 or 403).

required

Raises:

Type Description
ValueError

If status_code is not 401 or 403.

JevError

Bases: Exception

Base exception for all Jev-related errors.

This is the parent of the service-error hierarchy, not local policy errors or every HTTPX exception. Redirects can propagate raw HTTPX status errors. The base class always reports retryable=False; subclasses override it.

Attributes:

Name Type Description
args tuple

Standard exception arguments containing the message.

status_code int | None

The HTTP status code if available, None otherwise.

retryable bool

Advisory retry classification; False on this base class.

Examples:

error = JevError("Something went wrong", 500)
assert error.retryable is False

retryable property

Return True if the error is retryable.

Returns:

Type Description
bool

False on this base class, independent of status_code.

__init__(message, status_code=None)

Initialize the error.

Parameters:

Name Type Description Default
message str

The error message.

required
status_code int | None

The HTTP status code if available.

None

Examples:

error = JevError("Something went wrong", 500)
assert error.retryable is False

__str__()

Return string representation.

JevRateLimitError

Bases: JevError

Rate limit exceeded - 429.

Raised when the API returns a 429 status code indicating the client has exceeded the rate limit. The caller chooses retry limits; the adapter defaults to one attempt.

See: https://docs.typesafe.ai/api.md

Attributes:

Name Type Description
args tuple

Standard exception arguments containing the message.

status_code int

Always 429.

Examples:

error = JevRateLimitError("Rate limit exceeded", 429)
assert error.retryable is True

retryable property

Return True if the error is retryable.

Returns:

Type Description
bool

True for rate limit errors (429).

__init__(message, status_code)

Initialize the rate limit error.

Parameters:

Name Type Description Default
message str

The error message.

required
status_code int

The HTTP status code (must be 429).

required

Raises:

Type Description
ValueError

If status_code is not 429.

JevRequestError

Bases: JevError

Client request error - 4xx (except 401/403).

Raised when the API rejects the request due to invalid parameters, malformed input, or other client-side issues.

Attributes:

Name Type Description
args tuple

Standard exception arguments containing the message.

status_code int

The HTTP status code (4xx).

Examples:

error = JevRequestError("Bad Request", 400)
assert error.retryable is False

retryable property

Return True if the error is retryable.

Returns:

Type Description
bool

False for request errors (4xx).

__init__(message, status_code)

Initialize the request error.

Parameters:

Name Type Description Default
message str

The error message.

required
status_code int

The HTTP status code (4xx).

required

Raises:

Type Description
ValueError

If status_code is not a 4xx code or is 401/403.

JevResponseError

Bases: JevError

Response parsing error - 2xx with invalid body.

Raised when the API returns a 2xx status code but the response body cannot be parsed into the expected domain types. This is a local parsing failure. Live calls verify only the fields they exercised; other fields remain inferred from documentation.

Attributes:

Name Type Description
args tuple

Standard exception arguments containing the message.

status_code int

Always 2xx.

Examples:

error = JevResponseError("Parse error", 200)
assert error.retryable is False

retryable property

Return True if the error is retryable.

Returns:

Type Description
bool

False for response errors (2xx with invalid body).

__init__(message, status_code)

Initialize the response error.

Parameters:

Name Type Description Default
message str

The error message.

required
status_code int

The HTTP status code (2xx).

required

Raises:

Type Description
ValueError

If status_code is not a 2xx code.

JevServiceError

Bases: JevError

Server service error - 5xx or transport failures.

Raised when the API returns a 5xx status code or when a transport error occurs (network issues, timeouts, etc.).

Attributes:

Name Type Description
args tuple

Standard exception arguments containing the message.

status_code int | None

The HTTP status code (5xx) or None for transport errors.

Examples:

error = JevServiceError("Internal Server Error", 500)
assert error.retryable is True

retryable property

Return True if the error is retryable.

Returns:

Type Description
bool

True for service errors (5xx) and transport failures (status None).

__init__(message, status_code=None)

Initialize the service error.

Parameters:

Name Type Description Default
message str

The error message.

required
status_code int | None

The HTTP status code (5xx) or None for transport errors.

None

Raises:

Type Description
ValueError

If status_code is not a 5xx code when provided.

Noul

A yes/no question with optional descriptions for either outcome.

See: https://docs.typesafe.ai/primitives/noul

Attributes:

Name Type Description
instructions str | dict | Sequence | None

Question or statement to evaluate.

criteria dict | None

Optional. An object with true and false descriptions of what a yes and a no mean.

Examples:

question = Noul(
    instructions="Is this a valid question?",
    criteria={"true": "It is valid", "false": "It is not valid"},
)
assert question.instructions is not None
See Also

__init__(instructions=None, criteria=None)

Initialize a Noul question.

Parameters:

Name Type Description Default
instructions str | dict[str, Any] | Sequence[Any] | None

The yes/no question or statement to evaluate.

None
criteria dict[str, Any] | None

Optional descriptions of the yes and no outcomes.

None

__repr__()

Return a string representation of the Noul.

NoulAnswer dataclass

A yes/no answer with probability of true.

See: https://docs.typesafe.ai/primitives/noul

This is a frozen dataclass with validation in __post_init__ to ensure noul is finite and numeric (not bool) and in [0.0, 1.0].

Attributes:

Name Type Description
noul float

Probability of a yes answer or true statement, from 0 to 1.

Examples:

answer = NoulAnswer(noul=0.75)
assert 0.0 <= answer.noul <= 1.0
See Also

__post_init__()

Validate noul is finite, numeric and in [0.0, 1.0], excluding bool.

Raises:

Type Description
TypeError

If noul is not a numeric type or is a bool.

ValueError

If noul is nonfinite or outside [0.0, 1.0].

Score

A question that assigns a score using an ordered rubric.

See: https://docs.typesafe.ai/primitives/score

Attributes:

Name Type Description
criteria Sequence[str | dict | Sequence]

Ordered list of descriptions.

instructions str | dict | Sequence | None

What the model should rate.

Examples:

question = Score(
    criteria=["Poor", "Fair", "Good", "Excellent"],
    instructions="Rate the response:",
)
assert len(question.criteria) >= 2
See Also

__init__(criteria, instructions=None)

Initialize a Score question.

Parameters:

Name Type Description Default
criteria Sequence[str | dict[str, Any] | Sequence[Any]]

Ordered list of descriptions, one per score from zero.

required
instructions str | dict[str, Any] | Sequence[Any] | None

What the model should rate.

None

__repr__()

Return a string representation of the Score.

ScoreAnswer dataclass

A scored response with rubric and probabilities.

See: https://docs.typesafe.ai/primitives/score

This frozen dataclass validates values in __post_init__. Score must lie in legend range and be finite and numeric, excluding booleans. Confidence and probabilities must also be finite and numeric, excluding booleans, and within [0.0, 1.0]. Probabilities must sum to 1.0, and legend/probability keys must match.

Attributes:

Name Type Description
score float

Expected score (probability-weighted average of rubric levels).

confidence float

Confidence in the score, from 0 to 1.

legend dict[int, str]

Rubric descriptions keyed by integer score.

probabilities dict[int, float]

Probability of each score level, keyed by integer score.

Examples:

answer = ScoreAnswer(
    score=2.5,
    confidence=0.9,
    legend={1: "poor", 2: "fair", 3: "good"},
    probabilities={1: 0.1, 2: 0.2, 3: 0.7},
)
assert 1 <= len(answer.legend) == len(answer.probabilities)
See Also

__post_init__()

Validate score, confidence, legend, and probabilities.

Checks finite score against legend range and finite confidence against [0.0, 1.0]. Checks finite numeric probabilities against [0.0, 1.0] and their sum against 1.0. Checks that legend/probability keys match.

Raises:

Type Description
TypeError

If any numeric key or value is not the expected type or is a boolean.

ValueError

If any numeric value is nonfinite, score is outside legend range, or confidence or any probability is outside [0.0, 1.0]. Also raised if probabilities do not sum to 1.0 or legend/probability keys do not match.

SystemOneResponse dataclass

Answers grouped by question type with model and usage metadata.

See: https://docs.typesafe.ai/concepts/system-one

Frozen instances prevent attribute reassignment. The original answers dictionary remains mutable. Each typed property filters its current contents into a fresh dictionary. Editing that returned mapping leaves answers unchanged; the answer objects and their nested dictionaries remain shared. Missing or wrong-variant keys raise normal KeyError when indexed.

Attributes:

Name Type Description
model str

The model used to answer the request.

usage Usage

Token usage for the request.

answers dict[str, Answer]

All answer objects keyed by question name.

nouls dict[str, NoulAnswer]

Current Noul answers in a fresh dictionary.

choices dict[str, ChoiceAnswer]

Current Choice answers in a fresh dictionary.

scores dict[str, ScoreAnswer]

Current Score answers in a fresh dictionary.

Examples:

from judgevet.domain.answers import NoulAnswer
from judgevet.domain.usage import Usage

response = SystemOneResponse(
    model="jev-latest",
    usage=Usage(input_tokens=100, output_tokens=50),
    answers={"q1": NoulAnswer(noul=0.75)},
)
assert response.model == "jev-latest"
See Also

answers = field(default_factory=dict) class-attribute instance-attribute

All answer objects keyed by question name.

The field is always a dict (empty if no answers were provided).

choices property

Return a fresh plain dict of ChoiceAnswer entries from self.answers.

Returns:

Type Description
dict[str, ChoiceAnswer]

A new dict preserving insertion order with exact ChoiceAnswer object references.

dict[str, ChoiceAnswer]

Empty if no matching entries; KeyError on wrong-variant indexing.

nouls property

Return a fresh plain dict of NoulAnswer entries from self.answers.

Returns:

Type Description
dict[str, NoulAnswer]

A new dict preserving insertion order with exact NoulAnswer object references.

dict[str, NoulAnswer]

Empty if no matching entries; KeyError on wrong-variant indexing.

scores property

Return a fresh plain dict of ScoreAnswer entries from self.answers.

Returns:

Type Description
dict[str, ScoreAnswer]

A new dict preserving insertion order with exact ScoreAnswer object references.

dict[str, ScoreAnswer]

Empty if no matching entries; KeyError on wrong-variant indexing.

__repr__()

Return a string representation of the SystemOneResponse.

Returns:

Type Description
str

A string representation including model, usage, and answers.

Usage dataclass

Token counts for a request.

See: https://docs.typesafe.ai/api.md

This is a frozen dataclass. Values must be non-negative if provided.

Attributes:

Name Type Description
input_tokens int | None

Number of input tokens used.

output_tokens int | None

Number of output tokens used.

Examples:

usage = Usage(input_tokens=100, output_tokens=50)
assert usage.input_tokens == 100
See Also

__post_init__()

Validate token counts.

Raises:

Type Description
TypeError

If a token count is not int (bool rejected).

ValueError

If a token count is negative.