Tighten hot-path backend consistency
- route SessionContext anchor CGA through algebra.backend - move aspect-weight carry into FieldEnergyOperator.compute - remove duplicated propagate_step threshold patch and per-step imports - add carry_aspect_weight tests for parity, fallback, and propagation preservation - preserve normalization, propagation, vault, Rust dispatch, and energy cadence semantics
This commit is contained in:
parent
f973e61bc2
commit
15ed2cee89
4 changed files with 48 additions and 33 deletions
|
|
@ -87,12 +87,13 @@ class FieldEnergyOperator:
|
|||
coherence_residual: float = 0.0,
|
||||
morphology_features: Mapping[str, object] | None = None,
|
||||
anchor_adjacent: bool = False,
|
||||
carry_aspect_weight: float = 0.0,
|
||||
) -> EnergyProfile:
|
||||
convergence = min(log1p(max(0, convergence_density)) / log1p(8), 1.0)
|
||||
age = max(0, int(current_cycle) - int(last_activation_cycle))
|
||||
recency = min(max(0, activation_count), 8) / 8.0 * exp(-age / 12.0)
|
||||
residual = min(max(0.0, float(coherence_residual)), 1.0)
|
||||
aspect = aspect_weight(morphology_features)
|
||||
aspect = carry_aspect_weight if carry_aspect_weight > 0.0 else aspect_weight(morphology_features)
|
||||
raw = (0.35 * convergence) + (0.25 * recency) + (0.20 * residual) + (0.20 * aspect)
|
||||
if anchor_adjacent and raw >= 0.72:
|
||||
energy_class = EnergyClass.E4
|
||||
|
|
|
|||
|
|
@ -55,38 +55,10 @@ def propagate_step(state: FieldState, V) -> FieldState:
|
|||
current_cycle=new_step,
|
||||
last_activation_cycle=ep.last_activation_cycle,
|
||||
coherence_residual=0.0,
|
||||
morphology_features=None, # aspect weight baked at injection; not re-read here
|
||||
morphology_features=None,
|
||||
anchor_adjacent=ep.anchor_adjacent,
|
||||
carry_aspect_weight=ep.aspect_weight,
|
||||
)
|
||||
# Carry the baked aspect_weight forward: the operator won't re-derive
|
||||
# it from morphology_features=None, so we patch the raw score to
|
||||
# preserve the aspect contribution that was set at the gate.
|
||||
if ep.aspect_weight > 0.0:
|
||||
from dataclasses import replace as _replace
|
||||
# Recompute with the original aspect weight patched back in:
|
||||
# raw already accounts for convergence/recency/residual from above.
|
||||
# We rebuild raw adding the aspect component the operator lost.
|
||||
patched_raw = new_energy.raw + 0.20 * ep.aspect_weight
|
||||
patched_raw = min(patched_raw, 1.0)
|
||||
from core.physics.energy import EnergyClass as _EC
|
||||
if ep.anchor_adjacent and patched_raw >= 0.72:
|
||||
patched_class = _EC.E4
|
||||
elif patched_raw >= 0.82:
|
||||
patched_class = _EC.E4
|
||||
elif patched_raw >= 0.62:
|
||||
patched_class = _EC.E3
|
||||
elif patched_raw >= 0.38:
|
||||
patched_class = _EC.E2
|
||||
elif patched_raw >= 0.16:
|
||||
patched_class = _EC.E1
|
||||
else:
|
||||
patched_class = _EC.E0
|
||||
new_energy = _replace(
|
||||
new_energy,
|
||||
raw=patched_raw,
|
||||
energy_class=patched_class,
|
||||
aspect_weight=ep.aspect_weight,
|
||||
)
|
||||
else:
|
||||
new_energy = None
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ from __future__ import annotations
|
|||
|
||||
import numpy as np
|
||||
|
||||
from algebra.backend import versor_apply
|
||||
from algebra.cga import cga_inner, outer_product
|
||||
from algebra.backend import cga_inner, versor_apply
|
||||
from algebra.cga import outer_product
|
||||
from field.state import FieldState
|
||||
from generate.dialogue import DialogueTurn
|
||||
from generate.proposition import Proposition
|
||||
|
|
|
|||
|
|
@ -344,6 +344,48 @@ class TestPropagateStepEnergyRecomputation:
|
|||
assert state.energy.energy_class is not EnergyClass.E4
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# carry_aspect_weight consolidation
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestCarryAspectWeight:
|
||||
def test_carry_aspect_matches_morphology_derived(self):
|
||||
"""carry_aspect_weight produces identical raw/class as morphology-derived aspect."""
|
||||
base_kw = dict(
|
||||
convergence_density=4,
|
||||
activation_count=4,
|
||||
current_cycle=1,
|
||||
last_activation_cycle=0,
|
||||
coherence_residual=0.0,
|
||||
anchor_adjacent=False,
|
||||
)
|
||||
from_morph = _op.compute(**base_kw, morphology_features={"mood": "imperative"})
|
||||
from_carry = _op.compute(**base_kw, carry_aspect_weight=0.90)
|
||||
assert from_carry.raw == pytest.approx(from_morph.raw)
|
||||
assert from_carry.energy_class is from_morph.energy_class
|
||||
assert from_carry.aspect_weight == pytest.approx(from_morph.aspect_weight)
|
||||
|
||||
def test_carry_zero_falls_back_to_morphology(self):
|
||||
ep = _op.compute(
|
||||
morphology_features={"aspect": "yiqtol"},
|
||||
carry_aspect_weight=0.0,
|
||||
)
|
||||
assert ep.aspect_weight == pytest.approx(0.65)
|
||||
|
||||
def test_propagate_step_preserves_baked_aspect_weight(self):
|
||||
"""Aspect weight injected at the gate survives propagation via carry."""
|
||||
ep = _op.compute(
|
||||
convergence_density=4,
|
||||
activation_count=2,
|
||||
current_cycle=0,
|
||||
morphology_features={"mood": "imperative"},
|
||||
)
|
||||
state = FieldState(F=_clean_versor(), node=0, step=0, energy=ep)
|
||||
new_state = propagate_step(state, _identity_rotor())
|
||||
assert new_state.energy.aspect_weight == pytest.approx(0.90)
|
||||
assert new_state.energy.raw > 0.0
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# EnergyProfile field storage round-trip on FieldState
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue