cadrumo.application.user_profile.validation module

Schema-driven validation service for user-profile lifecycle commands.

ProfileValidationService validates a UserProfileRecord against an operation-pinned schema definition and returns structured ProfileValidationIssue entries for every constraint violation.

REQUIRED_FIELD_MISSING_CODE: Final[str]

Issue code for a schema-required field absent from the fact set.

CONDITIONAL_REQUIRED_FIELD_MISSING_CODE: Final[str]

Issue code for a field required only under some other fact’s value.

CONDITIONALLY_FORBIDDEN_FIELD_CODE: Final[str]

Issue code for a field carrying a value some other fact’s value prohibits.

The mirror of the code above, and deliberately NOT a completeness code. A missing conditional field is an unfinished profile and may be deferred to the ACTIVE promotion; a field the record layout forbids is a value that must never reach an export, so it refuses at registration like any other malformed value.

The distinction is the whole reason this is its own code. Reporting a prohibited value as a missing one would send the operator to supply MORE of exactly the thing the form does not allow.

NUMERIC_VALUE_ISSUE_CODE: Final[str]

Issue code for a numeric field carrying a non-number or an out-of-range value.

Deliberately NOT a completeness code: a malformed or out-of-range value is a bad answer rather than a missing one, so it refuses even while a profile is still SETUP_INCOMPLETE, exactly as a bad date or an unknown enum token already does. Deferring it would let a wrong number sit in a profile until the ACTIVE promotion and then refuse the promotion instead of the write that caused it.

BOOLEAN_VALUE_ISSUE_CODE: Final[str]

Issue code for a boolean field carrying something that is not a yes/no answer.

Not a completeness code, for the same reason as its numeric sibling: an unreadable answer is a bad one rather than a missing one. A blank is refused here rather than deferred, because a boolean field’s readers resolve an unreadable value to False – so a value admitted unread does not stay undecided, it silently becomes “no”.

ENUM_VALUE_ISSUE_CODE: Final[str]

Issue code for an enum field carrying a token outside its declared set.

DATE_VALUE_ISSUE_CODE: Final[str]

Issue code for a date field carrying something that is not a calendar day.

EMAIL_VALUE_ISSUE_CODE: Final[str]

Issue code for an email field carrying something that is not an address.

Not a completeness code, for the same reason as its siblings: an entry that is not an address is a bad answer rather than a missing one. The declaration was previously the only content-format type in the schema that nothing checked, so banana stored and stayed.

DERIVED_FIELD_ISSUE_CODE: Final[str]

Issue code for a write aimed at a path the engine computes.

Path legitimacy, not value admissibility, which is why it is judged here beside unknown_field rather than through the value-refusal authority. That is now the only thing keeping the rule answerable: the schema declares the derived namespaces as [[derived_selectors]] patterns and nothing else, so the field index does NOT hold them and there is no declaration left to judge against.

Evaluated BEFORE the unknown_field refusal, and that ordering is what makes the refusal instructive rather than merely correct. Both codes would block the write, but only this one names the entry surface that edits the source facts; reaching unknown_field first would tell an operator the engine’s own path does not exist.

UNKNOWN_FIELD_ISSUE_CODE: Final[str]

Issue code for a write aimed at a path the schema does not declare.

EFFECTIVE_WINDOW_UNUSED_CODE: Final[str]

Issue code for a window attached to a non-effective-dated field.

EFFECTIVE_WINDOW_END_NOT_ENFORCED_CODE: Final[str]

Issue code for a valid_to boundary no profile reader enforces.

MODELO_WORK_PROFILE_BASELINE_MISSING_CODE: Final[str]

Issue code for a filing-grade Modelo work baseline field that is absent.

PROFILE_VALIDATION_ISSUE_CODES: Final[tuple[str, ...]]

Complete finite vocabulary emitted under profile.validation.*.

The first twelve values are emitted by ProfileValidationService; the filing-grade baseline value is emitted by the Modelo readiness gate. The tuple lives beside the issue-code declarations so a new producer must update one source of truth before its dynamic locale key can be rendered.

COMPLETENESS_ISSUE_CODES: Final[frozenset[str]]

The issue codes that mean “not finished yet” rather than “malformed”.

A profile born SETUP_INCOMPLETE defers exactly these; every other blocking issue (bad shape, bad value, unknown path) still refuses at registration. They come due in full at the promotion out of setup — see complete_setup(), which judges with require_complete=True precisely because COMPLETE is the claim that nothing required is missing.

class ProfileValidationService(*, schema)[source]

Bases: object

Validate a profile record against a loaded schema.

Stateless. Constructed with a loaded ProfileSchemaDefinition so the same instance can validate many records or commands.

Parameters:

schema (ProfileSchemaDefinition)

property schema: ProfileSchemaDefinition

Return the loaded schema this validator was constructed with.

validate_record(record)[source]

Validate every fact on a profile against the schema.

Parameters:

record (UserProfileRecord) – The UserProfileRecord whose facts are validated.

Return type:

ProfileValidationReport

Returns a ProfileValidationReport.

validate_facts(profile_id, facts)[source]

Validate a free-standing collection of facts.

Returns a ProfileValidationReport.

Return type:

ProfileValidationReport

Parameters:
reject_invalid_profile_facts(profile_id, facts, *, require_complete, schema)[source]

Refuse a fact set on blocking schema issues, or return silently.

Every door that writes profile facts – registration’s initial record, the wizard’s fact patch, and the cotejo censal’s adoption of certificate values alike – judges through here, so an engine-derived path, an unknown path or a mis-shaped value is refused at the write rather than at whichever surface happened to collect it. A check living only in an edit dialog binds nobody who writes through another surface, and a stored value at a derived path silently displaces the computation that owns it.

The whole resulting fact sequence is judged rather than the incoming change alone, so a patch is never left half-applied by a later field’s refusal.

require_complete selects which issues block. A profile that is still INCOMPLETE is by definition allowed to be missing the fields filing depends on – demanding them in order to build an incomplete profile is a contradiction. Shape and value are judged in both modes; only the missing-required-field issues are deferred, to the moment the profile is completed.

Raises:

ProfileSchemaValidationError – When any blocking issue remains, naming the refused paths and why.

Return type:

None

Parameters: