feat(fase1): dimension IR + admits, MAF-free guard extended (F1)
This commit is contained in:
parent
254e3da1d8
commit
a44256a994
3 changed files with 135 additions and 8 deletions
44
src/portfolio_optimiser/dimension.py
Normal file
44
src/portfolio_optimiser/dimension.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
"""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
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue