46 lines
1.4 KiB
Python
46 lines
1.4 KiB
Python
|
|
"""Energy events — capture only.
|
||
|
|
|
||
|
|
H-005 is dormant by decision: verification energy is not testable at the current
|
||
|
|
scale, and a scoring function producing a number nobody can check is worse than
|
||
|
|
no number. Events are recorded from the first run because history cannot be
|
||
|
|
reconstructed later; scores always can.
|
||
|
|
|
||
|
|
There is deliberately no score() function in this module.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from dataclasses import asdict, dataclass, field
|
||
|
|
from datetime import datetime, timezone
|
||
|
|
from enum import Enum
|
||
|
|
from typing import Any
|
||
|
|
|
||
|
|
|
||
|
|
class EnergyEventType(str, Enum):
|
||
|
|
DEFECT_DETECTED = "DEFECT_DETECTED"
|
||
|
|
REGRESSION_CAUGHT = "REGRESSION_CAUGHT"
|
||
|
|
MECHANICAL_ADAPTATION = "MECHANICAL_ADAPTATION"
|
||
|
|
SEMANTIC_ADAPTATION = "SEMANTIC_ADAPTATION"
|
||
|
|
TEST_DEFECT = "TEST_DEFECT"
|
||
|
|
FALSE_POSITIVE = "FALSE_POSITIVE"
|
||
|
|
DUPLICATE = "DUPLICATE"
|
||
|
|
CRYSTALLIZED = "CRYSTALLIZED"
|
||
|
|
USECASE_DEPRECATED = "USECASE_DEPRECATED"
|
||
|
|
EXECUTED = "EXECUTED"
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass(frozen=True, slots=True)
|
||
|
|
class EnergyEvent:
|
||
|
|
"""Immutable. Energy is derived from event history, never stored as state."""
|
||
|
|
|
||
|
|
asset_id: str
|
||
|
|
run_id: str
|
||
|
|
event_type: EnergyEventType
|
||
|
|
detail: dict[str, Any] = field(default_factory=dict)
|
||
|
|
at: str = field(
|
||
|
|
default_factory=lambda: datetime.now(timezone.utc).isoformat()
|
||
|
|
)
|
||
|
|
|
||
|
|
def as_dict(self) -> dict[str, Any]:
|
||
|
|
return {**asdict(self), "event_type": self.event_type.value}
|