Skip to content

TN-002: Open Schema for DeviceResponse (extra="allow")

Summary

DeviceResponse uses Pydantic's extra="allow" configuration so that unknown fields from the device firmware pass through without requiring a schema update.

Background

The OSECHI detector firmware (kurikintons) evolves independently of the kazunoko library. New firmware versions may add response fields at any time. If DeviceResponse had a closed schema (Pydantic's default extra="ignore" or extra="forbid"), every firmware update that introduced a new field would either silently drop data or raise a validation error — both unacceptable for a data acquisition library.

Decision

DeviceResponse is defined with model_config = ConfigDict(extra="allow").

Three fields are explicitly typed and validated:

Field Type Notes
type str Required. "response" or "event"
status str \| None "ok" or "error"
received_us int \| None Host-side receipt timestamp

All other fields from the device are accepted as-is and accessible via dot notation or model_dump():

response = parse_jsonl('{"type":"response","status":"ok","version":"1.10.1","poll_count":10}')
print(response.version)     # "1.10.1"  ← not in schema, passes through
print(response.poll_count)  # 10

Alternatives Considered

Alternative Reason Not Chosen
Explicit field per device attribute Breaks on every firmware update; requires library release to accept new fields
extra="ignore" (silently drop unknowns) Loses data; users cannot access new fields without a library update
extra="forbid" Raises ValidationError on any new firmware field; too brittle
Separate typed models per command Duplicates the open-field problem; N models instead of one

Consequences

  • New firmware fields are immediately available as attributes with no library change.
  • Type checking tools (mypy) cannot infer the types of extra fields — callers must use getattr or model_dump() if accessing programmatically by name.
  • Malformed values in extra fields are not validated; only type, status, and received_us are type-checked.
  • model_dump() includes all fields, making serialization complete and lossless.