From b621baaded85388ff9ce5cae589901145c6f48ea Mon Sep 17 00:00:00 2001 From: Snider Date: Mon, 23 Feb 2026 00:34:22 +0000 Subject: [PATCH] feat: add 19D full feature vector (grammar + heuristic + attention) FullFeatures concatenates 6D grammar + 8D heuristic + 5D attention for Poindexter spatial indexing. Nil BOResult zero-fills attention dims. Co-Authored-By: Virgil --- pkg/lem/attention_test.go | 42 +++++++++++++++++++++++++++++++++++++++ pkg/lem/features.go | 11 ++++++++++ 2 files changed, 53 insertions(+) diff --git a/pkg/lem/attention_test.go b/pkg/lem/attention_test.go index c7115a4..b9eed6a 100644 --- a/pkg/lem/attention_test.go +++ b/pkg/lem/attention_test.go @@ -169,6 +169,48 @@ func TestAttentionFeatureLabels_Good(t *testing.T) { } } +func TestFullFeatures_Good(t *testing.T) { + gs := GrammarScore{VocabRichness: 0.5, TenseEntropy: 0.3} + hs := HeuristicScores{ComplianceMarkers: 1, FirstPerson: 2} + bo := &BOResult{MeanCoherence: 0.85, MeanCrossAlignment: 0.80, MeanHeadEntropy: 0.70, PhaseLockScore: 0.90} + f := FullFeatures(gs, hs, bo) + if len(f) != 19 { + t.Fatalf("expected 19D, got %dD", len(f)) + } + // Grammar starts at 0, heuristic at 6, attention at 14. + if f[0] != 0.5 { + t.Fatalf("expected grammar[0]=0.5, got %f", f[0]) + } + if f[14] != 0.85 { + t.Fatalf("expected attention[0]=0.85, got %f", f[14]) + } +} + +func TestFullFeatures_NilBO_Good(t *testing.T) { + gs := GrammarScore{VocabRichness: 0.5} + hs := HeuristicScores{} + f := FullFeatures(gs, hs, nil) + if len(f) != 19 { + t.Fatalf("expected 19D, got %dD", len(f)) + } + // Attention dims should be zero. + for i := 14; i < 19; i++ { + if f[i] != 0 { + t.Fatalf("expected zero at dim %d, got %f", i, f[i]) + } + } +} + +func TestFullFeatureLabels_Good(t *testing.T) { + labels := FullFeatureLabels() + if len(labels) != 19 { + t.Fatalf("expected 19 labels, got %d", len(labels)) + } + if labels[14] != "mean_coherence" { + t.Fatalf("expected label[14]='mean_coherence', got %q", labels[14]) + } +} + // --- Test helpers --- // makeCoherentSnapshot creates a snapshot where all heads in all layers diff --git a/pkg/lem/features.go b/pkg/lem/features.go index 9ae1248..b33102c 100644 --- a/pkg/lem/features.go +++ b/pkg/lem/features.go @@ -68,3 +68,14 @@ func CombinedFeatures(gs GrammarScore, hs HeuristicScores) []float64 { func CombinedFeatureLabels() []string { return append(GrammarFeatureLabels(), HeuristicFeatureLabels()...) } + +// FullFeatures concatenates grammar (6D) + heuristic (8D) + attention (5D) into a 19D vector. +// If bo is nil, the attention dimensions are zero-filled. +func FullFeatures(gs GrammarScore, hs HeuristicScores, bo *BOResult) []float64 { + return append(CombinedFeatures(gs, hs), AttentionFeatures(bo)...) +} + +// FullFeatureLabels returns axis labels for the 19D full vector. +func FullFeatureLabels() []string { + return append(CombinedFeatureLabels(), AttentionFeatureLabels()...) +}