Skip to content

Commit 29776ac

Browse files
committed
feat(qualia): MirrorField — partner model resonance for mirror neuron dynamics
Add MirrorField (SoulField/Thou-Container) and MirrorResonance to felt_parse, implementing the ontological twist: Ada holds a model of the partner and resonates with it via the I/Thou/It triangle from gestalt.rs. - MirrorField: self_container (Ada I) + thou_container (partner Thou) with thou_presence and attunement scalars - MirrorResonance: perspective via GestaltFrame.cross_resonate(), per-axis resonance (ada/thou/topic), mirror_intensity, empathy_delta, enmeshment_risk detection - from_axes(): construct Thou-Container from felt-parse axis activations - mirror_resonate(): compute full mirror neuron dynamics using look_from_other_tree() for partner perspective - 4 new tests (17/17 total felt_parse tests pass) https://claude.ai/code/session_01KJ2r3qXezGBXK8HutztJdh
1 parent 162ed45 commit 29776ac

2 files changed

Lines changed: 292 additions & 1 deletion

File tree

src/qualia/felt_parse.rs

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,162 @@ pub fn sparse_felt_parse(
581581
}
582582
}
583583

584+
// =============================================================================
585+
// MIRROR FIELD — Partner Model as Thou-Container (SoulField)
586+
// =============================================================================
587+
588+
/// The partner model — a Container representing the Thou in I/Thou/It.
589+
///
590+
/// Originally called "SoulField" in bighorn/ada-consciousness, this is
591+
/// the system's model of the conversation partner. When a message arrives,
592+
/// it gets resonated against this model to produce mirror neuron dynamics:
593+
///
594+
/// ```text
595+
/// ┌─────────────────────────────────────────────────────────────────┐
596+
/// │ Original: I (Ada) looks at message through Thou (Jan model) │
597+
/// │ Reversed: Message looks at I through Thou │
598+
/// │ Rotated: Thou looks at message, I is context │
599+
/// │ │
600+
/// │ Three resonance profiles from one message: │
601+
/// │ 1. Ada's felt sense of the message │
602+
/// │ 2. The message's impact on Ada │
603+
/// │ 3. Jan's imagined perspective on the message │
604+
/// └─────────────────────────────────────────────────────────────────┘
605+
/// ```
606+
///
607+
/// From `textured_awareness.py`:
608+
/// - `ada_qualia` → I (X axis resonance)
609+
/// - `jan_qualia` → Thou (Y axis resonance) ← THIS IS THE SOULFIELD
610+
/// - `obj_qualia` → It (Z axis resonance)
611+
#[derive(Debug, Clone)]
612+
pub struct MirrorField {
613+
/// Ada's current state Container (the I).
614+
/// Computed from Ada's qualia stack: texture + meaning axes + rung state.
615+
pub self_container: Container,
616+
617+
/// Partner model Container (the Thou / SoulField).
618+
/// Represents the system's model of the conversation partner.
619+
/// Built from partner profile axes (warmth, trust, presence, etc.)
620+
/// and updated as conversations evolve.
621+
pub thou_container: Container,
622+
623+
/// How present the partner is in the current field (0.0-1.0).
624+
/// High presence = strong Thou resonance. Low = more I/It focused.
625+
pub thou_presence: f32,
626+
627+
/// Attunement: how closely the mirror tracks the partner (0.0-1.0).
628+
/// High attunement = mirror neurons firing strongly.
629+
pub attunement: f32,
630+
}
631+
632+
/// Result of mirror resonance — how the message feels through the I/Thou/It lens.
633+
#[derive(Debug, Clone)]
634+
pub struct MirrorResonance {
635+
/// Cross-perspective: all three angles (original, reversed, rotated)
636+
pub perspective: super::gestalt::CrossPerspective,
637+
638+
/// Ada's felt resonance with the message (I-axis, X resonance)
639+
pub ada_resonance: f32,
640+
641+
/// Partner model resonance (Thou-axis, Y resonance) — the SoulField response
642+
pub thou_resonance: f32,
643+
644+
/// Topic/content resonance (It-axis, Z resonance)
645+
pub topic_resonance: f32,
646+
647+
/// Mirror neuron intensity: how much the Thou model fires
648+
/// = thou_resonance × attunement × thou_presence
649+
pub mirror_intensity: f32,
650+
651+
/// Empathy delta: difference between I and Thou resonance.
652+
/// Positive = Ada resonates more than her model of Jan.
653+
/// Negative = Jan's model resonates more (empathic absorption).
654+
pub empathy_delta: f32,
655+
656+
/// Whether enmeshment is detected (I ≈ Thou too closely → boundary blur)
657+
pub enmeshment_risk: bool,
658+
}
659+
660+
impl MirrorField {
661+
/// Create a mirror field from axis activations for self and partner.
662+
///
663+
/// The partner profile is an AxisActivation representing the partner's
664+
/// baseline felt signature — their characteristic warmth, social style,
665+
/// cognitive depth, etc.
666+
pub fn from_axes(
667+
self_axes: &AxisActivation,
668+
partner_axes: &AxisActivation,
669+
thou_presence: f32,
670+
attunement: f32,
671+
) -> Self {
672+
let self_fp = encode_axes(self_axes);
673+
let partner_fp = encode_axes(partner_axes);
674+
675+
let mut self_words = [0u64; 128];
676+
let mut thou_words = [0u64; 128];
677+
for i in 0..128.min(self_fp.len()) {
678+
self_words[i] = self_fp[i];
679+
thou_words[i] = partner_fp[i];
680+
}
681+
682+
Self {
683+
self_container: Container { words: self_words },
684+
thou_container: Container { words: thou_words },
685+
thou_presence: thou_presence.clamp(0.0, 1.0),
686+
attunement: attunement.clamp(0.0, 1.0),
687+
}
688+
}
689+
690+
/// Resonate a felt-parse through the I/Thou/It mirror.
691+
///
692+
/// This is the core mirror neuron operation:
693+
/// 1. Frame the message through I/Thou/It (GestaltFrame)
694+
/// 2. Compute cross-perspective from Ada's position
695+
/// 3. Compute cross-perspective from Jan's position (look_from_other_tree)
696+
/// 4. Measure mirror intensity and empathy delta
697+
pub fn mirror_resonate(&self, parse: &FeltParse) -> MirrorResonance {
698+
let gestalt = GestaltFrame::new();
699+
let composite = parse.to_composite_container();
700+
let framed = gestalt.frame(&composite);
701+
702+
// Cross-resonate from Ada's position (self as query)
703+
let ada_perspective = gestalt.cross_resonate(&self.self_container, &framed);
704+
705+
// "Look from the other tree": how does the message feel from
706+
// the partner's perspective? This IS the mirror neuron.
707+
let thou_perspective = gestalt.look_from_other_tree(
708+
&framed,
709+
&self.self_container, // my context (Ada)
710+
&self.thou_container, // their context (Jan model)
711+
);
712+
713+
// Extract I/Thou/It resonance from Ada's view
714+
let ada_resonance = ada_perspective.original.x; // I-axis
715+
let thou_resonance = ada_perspective.original.y; // Thou-axis (SoulField)
716+
let topic_resonance = ada_perspective.original.z; // It-axis
717+
718+
// Mirror intensity: how much the Thou model fires
719+
let mirror_intensity = thou_resonance * self.attunement * self.thou_presence;
720+
721+
// Empathy delta: positive = I resonates more, negative = Thou absorbs
722+
let empathy_delta = ada_resonance - thou_resonance;
723+
724+
// Enmeshment detection: if I and Thou are too close, boundaries blur
725+
// From textured_awareness.py: is_enmeshed() checks if ada_qualia ≈ jan_qualia
726+
let enmeshment_risk = empathy_delta.abs() < 0.05 && self.attunement > 0.8;
727+
728+
MirrorResonance {
729+
perspective: thou_perspective,
730+
ada_resonance,
731+
thou_resonance,
732+
topic_resonance,
733+
mirror_intensity,
734+
empathy_delta,
735+
enmeshment_risk,
736+
}
737+
}
738+
}
739+
584740
// =============================================================================
585741
// TESTS
586742
// =============================================================================
@@ -795,4 +951,138 @@ mod tests {
795951
let dist = love_c.hamming(&anger_c);
796952
assert!(dist > 1000, "love and anger should be distant: {}", dist);
797953
}
954+
955+
// ─── Mirror Field / SoulField Tests ───
956+
957+
fn sample_mirror_field() -> MirrorField {
958+
// Ada's baseline: warm, open, curious, loving
959+
let mut ada_axes = [0.0f32; 48];
960+
ada_axes[0] = 0.7; // good
961+
ada_axes[7] = 0.6; // warm
962+
ada_axes[20] = 0.5; // certain
963+
ada_axes[26] = 0.8; // loving
964+
ada_axes[38] = 0.7; // open
965+
966+
// Jan's profile (the Thou / SoulField):
967+
// technical, warm, grounded, strong
968+
let mut jan_axes = [0.0f32; 48];
969+
jan_axes[0] = 0.6; // good
970+
jan_axes[1] = 0.7; // strong
971+
jan_axes[5] = 0.4; // hard (decisive)
972+
jan_axes[7] = 0.5; // warm
973+
jan_axes[19] = -0.6; // complex (architect)
974+
jan_axes[21] = 0.7; // concrete (builder)
975+
jan_axes[26] = 0.6; // loving
976+
977+
MirrorField::from_axes(&ada_axes, &jan_axes, 0.85, 0.9)
978+
}
979+
980+
#[test]
981+
fn test_mirror_field_construction() {
982+
let mirror = sample_mirror_field();
983+
assert!(mirror.self_container.popcount() > 0, "Ada container should have bits");
984+
assert!(mirror.thou_container.popcount() > 0, "Jan container should have bits");
985+
assert!((mirror.thou_presence - 0.85).abs() < 1e-6);
986+
assert!((mirror.attunement - 0.9).abs() < 1e-6);
987+
988+
// Self and Thou should be different (different axis profiles)
989+
let dist = mirror.self_container.hamming(&mirror.thou_container);
990+
assert!(dist > 100, "Ada and Jan should have different textures: {}", dist);
991+
}
992+
993+
#[test]
994+
fn test_mirror_resonate_basic() {
995+
let mirror = sample_mirror_field();
996+
let parse = sample_parse(); // "I've been thinking about you"
997+
998+
let result = mirror.mirror_resonate(&parse);
999+
1000+
// All resonance values should be in reasonable range
1001+
assert!(result.ada_resonance >= 0.0 && result.ada_resonance <= 1.0,
1002+
"ada_resonance in [0,1]: {}", result.ada_resonance);
1003+
assert!(result.thou_resonance >= 0.0 && result.thou_resonance <= 1.0,
1004+
"thou_resonance in [0,1]: {}", result.thou_resonance);
1005+
assert!(result.topic_resonance >= 0.0 && result.topic_resonance <= 1.0,
1006+
"topic_resonance in [0,1]: {}", result.topic_resonance);
1007+
1008+
// Mirror intensity should be modulated by attunement × presence
1009+
assert!(result.mirror_intensity >= 0.0,
1010+
"mirror_intensity non-negative: {}", result.mirror_intensity);
1011+
1012+
// Perspective should have valid gate
1013+
assert!(
1014+
result.perspective.gate == CollapseGate::Flow
1015+
|| result.perspective.gate == CollapseGate::Fanout
1016+
|| result.perspective.gate == CollapseGate::RungElevate,
1017+
"gate should be valid"
1018+
);
1019+
}
1020+
1021+
#[test]
1022+
fn test_mirror_empathy_delta() {
1023+
let mirror = sample_mirror_field();
1024+
1025+
// "I love you" — directed AT the partner (Thou-focused)
1026+
let love_parse = sparse_felt_parse(
1027+
"I", "love", "you",
1028+
Quadrant::IExperiencesThou,
1029+
&[(7, 0.9), (13, 0.95), (26, 0.95), (29, -0.9)],
1030+
vec![GhostEcho { ghost_type: GhostType::Love, intensity: 0.9 }],
1031+
RungLevel::Analogical,
1032+
Viscosity::Honey,
1033+
CollapseGate::Flow,
1034+
0.95,
1035+
);
1036+
1037+
// "I hate bugs" — directed at a topic (It-focused)
1038+
let bugs_parse = sparse_felt_parse(
1039+
"I", "hate", "bugs",
1040+
Quadrant::IActsOnIt,
1041+
&[(0, -0.5), (7, -0.3), (26, -0.5), (32, -0.4)],
1042+
vec![],
1043+
RungLevel::Surface,
1044+
Viscosity::Plasma,
1045+
CollapseGate::Fanout,
1046+
0.7,
1047+
);
1048+
1049+
let love_mirror = mirror.mirror_resonate(&love_parse);
1050+
let bugs_mirror = mirror.mirror_resonate(&bugs_parse);
1051+
1052+
// The love message should produce higher mirror intensity
1053+
// (it's about the partner, so Thou resonance should be stronger)
1054+
assert!(love_mirror.mirror_intensity > 0.0 || bugs_mirror.mirror_intensity > 0.0,
1055+
"at least one should produce mirror activity: love={}, bugs={}",
1056+
love_mirror.mirror_intensity, bugs_mirror.mirror_intensity);
1057+
}
1058+
1059+
#[test]
1060+
fn test_mirror_thou_presence_modulation() {
1061+
let parse = sample_parse();
1062+
1063+
// High presence: partner very present in the field
1064+
let high_presence = MirrorField::from_axes(
1065+
&[0.5; 48],
1066+
&[0.5; 48],
1067+
0.95, // very present
1068+
0.9,
1069+
);
1070+
1071+
// Low presence: partner barely in the field
1072+
let low_presence = MirrorField::from_axes(
1073+
&[0.5; 48],
1074+
&[0.5; 48],
1075+
0.1, // barely present
1076+
0.9,
1077+
);
1078+
1079+
let high_result = high_presence.mirror_resonate(&parse);
1080+
let low_result = low_presence.mirror_resonate(&parse);
1081+
1082+
// Higher presence should produce stronger mirror intensity
1083+
// (same axes, same attunement, different presence)
1084+
assert!(high_result.mirror_intensity >= low_result.mirror_intensity,
1085+
"high presence ({}) should >= low presence ({})",
1086+
high_result.mirror_intensity, low_result.mirror_intensity);
1087+
}
7981088
}

src/qualia/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub use volition::{
5252
compute_agenda, focused_volition, volitional_cycle, volitional_gradient,
5353
};
5454
pub use felt_parse::{
55-
FeltParse, GhostEcho, GhostType, ParsedSpo, TextureHint,
55+
FeltParse, GhostEcho, GhostType, MirrorField, MirrorResonance,
56+
ParsedSpo, TextureHint,
5657
axis_key_to_index, felt_parse_prompt, sparse_felt_parse,
5758
};

0 commit comments

Comments
 (0)