From 37c120d21962e04cf98408f22a504d8788783db8 Mon Sep 17 00:00:00 2001 From: Edouard CLAUDE Date: Fri, 20 Feb 2026 07:48:31 +0400 Subject: [PATCH] feat(aieos): validate OCEAN values in [0.0, 1.0] range Address review feedback from @nikolasdehor on PR #469. Out-of-range psychology values would produce unexpected natural language output, so we now reject them at load time. --- pkg/aieos/loader.go | 22 ++++++++++++++++++++ pkg/aieos/loader_test.go | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/pkg/aieos/loader.go b/pkg/aieos/loader.go index f989d0d8d..4f2c6816d 100644 --- a/pkg/aieos/loader.go +++ b/pkg/aieos/loader.go @@ -47,5 +47,27 @@ func validate(p *Profile) error { if p.Identity.Name == "" { return fmt.Errorf("aieos: identity.name is required") } + if p.Psychology != nil { + if err := validateOCEAN(p.Psychology); err != nil { + return err + } + } + return nil +} + +// validateOCEAN checks that all OCEAN trait values are in [0.0, 1.0]. +func validateOCEAN(psy *Psychology) error { + traits := map[string]float64{ + "openness": psy.Openness, + "conscientiousness": psy.Conscientiousness, + "extraversion": psy.Extraversion, + "agreeableness": psy.Agreeableness, + "neuroticism": psy.Neuroticism, + } + for name, val := range traits { + if val < 0.0 || val > 1.0 { + return fmt.Errorf("aieos: psychology.%s must be in [0.0, 1.0], got %v", name, val) + } + } return nil } diff --git a/pkg/aieos/loader_test.go b/pkg/aieos/loader_test.go index cebcf586b..7de2f9437 100644 --- a/pkg/aieos/loader_test.go +++ b/pkg/aieos/loader_test.go @@ -103,3 +103,46 @@ func TestDefaultProfilePath(t *testing.T) { got := DefaultProfilePath("/home/user/workspace") assert.Equal(t, "/home/user/workspace/aieos.json", got) } + +func TestLoadProfileOCEANOutOfRange(t *testing.T) { + tests := []struct { + name string + json string + want string + }{ + { + name: "openness too high", + json: `{"version":"1.1","identity":{"name":"A"},"psychology":{"openness":1.5}}`, + want: "psychology.openness must be in [0.0, 1.0]", + }, + { + name: "neuroticism negative", + json: `{"version":"1.1","identity":{"name":"A"},"psychology":{"neuroticism":-0.1}}`, + want: "psychology.neuroticism must be in [0.0, 1.0]", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "aieos.json") + require.NoError(t, os.WriteFile(path, []byte(tt.json), 0644)) + + _, err := LoadProfile(path) + assert.Error(t, err) + assert.Contains(t, err.Error(), tt.want) + }) + } +} + +func TestLoadProfileOCEANValidBoundary(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "aieos.json") + + data := `{"version":"1.1","identity":{"name":"A"},"psychology":{"openness":0.0,"conscientiousness":1.0,"extraversion":0.5,"agreeableness":0.0,"neuroticism":1.0}}` + require.NoError(t, os.WriteFile(path, []byte(data), 0644)) + + p, err := LoadProfile(path) + require.NoError(t, err) + assert.Equal(t, 0.0, p.Psychology.Openness) + assert.Equal(t, 1.0, p.Psychology.Conscientiousness) +}