feat(sim): emotions are a right-brain output (Right knob alone)
The affect channel previously gated on BOTH knobs (strength = min(left, right)), so the analytical Left brain co-controlled the emotion words. Per operator direction, emotions are now driven by the Right (dreamlike) knob ALONE — Left no longer gates them. This sharpens the split: Left = measurement (detections + measurements), Right = the dream AND the feeling it evokes. - player/alteration.py: `_affect_strength(right) = right` (was min(left,right)); `_affect_intensity` keyed off Right. AffectOverlay + is_identity docs updated (is_identity still holds: right>0 ⇒ dream.strength>0). - simulator/static/app.js: renderAffect comments (gating is Right via `strength`); the client logic already keyed min_level/tier off the passed strength + right. - Affect design spec: revision note + every min(left,right) → right. - Tests rewritten: affect is Right-driven (full Right + Left 0 surfaces affect; Right 0 + Left 4 surfaces none). 271 passed, 2 skipped. Live API verified: left=0/right=4 → strength 4; left=4/ right=0 → strength 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+17
-14
@@ -88,11 +88,12 @@ class AnalyticalOverlay:
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AffectOverlay:
|
||||
"""Affect channel (Left x Right): emotion-words surfaced only when BOTH the
|
||||
analytical (Left) and dreamlike (Right) knobs are up. `strength` is
|
||||
`min(left, right)` (0..4) — a runtime affect track picks which feeling words
|
||||
appear by it; `intensity` 0..1 is their opacity. The dream leaking into the
|
||||
machine's reading (affect-channel design, session 0013)."""
|
||||
"""Affect channel (RIGHT brain): emotion-words surfaced by the Right (dreamlike)
|
||||
knob alone — the analytical Left knob does NOT gate them. `strength` is the Right
|
||||
knob (0..4) — a runtime affect track picks which feeling words appear by it;
|
||||
`intensity` 0..1 is their opacity. Feeling is the right brain's output, surfaced
|
||||
as the machine's felt reading (affect-channel design, session 0013; Right-only
|
||||
since session 0018)."""
|
||||
|
||||
strength: int
|
||||
intensity: float
|
||||
@@ -122,8 +123,9 @@ class RenderPlan:
|
||||
@property
|
||||
def is_identity(self) -> bool:
|
||||
"""True when the plan leaves the neutral base un-altered. Affect needs no
|
||||
clause: `min(left,right) > 0` implies `left > 0`, so `overlay.level > 0`
|
||||
already makes a plan with active affect non-identity."""
|
||||
clause: `affect.strength == right`, and `right > 0` already makes
|
||||
`dream.strength > 0`, so an active-affect plan is non-identity via the
|
||||
dream check below."""
|
||||
return (
|
||||
self.grade.is_identity
|
||||
and self.overlay.level == 0
|
||||
@@ -135,13 +137,14 @@ def _overlay_intensity(left: int, cal: Calibration) -> float:
|
||||
return _clamp(cal.overlay_gain * left / KNOB_MAX, 0.0, 1.0)
|
||||
|
||||
|
||||
def _affect_strength(left: int, right: int) -> int:
|
||||
"""Affect surfaces only when BOTH knobs are up — gated by the smaller one."""
|
||||
return min(left, right)
|
||||
def _affect_strength(right: int) -> int:
|
||||
"""Affect is a RIGHT-brain output: the emotion channel is driven by the Right
|
||||
(dreamlike) knob alone — the analytical Left knob no longer gates it."""
|
||||
return right
|
||||
|
||||
|
||||
def _affect_intensity(left: int, right: int, cal: Calibration) -> float:
|
||||
return _clamp(cal.overlay_gain * _affect_strength(left, right) / KNOB_MAX, 0.0, 1.0)
|
||||
def _affect_intensity(right: int, cal: Calibration) -> float:
|
||||
return _clamp(cal.overlay_gain * _affect_strength(right) / KNOB_MAX, 0.0, 1.0)
|
||||
|
||||
|
||||
def _dream_intensity(right: int, cal: Calibration) -> float:
|
||||
@@ -163,8 +166,8 @@ def plan_alteration(
|
||||
intensity=_overlay_intensity(coord.left, calibration),
|
||||
),
|
||||
affect=AffectOverlay(
|
||||
strength=_affect_strength(coord.left, coord.right),
|
||||
intensity=_affect_intensity(coord.left, coord.right, calibration),
|
||||
strength=_affect_strength(coord.right),
|
||||
intensity=_affect_intensity(coord.right, calibration),
|
||||
),
|
||||
dream=Dream(
|
||||
strength=coord.right,
|
||||
|
||||
Reference in New Issue
Block a user