@@ -52,4 +52,91 @@ grep -q 'MINIO_TELEMETRY_DISABLED.*1' extensions/services/langfuse/compose.yaml.
5252 grep -q ' MINIO_TELEMETRY_DISABLED.*1' extensions/services/langfuse/compose.yaml 2> /dev/null || \
5353 { echo " [FAIL] MinIO telemetry not disabled" ; exit 1; }
5454
55+ # --- classify-hardware: shared device_id disambiguation ---
56+ echo " [contract] classify-hardware shared device_id"
57+ _classify () {
58+ bash scripts/classify-hardware.sh --device-id " $1 " --gpu-name " $2 " --gpu-vendor " ${3:- amd} " --vram-mb " ${4:- 0} " 2> /dev/null
59+ }
60+ _classify_id () { _classify " $@ " | jq -r ' .id' ; }
61+ _classify_tier () { _classify " $@ " | jq -r ' .recommended.tier' ; }
62+ _classify_bw () { _classify " $@ " | jq -r ' .bandwidth_gbps' ; }
63+
64+ # --- 0x744c: XTX / XT / GRE (same die, different SKUs) ---
65+
66+ # Happy path: device_id + name → exact match
67+ [[ " $( _classify_id 0x744c " AMD Radeon RX 7900 XTX" amd 24576) " == " rx_7900_xtx" ]] \
68+ || { echo " [FAIL] XTX with name" ; exit 1; }
69+ [[ " $( _classify_id 0x744c " AMD Radeon RX 7900 XT" amd 20480) " == " rx_7900_xt" ]] \
70+ || { echo " [FAIL] XT with name" ; exit 1; }
71+ [[ " $( _classify_id 0x744c " AMD Radeon RX 7900 GRE" amd 16384) " == " rx_7900_gre" ]] \
72+ || { echo " [FAIL] GRE with name" ; exit 1; }
73+
74+ # Substring safety: "RX 7900 XT" is a substring of "RX 7900 XTX"
75+ # XT name must NOT match XTX entry (longest pattern wins)
76+ [[ " $( _classify_id 0x744c " AMD Radeon RX 7900 XT" amd 20480) " != " rx_7900_xtx" ]] \
77+ || { echo " [FAIL] XT matched XTX (substring collision)" ; exit 1; }
78+ # XTX name must NOT match XT entry
79+ [[ " $( _classify_id 0x744c " AMD Radeon RX 7900 XTX" amd 24576) " != " rx_7900_xt" ]] \
80+ || { echo " [FAIL] XTX matched XT" ; exit 1; }
81+
82+ # Tier correctness: GRE is T2, the others are T3
83+ [[ " $( _classify_tier 0x744c " AMD Radeon RX 7900 XTX" amd 24576) " == " T3" ]] \
84+ || { echo " [FAIL] XTX tier" ; exit 1; }
85+ [[ " $( _classify_tier 0x744c " AMD Radeon RX 7900 GRE" amd 16384) " == " T2" ]] \
86+ || { echo " [FAIL] GRE tier" ; exit 1; }
87+
88+ # Bandwidth correctness: each SKU has a different value
89+ [[ " $( _classify_bw 0x744c " AMD Radeon RX 7900 XTX" amd 24576) " == " 960" ]] \
90+ || { echo " [FAIL] XTX bandwidth" ; exit 1; }
91+ [[ " $( _classify_bw 0x744c " AMD Radeon RX 7900 XT" amd 20480) " == " 800" ]] \
92+ || { echo " [FAIL] XT bandwidth" ; exit 1; }
93+ [[ " $( _classify_bw 0x744c " AMD Radeon RX 7900 GRE" amd 16384) " == " 576" ]] \
94+ || { echo " [FAIL] GRE bandwidth" ; exit 1; }
95+
96+ # Empty name: VRAM tiebreaker picks closest match
97+ [[ " $( _classify_id 0x744c " " amd 24576) " == " rx_7900_xtx" ]] \
98+ || { echo " [FAIL] empty name + 24GB → XTX" ; exit 1; }
99+ [[ " $( _classify_id 0x744c " " amd 20480) " == " rx_7900_xt" ]] \
100+ || { echo " [FAIL] empty name + 20GB → XT" ; exit 1; }
101+ [[ " $( _classify_id 0x744c " " amd 16384) " == " rx_7900_gre" ]] \
102+ || { echo " [FAIL] empty name + 16GB → GRE" ; exit 1; }
103+
104+ # Empty name + zero VRAM: picks smallest card (under-provision is safe,
105+ # over-provision would crash the model loader)
106+ [[ " $( _classify_id 0x744c " " amd 0) " == " rx_7900_gre" ]] \
107+ || { echo " [FAIL] empty name + 0 VRAM → should be GRE (smallest)" ; exit 1; }
108+
109+ # Empty name + close-but-not-exact VRAM: picks nearest
110+ # 22000 MB is closer to XT (20480, diff=1520) than XTX (24576, diff=2576)
111+ [[ " $( _classify_id 0x744c " " amd 22000) " == " rx_7900_xt" ]] \
112+ || { echo " [FAIL] empty name + 22GB → should be XT (nearest)" ; exit 1; }
113+ # 18000 MB is closer to GRE (16384, diff=1616) than XT (20480, diff=2480)
114+ [[ " $( _classify_id 0x744c " " amd 18000) " == " rx_7900_gre" ]] \
115+ || { echo " [FAIL] empty name + 18GB → should be GRE (nearest)" ; exit 1; }
116+
117+ # --- 0x7480: RX 7800 XT / RX 7700 XT (second shared device_id pair) ---
118+
119+ [[ " $( _classify_id 0x7480 " AMD Radeon RX 7800 XT" amd 16384) " == " rx_7800_xt" ]] \
120+ || { echo " [FAIL] 7800 XT with name" ; exit 1; }
121+ [[ " $( _classify_id 0x7480 " AMD Radeon RX 7700 XT" amd 12288) " == " rx_7700_xt" ]] \
122+ || { echo " [FAIL] 7700 XT with name" ; exit 1; }
123+ [[ " $( _classify_id 0x7480 " " amd 16384) " == " rx_7800_xt" ]] \
124+ || { echo " [FAIL] 0x7480 empty name + 16GB → 7800 XT" ; exit 1; }
125+ [[ " $( _classify_id 0x7480 " " amd 12288) " == " rx_7700_xt" ]] \
126+ || { echo " [FAIL] 0x7480 empty name + 12GB → 7700 XT" ; exit 1; }
127+
128+ # --- Name-only match (no device_id) ---
129+
130+ [[ " $( _classify_id " " " RYZEN AI MAX+ 395" amd 0) " == " strix_halo_395" ]] \
131+ || { echo " [FAIL] Strix Halo name-only match" ; exit 1; }
132+ [[ " $( _classify_id " " " RX 9070 XT" amd 16384) " == " rx_9070_xt" ]] \
133+ || { echo " [FAIL] RX 9070 XT name-only match" ; exit 1; }
134+
135+ # --- No match → heuristic fallback (should not crash) ---
136+
137+ result=$( _classify_id " 0xFFFF" " Unknown GPU" amd 8192)
138+ [[ -n " $result " && " $result " != " null" ]] \
139+ || { echo " [FAIL] unknown GPU crashed" ; exit 1; }
140+
141+
55142echo " [PASS] installer contracts"
0 commit comments