22
33import hashlib
44import json
5- import sys
65import tempfile
76import unittest
87from pathlib import Path
9- from types import ModuleType
108
119from quant_platform_kit .common .feature_snapshot import load_feature_snapshot_guarded
1210
1311
1412class FeatureSnapshotGuardAliasTests (unittest .TestCase ):
15- def test_guard_accepts_legacy_strategy_profile_alias_in_manifest (self ) -> None :
16- package = ModuleType ("us_equity_strategies" )
17- catalog = ModuleType ("us_equity_strategies.catalog" )
18-
19- def resolve_canonical_profile (profile : str | None ) -> str :
20- mapping = {
21- "tech_pullback_cash_buffer" : "qqq_tech_enhancement" ,
22- "qqq_tech_enhancement" : "qqq_tech_enhancement" ,
23- }
24- return mapping .get (str (profile ), str (profile ))
25-
26- catalog .resolve_canonical_profile = resolve_canonical_profile
27- sys .modules [package .__name__ ] = package
28- sys .modules [catalog .__name__ ] = catalog
29- self .addCleanup (sys .modules .pop , package .__name__ , None )
30- self .addCleanup (sys .modules .pop , catalog .__name__ , None )
31-
13+ def test_guard_rejects_retired_strategy_profile_alias_in_manifest (self ) -> None :
3214 with tempfile .TemporaryDirectory () as tmp_dir :
3315 tmp_path = Path (tmp_dir )
3416 snapshot_path = tmp_path / "snapshot.csv"
3517 manifest_path = tmp_path / "snapshot.csv.manifest.json"
36- config_path = tmp_path / "tech_pullback_cash_buffer.json"
3718 snapshot_path .write_text (
3819 "as_of,symbol,close\n 2026-04-01,QQQ,500\n " ,
3920 encoding = "utf-8" ,
4021 )
41- config_path .write_text ('{"name": "tech_pullback_cash_buffer"}' , encoding = "utf-8" )
4222 snapshot_sha256 = hashlib .sha256 (snapshot_path .read_bytes ()).hexdigest ()
43- config_sha256 = hashlib .sha256 (config_path .read_bytes ()).hexdigest ()
4423 manifest_path .write_text (
4524 json .dumps (
4625 {
@@ -49,7 +28,7 @@ def resolve_canonical_profile(profile: str | None) -> str:
4928 "config_name" : "tech_pullback_cash_buffer" ,
5029 "contract_version" : "tech_pullback_cash_buffer.feature_snapshot.v1" ,
5130 "snapshot_sha256" : snapshot_sha256 ,
52- "config_sha256" : config_sha256 ,
31+ "config_sha256" : "abc" ,
5332 "price_as_of" : "2026-04-01" ,
5433 "universe_as_of" : "2026-03-31" ,
5534 "source_input_status" : "fresh" ,
@@ -70,13 +49,13 @@ def resolve_canonical_profile(profile: str | None) -> str:
7049 expected_config_name = "qqq_tech_enhancement" ,
7150 )
7251
73- self .assertIsNotNone (result .frame )
74- self .assertEqual (result .metadata ["snapshot_guard_decision" ], "proceed " )
52+ self .assertIsNone (result .frame )
53+ self .assertEqual (result .metadata ["snapshot_guard_decision" ], "fail_closed " )
7554 self .assertEqual (result .metadata ["snapshot_manifest_strategy_profile" ], "tech_pullback_cash_buffer" )
76- self .assertEqual ( result . metadata [ "snapshot_manifest_price_as_of" ], "2026-04-01" )
77- self . assertEqual ( result . metadata [ "snapshot_manifest_universe_as_of" ], "2026-03-31" )
78- self . assertEqual (result .metadata ["snapshot_manifest_source_input_status" ], "fresh" )
79- self . assertEqual ( result . metadata [ "snapshot_manifest_source_refresh_run_id" ], "12345" )
55+ self .assertIn (
56+ "feature_snapshot_manifest_strategy_profile_mismatch" ,
57+ str (result .metadata ["fail_reason" ]),
58+ )
8059
8160 def test_guard_includes_manifest_diagnostics_when_stale (self ) -> None :
8261 with tempfile .TemporaryDirectory () as tmp_dir :
0 commit comments