@@ -103,6 +103,55 @@ describe('Personality routes', () => {
103103 testDb . close ( ) ;
104104 } ) ;
105105
106+ describe ( 'GET /api/personality' , ( ) => {
107+ it ( 'serves a cached snapshot as-is when its profileVersion matches the current version' , async ( ) => {
108+ seedSnapshot ( '2026-W30' , '__all__' , {
109+ results_json : JSON . stringify ( { profileVersion : 2 , sessionCount : 3 , marker : 'from-cache' } ) ,
110+ } ) ;
111+
112+ const app = createApp ( ) ;
113+ const res = await app . request ( '/api/personality?period=2026-W30' ) ;
114+ expect ( res . status ) . toBe ( 200 ) ;
115+ const body = await res . json ( ) ;
116+ expect ( body . marker ) . toBe ( 'from-cache' ) ;
117+ } ) ;
118+
119+ it ( 'ignores a cached snapshot missing profileVersion (pre-MBTI schema) and recomputes fresh instead' , async ( ) => {
120+ // Simulates a snapshot persisted before the cognitiveFunctions + mbti addition —
121+ // no profileVersion field at all, so it JSON.parses fine but is missing fields the
122+ // frontend (MbtiCard, CognitiveFunctionRadarChart) unconditionally reads, which used
123+ // to crash the dashboard. readSnapshot must treat this as a cache miss.
124+ seedSnapshot ( '2026-W30' , '__all__' , {
125+ results_json : JSON . stringify ( { sessionCount : 3 , marker : 'stale-pre-v2-cache' } ) ,
126+ } ) ;
127+ seedProject ( 'proj-1' , 'alpha' ) ;
128+ seedSession ( 'sess-1' , 'proj-1' , { project_id : 'proj-1' , started_at : '2026-07-20T10:00:00Z' } ) ;
129+ seedFacets ( 'sess-1' ) ;
130+
131+ const app = createApp ( ) ;
132+ const res = await app . request ( '/api/personality?period=2026-W30' ) ;
133+ expect ( res . status ) . toBe ( 200 ) ;
134+ const body = await res . json ( ) ;
135+ expect ( body . marker ) . toBeUndefined ( ) ;
136+ expect ( body . profileVersion ) . toBe ( 2 ) ;
137+ expect ( body . mbti ) . toBeDefined ( ) ;
138+ expect ( body . cognitiveFunctions ) . toBeDefined ( ) ;
139+ } ) ;
140+
141+ it ( 'ignores a cached snapshot with an old numeric profileVersion (1) and recomputes fresh instead' , async ( ) => {
142+ seedSnapshot ( '2026-W30' , '__all__' , {
143+ results_json : JSON . stringify ( { profileVersion : 1 , sessionCount : 3 , marker : 'stale-v1-cache' } ) ,
144+ } ) ;
145+
146+ const app = createApp ( ) ;
147+ const res = await app . request ( '/api/personality?period=2026-W30' ) ;
148+ expect ( res . status ) . toBe ( 200 ) ;
149+ const body = await res . json ( ) ;
150+ expect ( body . marker ) . toBeUndefined ( ) ;
151+ expect ( body . profileVersion ) . toBe ( 2 ) ;
152+ } ) ;
153+ } ) ;
154+
106155 describe ( 'GET /api/personality/projects' , ( ) => {
107156 it ( 'returns empty array when no projects have facet-analyzed sessions' , async ( ) => {
108157 seedProject ( 'proj-1' , 'alpha' ) ;
0 commit comments