@@ -12,7 +12,7 @@ use crate::video_profile::{
1212 apply_profile_memory, vote_detect, DetectResult , ObservedSignals , ProfileCandidate ,
1313 ProfileKind , ProfileMemory ,
1414} ;
15- use crate :: video_profile_spec:: ContentForm ;
15+ use crate :: video_profile_spec:: { ContentForm , VisualTier } ;
1616
1717/// 构造观测信号辅助(默认全 None)。
1818fn signals ( ) -> ObservedSignals {
@@ -173,3 +173,48 @@ fn detect_result_old_json_missing_memory_conflict() {
173173 assert_eq ! ( r. memory_conflict, None ) ;
174174 assert_eq ! ( r. candidates[ 0 ] . kind, ProfileKind :: Lecture ) ;
175175}
176+
177+ /// 批 7 T19(U2):记忆档随检测结果带回(检测卡档位下拉初值 ⇒ 显示 == 实际生效档)。
178+ #[ test]
179+ fn memory_tier_reported_for_display ( ) {
180+ // Arrange:只记过档位(未记形态/kind)
181+ let memory = {
182+ let mut m = ProfileMemory :: default ( ) ;
183+ m. remember_tier ( "零基础化妆教程" , VisualTier :: Rich ) ;
184+ m
185+ } ;
186+ // Act
187+ let result = apply_profile_memory ( vote_detect ( & signals ( ) ) , & memory, "零基础化妆教程" ) ;
188+ // Assert:档位独立通道回填;kind/form 通道**未被** tier-only 条目污染
189+ assert_eq ! ( result. memory_tier, Some ( VisualTier :: Rich ) , "记忆档应随检测结果带回" ) ;
190+ assert_eq ! ( result. memory_hit, None , "tier-only 条目不得伪造 kind 命中" ) ;
191+ assert_eq ! ( result. memory_form, None , "tier-only 条目不得伪造形态命中" ) ;
192+ }
193+
194+ /// 批 7 T19(U2)边界:② 冲突象限(检测为准)**仍**带回记忆档——档位是独立轴,
195+ /// 与形态判定无关,且与 start_live_session 的解析(显式 > 记忆)口径一致。
196+ #[ test]
197+ fn memory_tier_reported_even_when_detection_wins ( ) {
198+ let memory = {
199+ let mut m = ProfileMemory :: default ( ) ;
200+ m. remember_tier ( "实操演练" , VisualTier :: Low ) ;
201+ m
202+ } ;
203+ let result = apply_profile_memory ( vote_detect ( & strong_hands_on_signals ( ) ) , & memory, "实操演练" ) ;
204+ // Assert:形态按检测(无 memory_hit),档位仍按记忆
205+ assert_eq ! ( result. memory_hit, None , "前置条件:高置信冲突 ⇒ 检测为准" ) ;
206+ assert_eq ! ( result. memory_tier, Some ( VisualTier :: Low ) , "独立轴:档位不随形态冲突被丢弃" ) ;
207+ }
208+
209+ /// 批 7 T19(U2)负控:无记忆档 ⇒ None(前端回落本地映射兜底,AGENTS.md §3.4)。
210+ #[ test]
211+ fn memory_tier_none_without_memory ( ) {
212+ let result = apply_profile_memory ( vote_detect ( & signals ( ) ) , & ProfileMemory :: default ( ) , "未记过的标题" ) ;
213+ assert_eq ! ( result. memory_tier, None ) ;
214+ // 旧 JSON 兼容:缺 memory_tier 字段 → None(零迁移)
215+ let old: DetectResult = serde_json:: from_str (
216+ r#"{"candidates":[{"kind":"lecture","score":1.0}],"needs_confirmation":false,"memory_hit":null}"# ,
217+ )
218+ . unwrap ( ) ;
219+ assert_eq ! ( old. memory_tier, None ) ;
220+ }
0 commit comments