Dominance Dimension — Design Note (G7)¶
Status: IMPLEMENTED in v0.8.2 — commit 8b9ddbe (2026-05-04). Option A shipped.
References: Mehrabian & Russell (1974); benchmarks/fidelity/test_pad_dominance.py;
benchmarks/fidelity/test_dominance_retrieval_gap.py.
1. State before v0.8.2 (historical)¶
CoreAffect was a 2-dimensional (valence × arousal) value object.
Dominance lived only in MoodField as a derived scalar via the PAD heuristic:
MoodField.dominance drove no retrieval signal. Two memories encoded at
identical (valence, arousal) but with semantically opposite dominance —
e.g., "I seized control of the argument" (high dominance) vs "I felt helpless"
(low dominance) — received identical CoreAffect fingerprints and were
indistinguishable by any of AFT's 6 retrieval signals.
This gap was operationalised by test_dominance_retrieval_gap.py (xfail until
v0.8.2).
2. The gap¶
The gap is operationalised in benchmarks/fidelity/test_dominance_retrieval_gap.py
(currently xfail): a high-dominance query cannot preferentially retrieve
high-dominance memories when both memories share the same valence and arousal.
This matters for: - Assertiveness vs helplessness — semantically opposite but mood-matched - Authority vs submission contexts in conversation memory - Approach/avoidance patterns that PAD theory attributes to dominance, not to valence or arousal alone
3. Design options¶
Option A: Elevate dominance to a CoreAffect primary dimension¶
Add dominance: float (clamped to [0, 1]) to CoreAffect alongside valence
and arousal.
Implications:
- CoreAffect.distance() / CoreAffect.similarity() become 3D — weighted
Euclidean in (valence, arousal, dominance) space, e.g., weights (1.0, 1.0, 0.5)
reflecting PAD's empirical finding that dominance has lower cross-situational
variance than valence.
- AppraisalVector → CoreAffect must produce a dominance estimate; the
Scherer CPM prompt must be extended.
- KeywordAppraisalEngine needs dominance rules (authority/control vs
helplessness/submission vocabulary).
- EmotionalTag and all serialisation paths gain a dominance field.
- Migration: existing memories decoded without dominance default to 0.5
(neutral).
Option B: Keep 2D CoreAffect; add dominance as a separate retrieval signal¶
Keep CoreAffect 2D; add dominance: float to EmotionalTag and
AffectiveState, and add a 7th retrieval signal "dominance proximity" that
computes distance between query dominance and stored memory dominance.
Implications:
- Lower migration cost (CoreAffect stays stable).
- Dominance proximity requires a dominance estimate at retrieval time
(from query appraisal or user-set affect).
- Signal can be toggled off (adds enable_dominance: bool to
RetrievalConfig), consistent with the ablation framework.
4. Decision¶
Preferred: Option A for v0.8.0, with these guards:
- The existing
test_pad_dominance.pysuite must continue passing (regression guard onMoodFieldbehaviour). test_dominance_retrieval_gap.pybecomes the acceptance test: it is currentlyxfail(strict=True)and must PASS after implementation.- A migration script or auto-defaulting must preserve existing serialised memories (dominance=0.5 for legacy records).
- Appraisal prompt extension is behind the
LLMAppraisalEnginepath;KeywordAppraisalEnginegets rule-based dominance heuristics (authority and control vocabulary). - The
AppraisalVector.dominancefield already exists — it only needs to be wired intoCoreAffectproduction inengine.encode().
5. Evidence needed before implementation¶
- At least one fidelity scenario where dominance-differential memories share
valence/arousal (provided by
test_dominance_retrieval_gap.py). - Smoke test confirming that existing round-trip serialisation (encode → export → import → retrieve) is dominance-neutral at default 0.5.
- No regression on any of the 126 existing fidelity cases.
6. Interaction with G4/G5 (realistic_recall_v2)¶
realistic_recall_v2.json includes the momentum_alignment challenge type.
Dominance is NOT required for momentum_alignment; that challenge relies on
AffectiveMomentum (velocity + acceleration over valence/arousal history).
The v2 dataset should therefore NOT require dominance-specific scenarios — it
remains compatible with the current 2D CoreAffect.
Adding a dominance-specific challenge type would be a natural extension for
realistic_recall_v3 (post v0.8.0).
7. Closure — v0.8.2 implementation (2026-05-04)¶
Option A was shipped in commit 8b9ddbe. Implementation summary:
CoreAffectis now 3D (valence × arousal × dominance).dominance: float = 0.5(neutral default, clamped [0, 1] by Pydantic validator)._MAX_AFFECT_DISTinretrieval.pyupdated √5 → √6 (Euclidean normalizer for 3D PAD).AppraisalVector.coping_potentialmaps directly toCoreAffect.dominance(no signed conversion needed — same [0, 1] scale).MoodFieldreadscore_affect.dominancedirectly in the EMA update (no heuristic).AffectiveMomentumgainsd_dominanceanddd_dominancefields.AffectiveState._historytuples extended to 4-element(ts, v, a, d).test_dominance_retrieval_gap.pyxfail removed — test passes.test_pad_dominance.pyrewritten to test EMA-direct behaviour (not the old heuristic).
The backward-compat migration path (Option A §3 above) was intentionally skipped:
existing serialised states with 3-element history tuples are rejected on restore
(len(entry) >= 4 guard). Fresh encode → export → import round-trips use the 4-element
format natively.