"""Typed IR for a cost-reduction *dimension* + the ``admits`` scoping gate (Fase 1, F1). Pure module — imports **only** ``pydantic`` + stdlib. No ``agent_framework`` and no ``verdicts`` (so ``ProposalFeatures`` is never referenced here); ``admits`` takes primitives. This keeps the module D7-portable and MAF-free, enforced by ``tests/test_okf.py::test_okf_is_maf_free`` which AST-scans this file alongside ``okf.py``. A dimension is one cost axis a project is reduced along (energy, paving, ...). ``admits`` decides whether a candidate measure belongs to a dimension: its ``measure_type`` must be allowed, and — when the dimension constrains cost codes — at least one affected code must match an allowed prefix. """ from __future__ import annotations from pydantic import BaseModel, Field class Dimension(BaseModel): """One cost-reduction axis a project's candidate measures are scoped to.""" id: str label: str = Field(min_length=1) allowed_measure_types: frozenset[str] allowed_code_prefixes: frozenset[str] = frozenset() def admits(*, measure_type: str, codes: frozenset[str], dimension: Dimension) -> bool: """True iff a candidate measure belongs to ``dimension``. Two conjoined conditions: - ``measure_type`` is in ``dimension.allowed_measure_types``; **and** - the dimension imposes no code constraint (``allowed_code_prefixes`` empty), **or** at least one of ``codes`` starts with one of the allowed prefixes. """ if measure_type not in dimension.allowed_measure_types: return False if not dimension.allowed_code_prefixes: return True return any( code.startswith(prefix) for code in codes for prefix in dimension.allowed_code_prefixes )