Problem
Every contract crossing a module boundary should reject unknown keys. Without a StrictModel base, individual models can drift from the rule and unknown-key bugs surface only at runtime.
Proposed solution
Port src/models/_base.py (StrictModel(BaseModel) with model_config = ConfigDict(extra="forbid", strict=True)). Add src/models/health.py, src/models/session.py, src/models/config.py. The config module uses Pydantic-Settings with generic env-driven LLM provider config (LLM_PROVIDER, LLM_API_KEY, LLM_BASE_URL, LLM_MODEL). Add tests/test_models.py asserting that unknown keys raise ValidationError.
Acceptance criteria
Priority rationale
Critical: invariant 1 of docs/INVARIANTS.md depends on this. The whole "every seam is typed" story rests here.
Depends on
#17
Problem
Every contract crossing a module boundary should reject unknown keys. Without a
StrictModelbase, individual models can drift from the rule and unknown-key bugs surface only at runtime.Proposed solution
Port
src/models/_base.py(StrictModel(BaseModel)withmodel_config = ConfigDict(extra="forbid", strict=True)). Addsrc/models/health.py,src/models/session.py,src/models/config.py. The config module uses Pydantic-Settings with generic env-driven LLM provider config (LLM_PROVIDER,LLM_API_KEY,LLM_BASE_URL,LLM_MODEL). Addtests/test_models.pyasserting that unknown keys raiseValidationError.Acceptance criteria
StrictModeldefinition matches Teller's_base.pybyte-for-byte modulo imports.StrictModel.tests/test_models.pycovers the extra="forbid" guarantee.config.pydoes not reference Azure or OpenAI specifically; provider is pluggable via env.Priority rationale
Critical: invariant 1 of
docs/INVARIANTS.mddepends on this. The whole "every seam is typed" story rests here.Depends on
#17