28 KiB
filament_id: generation rule + system-profile fix plan
Follow-up to PR #14459 (commit c2e91cb8, validator -f / check_duplicate_filament_subtypes).
Goal 1: a filament_id generation rule for all vendors. Goal 2: an error-pattern taxonomy and a
migration plan that removes every ambiguous filament_id, without touching Bambu (BBL) profiles.
All numbers below are reproducible: a loader-faithful audit script re-derives the validator's
output exactly (1256/1256 printer-level errors, 356 logical collision groups, 30 vendors).
Every code claim was verified against source with file:line references.
0. Executive summary
filament_idis a material-family id: one id per commercial product line, shared by all of that material's per-printer/per-nozzle variants. Matching is always(filament_id + printer compatibility); the invariant from PR #14459 is per printer preset, at most one compatible instantiated filament preset per id.- Every modern device ecosystem funnels through this id — not just Bambu AMS: Qidi box,
Creality CFS, Klipper AFC/Happy Hare, Snapmaker all emit/consume
tray_info_idx(see §1). Several consumers match globally, without printer scoping, so two different materials sharing one id is unsafe even across vendors. - Proposed rule (§3): deterministic, script-minted ids —
OF+ 6 base62 chars fromuuid5(vendor + family), declared only on family-root (@base) presets; variants inherit. Nobody ever invents an id by hand; CI prints the expected id when one is missing. Existing unambiguous ids are grandfathered and frozen;GF*(Bambu),QD_*(Qidi device protocol), andP<7-hex>(user custom presets) are reserved namespaces that must never be minted into. This was selected by an adversarial design/judge process over a registry-grammar alternative and a structure-only alternative, then stress-tested; amendments from that stress test are folded in below. - Migration (§5): fresh-never-reused ids only, family-atomic, names never changed. This is
provably safe: user presets re-derive
filament_idfrom their parent on every load (Preset.cpp:1658-1682), 3mf resolves presets by name+config (Preset.cpp:2490-2576), and Klipper/Creality/Snapmaker derive tray ids at runtime. One PR per vendor; CI's-fscope ratchets per vendor until tree-wide.
1. How filament_id actually works (verified)
Consumers and scoping
All device integrations converge on one pipeline: device/agent sets tray_info_idx →
DevAmsTray.setting_id → Sidebar::build_filament_ams_list (Plater.cpp:3423-3493) →
PresetBundle::sync_ams_list / get_ams_cobox_infos (PresetBundle.cpp:3112-3308) match it
against filament presets.
| Ecosystem | Where the id comes from | Effect of changing a system id |
|---|---|---|
| BBL AMS | device-side (RFID / user tray setting), DeviceManager.cpp:3823+ |
breaks matching — frozen by mandate |
| Qidi box | built from device enums: "QD_" + series + "_" + vendor + "_" + type_idx, QidiPrinterAgent.cpp:146-152; needs an exactly-matching visible preset |
breaks matching — QD_* ids are a frozen device contract |
| Creality CFS | runtime brand/type scoring returns current preset's id (CrealityPrintAgent.cpp:46-118) |
invisible |
| Klipper (AFC / Happy Hare) | runtime filament_id_by_type (MoonrakerPrinterAgent.cpp:808,936) |
invisible |
| Snapmaker | runtime color/vendor/type match (SnapmakerPrinterAgent.cpp:22-64) |
invisible |
Matching is printer-scoped (is_compatible) in the AMS sync paths and all printer agents — this
is what makes the per-printer invariant sufficient there. But several consumers match
globally by id alone, first match wins:
get_filament_by_filament_id("")— tray display name,filament_is_support,temperature_vitrificationwarnings (PresetBundle.cpp:690-733; callersDevFilaBlackList.cpp:70,Plater.cpp:3453,SelectMachine.cpp:3560,4623). The code comment at:695states the assumption outright: an id maps to ONE material globally.MachineObject::setting_id_to_type(DeviceManager.cpp:2538), calibration-history name lookup (CaliHistoryDialog.cpp:62), custom-filament cloud grouping (Preset.cpp:2839).- The slicing pipeline itself: multi-nozzle filament grouping merges project filaments whose
(filament_id, color)match (FilamentGroup.cpp:513-528viaToolOrdering.cpp:1164).
Consequence: within one printer, duplicate ids break AMS matching (silent first-wins,
find_if at PresetBundle.cpp:3132/3233; the AMS tray-edit dialog even hides the second
preset, AMSMaterialsSetting.cpp:894-897). Across vendors, the same id on different
materials feeds wrong name/type/vitrification data to the global consumers and can merge
different materials into one nozzle group. Same id on the same material (e.g. GFL99 =
Generic PLA in 29 vendors) is comparatively benign — those attributes agree.
Identity machinery
- Effective id resolution (
PresetBundle.cpp:4842-5080): ownfilament_idkey → vendorfilament_id_maps[inherits](file order in the vendor index is load-bearing) → OrcaFilamentLibrary base-bundle map. An instantiated system filament that resolves no id is a hard load error that discards the whole vendor bundle (:5072, throw at:5141-5147) — so "missing id" cannot ship; what looked like 26 id-less Flashforge presets actually resolve to OFL'sOGFL99/OGFG99through the base-bundle fallback. - Two family-identity systems exist:
filament_id(device matching) andalias(name before" @"). OFL shadowing is keyed on alias:update_library_profile_excluded_from(Preset.cpp:3684-3714) hides an OFL preset (emptycompatible_printers= compatible with everything,Preset.cpp:837) on printers claimed by a same-alias vendor preset. There is no id-based shadowing. A vendor preset that tunes an OFL generic but renames it re-exposes the OFL preset and creates a live duplicate. The rule below aligns the two systems: one family = one alias = one id. - User-custom id space: user-created filaments get
"P" + md5(name)[0:7](8 chars,CreatePresetsDialog.cpp:533), or reuse a system id when the base name matches an existing preset (:510-528)."null"is used as a sentinel. Root user presets persist their id forever; inheriting user presets re-derive it on every load.
2. The id landscape today
Bambu's grammar (derived from all 1970 BBL instantiated presets; BBL is internally clean — 181 id definitions, 0 duplicates):
- Classic
GF<LETTER><NN>: letter = family (A Bambu-PLA, B ABS/ASA, C PC, G PETG/PCTG, L third-party+generic PLA, N PA/PPA, P PP/PE, R misc, S support, T PET/PPS, U TPU). Numbers: 00-49 branded ascending, 50-59 fiber-filled, 60-70 partner block, 95-99 generic tier descending (99 = the family's plain generic). - Brand partners
GF<BRANDCODE><NNN>: GFPM Polymaker, GFOT Overture, GFSNL SUNLU, GFNMK Numakers. One id per product line; never per color, never per printer/nozzle/diameter. - Structural rule: the id lives on the material's
@base; every variant inherits it. - Hardcoded in C++:
GFS00/GFS01support check (DeviceManager.cpp:4739), per-family PA defaultsGFU01/03/04(CalibUtils.cpp:54-75) —GF*is Bambu's space, byte-frozen.
Everything else is ad-hoc, invented by individual contributors and imitated (full history
in §7): OFL's O-prefix mirrors (OGFA00; introduced 2025-03-31, commit 8c4a65e3e1),
Tiertime/Afinia GFx##_## per-printer-line suffixes, SeeMeCNC per-nozzle ids, LH LHF_pla,
LONGER 11-char pseudo-GF ids, Anycubic ids with spaces ("GFPLA Silk"), Prusa ids that are
entire preset names (36 chars), and mass copy-paste of GFL99/GFB99/GFG99 onto everything
(Qidi alone stamped GFB99 into 317 files across all materials). The only guidance that
ever existed was "≤ 8 chars" — enforced for BBL only (orca_extra_profile_check.py:292,320),
and the (now removed) profile wiki's own examples taught id copy-pasting.
The damage, quantified (audit reproduces validator 1256/1256):
| Ledger | Count |
|---|---|
Within-vendor logical collision groups (validator -f) |
356 across 30 vendors (1256 printer-level errors) |
| OFL×vendor same-id groups (validator blind spot) | 42 — of which 10 are live (alias mismatch defeats shadowing); 32 already neutralized by alias shadowing |
| OFL-internal: one id, several materials, visible on every printer | 16 ids (e.g. OEPLAB00 = 14 distinct Elegoo PLA products; OGFL06 = eSUN PLA-Marble and Fiberon PETG-ESD) |
| Cross-vendor semantic collisions (same id, different materials) | 67 ids (e.g. GFU99 also covers a PEBA; Anycubic minted GFL95 "Matte" ≠ Bambu GFL95 "High Speed") |
Worst vendors by groups: Qidi 97, Flashforge 69, Elegoo 37, Prusa 31, Cubicon 17, Anycubic 14, InfiMech 14, Snapmaker 11, Artillery 8, Creality 8, FlyingBear 8.
3. The rule (proposal)
Selected by a 3-design / 2-judge adversarial process (deterministic-mint won over registry-grammar and structure-only on ambiguity-prevention, contributor simplicity, and enforceability), then hardened by three adversarial review passes. This section is written as the future authoring doc.
3.1 The one-question test
Would a user consider this a different spool product than anything already in the tree? Different polymer, different sub-brand (Basic / Matte / Silk / HF), fiber-filled sibling, or a second selectable diameter → new family, new id. The same spool tuned for another printer or nozzle → join the existing family (inherit its
@base, no id key). Tuning a generic material → join the OFL family (inherit theGeneric X @Systempreset, keep theGeneric Xbase name, add no id).
Same id / new id at a glance:
| Situation | id |
|---|---|
| Per-printer / per-nozzle variant of an existing material | same id (inherit, never write the key) |
| Sub-brand or product line (PLA vs PLA Matte vs PLA Silk vs PLA HF) | new id each |
| Color | never a new id |
| Second diameter selectable on the same printer (1.75 + 2.85) | sibling family, new id |
| "High-speed" tuned for a different printer model | same id (it's a printer variant) |
| "High-speed" selectable alongside the normal preset on one printer | new id (it's a product line) |
3.2 Structure
- One family = one root. Each material family has root preset(s) (
instantiation:false, typically<Family> @base) and only roots carry thefilament_idkey. Instantiated variants inherit a root and never writefilament_id. (A family MAY have several roots — e.g. Qidi's per-series bases — but they must all declare the identical id.) - Family identity is declared, not name-derived. Default: the family name is the
instantiated presets' base name (name with
/\s?@.*$/stripped — note optional space, becauseAfinia PLA@HS-style names exist). When vendor naming makes that ambiguous, the root declares an explicit"filament_family"key that overrides derivation; tooling errors loudly when a root's derived family differs from its children's. - Within a family, variants'
compatible_printersare pairwise disjoint — that is the PR #14459 invariant, enforced by the validator. - Generics belong to OFL. A vendor tuning
Generic PLAinheritsGeneric PLA @System, keeps theGeneric PLAbase name/alias (so alias shadowing excludes the OFL preset on those printers,Preset.cpp:3684), sets non-emptycompatible_printers, and writes no id. A vendor-branded filament never rides a generic family id. - Ids are immutable once shipped. Renaming a family does not change its id (use
renamed_from). No id is ever recycled for a different material — stale ids live on in user root presets and old 3mfs, and a recycled id would silently match the wrong material.
3.3 Minting — nobody invents ids
New family ids are computed, exactly like the setting_id precedent
(scripts/assign_vendor_setting_ids.py / Slic3r::generate_preset_setting_id):
filament_id = "OF" + base62_6( uuid5( NAMESPACE, "filament_family/<vendor>/<family>" ) )
8 chars total (satisfies the AMS length limit), same base62 derivation and a dedicated
namespace constant. On the astronomically rare collision with an existing id, the minter salts
the input (.../1, /2, …) until free; the result is simply frozen in the file.
- Script path: author commits the family with no id anywhere;
python scripts/assign_filament_ids.pyinserts the minted id into the root(s). Idempotent; never rewrites a valid existing id. A--mint "<Vendor>/<Family>"one-shot prints the id without touching the tree. - No-script path: CI fails with the exact line to paste:
family "MyBrand PLA" (vendor X) needs filament_id "OFq3xT9k" in "MyBrand PLA @base.json".
Reserved namespaces — never mint or hand-write into:
| Space | Owner | Status |
|---|---|---|
GF* |
Bambu AMS/RFID catalog | byte-copies of authentic Bambu ids only, and only where a checked-in shared_catalog list sanctions the family (BBL bundle; OFL mirrors; byte-matching families in other vendors, e.g. Snapmaker's Fiberon) |
QD_* |
Qidi device protocol | frozen; Qidi-only; exempt from family-shape checks |
P[0-9A-Fa-f]{7}, "null" |
user-created custom filaments (CreatePresetsDialog.cpp:533) |
never emitted for system presets (reserve case-insensitively) |
| everything already shipped | grandfather snapshot | frozen as-is (§5) |
Trade-off accepted: minted ids are opaque (OFq3xT9k carries no "PLA" mnemonic — the family
name in the same file provides that). The judges preferred this over a Bambu-style extended
grammar because it removes the "who allocates the next number" ceremony, cannot race between
concurrent PRs, and needs no registry maintenance. If mnemonic ids are strongly preferred, the
runner-up design (<NSCODE><FAMLETTER><SEQ> + registry file) is documented in the workflow
records; everything else in this plan is unchanged under either format.
3.4 What CI enforces (all vendors, ratcheted)
Extend scripts/orca_extra_profile_check.py (it imports the same mint function; setting_id
precedent) and the C++ validator:
- Format: an id is valid iff
OF[0-9A-Za-z]{6}or in the grandfather snapshot or vendor==BBL orQD_*in Qidi. No whitespace/ASCII/length checks needed outside the grandfather set — new ids are minted, and the grandfather set is closed. - Uniqueness ratchet: id→families multimap computed tree-wide; no id may acquire a family
claim not recorded in the snapshot (snapshot legalizes today's benign
GFL99-style sharing; new multi-claims are errors;shared_catalogentries are the sanctioned exception). - Structure ratchet:
filament_idkey only on roots; every instantiated filament must resolve an effective id via the simulated loader walk; all members of one family resolve the same id; a preset may not declare an id different from its inherited effective id (theGeneric SBSdrift bug class). Pre-existing violations are snapshot-frozen; new ones error. - Mint conformance: an id new relative to the snapshot must equal the mint (or a salt iteration); the error message prints the expected value.
- Stability: an
(id, family)pair on main may not change or vanish, followingrenamed_fromchains (so an honest rename passes), unless listed in a maintainer-gated migrations file. Retired ids go to an append-onlyretired_idsledger; a retired id may never be defined again for any family. - Alias hygiene for tuned generics: a preset inheriting an OFL
Generic * @System(with no own id anywhere in its vendor chain) must keep the OFL base name and have non-emptycompatible_printers— error message names the rename as the cause. - C++ validator: extend
check_duplicate_filament_subtypes(PresetBundle.cpp:5654) to include OFL presets in every vendor's per-printer check, minus alias-excluded ones —m_excluded_fromis already populated in the validator context (update_system_mapsatPresetBundle.cpp:2302), so the 32 shadowed pairs won't false-positive and the 10 live ones will be caught. Run-fper vendor in CI, widening as vendors are cleaned (§5). - Runtime backstop (one-line change): log a warning when the AMS-sync
find_if(PresetBundle.cpp:3132/3233) finds 2+ compatible presets for one id — the only layer that can see side-loaded/forked bundles.
4. Error-pattern taxonomy (goal 2) — with counts and fixes
356 groups were classified by 37 agents reading the actual profiles, spot-checked
independently (1 substantive disagreement in 14 samples). Counts below fold the spot-check
corrections in. Fix rule for all patterns: replacement id values are always freshly minted
OF*; the "which preset keeps the id" decision uses the precedence Bambu-catalog material >
OFL generic family > family that historically introduced the id.
| # | Pattern | Groups | Fix |
|---|---|---|---|
| P1 | copy_paste_id — different materials share an id verbatim (task's error 1). Qidi's GFB99×317-files epidemic; Anycubic's three id "eras"; Peopoly GFSL99 on ABS |
~167 | impostor families get minted ids on their roots; owner keeps the id |
| P2 | wrong_inherits / id-less product lines — a variant inherits another family's root (PR #14459's Panchroma case) or a product line never got its own root (Prusa HF; Flashforge's ~140-preset FFG01 umbrella) |
~87 | create per-family roots with minted ids; re-point inherits; never delete the id-less shadow/base files — convert them (they carry real config: Flashforge fdm_filament_pla differs materially from OFL's) |
| P3 | generic_family_overlap — vendor-branded preset rides a generic family id via inheritance (task's error 2, generalized). Includes the 10 live OFL duplicates |
~68 | branded presets get minted family ids; true generic tunings instead adopt the OFL family with matching alias (rule 3.2.4); Sovol is the elegant case — just delete its wrong own-id lines and let OFL ids flow through inheritance |
| P4 | overclaim_compat — same material, broader variant claims a printer that a dedicated variant covers (the BBL H2DP pattern fixed in #14459) |
~24 | trim compatible_printers of the broader preset (Dremel, Cubicon @bases that are also instantiated, Wanhao France Bowden/Direct) |
| P5 | template-carried id — id declared on a shared settings template (fdm_filament_*, fdm_filament_common) so every family inheriting it collapses (Prusa, Ginger Additive, Snapmaker TPU base) |
inside P1/P2 counts | move ids off templates onto family roots |
| P6 | OFL-internal collisions — 16 ids spanning several materials, visible on every printer (Elegoo blocks, Elas OGFA00×3, OGFL06 polymer mismatch, Generic PETG HF/PETG-CF @System missing own ids) |
16 ids | fix inside OFL first (it's the base bundle every vendor resolves against) |
| P7 | alias-mismatch re-exposure — vendor tunes a generic under a different name, OFL preset resurfaces (Snapmaker PolyTerra J1 PLA vs OFL PolyTerra PLA) |
10 live | rename-to-alias where it's genuinely the same family, else mint |
| P8 | per-variant ids — no ambiguity, but family semantics broken: every variant has its own id (Prusa name-ids, SeeMeCNC nozzle suffixes, Afinia/Tiertime _##, iQ) so device matching can't identify the material across nozzles |
~210 presets | grandfather (they're unambiguous); converge opportunistically; document as anti-pattern |
| P9 | format violations — spaces ("GFPLA Silk"), >8 chars (LONGER, SeeMeCNC, LH), GF-shaped inventions (Anycubic GFL93-97, CoLiDo GFA99) |
in the above | fixed as a byproduct of re-minting; snapshot freezes the unambiguous rest |
| P10 | cross-vendor semantic collisions — 67 ids meaning different materials in different vendors (dangerous via the global unscoped consumers, §1) | 67 ids | mostly eliminated by P1-P3 re-minting; the remaining same-material generic sharing is legalized by the snapshot |
| P11 | deliberate coexistence & data hygiene — Snapmaker "Benchy" demo presets (gated by compatible_prints, which the id check can't see) and a self-collision from duplicate compatible_printers entries |
4 | give demo presets own minted ids; dedupe list entries; add a lint for duplicate array entries |
New patterns beyond the two in the task (goal 2.3): P5-P11.
5. Migration plan
Safety foundation (verified, §1/§7)
Safe: fresh never-used ids, family-consistent; trims of compatible_printers; inherits
re-pointing; OFL id changes (children re-derive). Unsafe: touching BBL/QD_*; recycling or
swapping ids; splitting a family's id; deleting or renaming preset names (user presets
whose inherits no longer resolves are dropped at load, Preset.cpp:1687-1691) — if a name
must go, renamed_from coverage is mandatory.
Phases
- Land the rule + tooling first (no profile changes):
scripts/assign_filament_ids.py(mint + insert +--mint), the extendedorca_extra_profile_check.pychecks in snapshot-ratchet mode, the C++ validator OFL cross-check, the runtime warning, the rule doc. Generatefilament_id_snapshot.json(id→families multimap over main) and emptyretired_ids.json— both checked in. - OFL first (it's the base bundle every vendor resolves against): fix the 16 internal
collisions (Elas/eSUN/DREMC copy-pastes get mints;
Generic PETG HF/PETG-CF/PP-CF/PP-GF/ PE-CF/PLA Matte @Systemget their own family roots+ids instead of collapsing into their parent generic), keeping every current effective id that is unambiguous. - Per-vendor PRs, worst-first: Qidi → Flashforge → Elegoo → Prusa → Cubicon → Anycubic →
InfiMech → Snapmaker → the long tail (22 vendors, mostly 1-8 one-line fixes). Each PR flips
that vendor into CI's
-fscope (check_profiles.ymlcurrently-v BBL -f; append vendors as they reach zero; when all are in, drop-vand run tree-wide). - Delete the ratchet allowlists once tree-wide zero holds; checks become hard rules for everything born after the snapshot.
Migration-script contract (from the adversarial pass — important)
- Consumes from the classification only: group membership, fix category, keep-id precedence,
inherits-repoint targets. All replacement id values are recomputed via the mint — id
literals in analysis notes (e.g.
GFA00_02,GFS98,GFG96) are legacy-culture artifacts and are ignored with a warning; assert no emitted id matches^(GF|QD_|P[0-9A-Fa-f]{7}$). - Family-atomic: re-idding any preset re-ids every same-family sibling in the same commit,
even siblings outside the collision group (FlyingBear
GFB99 @S1vs@Ghost7); Prusa is family-atomic per material (its HF/CF families span frozen_N-suffix ids — freeze what's unambiguous, mint once per family for the colliding members). - Diff bound: a vendor migration PR may only touch collision-group files + same-family siblings of re-idded presets; every id that is per-printer-unambiguous today stays byte-identical.
- Config-equivalence gate: dump every instantiated preset's flattened effective config on
main and on the PR head; the diff must be empty except
filament_id/inherits/compatible_printersedits the plan prescribes (this is what makes the Flashforge shadow-file conversions safe: each id-lessfdm_filament_*shadow becomes a named vendor family root carrying its config byte-for-byte, children re-pointed, then the shadow name retired). - No deletions: redundant presets (Flashforge's byte-identical
Generic X/Flashforge Xtwins) are re-minted, not dropped; consolidation withrenamed_fromis a separate, human-reviewed cleanup. - Expected user impact: none for inheriting user presets, 3mfs, Klipper/Creality/Snapmaker sync. Residue: user root presets that copied an old system id keep it forever (AMS auto-match falls back to generic-by-type — low severity, unavoidable from the repo).
Vendor-specific notes (from classification)
- Qidi (97): three profile generations.
QD_*generics are correct and frozen; the fix is the brand families (Bambu/HATCHBOX/Overture/PolyLite/Tinmorry/QIDI-brand) that all carryGFB99/GFG99/GFL99. Multi-root families are the norm (...@Q2-Series/@Q2C-Series/@X-Max 4-Seriesbases) — same mint lands in every series root of one family. - Flashforge (69): two umbrellas (
FFG01~140 presets;GFB99/GFG99/GFL99G3U-era) + OFL-riding branded presets + shadow-file conversion (above). - Elegoo (37): single mistake — every commercial variant inherits the material-class
@base(E<MAT>B00); mint one id per product line (Silk/Matte/PRO/Rapid/…), roots exist. - Prusa (31): HF product lines need their own roots; ids move off
fdm_filament_*templates; frozen name-shaped and_Nids stay. - Sovol (6): delete the wrong own-id lines; correct ids flow from OFL by inheritance.
- Cubicon (17):
@basepresets are themselves instantiated + over-claiming; 9 file edits.
6. Concrete work items (PR-sized)
scripts/assign_filament_ids.py+ mint function + tests (incl. the 14-group regression set from the adversarial pass). (new)orca_extra_profile_check.py: checks §3.4-1..6 in ratchet mode + snapshot/ledger files; drop the BBL/OFL-only gate at:292and the OFL skip at:601. (extend)- C++ validator: OFL-aware
check_duplicate_filament_subtypes; runtime ambiguity warning at the twofind_ifsites. (small) - Rule documentation:
doc/developer-reference/filament_id.md(recreate the path; wiki cross-link) + profile-PR template checkbox ("new materials: no filament_id key anywhere; CI prints the minted id"). (new) - OFL migration PR (phase 1).
- Per-vendor migration PRs (phase 2), each widening CI
-fscope.
The audit tooling from this analysis (loader-faithful resolver; reproduces the validator
1256/1256) is in this session's scratchpad (audit_filament_ids.py) and is the natural seed
for items 1-2.
7. Evidence & methodology
- Validator ground truth:
OrcaSlicer_profile_validator -ftree-wide → 1256 errors; audit script reproduces exactly (356 logical groups after dedup by (vendor, id, preset-set)). - Code analysis: 5 parallel agents over runtime consumers, persistence/migration surface,
loader semantics, Bambu grammar, and convention history — all claims carry
file:line. - Classification: 37 agents (one per vendor chunk) reading actual profile JSONs; 14-sample
independent re-derivation found 1 substantive error (a Flashforge group mislabeled
missing_id; corrected — the loader resolves those ids from OFL). - Design: 3 independent designs → 2 judges (both chose the deterministic mint; scores 58/50/56
and 60/54/56) → 3 adversarial attackers (35 scenarios; every
breaksfinding is folded into §3.2-3.4/§5 as an amendment: declared families, multi-root support, ratchet-not-absolute checks, no-deletion rule, shadow-file conversion, classification-id-literal quarantine, diameter siblings, case-insensitive P-hex reservation, fork guidance). - Key history:
OGF*born 2025-03-31 (8c4a65e3e1, no PR);_##suffix born PR #9739; 8-char check born PR #9574; wiki (with the id-copy-paste example) removed 2025-11-24 (f0d79b99eb).
8. Open decisions for maintainers
- Id format: opaque deterministic
OF*mint (recommended, judges 2/2) vs mnemonic registry grammar (runner-up). Everything else in the plan is format-agnostic. - Multi-vendor brands (Snapmaker ships Fiberon with authentic
GF*ids): sanction viashared_catalog(recommended, low churn) vs hoisting those families into OFL. - Benchy-style demo presets: mint ids per demo preset (recommended) vs teaching the
validator
compatible_printsgating. - Alias alignment: fix the 10 live alias-mismatch OFL duplicates by rename-to-alias
(better long-term, needs
renamed_from) vs minting vendor ids (safer, more ids). - Where the rule doc lives: in-repo
doc/(recommended — CI messages need a stable link) vs wiki-only.