diff --git a/scripts/assign_filament_ids.py b/scripts/assign_filament_ids.py index 6f12554f14..c5e6aefe58 100644 --- a/scripts/assign_filament_ids.py +++ b/scripts/assign_filament_ids.py @@ -26,7 +26,11 @@ Policy (companion to assign_vendor_setting_ids.py; see filament_id_plan_v3.md): resolving. * Reserved id spaces that are never minted into or altered: - GF* Bambu AMS/RFID catalog (vendor BBL untouchable) - - QD_* Qidi device protocol + - QD_* Qidi device protocol (dissolved island, plan v4: + every shipped QD_* id is retired in the ledger and + the QidiPrinterAgent translates device-composed + QD_* ids through the succession walk; no preset + may ever declare one again) - P + 7 hex chars (case-insensitive) and the literal "null" user-custom presets (CreatePresetsDialog.cpp) - every already-shipped id, grandfathered via scripts/filament_id_snapshot.json @@ -40,7 +44,7 @@ Policy (companion to assign_vendor_setting_ids.py; see filament_id_plan_v3.md): rule over the vanished id's old claims — and the runtime follows those chains (plus cross-island "hints" for ids Orca cannot retire, e.g. GF*) on resolution miss. A retired id may never be used again for anything. - Vanished ids in a FOREIGN island's space (GF*/QD_*) are released with a + Vanished ids in a FOREIGN island's space (GF*) are released with a hint instead of retired: the island's catalog owns them and may legitimately (re)ship them. @@ -325,8 +329,9 @@ def resolve_triple(name, filaments, ofl_filaments): def is_island_declaration(vendor, fid): - """Declarations frozen outside the OF mint domain: all of BBL, QD_* in Qidi.""" - return vendor == "BBL" or (vendor == "Qidi" and fid.startswith("QD_")) + """Declarations frozen outside the OF mint domain: all of BBL (the QD_* + island was dissolved by plan v4 — Qidi declarations mint like any other).""" + return vendor == "BBL" def analyze_tree(profiles_dir): @@ -598,12 +603,21 @@ def reserved_space_owner(fid): if fid.startswith("GF"): return True, "BBL" if fid.startswith("QD_"): - return True, "Qidi" + return True, None # dissolved Qidi device-protocol space: NO vendor may declare it if USER_CUSTOM_ID_RE.match(fid) or fid == "null": return True, None # user-custom space: no system vendor may own it return False, None +def reserved_space_desc(fid, owner): + """Human description of a reserved space for error messages.""" + if owner: + return f"owned by {owner}" + if fid.startswith("QD_"): + return "Qidi device protocol; dissolved island — ids are retired, never declarable" + return "reserved for user-custom presets" + + # --------------------------------------------------------------------------- # Checks (imported and called tree-wide by orca_extra_profile_check.py) # --------------------------------------------------------------------------- @@ -613,8 +627,7 @@ def check_filament_ids(profiles_dir=PROFILES_DIR, snapshot_path=SNAPSHOT_PATH, """Validate filament_id state across every vendor. Returns the error count. 1. Format: every id occurring in the tree (declared or effective) must be in - the snapshot, or match ^OF[0-9A-Za-z]{6}$, or belong to vendor BBL, or be - a QD_* id within vendor Qidi. + the snapshot, or match ^OF[0-9A-Za-z]{6}$, or belong to vendor BBL. 2. Snapshot equality, both directions: the tree-derived id->families multimap AND the id->triples map of the declarers must equal the snapshot exactly (the snapshot diff is the maintainer gate). @@ -625,8 +638,8 @@ def check_filament_ids(profiles_dir=PROFILES_DIR, snapshot_path=SNAPSHOT_PATH, 5. Alias hygiene: a vendor preset riding an OFL family must keep the OFL base name, claim printers via non-empty compatible_printers, and declare no filament_id key of its own. - 6. Reserved namespaces (GF*/QD_*/P-hex/"null") only for their owner vendors, - except claims grandfathered in the snapshot. + 6. Reserved namespaces (GF* for BBL; QD_*/P-hex/"null" for nobody) must not + be claimed by other vendors, except claims grandfathered in the snapshot. 7. Structure ratchet: (a) no NEW instantiated preset carries its own filament_id key; (b) no NEW declared-vs-inherited id drift; (c) every instantiated filament resolves an effective id (a hard load error in C++). @@ -664,8 +677,6 @@ def check_filament_ids(profiles_dir=PROFILES_DIR, snapshot_path=SNAPSHOT_PATH, continue if vendor == "BBL": continue - if vendor == "Qidi" and fid.startswith("QD_"): - continue print_error( f'filament_id "{fid}" ({vendor}) is neither grandfathered in the ' f'snapshot nor a minted "OF" id; new family ids must come from ' @@ -765,7 +776,7 @@ def check_filament_ids(profiles_dir=PROFILES_DIR, snapshot_path=SNAPSHOT_PATH, continue if claim in snap_ids.get(fid, []): continue # grandfathered - space = f"owned by {owner}" if owner else "reserved for user-custom presets" + space = reserved_space_desc(fid, owner) print_error( f'filament_id "{fid}" of "{claim}" is in a reserved id space ' f"({space}) and must not be claimed by system presets of other vendors") @@ -861,7 +872,7 @@ def check_filament_ids(profiles_dir=PROFILES_DIR, snapshot_path=SNAPSHOT_PATH, if island is None: print_error( f'hint key "{key}" ({RETIRED_REL}) is not in an island id space ' - f"(GF*/QD_*); non-island ids are retired with a successor instead") + f"(GF*); non-island ids are retired with a successor instead") errors += 1 continue if key in retired: @@ -902,7 +913,7 @@ def update_snapshot(profiles_dir=PROFILES_DIR, snapshot_path=SNAPSHOT_PATH, Vanished ids gain a succession-ledger entry whose successor is picked by the mode rule over their old claims (None when the family died heirless); - vanished ids in a foreign island's space (GF*/QD_*) are released with a + vanished ids in a foreign island's space (GF*) are released with a hint instead — the island catalog owns them, so they must stay mintable there and must never be blocked by check 4. --forget-never-shipped lists ids to drop from lineage instead of retiring @@ -955,7 +966,7 @@ def update_snapshot(profiles_dir=PROFILES_DIR, snapshot_path=SNAPSHOT_PATH, refusals.append((fid, f"{vendor}/(declared only)", owner)) if refusals and not allow_shared_catalog: for fid, claim, owner in refusals: - space = f"owned by {owner}" if owner else "reserved for user-custom presets" + space = reserved_space_desc(fid, owner) print_error( f'refusing to sanction new claim "{claim}" on reserved-namespace id ' f'"{fid}" ({space}); pass --allow-shared-catalog only for ' @@ -977,7 +988,7 @@ def update_snapshot(profiles_dir=PROFILES_DIR, snapshot_path=SNAPSHOT_PATH, # Retire ids that fully vanished from the tree (append-only ledger), with a # mode-rule successor so devices and user presets keep resolving. Vanished - # ids in a FOREIGN island's reserved space (GF*/QD_*) are never retired — + # ids in a FOREIGN island's reserved space (GF*) are never retired — # the island's catalog still owns them and may legitimately (re)ship them — # they are RELEASED, with a succession hint so they keep resolving on miss. claim_ids = claim_effective_ids(analysis) @@ -1073,7 +1084,7 @@ def update_snapshot(profiles_dir=PROFILES_DIR, snapshot_path=SNAPSHOT_PATH, def add_hints(pairs, profiles_dir=PROFILES_DIR, retired_path=RETIRED_PATH): """--add-hint "OLD=NEW": forward an island-space id to a live id. - OLD must sit in an island id space (GF*/QD_*), must not be retired, and — + OLD must sit in an island id space (GF*), must not be retired, and — when live in the tree — may be declared only by island vendors (Orca cannot retire it). An absent OLD is fine: island catalogs own ids Orca never shipped or has released. NEW must be live in the tree. All pairs validate @@ -1103,7 +1114,7 @@ def add_hints(pairs, profiles_dir=PROFILES_DIR, retired_path=RETIRED_PATH): errors += 1 elif island is None: print_error( - f'--add-hint: "{old}" is not in an island id space (GF*/QD_*); ' + f'--add-hint: "{old}" is not in an island id space (GF*); ' f"non-island ids are retired with a successor by --update-snapshot") errors += 1 elif outsiders: diff --git a/scripts/filament_id_snapshot.json b/scripts/filament_id_snapshot.json index c8ae5b34be..14d207b34f 100644 --- a/scripts/filament_id_snapshot.json +++ b/scripts/filament_id_snapshot.json @@ -16227,6 +16227,1434 @@ "ABS", "FLSun S1 ABS" ] + ], + "QD_0_1_1": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido" + ] + ], + "QD_0_1_15": [ + [ + "QIDI", + "TPU-GF", + "QIDI TPU-GF" + ] + ], + "QD_0_1_2": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Matte" + ] + ], + "QD_0_1_20": [ + [ + "QIDI", + "ASA-CF", + "QIDI ASA-CF" + ] + ], + "QD_0_1_24": [ + [ + "QIDI", + "UltraPA", + "QIDI PA-Ultra" + ] + ], + "QD_0_1_26": [ + [ + "QIDI", + "UltraPA-CF25", + "QIDI UltraPA-CF25" + ] + ], + "QD_0_1_27": [ + [ + "QIDI", + "PA12-CF", + "QIDI PA12-CF" + ] + ], + "QD_0_1_3": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Metal" + ] + ], + "QD_0_1_30": [ + [ + "QIDI", + "PAHT-CF", + "QIDI PAHT-CF" + ] + ], + "QD_0_1_31": [ + [ + "QIDI", + "PAHT-GF", + "QIDI PAHT-GF" + ] + ], + "QD_0_1_32": [ + [ + "QIDI", + "PAHT-S", + "QIDI Support For PAHT" + ] + ], + "QD_0_1_33": [ + [ + "QIDI", + "PA-S", + "QIDI Support For PET/PA" + ] + ], + "QD_0_1_34": [ + [ + "QIDI", + "PC-ABS-FR", + "Qidi PC-ABS-FR" + ] + ], + "QD_0_1_36": [ + [ + "QIDI", + "PEBA", + "QIDI PEBA 95A" + ] + ], + "QD_0_1_37": [ + [ + "QIDI", + "PET-CF", + "QIDI PET-CF" + ] + ], + "QD_0_1_38": [ + [ + "QIDI", + "PET-GF", + "QIDI PET-GF" + ] + ], + "QD_0_1_39": [ + [ + "QIDI", + "PETG", + "QIDI PETG Basic" + ] + ], + "QD_0_1_4": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Silk" + ] + ], + "QD_0_1_40": [ + [ + "QIDI", + "PETG", + "QIDI PETG Tough" + ] + ], + "QD_0_1_41": [ + [ + "QIDI", + "PETG", + "QIDI PETG Rapido" + ] + ], + "QD_0_1_42": [ + [ + "QIDI", + "PETG-CF", + "QIDI PETG-CF" + ] + ], + "QD_0_1_43": [ + [ + "QIDI", + "PETG-GF", + "QIDI PETG-GF" + ] + ], + "QD_0_1_44": [ + [ + "QIDI", + "PPS-CF", + "QIDI PPS-CF" + ] + ], + "QD_0_1_45": [ + [ + "QIDI", + "PETG", + "QIDI PETG Translucent" + ] + ], + "QD_0_1_46": [ + [ + "QIDI", + "PPS-GF", + "QIDI PPS-GF" + ] + ], + "QD_0_1_49": [ + [ + "QIDI", + "TPU-AERO", + "QIDI TPU-Aero" + ] + ], + "QD_0_1_5": [ + [ + "QIDI", + "PLA-CF", + "QIDI PLA-CF" + ] + ], + "QD_0_1_50": [ + [ + "QIDI", + "TPU", + "Qidi TPU 95A-HF" + ] + ], + "QD_0_1_6": [ + [ + "QIDI", + "PLA", + "QIDI WOOD Rapido" + ] + ], + "QD_0_1_7": [ + [ + "QIDI", + "PLA", + "QIDI PLA Basic" + ] + ], + "QD_0_1_8": [ + [ + "QIDI", + "PLA", + "QIDI PLA Matte Basic" + ] + ], + "QD_1_0_1": [ + [ + "Generic", + "PLA", + "Generic PLA" + ] + ], + "QD_1_0_11": [ + [ + "Generic", + "ABS", + "Generic ABS" + ] + ], + "QD_1_0_23": [ + [ + "Generic", + "PC", + "Generic PC" + ] + ], + "QD_1_0_4": [ + [ + "Generic", + "PLA", + "Generic PLA Silk" + ] + ], + "QD_1_0_41": [ + [ + "Generic", + "PETG", + "Generic PETG" + ] + ], + "QD_1_0_50": [ + [ + "Generic", + "TPU", + "Generic TPU 95A" + ] + ], + "QD_1_1_1": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido" + ] + ], + "QD_1_1_11": [ + [ + "QIDI", + "ABS", + "QIDI ABS Rapido" + ] + ], + "QD_1_1_12": [ + [ + "QIDI", + "ABS-GF", + "QIDI ABS-GF" + ] + ], + "QD_1_1_13": [ + [ + "QIDI", + "ABS", + "QIDI ABS Rapido Metal" + ] + ], + "QD_1_1_14": [ + [ + "QIDI", + "ABS", + "QIDI ABS Odorless" + ] + ], + "QD_1_1_15": [ + [ + "QIDI", + "TPU-GF", + "QIDI TPU-GF" + ] + ], + "QD_1_1_18": [ + [ + "QIDI", + "ASA", + "QIDI ASA" + ] + ], + "QD_1_1_19": [ + [ + "QIDI", + "ASA-AERO", + "QIDI ASA-Aero" + ] + ], + "QD_1_1_2": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Matte" + ] + ], + "QD_1_1_20": [ + [ + "QIDI", + "ASA-CF", + "QIDI ASA-CF" + ] + ], + "QD_1_1_24": [ + [ + "QIDI", + "UltraPA", + "QIDI UltraPA" + ] + ], + "QD_1_1_26": [ + [ + "QIDI", + "UltraPA-CF25", + "QIDI UltraPA-CF25" + ] + ], + "QD_1_1_27": [ + [ + "QIDI", + "PA12-CF", + "QIDI PA12-CF" + ] + ], + "QD_1_1_3": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Metal" + ] + ], + "QD_1_1_30": [ + [ + "QIDI", + "PAHT-CF", + "QIDI PAHT-CF" + ] + ], + "QD_1_1_31": [ + [ + "QIDI", + "PAHT-GF", + "QIDI PAHT-GF" + ] + ], + "QD_1_1_32": [ + [ + "QIDI", + "PAHT-S", + "QIDI Support For PAHT" + ] + ], + "QD_1_1_33": [ + [ + "QIDI", + "PA-S", + "QIDI Support For PET/PA" + ] + ], + "QD_1_1_34": [ + [ + "QIDI", + "PC-ABS-FR", + "QIDI PC-ABS-FR" + ] + ], + "QD_1_1_36": [ + [ + "QIDI", + "PEBA", + "QIDI PEBA 95A" + ] + ], + "QD_1_1_37": [ + [ + "QIDI", + "PET-CF", + "QIDI PET-CF" + ] + ], + "QD_1_1_38": [ + [ + "QIDI", + "PET-GF", + "QIDI PET-GF" + ] + ], + "QD_1_1_39": [ + [ + "QIDI", + "PETG", + "QIDI PETG Basic" + ] + ], + "QD_1_1_4": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Silk" + ] + ], + "QD_1_1_40": [ + [ + "QIDI", + "PETG", + "QIDI PETG Tough" + ] + ], + "QD_1_1_41": [ + [ + "QIDI", + "PETG", + "QIDI PETG Rapido" + ] + ], + "QD_1_1_42": [ + [ + "QIDI", + "PETG-CF", + "QIDI PETG-CF" + ] + ], + "QD_1_1_43": [ + [ + "QIDI", + "PETG-GF", + "QIDI PETG-GF" + ] + ], + "QD_1_1_44": [ + [ + "QIDI", + "PPS-CF", + "QIDI PPS-CF" + ] + ], + "QD_1_1_45": [ + [ + "QIDI", + "PETG", + "QIDI PETG Translucent" + ] + ], + "QD_1_1_46": [ + [ + "QIDI", + "PPS-GF", + "QIDI PPS-GF" + ] + ], + "QD_1_1_49": [ + [ + "QIDI", + "TPU-AERO", + "QIDI TPU-Aero" + ] + ], + "QD_1_1_5": [ + [ + "QIDI", + "PLA-CF", + "QIDI PLA-CF" + ] + ], + "QD_1_1_50": [ + [ + "QIDI", + "TPU", + "QIDI TPU 95A-HF" + ] + ], + "QD_1_1_6": [ + [ + "QIDI", + "PLA", + "QIDI WOOD Rapido" + ] + ], + "QD_1_1_7": [ + [ + "QIDI", + "PLA", + "QIDI PLA Basic" + ] + ], + "QD_1_1_8": [ + [ + "QIDI", + "PLA", + "QIDI PLA Matte Basic" + ] + ], + "QD_2_0_1": [ + [ + "Generic", + "PLA", + "Generic PLA" + ] + ], + "QD_2_0_11": [ + [ + "Generic", + "ABS", + "Generic ABS" + ] + ], + "QD_2_0_23": [ + [ + "Generic", + "PC", + "Generic PC" + ] + ], + "QD_2_0_4": [ + [ + "Generic", + "PLA", + "Generic PLA Silk" + ] + ], + "QD_2_0_41": [ + [ + "Generic", + "PETG", + "Generic PETG" + ] + ], + "QD_2_0_50": [ + [ + "Generic", + "TPU", + "Generic TPU 95A" + ] + ], + "QD_2_1_1": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido" + ] + ], + "QD_2_1_11": [ + [ + "QIDI", + "ABS", + "QIDI ABS Rapido" + ] + ], + "QD_2_1_12": [ + [ + "QIDI", + "ABS-GF", + "QIDI ABS-GF" + ] + ], + "QD_2_1_13": [ + [ + "QIDI", + "ABS", + "QIDI ABS Rapido Metal" + ] + ], + "QD_2_1_14": [ + [ + "QIDI", + "ABS", + "QIDI ABS Odorless" + ] + ], + "QD_2_1_15": [ + [ + "QIDI", + "TPU-GF", + "QIDI TPU-GF" + ] + ], + "QD_2_1_18": [ + [ + "QIDI", + "ASA", + "QIDI ASA" + ] + ], + "QD_2_1_19": [ + [ + "QIDI", + "ASA-AERO", + "QIDI ASA-Aero" + ] + ], + "QD_2_1_2": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Matte" + ] + ], + "QD_2_1_20": [ + [ + "QIDI", + "ASA-CF", + "QIDI ASA-CF" + ] + ], + "QD_2_1_24": [ + [ + "QIDI", + "UltraPA", + "QIDI UltraPA" + ] + ], + "QD_2_1_26": [ + [ + "QIDI", + "UltraPA-CF25", + "QIDI UltraPA-CF25" + ] + ], + "QD_2_1_27": [ + [ + "QIDI", + "PA12-CF", + "QIDI PA12-CF" + ] + ], + "QD_2_1_3": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Metal" + ] + ], + "QD_2_1_30": [ + [ + "QIDI", + "PAHT-CF", + "QIDI PAHT-CF" + ] + ], + "QD_2_1_31": [ + [ + "QIDI", + "PAHT-GF", + "QIDI PAHT-GF" + ] + ], + "QD_2_1_32": [ + [ + "QIDI", + "PAHT-S", + "QIDI Support For PAHT" + ] + ], + "QD_2_1_33": [ + [ + "QIDI", + "PA-S", + "QIDI Support For PET/PA" + ] + ], + "QD_2_1_34": [ + [ + "QIDI", + "PC-ABS-FR", + "QIDI PC-ABS-FR" + ] + ], + "QD_2_1_36": [ + [ + "QIDI", + "PEBA", + "QIDI PEBA 95A" + ] + ], + "QD_2_1_37": [ + [ + "QIDI", + "PET-CF", + "QIDI PET-CF" + ] + ], + "QD_2_1_38": [ + [ + "QIDI", + "PET-GF", + "QIDI PET-GF" + ] + ], + "QD_2_1_39": [ + [ + "QIDI", + "PETG", + "QIDI PETG Basic" + ] + ], + "QD_2_1_4": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Silk" + ] + ], + "QD_2_1_40": [ + [ + "QIDI", + "PETG", + "QIDI PETG Tough" + ] + ], + "QD_2_1_41": [ + [ + "QIDI", + "PETG", + "QIDI PETG Rapido" + ] + ], + "QD_2_1_42": [ + [ + "QIDI", + "PETG-CF", + "QIDI PETG-CF" + ] + ], + "QD_2_1_43": [ + [ + "QIDI", + "PETG-GF", + "QIDI PETG-GF" + ] + ], + "QD_2_1_44": [ + [ + "QIDI", + "PPS-CF", + "QIDI PPS-CF" + ] + ], + "QD_2_1_45": [ + [ + "QIDI", + "PETG", + "QIDI PETG Translucent" + ] + ], + "QD_2_1_46": [ + [ + "QIDI", + "PPS-GF", + "QIDI PPS-GF" + ] + ], + "QD_2_1_49": [ + [ + "QIDI", + "TPU-AERO", + "QIDI TPU-Aero" + ] + ], + "QD_2_1_5": [ + [ + "QIDI", + "PLA-CF", + "QIDI PLA-CF" + ] + ], + "QD_2_1_50": [ + [ + "QIDI", + "TPU", + "QIDI TPU 95A-HF" + ] + ], + "QD_2_1_6": [ + [ + "QIDI", + "PLA", + "QIDI WOOD Rapido" + ] + ], + "QD_2_1_7": [ + [ + "QIDI", + "PLA", + "QIDI PLA Basic" + ] + ], + "QD_2_1_8": [ + [ + "QIDI", + "PLA", + "QIDI PLA Matte Basic" + ] + ], + "QD_3_0_1": [ + [ + "Generic", + "PLA", + "Generic PLA" + ] + ], + "QD_3_0_11": [ + [ + "Generic", + "ABS", + "Generic ABS" + ] + ], + "QD_3_0_23": [ + [ + "Generic", + "PC", + "Generic PC" + ] + ], + "QD_3_0_4": [ + [ + "Generic", + "PLA", + "Generic PLA Silk" + ] + ], + "QD_3_0_41": [ + [ + "Generic", + "PETG", + "Generic PETG" + ] + ], + "QD_3_0_50": [ + [ + "Generic", + "TPU", + "Generic TPU 95A" + ] + ], + "QD_3_1_1": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido" + ] + ], + "QD_3_1_11": [ + [ + "QIDI", + "ABS", + "QIDI ABS Rapido" + ] + ], + "QD_3_1_12": [ + [ + "QIDI", + "ABS-GF", + "QIDI ABS-GF" + ] + ], + "QD_3_1_13": [ + [ + "QIDI", + "ABS", + "QIDI ABS Rapido Metal" + ] + ], + "QD_3_1_14": [ + [ + "QIDI", + "ABS", + "QIDI ABS Odorless" + ] + ], + "QD_3_1_15": [ + [ + "QIDI", + "TPU-GF", + "QIDI TPU-GF" + ] + ], + "QD_3_1_18": [ + [ + "QIDI", + "ASA", + "QIDI ASA" + ] + ], + "QD_3_1_19": [ + [ + "QIDI", + "ASA-AERO", + "QIDI ASA-Aero" + ] + ], + "QD_3_1_2": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Matte" + ] + ], + "QD_3_1_20": [ + [ + "QIDI", + "ASA-CF", + "QIDI ASA-CF" + ] + ], + "QD_3_1_24": [ + [ + "QIDI", + "UltraPA", + "QIDI UltraPA" + ] + ], + "QD_3_1_26": [ + [ + "QIDI", + "UltraPA-CF25", + "QIDI UltraPA-CF25" + ] + ], + "QD_3_1_27": [ + [ + "QIDI", + "PA12-CF", + "QIDI PA12-CF" + ] + ], + "QD_3_1_3": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Metal" + ] + ], + "QD_3_1_30": [ + [ + "QIDI", + "PAHT-CF", + "QIDI PAHT-CF" + ] + ], + "QD_3_1_31": [ + [ + "QIDI", + "PAHT-GF", + "QIDI PAHT-GF" + ] + ], + "QD_3_1_32": [ + [ + "QIDI", + "PAHT-S", + "QIDI Support For PAHT" + ] + ], + "QD_3_1_33": [ + [ + "QIDI", + "PA-S", + "QIDI Support For PET/PA" + ] + ], + "QD_3_1_34": [ + [ + "QIDI", + "PC-ABS-FR", + "QIDI PC/ABS-FR" + ] + ], + "QD_3_1_36": [ + [ + "QIDI", + "PEBA", + "QIDI PEBA 95A" + ] + ], + "QD_3_1_37": [ + [ + "QIDI", + "PET-CF", + "QIDI PET-CF" + ] + ], + "QD_3_1_38": [ + [ + "QIDI", + "PET-GF", + "QIDI PET-GF" + ] + ], + "QD_3_1_39": [ + [ + "QIDI", + "PETG", + "QIDI PETG Basic" + ] + ], + "QD_3_1_4": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Silk" + ] + ], + "QD_3_1_40": [ + [ + "QIDI", + "PETG", + "QIDI PETG Tough" + ] + ], + "QD_3_1_41": [ + [ + "QIDI", + "PETG", + "QIDI PETG Rapido" + ] + ], + "QD_3_1_42": [ + [ + "QIDI", + "PETG-CF", + "QIDI PETG-CF" + ] + ], + "QD_3_1_43": [ + [ + "QIDI", + "PETG-GF", + "QIDI PETG-GF" + ] + ], + "QD_3_1_44": [ + [ + "QIDI", + "PPS-CF", + "QIDI PPS-CF" + ] + ], + "QD_3_1_45": [ + [ + "QIDI", + "PETG", + "QIDI PETG Translucent" + ] + ], + "QD_3_1_46": [ + [ + "QIDI", + "PPS-GF", + "QIDI PPS-GF" + ] + ], + "QD_3_1_49": [ + [ + "QIDI", + "TPU-AERO", + "QIDI TPU-Aero" + ] + ], + "QD_3_1_5": [ + [ + "QIDI", + "PLA-CF", + "QIDI PLA-CF" + ] + ], + "QD_3_1_50": [ + [ + "QIDI", + "TPU", + "QIDI TPU 95A-HF" + ] + ], + "QD_3_1_6": [ + [ + "QIDI", + "PLA", + "QIDI WOOD Rapido" + ] + ], + "QD_3_1_7": [ + [ + "QIDI", + "PLA", + "QIDI PLA Basic" + ] + ], + "QD_3_1_8": [ + [ + "QIDI", + "PLA", + "QIDI PLA Matte Basic" + ] + ], + "QD_4_0_1": [ + [ + "Generic", + "PLA", + "Generic PLA" + ] + ], + "QD_4_0_11": [ + [ + "Generic", + "ABS", + "Generic ABS" + ] + ], + "QD_4_0_23": [ + [ + "Generic", + "PC", + "Generic PC" + ] + ], + "QD_4_0_4": [ + [ + "Generic", + "PLA", + "Generic PLA Silk" + ] + ], + "QD_4_0_41": [ + [ + "Generic", + "PETG", + "Generic PETG" + ] + ], + "QD_4_0_50": [ + [ + "Generic", + "TPU", + "Generic TPU 95A" + ] + ], + "QD_4_1_1": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido" + ] + ], + "QD_4_1_11": [ + [ + "QIDI", + "ABS", + "QIDI ABS Rapido" + ] + ], + "QD_4_1_12": [ + [ + "QIDI", + "ABS-GF", + "QIDI ABS-GF" + ] + ], + "QD_4_1_13": [ + [ + "QIDI", + "ABS", + "QIDI ABS Rapido Metal" + ] + ], + "QD_4_1_14": [ + [ + "QIDI", + "ABS", + "QIDI ABS Odorless" + ] + ], + "QD_4_1_15": [ + [ + "QIDI", + "TPU-GF", + "QIDI TPU-GF" + ] + ], + "QD_4_1_18": [ + [ + "QIDI", + "ASA", + "QIDI ASA" + ] + ], + "QD_4_1_19": [ + [ + "QIDI", + "ASA-AERO", + "QIDI ASA-Aero" + ] + ], + "QD_4_1_2": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Matte" + ] + ], + "QD_4_1_20": [ + [ + "QIDI", + "ASA-CF", + "QIDI ASA-CF" + ] + ], + "QD_4_1_24": [ + [ + "QIDI", + "UltraPA", + "QIDI UltraPA" + ] + ], + "QD_4_1_25": [ + [ + "QIDI", + "PA6-CF", + "QIDI PA6-CF" + ] + ], + "QD_4_1_26": [ + [ + "QIDI", + "UltraPA-CF25", + "QIDI UltraPA-CF25" + ] + ], + "QD_4_1_27": [ + [ + "QIDI", + "PA12-CF", + "QIDI PA12-CF" + ] + ], + "QD_4_1_3": [ + [ + "QIDI", + "PLA", + "QIDI PLA Rapido Metal" + ] + ], + "QD_4_1_30": [ + [ + "QIDI", + "PAHT-CF", + "QIDI PAHT-CF" + ] + ], + "QD_4_1_31": [ + [ + "QIDI", + "PAHT-GF", + "QIDI PAHT-GF" + ] + ], + "QD_4_1_32": [ + [ + "QIDI", + "PAHT-S", + "QIDI Support For PAHT" + ] + ], + "QD_4_1_33": [ + [ + "QIDI", + "PA-S", + "QIDI Support For PET/PA" + ] + ], + "QD_4_1_34": [ + [ + "QIDI", + "PC-ABS-FR", + "QIDI PC/ABS-FR" + ] + ], + "QD_4_1_36": [ + [ + "QIDI", + "PEBA", + "QIDI PEBA 95A" + ] + ], + "QD_4_1_37": [ + [ + "QIDI", + "PET-CF", + "QIDI PET-CF" + ] + ], + "QD_4_1_38": [ + [ + "QIDI", + "PET-GF", + "QIDI PET-GF" + ] + ], + "QD_4_1_39": [ + [ + "QIDI", + "PETG", + "QIDI PETG Basic" + ] + ], + "QD_4_1_4": [ + [ + "QIDI", + "PLA", + "QIDI PLA Silk" + ] + ], + "QD_4_1_40": [ + [ + "QIDI", + "PETG", + "QIDI PETG Tough" + ] + ], + "QD_4_1_41": [ + [ + "QIDI", + "PETG", + "QIDI PETG Rapido" + ] + ], + "QD_4_1_42": [ + [ + "QIDI", + "PETG-CF", + "QIDI PETG-CF" + ] + ], + "QD_4_1_43": [ + [ + "QIDI", + "PETG-GF", + "QIDI PETG-GF" + ] + ], + "QD_4_1_44": [ + [ + "QIDI", + "PPS-CF", + "QIDI PPS-CF" + ] + ], + "QD_4_1_45": [ + [ + "QIDI", + "PETG", + "QIDI PETG Translucent" + ] + ], + "QD_4_1_46": [ + [ + "QIDI", + "PPS-GF", + "QIDI PPS-GF" + ] + ], + "QD_4_1_49": [ + [ + "QIDI", + "TPU-AERO", + "QIDI TPU-Aero" + ] + ], + "QD_4_1_5": [ + [ + "QIDI", + "PLA-CF", + "QIDI PLA-CF" + ] + ], + "QD_4_1_50": [ + [ + "QIDI", + "TPU", + "QIDI TPU 95A-HF" + ] + ], + "QD_4_1_6": [ + [ + "QIDI", + "PLA", + "QIDI WOOD Rapido" + ] + ], + "QD_4_1_7": [ + [ + "QIDI", + "PLA", + "QIDI PLA Basic" + ] + ], + "QD_4_1_8": [ + [ + "QIDI", + "PLA", + "QIDI PLA Matte Basic" + ] ] } } diff --git a/scripts/tests/test_filament_id.py b/scripts/tests/test_filament_id.py index cfba38866c..0918702017 100644 --- a/scripts/tests/test_filament_id.py +++ b/scripts/tests/test_filament_id.py @@ -8,6 +8,7 @@ import contextlib import io import json import os +import re import shutil import sys import tempfile @@ -400,7 +401,8 @@ class TestTripleResolution(unittest.TestCase): class TestReservedSpaces(unittest.TestCase): def test_owners(self): self.assertEqual(afi.reserved_space_owner("GFL99"), (True, "BBL")) - self.assertEqual(afi.reserved_space_owner("QD_X4_PLA"), (True, "Qidi")) + # dissolved island (plan v4): reserved, but no vendor may declare it + self.assertEqual(afi.reserved_space_owner("QD_X4_PLA"), (True, None)) self.assertEqual(afi.reserved_space_owner("P1234abc"), (True, None)) self.assertEqual(afi.reserved_space_owner("pAbCdEf1"), (True, None)) # case-insensitive self.assertEqual(afi.reserved_space_owner("null"), (True, None)) @@ -410,7 +412,8 @@ class TestReservedSpaces(unittest.TestCase): def test_island_declarations(self): self.assertTrue(afi.is_island_declaration("BBL", "GFL99")) self.assertTrue(afi.is_island_declaration("BBL", "OF5CgdDq")) - self.assertTrue(afi.is_island_declaration("Qidi", "QD_X4_PLA")) + # dissolved island (plan v4): Qidi declarations mint like any other + self.assertFalse(afi.is_island_declaration("Qidi", "QD_X4_PLA")) self.assertFalse(afi.is_island_declaration("Qidi", "OF5CgdDq")) self.assertFalse(afi.is_island_declaration("VendorA", "GFL99")) @@ -567,7 +570,7 @@ class TestChecks(SyntheticTreeCase): def test_check6_reserved_namespace_claims(self): for fid, marker in [("GFX99", "owned by BBL"), - ("QD_X_PLA", "owned by Qidi"), + ("QD_X_PLA", "dissolved island"), ("P1a2b3c4", "user-custom"), ("null", "user-custom")]: with self.subTest(fid=fid): @@ -1478,6 +1481,31 @@ class TestRealTree(unittest.TestCase): self.assertEqual(analysis["missing_effective"], []) self.assertEqual(analysis["read_errors"], []) + # Code<->ledger lockstep for the Qidi box (plan v4 SS2): the QD_* literals + # QidiPrinterAgent::map_filament_type_to_setting_id returns must stay + # retired ledger keys whose chains end at a live preset id, because the + # agent resolves them through resolve_filament_id_succession() at runtime. + @unittest.skip("enable with plan v4.2: QD_* ids are not retired yet") + def test_qidi_agent_fallback_ids_resolve_through_ledger(self): + cpp = os.path.join(REPO_ROOT, "src", "slic3r", "Utils", "QidiPrinterAgent.cpp") + with open(cpp, encoding="utf-8") as f: + src = f.read() + m = re.search( + r"map_filament_type_to_setting_id\(const std::string& filament_type\)" + r"\s*\{(.*?)\n\}", src, re.DOTALL) + self.assertIsNotNone(m, "map_filament_type_to_setting_id not found in QidiPrinterAgent.cpp") + qd_ids = re.findall(r'return "(QD_[0-9_]+)";', m.group(1)) + self.assertTrue(qd_ids, "no QD_* literals parsed from map_filament_type_to_setting_id") + ledger = afi.load_ledger(afi.RETIRED_PATH) + live = set(afi.analyze_tree(REAL_PROFILES)["ids"]) + for fid in qd_ids: + self.assertIn(fid, ledger["retired"], f'"{fid}" must be a retired ledger key') + status, node = afi.follow_succession( + fid, set(), ledger["retired"], ledger["hints"], live) + self.assertEqual( + status, "live", + f'"{fid}" succession must end at a live id (got {status} at "{node}")') + # --------------------------------------------------------------------------- # review-fix regressions