core/core/physics/exertion.py
Shay 159c783c2e feat(physics): add mind-physics layer — ADR-0008/0009/0010, blueprint, and operator stubs
- docs/decisions/ADR-0008-allocation-physics.md
  Formalizes salience, attention, inhibition, and coherence-budget
  as the allocation physics of cognition. Replaces attention-as-weights
  with attention-as-field-curvature over the versor manifold.

- docs/decisions/ADR-0009-compositional-physics.md
  Defines temporal binding, digest cycles, reasoning trajectories,
  and articulation planning as the compositional physics layer —
  how CORE assembles pressure into structured thought and output.

- docs/decisions/ADR-0010-identity-physics.md
  Establishes IdentityManifold, DriveGradientMap, ExertionMeter,
  and CharacterProfile as structural identity primitives. Identity
  is a field over the geometry, not a prompt veneer. Grounded in
  John 1:1–2 and the Logos theology that anchors the architecture.

- docs/architecture/MIND-PHYSICS-BLUEPRINT.md
  Integration blueprint showing how allocation → compositional →
  identity physics layers compose into the full cognitive cycle.

- core/physics/ (11 Python interface stubs)
  SalienceOperator, AttentionOperator, InhibitionOperator,
  BindingFrame, DigestCycle, ReasoningTrajectory,
  ArticulationPlanner, DriveGradientMap, ExertionMeter,
  IdentityManifold, CharacterProfile — all typed, all frozen
  where stateless, all carrying explicit field contracts.

Third Door: no off-the-shelf cognitive architecture borrowed.
All operators defined from the geometry up.
2026-05-12 23:20:58 -07:00

68 lines
2.2 KiB
Python

"""core.physics.exertion — Exertion tracking and fatigue modeling.
ADR-0010: Identity is not infinitely elastic. Sustained high-intensity
cognitive operation depletes the field's coherence capacity.
The ExertionMeter tracks cumulative activation cost and computes
a FatigueIndex that modulates available CoherenceBudget.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Tuple
@dataclass(frozen=True)
class CycleCost:
"""Resource consumption record for a single cognitive cycle."""
cycle_index: int
attention_cost: float
inhibition_cost: float
digest_cost: float
trajectory_cost: float
@property
def total(self) -> float:
return self.attention_cost + self.inhibition_cost + self.digest_cost + self.trajectory_cost
@dataclass(frozen=True)
class FatigueIndex:
"""Scalar fatigue state in [0.0, 1.0].
0.0 = fully rested, full coherence capacity available.
1.0 = fully depleted, minimum coherence capacity available.
Values between 0.0 and 1.0 compress CoherenceBudget proportionally.
"""
value: float
computed_at_cycle: int
def __post_init__(self) -> None:
if not (0.0 <= self.value <= 1.0):
raise ValueError("FatigueIndex.value must be in [0.0, 1.0]")
def apply_to_budget(self, total_capacity: float) -> float:
"""Return the available capacity after fatigue compression."""
return total_capacity * (1.0 - self.value)
class ExertionMeter:
"""Tracks cumulative activation cost and computes FatigueIndex.
rest() resets accumulated cost to zero (end of a deliberate rest point).
fatigue() returns the current FatigueIndex without modifying state.
"""
def __init__(self, capacity_ceiling: float) -> None:
self._capacity_ceiling = capacity_ceiling
self._cycle_costs: list[CycleCost] = []
def record(self, cost: CycleCost) -> None:
self._cycle_costs.append(cost)
def fatigue(self, at_cycle: int) -> FatigueIndex:
total_spent = sum(c.total for c in self._cycle_costs)
ratio = min(total_spent / self._capacity_ceiling, 1.0)
return FatigueIndex(value=ratio, computed_at_cycle=at_cycle)
def rest(self) -> None:
self._cycle_costs.clear()