mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-24 10:27:35 +00:00
Compare commits
27 Commits
nightly-bu
...
feature/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f23e5875d5 | ||
|
|
8d83414d09 | ||
|
|
1c405f8a2c | ||
|
|
58d1a3b093 | ||
|
|
71563cc6c6 | ||
|
|
f3fa3a34bd | ||
|
|
1a62a25d36 | ||
|
|
f7c1b290fd | ||
|
|
e3ac835cc3 | ||
|
|
23386f6129 | ||
|
|
3ccc58a9fc | ||
|
|
acd5dd0794 | ||
|
|
2c0867619c | ||
|
|
67406b24ba | ||
|
|
a395701f29 | ||
|
|
ac12dff1af | ||
|
|
33923464ae | ||
|
|
55a3114ec9 | ||
|
|
ee125975cf | ||
|
|
23b0aabb35 | ||
|
|
095fd9fba4 | ||
|
|
674344b3c1 | ||
|
|
4fc964d293 | ||
|
|
516267d869 | ||
|
|
ab60229311 | ||
|
|
1482fb81fd | ||
|
|
051cdd4560 |
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@@ -20,6 +20,8 @@
|
||||
> Please describe the tests that you have conducted to verify the changes made in this PR.
|
||||
-->
|
||||
|
||||
- [ ] New filament/material profiles: I wrote **no** `filament_id` key by hand — I ran `python scripts/assign_filament_ids.py` and `--update-snapshot` and committed both diffs (see `doc/developer-reference/filament_id.md`)
|
||||
|
||||
<!--
|
||||
> A guide for users on how to download the artifacts from this PR.
|
||||
-->
|
||||
|
||||
9
.github/workflows/check_profiles.yml
vendored
9
.github/workflows/check_profiles.yml
vendored
@@ -64,13 +64,14 @@ jobs:
|
||||
set +e
|
||||
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -s -l 2 2>&1 | tee ${{ runner.temp }}/validate_slice.log
|
||||
exit ${PIPESTATUS[0]}
|
||||
# For now run filament subtype check only for BBL profiles until we fix other vendors' profiles.
|
||||
- name: validate filament subtype check for BBL profiles
|
||||
# All vendors' filament_id collisions were fixed (see scripts/filament_id_snapshot.json),
|
||||
# so the duplicate-filament-subtype check runs tree-wide.
|
||||
- name: validate filament subtype check
|
||||
id: validate_filament_subtypes
|
||||
continue-on-error: true
|
||||
run: |
|
||||
set +e
|
||||
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 -v BBL -f 2>&1 | tee ${{ runner.temp }}/validate_filament_subtypes.log
|
||||
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 -f 2>&1 | tee ${{ runner.temp }}/validate_filament_subtypes.log
|
||||
exit ${PIPESTATUS[0]}
|
||||
|
||||
- name: validate custom presets
|
||||
@@ -217,7 +218,7 @@ jobs:
|
||||
fi
|
||||
|
||||
if [ "${{ steps.validate_filament_subtypes.outcome }}" = "failure" ]; then
|
||||
echo "### BBL Filament Subtype Validation Failed"
|
||||
echo "### Filament Subtype Validation Failed"
|
||||
echo ""
|
||||
echo '```'
|
||||
head -c 30000 ${{ runner.temp }}/validate_filament_subtypes.log || echo "No output captured"
|
||||
|
||||
@@ -59,13 +59,6 @@ if (APPLE)
|
||||
message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
endif ()
|
||||
|
||||
# Keep MSVC's default /W3 out of CMAKE_<LANG>_FLAGS so it can be applied to our own
|
||||
# targets only. Silencing a bundled target would otherwise override a warning level,
|
||||
# which cl reports as D9025 for every file it compiles.
|
||||
if (POLICY CMP0092)
|
||||
cmake_policy(SET CMP0092 NEW)
|
||||
endif ()
|
||||
|
||||
project(OrcaSlicer)
|
||||
|
||||
# Backward compatibility for old CMake versions
|
||||
@@ -133,8 +126,6 @@ option(SLIC3R_GUI "Compile OrcaSlicer with GUI components (OpenGL,
|
||||
option(SLIC3R_FHS "Assume OrcaSlicer is to be installed in a FHS directory structure" 0)
|
||||
option(SLIC3R_PROFILE "Compile OrcaSlicer with an invasive Shiny profiler" 0)
|
||||
option(SLIC3R_PCH "Use precompiled headers" 1)
|
||||
option(SLIC3R_WARNINGS "Emit compiler warnings for OrcaSlicer sources" 1)
|
||||
option(SLIC3R_BUNDLED_WARNINGS "Emit compiler warnings for bundled third-party sources" 0)
|
||||
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
|
||||
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
||||
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
||||
@@ -344,20 +335,15 @@ if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||
|
||||
# clang-cl can interpret SYSTEM header paths if -imsvc is used
|
||||
set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-imsvc")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall \
|
||||
-Wno-old-style-cast -Wno-reserved-id-macro -Wno-c++98-compat-pedantic")
|
||||
else ()
|
||||
set(IS_CLANG_CL FALSE)
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
# CMP0092 only applies when the cache is created; an existing tree keeps its /W3,
|
||||
# which a silenced bundled target would then override (D9025, once per file).
|
||||
string(REGEX REPLACE "/W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
# /MP only matters for the VS generators, where CMake turns it into the
|
||||
# MultiProcessorCompilation property. Ninja parallelises on its own, and
|
||||
# clang-cl warns "argument unused" if the flag reaches it.
|
||||
if (SLIC3R_MSVC_COMPILE_PARALLEL AND CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
if (SLIC3R_MSVC_COMPILE_PARALLEL AND NOT IS_CLANG_CL)
|
||||
add_compile_options(/MP)
|
||||
endif ()
|
||||
# /bigobj (Increase Number of Sections in .Obj file)
|
||||
@@ -537,15 +523,8 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals" )
|
||||
endif()
|
||||
|
||||
if ((NOT MSVC OR IS_CLANG_CL) AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
|
||||
if (IS_CLANG_CL)
|
||||
# clang-cl reads -Wall as MSVC /Wall, which clang maps to -Weverything. /W4 is
|
||||
# its -Wall -Wextra and, unlike /clang:-Wall, is ordered with the -Wno-* below
|
||||
# instead of after them. The -Wextra-only warnings are dropped again so the set
|
||||
# matches what -Wall gives the GNU/Clang builds.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4" )
|
||||
add_compile_options(-Wno-unused-parameter -Wno-ignored-qualifiers -Wno-missing-field-initializers)
|
||||
elseif (NOT MINGW)
|
||||
if (NOT MSVC AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
|
||||
if (NOT MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" )
|
||||
endif ()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder" )
|
||||
@@ -1107,57 +1086,8 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
|
||||
endfunction()
|
||||
|
||||
|
||||
# Bundled sources set their own warning flags, and a plain -Wall there means /Wall
|
||||
# (= -Weverything) under clang-cl. Target options are applied after the ones a target
|
||||
# set on itself, so these win. Targets are discovered rather than listed so a newly
|
||||
# bundled library needs no maintenance here.
|
||||
function(orcaslicer_silence_third_party_warnings _dir)
|
||||
get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES)
|
||||
foreach (_subdir IN LISTS _subdirs)
|
||||
orcaslicer_silence_third_party_warnings("${_subdir}")
|
||||
endforeach ()
|
||||
get_property(_targets DIRECTORY "${_dir}" PROPERTY BUILDSYSTEM_TARGETS)
|
||||
foreach (_target IN LISTS _targets)
|
||||
get_target_property(_type ${_target} TYPE)
|
||||
if (NOT _type STREQUAL "INTERFACE_LIBRARY" AND NOT _type STREQUAL "UTILITY")
|
||||
if (MSVC AND NOT IS_CLANG_CL)
|
||||
# Drop any level the target set for itself, or -w overrides it and cl
|
||||
# reports D9025 once per file.
|
||||
get_target_property(_opts ${_target} COMPILE_OPTIONS)
|
||||
if (_opts)
|
||||
string(REGEX REPLACE "/W[0-4]|/Wall" "" _opts "${_opts}")
|
||||
string(REGEX REPLACE ";;+" ";" _opts "${_opts}")
|
||||
set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${_opts}")
|
||||
endif ()
|
||||
# CMake maps a level into the VS generator's WarningLevel element, while a
|
||||
# bare -w stays on the command line and trips D9025 there, once per file.
|
||||
target_compile_options(${_target} PRIVATE /W0)
|
||||
else ()
|
||||
target_compile_options(${_target} PRIVATE -w)
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
endfunction()
|
||||
|
||||
|
||||
# libslic3r, OrcaSlicer GUI and the OrcaSlicer executable.
|
||||
add_subdirectory(deps_src)
|
||||
|
||||
if (NOT SLIC3R_BUNDLED_WARNINGS)
|
||||
orcaslicer_silence_third_party_warnings("${CMAKE_CURRENT_SOURCE_DIR}/deps_src")
|
||||
endif ()
|
||||
|
||||
# Warning level for the targets added below: our sources, plus glad and libvgcode,
|
||||
# which are vendored but live under src/. The deps_src libraries were configured just
|
||||
# above. CMP0092 left MSVC without a default level, so it is set here.
|
||||
if (NOT SLIC3R_WARNINGS)
|
||||
add_compile_options(-w)
|
||||
elseif (MSVC AND NOT IS_CLANG_CL)
|
||||
# /we4715 is C4715, no return from a non-void function, matching the
|
||||
# -Werror=return-type the GNU/Clang builds apply.
|
||||
add_compile_options(/W3 /we4715)
|
||||
endif ()
|
||||
|
||||
add_subdirectory(src)
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT OrcaSlicer_app_gui)
|
||||
|
||||
@@ -1169,10 +1099,6 @@ endif()
|
||||
|
||||
if(BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
if (NOT SLIC3R_BUNDLED_WARNINGS)
|
||||
# Catch2 is vendored under tests/ and sets its own warning flags too.
|
||||
orcaslicer_silence_third_party_warnings("${CMAKE_CURRENT_SOURCE_DIR}/tests/catch2")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (NOT WIN32 AND NOT APPLE)
|
||||
|
||||
211
doc/developer-reference/filament_id.md
Normal file
211
doc/developer-reference/filament_id.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# Filament IDs (`filament_id`)
|
||||
|
||||
`filament_id` identifies a **material family**: one commercial product line = one id, shared by
|
||||
all of that material's per-printer / per-nozzle variants. Devices use it to match a physical
|
||||
spool or tray to a filament preset. It is never per-color, per-printer, per-nozzle, or
|
||||
per-preset (per-preset identity is `setting_id`).
|
||||
|
||||
This page is the rule for authoring `filament_id` in system profiles
|
||||
(`resources/profiles/**`). CI enforces everything below; the short version is:
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Never write a `filament_id` value by hand.** New families get their id from
|
||||
> `python scripts/assign_filament_ids.py`; existing families already have one — inherit it.
|
||||
|
||||
## Who consumes the id
|
||||
|
||||
Every device integration funnels a tray material id (`tray_info_idx`) through the same
|
||||
matching pipeline (`PresetBundle::sync_ams_list` and friends):
|
||||
|
||||
| Ecosystem | Where the id comes from |
|
||||
| --- | --- |
|
||||
| Bambu AMS | device side (RFID / user tray setting) — the `GF*` catalog |
|
||||
| Qidi box | built from device enums (`QD_*`); needs an exactly matching visible preset |
|
||||
| Creality CFS | runtime brand/type scoring returns the current preset's id |
|
||||
| Klipper (AFC / Happy Hare) | runtime lookup by filament type |
|
||||
| Snapmaker | runtime color/vendor/type match |
|
||||
|
||||
Tray-to-preset matching is printer-scoped, but **several consumers match globally by id alone,
|
||||
first hit wins**: tray display names, `filament_is_support`, vitrification warnings, and
|
||||
multi-nozzle filament grouping in the slicing pipeline. Two *different* materials sharing one
|
||||
id feed wrong data to those consumers even when the presets live in different vendors — so
|
||||
cross-material id sharing is never safe. Within one printer, duplicate ids silently break AMS
|
||||
matching (first match wins, the tray-edit dialog hides the second preset); the profile
|
||||
validator's `-f` check rejects this.
|
||||
|
||||
## Do I need a new id? 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`, write no id key). Tuning a
|
||||
generic material → **join the OrcaFilamentLibrary family** (inherit `Generic X @System`, keep
|
||||
the `Generic X` base name, write no id key).
|
||||
|
||||
| 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 is a printer variant) |
|
||||
| "High-speed" selectable *alongside* the normal preset on one printer | new id (it is a product line) |
|
||||
|
||||
## Structure rules
|
||||
|
||||
1. **Only family roots carry the key.** Root presets (any preset *not* marked
|
||||
`"instantiation": "true"`, typically `<Family> @base` with `"instantiation": "false"`)
|
||||
declare `filament_id`; instantiated variants inherit a root and never
|
||||
write the key. A family may have several roots (e.g. per-series bases) — all of them must
|
||||
declare the *identical* id.
|
||||
2. **The family name is the base name**: the preset name with everything from the first
|
||||
(optionally space-preceded) `@` stripped. `MyBrand PLA @Orca 3D Fuse1` and `MyBrand PLA@HS`
|
||||
both belong to family `MyBrand PLA`.
|
||||
3. **Within a family, variants' `compatible_printers` are pairwise disjoint** — per printer
|
||||
preset, at most one compatible instantiated preset per id. The C++ validator (`-f`)
|
||||
enforces this.
|
||||
4. **Generics belong to OrcaFilamentLibrary.** A vendor tuning a generic material inherits
|
||||
`Generic X @System`, keeps the `Generic X` base name (that alias is what hides the library
|
||||
preset on your printers), sets a non-empty `compatible_printers`, and writes no id key.
|
||||
A vendor-*branded* filament never rides a generic family id.
|
||||
5. **Ids follow the product identity.** The id is a pure function of the product triple
|
||||
`(filament_vendor, filament_type, family name)` — correcting any of them re-mints the id
|
||||
**by design**, and `--update-snapshot` records the old id in the shipped succession ledger
|
||||
with its successor so device trays, calibration records, and user presets keep resolving
|
||||
(`renamed_from` still gates preset-*name* compatibility as before). A shipped id is never
|
||||
recycled for a different material: retired ids are blocked forever.
|
||||
|
||||
## Minting — nobody invents ids
|
||||
|
||||
New ids are deterministic, computed exactly like the `setting_id` precedent
|
||||
(`scripts/assign_vendor_setting_ids.py`):
|
||||
|
||||
```text
|
||||
FILAMENT_ID_NAMESPACE = uuid5(setting-id NAMESPACE, "filament_id")
|
||||
= c4d3ff49-4c32-5534-a3e3-00894157ab97
|
||||
filament_id = "OF" + base62_6( uuid5(FILAMENT_ID_NAMESPACE,
|
||||
"filament_product/<filament_vendor>/<filament_type>/<family_name>") )
|
||||
```
|
||||
|
||||
`base62_6` is the low 6 base62 digits (alphabet `0-9A-Za-z`) of the UUID taken as a big-endian
|
||||
integer, most-significant digit first — 8 chars total, within the AMS length limit. The triple
|
||||
comes from the family root's *flattened* config: `<filament_vendor>` is the filament
|
||||
**manufacturer** (`"Polymaker"`, or `"Generic"` for generics — never the printer brand),
|
||||
`<filament_type>` the material type, `<family_name>` the root's base name; the two config
|
||||
values are inheritable list options and the first element counts. The key contains no bundle
|
||||
name, so the same product mints the same id in every bundle — hoisting a family into
|
||||
OrcaFilamentLibrary never changes its id. On the rare collision with any existing or retired
|
||||
id, the minter salts the input (`…/1`, `…/2`, …) until free and the result is frozen in the
|
||||
file. Example: `Polymaker/PLA/PolyLite PLA` mints `OF5CgdDq`.
|
||||
|
||||
Workflow for a new family:
|
||||
|
||||
```bash
|
||||
# 1. Author the family with NO filament_id key anywhere.
|
||||
python scripts/assign_filament_ids.py # 2. mint + insert ids into the family root(s)
|
||||
python scripts/assign_filament_ids.py --update-snapshot # 3. record the new claims in the ledger
|
||||
python scripts/assign_filament_ids.py --check # 4. verify — the same checks CI runs
|
||||
# 5. Commit the profile edits together with scripts/filament_id_snapshot.json.
|
||||
```
|
||||
|
||||
`--mint "filament_vendor/filament_type/family_name"` prints the id a triple would mint without
|
||||
touching anything. The default run is idempotent and never rewrites a valid existing id.
|
||||
Maintenance modes (normally only used by id migrations): `--remint VENDOR` re-derives a
|
||||
vendor's declared ids from their triples (a declaration already equal to a salt iteration
|
||||
of its own triple is conformant and left alone — deliberate salt splits keeping two
|
||||
presets of one product apart for per-printer AMS matching survive),
|
||||
`--drop-redundant-ids VENDOR` deletes declarations
|
||||
that merely re-declare an inherited OFL id, `--add-hint "OLD=NEW"` records a cross-island
|
||||
succession hint, and `--retire "OLD=NEW"` records succession for a shipped non-island id
|
||||
that vanished while another declarer kept it alive (lineage the automatic claim vote can no
|
||||
longer see).
|
||||
|
||||
If you skip the tooling, CI fails and prints the remedy: the expected id for your family, and
|
||||
the instruction to run `python scripts/assign_filament_ids.py --update-snapshot` and commit
|
||||
the resulting diff.
|
||||
|
||||
## Reserved namespaces — never mint or hand-write into
|
||||
|
||||
| Space | Owner | Rule |
|
||||
| --- | --- | --- |
|
||||
| `GF*` | Bambu AMS/RFID catalog | BBL vendor only; byte-copies elsewhere only where the snapshot already sanctions them |
|
||||
| `QD_*` | Qidi device protocol | frozen device contract; Qidi vendor only |
|
||||
| `P` + 7 hex chars (case-insensitive), `"null"` | user-created custom filaments (`CreatePresetsDialog.cpp`) | never appears in system profiles |
|
||||
| every already-shipped id | grandfather snapshot | frozen as-is; new claims need maintainer sign-off |
|
||||
| every retired id | `resources/profiles/retired_filament_ids.json` | never used again, for anything |
|
||||
|
||||
## The succession ledger
|
||||
|
||||
`resources/profiles/retired_filament_ids.json` ships with the app. Each retired id maps to
|
||||
`{"claims": [...], "successor": <id|null>}` — successor chains are followed to the live end —
|
||||
and a `hints` map carries the same forwarding for ids Orca cannot retire because another
|
||||
island owns them (e.g. a `GF*` id whose material also exists as an OFL family). The client
|
||||
consults the ledger **only on resolution miss** (AMS tray sync, tray-id type lookup,
|
||||
calibration history, filament-id preset lookup): a live preset always wins first, so BBL
|
||||
installs resolve `GF*` natively and behavior is unchanged wherever the raw id still exists.
|
||||
This is what makes identity-driven re-mints (structure rule 5) safe: the old id keeps
|
||||
resolving to the family's current preset instead of degrading to a `Generic <type>` fallback.
|
||||
The file is append-only and maintained exclusively by `--update-snapshot` / `--add-hint` /
|
||||
`--retire`.
|
||||
|
||||
## How CI enforces this
|
||||
|
||||
Profile CI (`check_profiles.yml` → `scripts/orca_extra_profile_check.py`) runs
|
||||
`check_filament_ids()` tree-wide. Its ground truth is
|
||||
**`scripts/filament_id_snapshot.json` — the sanctioned state**: the id state derived from the
|
||||
tree must equal the snapshot exactly, in both directions. Any change to the id landscape
|
||||
therefore surfaces as a diff to that file, and **that snapshot diff is what maintainers review
|
||||
and gate in a PR**. Never edit the snapshot by hand — `--update-snapshot` regenerates it
|
||||
deterministically (running it twice changes nothing).
|
||||
|
||||
The checks, in brief:
|
||||
|
||||
- **Format** — every id is either in the snapshot, `OF` + 6 base62 chars, BBL's, or Qidi `QD_*`.
|
||||
- **Snapshot equality** — tree claims == snapshot claims **and** tree triples == snapshot
|
||||
triples, both directions: any `filament_vendor`/`filament_type`/family-name change surfaces
|
||||
as a snapshot diff.
|
||||
- **Mint conformance** — a non-grandfathered `OF*` id must equal the mint (or a salt
|
||||
iteration) of its declarer's product triple; the error prints the expected id.
|
||||
- **Retired reuse** — any tree id present in `resources/profiles/retired_filament_ids.json` is an error.
|
||||
Ids that fully vanish from the tree are appended there by `--update-snapshot`; the file is
|
||||
**append-only**.
|
||||
- **Alias hygiene** — any vendor preset riding an OFL family id must keep the library
|
||||
preset's base name, a non-empty `compatible_printers`, and no own id key (structure rule 4);
|
||||
the error names the rename as the cause.
|
||||
- **Triple integrity** — every declarer outside the BBL/`QD_*` islands must resolve a
|
||||
non-empty `filament_vendor` and `filament_type` (generics use `"Generic"`), and all
|
||||
declarers of one family within a bundle must agree on the triple.
|
||||
- **Succession integrity** — retired successor chains terminate at a live id (or null) with
|
||||
no cycles; `hints` keys are live, island-owned ids.
|
||||
- **Reserved namespaces** — `GF*` outside BBL, `QD_*` outside Qidi, `P<7-hex>` or `null`
|
||||
anywhere, unless that exact claim is grandfathered in the snapshot.
|
||||
- **Structure** — no `filament_id` key on instantiated presets; no declared-vs-inherited id
|
||||
drift; every instantiated system filament must resolve an effective id through its
|
||||
`inherits` chain (an id-less one is a hard load error in C++ that discards the whole vendor
|
||||
bundle).
|
||||
|
||||
Sharing a **reserved-catalog** id with a new family or vendor (e.g. shipping a Bambu-cataloged
|
||||
product under another vendor with its authentic `GF*` id) is refused by `--update-snapshot`
|
||||
unless you pass `--allow-shared-catalog` — and it still lands in the snapshot diff for
|
||||
maintainer review. Any other new sharing of an existing id is caught by the mint-conformance
|
||||
check instead.
|
||||
|
||||
## FAQ
|
||||
|
||||
- **A new color of an existing product?** Never a new id — colors are not families.
|
||||
- **A second diameter (1.75 mm and 2.85 mm) of the same product?** A sibling family with its
|
||||
own id: two diameters are separately selectable spool products.
|
||||
- **A high-speed tune of an existing material for another printer model?** Same family:
|
||||
inherit the family's root, write no id key.
|
||||
- **A tuned generic ("our profile for Generic PLA")?** Inherit `Generic PLA @System`, keep the
|
||||
`Generic PLA` base name, set `compatible_printers`, write no id key.
|
||||
- **I need to rename a family (or fix its `filament_vendor`/`filament_type`).** Add
|
||||
`renamed_from` for the name, run `--remint <Vendor>` then `--update-snapshot`: the id
|
||||
re-derives from the corrected identity and the old id lands in the succession ledger
|
||||
pointing at the new one. Commit the profile, snapshot, and ledger diffs together.
|
||||
- **CI says my family needs an id.** Run `python scripts/assign_filament_ids.py`, then
|
||||
`--update-snapshot`, and commit both diffs. Do not type an id by hand.
|
||||
|
||||
For general profile authoring, see the profile development guide on the
|
||||
[OrcaSlicer wiki](https://www.orcaslicer.com/wiki).
|
||||
1029
filament_id_plan.html
Normal file
1029
filament_id_plan.html
Normal file
File diff suppressed because it is too large
Load Diff
397
filament_id_plan.md
Normal file
397
filament_id_plan.md
Normal file
@@ -0,0 +1,397 @@
|
||||
# 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_id` is 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 from
|
||||
`uuid5(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),
|
||||
and `P<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_id` from 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 `-f` scope
|
||||
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_vitrification` warnings (`PresetBundle.cpp:690-733`; callers
|
||||
`DevFilaBlackList.cpp:70`, `Plater.cpp:3453`, `SelectMachine.cpp:3560,4623`). The code
|
||||
comment at `:695` states 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-528` via `ToolOrdering.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`): own `filament_id` key → vendor
|
||||
`filament_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's `OGFL99`/`OGFG99` through the base-bundle fallback.
|
||||
- **Two family-identity systems exist**: `filament_id` (device matching) and `alias` (name
|
||||
before `" @"`). OFL shadowing is keyed on **alias**: `update_library_profile_excluded_from`
|
||||
(`Preset.cpp:3684-3714`) hides an OFL preset (empty `compatible_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/GFS01` support check (`DeviceManager.cpp:4739`), per-family PA
|
||||
defaults `GFU01/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 the `Generic X @System` preset, keep the
|
||||
> `Generic X` base 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
|
||||
|
||||
1. **One family = one root.** Each material family has root preset(s) (`instantiation:false`,
|
||||
typically `<Family> @base`) and only roots carry the `filament_id` key. Instantiated
|
||||
variants inherit a root and never write `filament_id`. (A family MAY have several roots —
|
||||
e.g. Qidi's per-series bases — but they must all declare the *identical* id.)
|
||||
2. **Family identity is declared, not name-derived.** Default: the family name is the
|
||||
instantiated presets' base name (name with `/\s?@.*$/` stripped — note *optional* space,
|
||||
because `Afinia 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.
|
||||
3. **Within a family, variants' `compatible_printers` are pairwise disjoint** — that *is* the
|
||||
PR #14459 invariant, enforced by the validator.
|
||||
4. **Generics belong to OFL.** A vendor tuning `Generic PLA` inherits
|
||||
`Generic PLA @System`, keeps the `Generic PLA` base name/alias (so alias shadowing excludes
|
||||
the OFL preset on those printers, `Preset.cpp:3684`), sets non-empty `compatible_printers`,
|
||||
and writes no id. A vendor-*branded* filament never rides a generic family id.
|
||||
5. **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.py` inserts 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:
|
||||
|
||||
1. **Format**: an id is valid iff `OF[0-9A-Za-z]{6}` **or** in the grandfather snapshot **or**
|
||||
vendor==BBL **or** `QD_*` in Qidi. No whitespace/ASCII/length checks needed outside the
|
||||
grandfather set — new ids are minted, and the grandfather set is closed.
|
||||
2. **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_catalog` entries are the sanctioned exception).
|
||||
3. **Structure ratchet**: `filament_id` key 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** (the
|
||||
`Generic SBS` drift bug class). Pre-existing violations are snapshot-frozen; new ones error.
|
||||
4. **Mint conformance**: an id new relative to the snapshot must equal the mint (or a salt
|
||||
iteration); the error message prints the expected value.
|
||||
5. **Stability**: an `(id, family)` pair on main may not change or vanish, *following
|
||||
`renamed_from` chains* (so an honest rename passes), unless listed in a maintainer-gated
|
||||
migrations file. Retired ids go to an append-only `retired_ids` ledger; a retired id may
|
||||
never be defined again for any family.
|
||||
6. **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-empty
|
||||
`compatible_printers` — error message names the rename as the cause.
|
||||
7. **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_from` is already populated in the validator context (`update_system_maps` at
|
||||
`PresetBundle.cpp:2302`), so the 32 shadowed pairs won't false-positive and the 10 live ones
|
||||
will be caught. Run `-f` per vendor in CI, widening as vendors are cleaned (§5).
|
||||
8. **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 `@base`s 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
|
||||
|
||||
0. **Land the rule + tooling first** (no profile changes): `scripts/assign_filament_ids.py`
|
||||
(mint + insert + `--mint`), the extended `orca_extra_profile_check.py` checks in
|
||||
snapshot-ratchet mode, the C++ validator OFL cross-check, the runtime warning, the rule doc.
|
||||
Generate `filament_id_snapshot.json` (id→families multimap over main) and empty
|
||||
`retired_ids.json` — both checked in.
|
||||
1. **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 @System` get their own family roots+ids instead of collapsing into their
|
||||
parent generic), keeping every current effective id that is unambiguous.
|
||||
2. **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 `-f` scope (`check_profiles.yml` currently `-v BBL -f`; append
|
||||
vendors as they reach zero; when all are in, drop `-v` and run tree-wide).
|
||||
3. **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 @S1` vs `@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_printers` edits the plan prescribes (this is what makes the Flashforge
|
||||
shadow-file conversions safe: each id-less `fdm_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 X`
|
||||
twins) are re-minted, not dropped; consolidation with `renamed_from` is 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 carry
|
||||
`GFB99/GFG99/GFL99`. Multi-root families are the norm (`...@Q2-Series` / `@Q2C-Series` /
|
||||
`@X-Max 4-Series` bases) — same mint lands in every series root of one family.
|
||||
- **Flashforge (69)**: two umbrellas (`FFG01` ~140 presets; `GFB99/GFG99/GFL99` G3U-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 `_N` ids stay.
|
||||
- **Sovol (6)**: delete the wrong own-id lines; correct ids flow from OFL by inheritance.
|
||||
- **Cubicon (17)**: `@base` presets are themselves instantiated + over-claiming; 9 file edits.
|
||||
|
||||
---
|
||||
|
||||
## 6. Concrete work items (PR-sized)
|
||||
|
||||
1. `scripts/assign_filament_ids.py` + mint function + tests (incl. the 14-group regression set
|
||||
from the adversarial pass). *(new)*
|
||||
2. `orca_extra_profile_check.py`: checks §3.4-1..6 in ratchet mode + snapshot/ledger files;
|
||||
drop the BBL/OFL-only gate at `:292` and the OFL skip at `:601`. *(extend)*
|
||||
3. C++ validator: OFL-aware `check_duplicate_filament_subtypes`; runtime ambiguity warning at
|
||||
the two `find_if` sites. *(small)*
|
||||
4. 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)*
|
||||
5. OFL migration PR (phase 1).
|
||||
6. Per-vendor migration PRs (phase 2), each widening CI `-f` scope.
|
||||
|
||||
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 -f` tree-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 `breaks` finding 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
|
||||
|
||||
1. **Id format**: opaque deterministic `OF*` mint (recommended, judges 2/2) vs mnemonic
|
||||
registry grammar (runner-up). Everything else in the plan is format-agnostic.
|
||||
2. **Multi-vendor brands** (Snapmaker ships Fiberon with authentic `GF*` ids): sanction via
|
||||
`shared_catalog` (recommended, low churn) vs hoisting those families into OFL.
|
||||
3. **Benchy-style demo presets**: mint ids per demo preset (recommended) vs teaching the
|
||||
validator `compatible_prints` gating.
|
||||
4. **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).
|
||||
5. **Where the rule doc lives**: in-repo `doc/` (recommended — CI messages need a stable link)
|
||||
vs wiki-only.
|
||||
314
filament_id_plan_v2.md
Normal file
314
filament_id_plan_v2.md
Normal file
@@ -0,0 +1,314 @@
|
||||
# filament_id plan v2: the `get_filament_id` (P+md5) proposal, validated
|
||||
|
||||
> **Status note:** the verdict in §0-§4 and §7-§8 stands. The work items in §5 are
|
||||
> superseded by `filament_id_plan_v3.md` (OFL-as-catalog, content-addressed triple key,
|
||||
> succession ledger): W1/W3 are carried into v3.0, W2/W5 carry unchanged, W4 is dropped.
|
||||
|
||||
Follow-up to `filament_id_plan.md` (v1, implemented on `feature/filament_id`: deterministic
|
||||
`OF*` mint + snapshot ledger + 30-vendor migration, tree-wide validator `-f` = 0).
|
||||
|
||||
**Proposal under review:** mint system `filament_id`s with the scheme of
|
||||
`static std::string get_filament_id(std::string vendor_typr_serial)`
|
||||
(`src/slic3r/GUI/CreatePresetsDialog.cpp:487-552`) — Bambu's user-custom-filament id
|
||||
allocator — so system ids are "compatible with Bambu AMS sync".
|
||||
|
||||
Every claim below was verified in source (`file:line`), against upstream BambuStudio, or in
|
||||
primary online sources (URLs in §8). Verdict first, evidence after.
|
||||
|
||||
---
|
||||
|
||||
## 0. Executive summary — the verdict
|
||||
|
||||
**Do not re-mint system ids as `P+md5(name)`. Keep the v1 `OF*` mint.** Three facts decide it:
|
||||
|
||||
1. **The AMS/device path never validates id *shape*.** `tray_info_idx` is an opaque string
|
||||
end-to-end: sent verbatim (`DeviceManager.cpp:1642`), parsed verbatim
|
||||
(`DevFilaSystem.cpp:512-514`), and firmware persists arbitrary bytes — an A1 stored and
|
||||
echoed a *corrupted* id `Pde2\xea58c` (bambulab/BambuStudio#5436). A P-shaped system id
|
||||
is not "more acceptable" to the device than an `OF*` one.
|
||||
2. **P-shape buys zero recognition.** The printer resolves tray ids only against its built-in
|
||||
`GF*` catalog plus the *account's* cloud custom-filament cache (official Bambu wiki); ids
|
||||
it cannot resolve round-trip as `?`. Orca can never upload system presets into that cache
|
||||
(`Preset.cpp:2071` gates cloud upload on `is_user()`), so an Orca system `P` id shows `?`
|
||||
exactly like an `OF` id. The public catalog id space is 100% `GF*` (ha-bambulab
|
||||
`filaments.json`: 86/86 ids).
|
||||
3. **P-shape is the one shape the codebase punishes.** The *only* id-shape dispatch in the
|
||||
entire tree is `MachineObject::check_ams_filament_valid` + `update_filament_list`
|
||||
(`DeviceManager.cpp:5335/5352/5395/5410`, gate `setting_id.size()==8 && [0]=='P'`), a
|
||||
user-custom lifecycle reconciler that **remotely wipes an AMS tray**
|
||||
(`command_ams_filament_settings(..., "", "", white, "", 0, 0)` at `:5345`) or rewrites its
|
||||
temps (`:5361-5367`) when a P-shaped tray id drops out of the user-root preset list
|
||||
(`:5219`, armed at `:5268`). Name-keyed minting makes system id == user-custom id *by
|
||||
design* (same name → same id), so "user deletes their now-redundant custom after the
|
||||
system preset ships" becomes a remote tray wipe. `GF*` (wrong length) and `OF*` (wrong
|
||||
first char) are structurally immune.
|
||||
|
||||
The proposal's *real* value lives in two places, and v2 captures both without the re-mint:
|
||||
|
||||
- **The adopt step** (the function's first branch, `:509-511/:526-528`): same base name →
|
||||
same id. In-app, this already gives Orca-local convergence today — a user custom named
|
||||
like a system family adopts the system id *whatever its shape*. At authoring time, the
|
||||
same semantics = the v1 `shared_catalog` mechanism; §5/W4 extends it (curated, optional)
|
||||
to let byte-authentic Bambu-catalog families carry authentic `GF*` ids.
|
||||
- **The hash step belongs to user space.** `P+md5(name)` is Bambu's allocator for *user*
|
||||
presets; the community is already asking for it there (OrcaSlicer PR #13315, unique ids
|
||||
for inherited user presets). §5/W5 endorses that lane. System profiles stay out of the
|
||||
`P` namespace — and v2 adds client hardening (W1) because ten *already-shipped* system
|
||||
P-hex ids (Cubicon `P510cf**`×8, Ginger `P510eff9`, Artillery `Pfcf9c4c`) sit inside the
|
||||
wipe-gate's shape match today.
|
||||
|
||||
Judge panel (3 independent lenses over 4 variants; §7): keep-`OF*` won 23/40 aggregate
|
||||
(device-ecosystem 6, identity-semantics 8, migration-enforceability 9) vs full Bambu
|
||||
emulation 11, hash-only name-keyed 12, vendor-scoped P-hash 12. The single dissent
|
||||
(device-ecosystem, favoring adoption) is honored by W4; its own verdict on the shape was
|
||||
"adopt the semantics, not the costume".
|
||||
|
||||
---
|
||||
|
||||
## 1. What the proposed generator actually is (verified)
|
||||
|
||||
`get_filament_id(vendor_typr_serial)` (`CreatePresetsDialog.cpp:487-552`), called with
|
||||
`"<vendor> <type> <serial>"` (`:1128`, `PLA-AERO`→`"PLA Aero"`), and per-preset with the
|
||||
display base name when cloning presets for a user-created printer
|
||||
(`Preset.cpp:2785-2803` → `:2798-2800`):
|
||||
|
||||
1. **Adopt:** scan a temp bundle of *every* vendor bundle on disk
|
||||
(`PresetBundle::load_system_filaments_json`, `PresetBundle.cpp:2342-2391`) plus the
|
||||
user's presets, then the live bundle (`Preset.cpp:2831-2842`); if any preset's base name
|
||||
(`name.substr(0, first('@') - 1)`) equals the input and its id ≠ `"null"`, **return that
|
||||
id** — which can be `GF*`, `QD_*`, `OF*`, or another user's P-hex.
|
||||
2. **Mint:** `"P" + md5(input)[0:7]`, lowercase hex over the raw UTF-8 bytes (`:533`,
|
||||
`:480`).
|
||||
3. **Collide:** if the id is held by a *different* name, re-hash with a local wall-clock
|
||||
salt (`md5(input + get_curr_time())`, `:547`) — non-deterministic by construction.
|
||||
|
||||
Upstream parity: the function and its caller input construction are **byte-identical** in
|
||||
BambuStudio master (`CreatePresetsDialog.cpp` L434-499 / L1061; diff empty, fetched
|
||||
2026-07-03). So identical dialog inputs in BBS and Orca yield identical ids — the kernel of
|
||||
the proposal's compatibility claim.
|
||||
|
||||
Reproduction limits (why "exactly the approach" cannot be ported to system minting anyway):
|
||||
|
||||
- The base-name parser truncates names lacking a space before `@` (`"Afinia PLA@HS"` →
|
||||
`"Afinia PL"`); 48 shipped presets hit this, and the *clone* path parses differently
|
||||
(`" @"` two-char, `Preset.cpp:2792`), so the app itself is internally inconsistent.
|
||||
- 597 presets (361 whole families, e.g. all of Anker) contain no `@` and are invisible to
|
||||
the adopt scan and its collision map (`:505-508`).
|
||||
- The collision salt is wall-clock time — unreproducible across machines, so id values
|
||||
cannot be CI-verified from names; a ledger would still be the sole source of truth.
|
||||
- Shipped P-hex ids don't round-trip from names today: Cubicon `P510cfb0` ≠
|
||||
`P+md5("Cubicon ABS")` = `Pc624b68` (verified) — so even Bambu-lineage P ids are not
|
||||
name-derivable in practice.
|
||||
|
||||
## 2. What Bambu AMS sync actually consumes (verified)
|
||||
|
||||
- Send: `command_ams_filament_settings` puts the preset's `filament_id` verbatim into
|
||||
`tray_info_idx` (`DeviceManager.cpp:1642`); cloud vs LAN differ only in transport
|
||||
(`:2502-2536`). No client- or firmware-side rejection path exists; the ack parse stores
|
||||
whatever the printer echoes (`:3808-3860`).
|
||||
- Resolve (slicer side): tray id → first compatible root preset with equal `filament_id` —
|
||||
system *and* user roots, no shape filter (`PresetBundle.cpp:3151`, `:3252-3254`); misses
|
||||
fall back by `"Generic <type>"` name, then similarity, then keep-previous
|
||||
(`:3157-3169`, `:3260-3305`). `setting_id_to_type` resolves against `is_system` presets
|
||||
only (`DeviceManager.cpp:2538-2559`) — a system preset resolves *because it is system*,
|
||||
never because of its id shape.
|
||||
- Resolve (device side): built-in `GF*` catalog + the account's cloud custom cache;
|
||||
custom-filament sync is **cloud-only** (not LAN), and an id the printer has no data for
|
||||
displays `?` until opened once on the printer screen (official wiki, §8). Third-party
|
||||
consumers see customs as "unknown" (ha-bambulab #466/#540).
|
||||
- Since Jan 2025, AMS configuration is gated behind Bambu-signed clients on new firmware
|
||||
(Developer Mode / older firmware exempt) — any AMS-sync benefit for Orca is conditional
|
||||
on that regardless of id scheme (Bambu authorization blog, §8).
|
||||
- Orca already ships non-`GF`/non-`P` shapes to Bambu trays in the field: OFL presets are
|
||||
compatible with every printer (`PresetBundle.cpp:5681-5684`) and carry `OGF*`/`OFL*` ids
|
||||
(e.g. `OFLSBS99`, hardcoded in `MoonrakerPrinterAgent.cpp:654`). The premise "the
|
||||
ecosystem has only ever seen `GF*`/P-hex" is already false, with no observed rejection.
|
||||
|
||||
**Cross-client reality check.** The name-keyed benefit ("a BBS-created custom named like an
|
||||
Orca system preset lands on the same id, so Orca's sync matches the system preset") is
|
||||
mechanically true but narrow: it needs byte-exact names (including the `PLA Aero` mapping
|
||||
and single spacing), the unsalted hash path, cloud mode, and permissive firmware. The
|
||||
symmetric case already works in Orca *without* any re-mint: an Orca user creating a custom
|
||||
named like a system family **adopts the system id** via the in-app adopt branch, so local
|
||||
custom ↔ system ↔ tray matching is shape-independent today.
|
||||
|
||||
## 3. The disqualifying finding, in mechanism form
|
||||
|
||||
`update_filament_list` (`DeviceManager.cpp:5208-5272`) snapshots `{filament_id → temps}`
|
||||
over **user root presets only** (`preset.is_user() && preset.inherits() == ""`, `:5219`);
|
||||
ids that vanish or change temps between snapshots are armed into `checked_filament`
|
||||
(`:5268`). `check_ams_filament_valid` (`:5311-5445`) then, for every AMS/virtual tray whose
|
||||
`setting_id` matches `size()==8 && [0]=='P'`:
|
||||
|
||||
- id armed and **not** in the current user-root list → remotely **clears the tray**
|
||||
(`:5335-5349`, `:5395-5408`);
|
||||
- id armed and in the list with unequal temps → **rewrites tray temps from the user
|
||||
preset**, ignoring same-id system presets (`:5352-5374`; `PresetBundle.cpp:3719` skips
|
||||
non-user presets; unguarded `find()->second` at `:3717`).
|
||||
|
||||
Failure scenario under the proposal: system `"PolyLite PLA"` ships with
|
||||
`P+md5("PolyLite PLA")`. A user's same-named custom (BBS- or Orca-created — same id by
|
||||
design) is on an AMS tray. The user deletes the now-redundant custom. Next status refresh:
|
||||
the id is armed, absent from user roots → Orca wipes the tray, even though the system
|
||||
preset still resolves that id perfectly. Runs continuously (`StatusPanel.cpp:3275-3277`).
|
||||
|
||||
Two corollaries independent of the proposal (→ W1):
|
||||
|
||||
- The ten shipped P-hex **system** ids (Cubicon/Ginger/Artillery) already pass the shape
|
||||
gate; only the "id must transit a user root" arming condition protects them, and the
|
||||
in-app adopt branch can create exactly that transit today.
|
||||
- `assert(it->first.size() == 8 && it->first[0] == 'P')` (`:5252`) is violable today: a
|
||||
user custom named `"Bambu PLA Basic"` adopts `GFA00` onto a user root and aborts debug
|
||||
builds.
|
||||
|
||||
## 4. Identity costs the re-mint would add (quantified, tree dry-run)
|
||||
|
||||
- 1148 distinct family base names; **198** appear in 2+ vendors; **159** groups carry ≥2
|
||||
distinct ids today and would silently merge under name-keying (Generic PETG alone: 15
|
||||
ids today). 112 involve BBL; 82 are `GF↔OGF` mirror pairs.
|
||||
- **4** cross-vendor groups share a name across materially different `filament_type`
|
||||
(Generic PLA Silk, Generic PETG-CF, Generic PA6-CF, Generic PE-CF) — one merged id would
|
||||
feed wrong type/name/vitrification to the global unscoped consumers
|
||||
(`PresetBundle.cpp:690-733`; `DeviceManager.cpp:2538`; `FilamentGroup.cpp:513-519`) (→ W3).
|
||||
- 33 deliberately-split families on the branch would re-merge (25 Elegoo-vs-OFL pairs, 7
|
||||
FlyingBear-vs-InfiMech "Other *" pairs, the salted Cubicon PC pair) — undoing v1
|
||||
decisions that the fixture gate forced.
|
||||
- Renames become id migrations: name-keyed ids re-key on any marketing rename; the ledger
|
||||
can freeze them, but then name-derivability — the scheme's selling point — dies family
|
||||
by family. The `OF*` key (`vendor/family`) survives display-name churn.
|
||||
- Entropy drops 35.7 → 28 bits (still 0 collisions at today's 1148 names; ~0.75 expected
|
||||
at 20k). Re-mint surface: 391 unshipped ids across 1327 files, 13 hardcoded tests, the
|
||||
reserved-namespace policy inversion, and a retired-ledger rebuild.
|
||||
|
||||
## 5. Work items (delta from `feature/filament_id` HEAD)
|
||||
|
||||
**W1 — client hardening (C++, small, ships with the migration PR train).**
|
||||
a. Skip the tray-reset and temp-rewrite in `check_ams_filament_valid` when **any
|
||||
`is_system` filament preset carries the tray's id** — no compatibility filter,
|
||||
mirroring the semantics of the global consumers (`get_filament_by_filament_id`,
|
||||
`setting_id_to_type`). This protects the ten shipped P-hex system ids and any BBS
|
||||
custom colliding with them, while ids resolving only to user presets (or to nothing)
|
||||
keep today's cleanup behavior.
|
||||
b. Relax the debug assert `DeviceManager.cpp:5252` to a log (user roots legitimately
|
||||
carry adopted `GF*`/`OF*` ids).
|
||||
c. Guard `PresetBundle.cpp:3717` (`find()` unchecked before `->second`).
|
||||
d. Regression-check that AMS sync never clears trays whose id it merely cannot resolve
|
||||
(OrcaSlicer#4431 class): the keep-previous fallbacks at `PresetBundle.cpp:3163-3169`,
|
||||
`:3296-3305` must cover the UI paths.
|
||||
|
||||
**W2 — tooling + doc guardrails.**
|
||||
a. Document `^OF[0-9A-Za-z]{6}$` as the system-mint namespace. **Do not add it to
|
||||
`reserved_space_owner`** (`scripts/assign_filament_ids.py:394-402`): check 6 exempts
|
||||
only snapshot-grandfathered claims and the `--update-snapshot` refusal gate
|
||||
(`:596-621`) would then reject every *future* mint. The space is already enforced —
|
||||
check 3 (mint conformance, `:488-509`) errors on any OF-shaped id that does not equal
|
||||
its own family's mint (covered by `test_check3_of_id_must_match_mint`), and the
|
||||
snapshot diff is the human gate. Add one doc paragraph + a test asserting a foreign
|
||||
vendor claiming another family's OF id fails check 3.
|
||||
b. `doc/developer-reference/filament_id.md`: add a "why not P-hex" section citing the
|
||||
`DeviceManager.cpp:5335` gate and the account-cache resolution model — community
|
||||
pressure toward `P+md5` exists (PR #13315) and will recur.
|
||||
c. Document that user roots may legitimately hold adopted system ids (incl. what that
|
||||
means for cloud upload, `Preset.cpp:1874-1876`), matching BBS behavior.
|
||||
|
||||
**W3 — data hygiene: the 4 same-name-different-type groups.** Audit each (they confuse
|
||||
name-based fallback matching and any future interop even under vendor-scoped ids):
|
||||
verify whether the divergent `filament_type` is a data bug (e.g. OFL `Generic PETG-CF`
|
||||
resolving `PETG`, OFL `Generic PE-CF` resolving `PE`, Flashforge `Generic PLA Silk`
|
||||
mixing `SILK`+`PLA`, Creality-vs-Elegoo `Generic PA6-CF` as `PA-CF`/`PA6-CF`) or
|
||||
intentional; fix by type alignment or rename with evidence, gated by
|
||||
config-equivalence (only `filament_type` diffs as prescribed) + full validator suite.
|
||||
|
||||
**W4 — optional, curated GF adoption (the proposal's adopt step, done safely).** Extend the
|
||||
v1 `--allow-shared-catalog` mechanism into an explicit per-family adoption worksheet: a
|
||||
family may carry a byte-authentic Bambu catalog id iff (i) it is verifiably the same
|
||||
commercial product as the BBL family (vendor evidence + equal `filament_type`), (ii)
|
||||
validator `-f` stays 0 tree-wide (alias shadowing covers BBL/OFL overlaps), (iii) the
|
||||
fixture gate passes, (iv) the snapshot diff records the adoption. Candidates: the 13
|
||||
actionable BBL-overlapping families minted `OF*` in v1 (e.g. Qidi `Bambu ABS`→`GFB00`,
|
||||
`PolyLite PLA`→`GFL00`, `Overture PLA`→`GFL04`, `PolyLite ABS`→`GFB60`; `OFLSBS99` is
|
||||
shipped and frozen; the two type-hazard OFL families are excluded until W3 lands).
|
||||
**Honest benefit statement:** these presets are compatible only with non-Bambu printers,
|
||||
so no Bambu device resolves their ids today; the payoff is one-product-one-id coherence
|
||||
for the global consumers, project portability, and readiness for W6. Recommended seed:
|
||||
the four Qidi brand families; generics deferred.
|
||||
|
||||
**W5 — user-preset lane (where the proposal's hash belongs).** Support unique ids for
|
||||
inherited user presets (the PR #13315 pain: children share the parent's id, so AMS always
|
||||
resolves the generic parent). `P + md5(preset name)` matching
|
||||
`CreatePresetsDialog::get_filament_id` is correct *in user space*: adopt-first against
|
||||
existing ids, then hash; ids frozen per preset after mint. Constraints: never emitted
|
||||
into system profiles (W2a makes that mechanical); W1 must land first so shared-id
|
||||
lifecycles can't wipe trays.
|
||||
|
||||
**W6 — recorded future option:** SoftFever's "upload OrcaSlicer's filament database
|
||||
(especially the filament ID) to the printer" (PR #12724 comment). If pursued, Orca ids
|
||||
become first-class device-visible artifacts and the P-mimicry question is permanently
|
||||
moot; the `OF*` scheme is the *better* citizen there (collision-free vendor-scoped ids,
|
||||
no user-custom masquerade).
|
||||
|
||||
Unchanged from v1: mint rule, snapshot/retired ledgers (no OF retirement — nothing is
|
||||
re-minted), CI wiring, migration commits. `filament_id_plan.md` remains the implemented
|
||||
baseline; this document records the v2 decision and its follow-on work.
|
||||
|
||||
## 6. Gates (per work item)
|
||||
|
||||
Same battery as v1, all local: `python scripts/orca_extra_profile_check.py` exit 0;
|
||||
`assign_filament_ids.py --check` exit 0 (46+ unit tests green; new tests for W2a
|
||||
reservation and, when implemented, W4 adoption sanctioning); validator `-l 2` exit 0,
|
||||
`-f` tree-wide exit 0, `-r` BBL+Qidi exit 0; custom-preset fixture overlays (the W1/W4
|
||||
changes touch exactly the preset-visibility machinery the fixtures exist to protect);
|
||||
config-equivalence: flattened effective configs differ only in prescribed keys
|
||||
(`filament_id` for W4, `filament_type` for W3, none for W1/W2). W1 additionally needs a
|
||||
manual AMS smoke test on a live Bambu printer (tray set/clear round-trip) — a release
|
||||
checklist item, not CI (the workflows have no hardware runners).
|
||||
|
||||
## 7. Scheme comparison (judge panel record)
|
||||
|
||||
| Variant | Device lens | Identity lens | Migration lens | Σ |
|
||||
|---|---|---|---|---|
|
||||
| V1 full Bambu emulation (adopt incl. `GF*` + P+md5 + salt) | 7 | 2 | 2 | 11 |
|
||||
| V2 hash-only name-keyed `P+md5(base name)` | 4 | 4 | 4 | 12 |
|
||||
| V3 vendor-scoped P-hash (`P+md5(vendor/family)`) | 2 | 5 | 5 | 12 |
|
||||
| **V4 keep `OF*` uuid5 vendor-scoped (chosen)** | 6 | 8 | 9 | **23** |
|
||||
|
||||
All three judges answered the pivotal question the same way: the P-hex **shape** confers no
|
||||
device/cloud benefit (resolution is by value against catalog + account cache; the path is
|
||||
otherwise shape-agnostic) and is the only shape with a destructive client-side gate. V3 is
|
||||
strictly dominated (all of the re-mint cost, none of the name-keyed benefit). V1's genuine
|
||||
half — GF adoption — is captured by W4 at zero re-mint cost.
|
||||
|
||||
## 8. Evidence index
|
||||
|
||||
Code (this branch): `CreatePresetsDialog.cpp:487-552,1128,2798-2800` (generator + callers);
|
||||
`DeviceManager.cpp:1642` (verbatim send), `:2538-2559` (system-only type resolve),
|
||||
`:5208-5272` (user-root snapshot, `:5219`, `:5252` assert, `:5268` arming), `:5311-5445`
|
||||
(P-shape gate + tray wipe `:5335/:5345`, temp rewrite `:5352-5374`, virtual tray
|
||||
`:5395-5435`); `DevFilaSystem.cpp:512-524`; `PresetBundle.cpp:690-733,3116-3128,3151,
|
||||
3252-3254,3709-3767,5674-5753`; `Preset.cpp:1874-1876,2071,2785-2842`;
|
||||
`AMSMaterialsSetting.cpp:886,894-897`; `WebGuideDialog.cpp:67`;
|
||||
`PresetComboBoxes.cpp:1952-1966`; `MoonrakerPrinterAgent.cpp:654`;
|
||||
`scripts/assign_filament_ids.py:69,71-72,118-144,394-402,596-621`.
|
||||
|
||||
Online (fetched 2026-07-03): BambuStudio master `CreatePresetsDialog.cpp` L434-499
|
||||
(byte-identical generator); wiki.bambulab.com `create-filament` (custom filaments AMS-able
|
||||
from firmware 1.6.6; only dialog-created presets sync) and `custom-filament-issue`
|
||||
(cloud-only sync; unknown ids show `?`); blog.bambulab.com authorization-control (Jan-2025
|
||||
AMS-config gating); bambulab/BambuStudio#5436 (firmware persists corrupted id);
|
||||
OrcaSlicer #4431 (tray clobber to `?`), #3874 (cloud-only confirmation), PR #14459
|
||||
(the `-f` invariant), PR #14423 + PR #12724 + PR #13315 (maintainer statements / community
|
||||
P+md5 pressure); greghesp/ha-bambulab `filaments.json` (86/86 `GF*`) + #466/#540.
|
||||
|
||||
Method: 6 parallel evidence agents (generator semantics; AMS/device path; exhaustive
|
||||
shape-dispatch sweep; upstream/online; tree-wide dry-run over 5892 presets / 1455 families;
|
||||
branch change inventory) → 3-judge panel (device-ecosystem, identity-semantics,
|
||||
migration-enforceability lenses). Dry-run artifacts: session scratchpad
|
||||
`phex_dryrun_{summary,details,followup}.json`.
|
||||
|
||||
## 9. Open decisions for maintainers
|
||||
|
||||
1. **W4 scope**: none / 4 Qidi brand families (recommended) / + generic-tier re-adoption.
|
||||
2. **W5 timing**: implement in-repo vs review upstream PR #13315 with the W1 hardening as a
|
||||
prerequisite either way.
|
||||
3. **W6**: pursue the filament-database-upload design (makes Orca ids device-visible and
|
||||
ends the mimicry debate for good).
|
||||
213
filament_id_plan_v3.md
Normal file
213
filament_id_plan_v3.md
Normal file
@@ -0,0 +1,213 @@
|
||||
# filament_id plan v3: OFL as the catalog, content-addressed product ids
|
||||
|
||||
Supersedes §5 of `filament_id_plan_v2.md` (whose P+md5 verdict stands unchanged) and
|
||||
revises the mint rule of `filament_id_plan.md` (v1, implemented on `feature/filament_id`).
|
||||
Decision driver: v1's mint key scoped families to the *profile bundle* (printer brand), so
|
||||
one commercial product tuned in N bundles carries N ids — e.g. PolyLite PLA ships in five
|
||||
bundles (`BBL`, `OrcaFilamentLibrary`, `OrcaArena`, `Qidi`, `Snapmaker`), all with
|
||||
`filament_vendor: "Polymaker"`, under up to five different ids (`GFL00`, `OFceJcLf`, …).
|
||||
That contradicts what `filament_id` means: one id per commercial product line.
|
||||
|
||||
## 0. The architecture
|
||||
|
||||
Three tiers, two frozen islands:
|
||||
|
||||
1. **BBL island — untouched.** Bambu profiles keep their `GF*` catalog ids byte-for-byte
|
||||
(device/RFID/cloud contract). No convergence between GF and OFL ids is attempted: the
|
||||
same product may permanently carry `GFL00` on the BBL side and an `OF*` id everywhere
|
||||
else. This is a deliberate trade for simplicity; v2's curated-GF-adoption (old W4) is
|
||||
dropped.
|
||||
2. **`QD_*` island — untouched.** Qidi's box builds `QD_<series>_<vendor>_<type>` from
|
||||
device enums and requires exactly-matching presets (`QidiPrinterAgent.cpp:146-152`).
|
||||
Qidi presets carrying `QD_*` are exempt from re-minting, forever.
|
||||
3. **Everything else converges on OrcaFilamentLibrary.** OFL is the product catalog: a
|
||||
material family's id is declared once, on its OFL family root. Vendor bundles carry
|
||||
only per-printer *specializations* of OFL families — same base name, non-empty
|
||||
`compatible_printers`, **no `filament_id` key** — which (a) alias-shadow the OFL preset
|
||||
on the printers they claim (`Preset.cpp:3684-3714`: "Generic PLA @Qidi Q2 0.4mm nozzle"
|
||||
hides "Generic PLA @System" on that machine) and (b) resolve the OFL family's id
|
||||
through the loader's inherits/base-bundle walk (`PresetBundle.cpp:4842-5080`). Products
|
||||
OFL does not (yet) carry mint their id in the vendor bundle **with the same rule**;
|
||||
because the key is bundle-independent (§1), later hoisting the family into OFL never
|
||||
changes its id.
|
||||
|
||||
Convergence therefore happens by *single declaration point*, not by copying ids across
|
||||
bundles — no adoption registry, no cross-bundle id claims to curate.
|
||||
|
||||
## 1. The mint rule
|
||||
|
||||
```
|
||||
triple = (filament_vendor, filament_type, family_name) # from the family ROOT's flattened config
|
||||
key = "filament_product/<filament_vendor>/<filament_type>/<family_name>"
|
||||
id = "OF" + base62_6( uuid5( FILAMENT_ID_NAMESPACE, key ) ) # namespace unchanged:
|
||||
# c4d3ff49-4c32-5534-a3e3-00894157ab97
|
||||
```
|
||||
|
||||
- **Triple resolution.** All three values come from the family root preset's *flattened
|
||||
effective config* (`filament_vendor` and `filament_type` are inheritable list options —
|
||||
take the first element; family_name = the root's base name, `\s?@.*` stripped once).
|
||||
For own-key-layout families (no root), each declaring preset's flattened config is used
|
||||
and CI requires all declarers of one family to agree on the triple. A root that resolves
|
||||
an empty `filament_vendor` or `filament_type` is a CI error (generics use `"Generic"`).
|
||||
Values enter the key verbatim (UTF-8, no case folding).
|
||||
- **Bundle-independent by design.** The key contains no bundle name, so the same product
|
||||
yields the same id whether minted in OFL or in a vendor bundle; migrating a family into
|
||||
OFL (§0.3) is id-stable. Two bundles independently adding the same triple converge
|
||||
automatically — and that is correct, because equal (vendor, type, name) *is* the
|
||||
definition of "same product" here. The known look-alike hazards stay separated by the
|
||||
type component: the 4 same-name-different-type groups (Flashforge `Generic PLA Silk` as
|
||||
SILK, OFL `Generic PETG-CF` as PETG, `Generic PA6-CF`, `Generic PE-CF`) hash apart until
|
||||
their type bugs are fixed (§5, W3) and converge automatically after — self-healing that
|
||||
pure name-keying (rejected in v2) could not provide.
|
||||
- **Format and salt unchanged from v1**: 8 chars, `OF` + 6 base62; deterministic `/1`,
|
||||
`/2`… salt past any taken or retired id (the O+7 widening was evaluated and rejected:
|
||||
62⁶ expects 1.9×10⁻⁵ collisions at today's 1,455 families, and `^O.{7}$` would sweep 35
|
||||
legacy ids into the conformance gate vs. one today).
|
||||
- **Content-addressed, deliberately.** If any triple component changes — a family rename,
|
||||
a `filament_vendor` correction, a `filament_type` fix — the id changes with it. This
|
||||
*replaces* v1's "ids are immutable once shipped" with "ids are derivable from the
|
||||
product identity, and identity changes are migrations" — made safe by the succession
|
||||
ledger (§2). `renamed_from` still gates preset-name compatibility as before.
|
||||
- CLI: `--mint "Polymaker/PLA/PolyLite PLA"` prints without touching the tree; running
|
||||
the script plain inserts missing ids; CI errors print the expected id.
|
||||
|
||||
## 2. The succession ledger (the amendment that makes this safe)
|
||||
|
||||
Shipped ids are referenced outside the tree: AFC/Klipper lane data, Bambu AMS trays
|
||||
holding OFL-only materials, on-device PA-calibration records, user-root preset copies,
|
||||
3mf `slice_info`. Retiring an id without a forwarding pointer downgrades all of those to
|
||||
`Generic <type>` fallbacks. Therefore:
|
||||
|
||||
- **Schema.** `scripts/retired_filament_ids.json` entries become objects:
|
||||
`{"retired": {"OGFL99": {"claims": [...], "successor": "OFxxxxxx"}}}`. Append-only as
|
||||
before; a successor may itself be retired later (chains allowed, cycle-checked, and
|
||||
followed to the live end). A retired id may never be minted again (check 4 unchanged).
|
||||
Cross-island *hint* entries are permitted for ids Orca cannot retire because another
|
||||
island owns them (e.g. `GFL99 → <OFL Generic PLA id>`): consulted only when no live
|
||||
preset matches, so BBL installs still resolve `GFL99` natively first. By the same
|
||||
principle, an id in a foreign island's space (`GF*`/`QD_*`) that vanishes from the tree
|
||||
is **released with a hint, never retired** — the island's catalog owns it and may
|
||||
legitimately (re)ship it later, which check 4 must never block. (Implementation
|
||||
amendment, v3.0: `--update-snapshot` routes such ids to `hints` automatically; hint
|
||||
keys may be absent from the tree.)
|
||||
- **Shipped and consulted at runtime.** The ledger ships in `resources/`; a small helper
|
||||
(`resolve_filament_id_succession(id)`) follows the chain and is consulted **only on
|
||||
resolution miss**, before the `Generic <type>` name fallback, in:
|
||||
`PresetBundle::get_filament_by_filament_id` (covers `DevFilaBlackList`, `SelectMachine`
|
||||
warnings, `Plater` tray configs in one place), the AMS sync match predicates
|
||||
(`PresetBundle.cpp:3151`, `:3252-3254` miss paths at `:3157-3169`/`:3260-3305`),
|
||||
`PresetComboBoxes::add_ams_filaments`, `MachineObject::setting_id_to_type`
|
||||
(`DeviceManager.cpp:2545` miss branch), calibration-history name lookup
|
||||
(`CaliHistoryDialog.cpp:62`), and the #14423 Moonraker lane matching when it lands.
|
||||
With this in place the OFL re-mint is near-residue-free and every future
|
||||
content-addressed rename stays safe.
|
||||
- **Kill the hardcoded generic map.** `MoonrakerPrinterAgent::map_filament_type_to_generic_id`
|
||||
(`MoonrakerPrinterAgent.cpp:608-658`) hardcodes 23 OFL ids (`OGFL99`… `OFLSBS99`).
|
||||
Replace it with a runtime lookup of the OFL generic preset by name ("Generic PLA
|
||||
@System" → its current id), removing the code↔profile lockstep permanently. (This also
|
||||
releases `OFLSBS99`, v2's one frozen OF-shaped legacy id, for normal re-minting.)
|
||||
|
||||
## 3. Validation rule changes
|
||||
|
||||
- **Check 3 (mint conformance)** becomes a pure function of the root's triple: a non-BBL,
|
||||
non-`QD_*` id must equal `mint(triple)` ± salt, or be snapshot-grandfathered (the
|
||||
grandfather set shrinks to ≈ nothing for non-BBL once migration completes).
|
||||
- **Check 5 (alias hygiene) generalizes and becomes load-bearing.** For *every*
|
||||
OFL-carried family (not just `Generic * @System`): a vendor specialization must keep the
|
||||
OFL base name (else the OFL preset un-shadows and creates a live per-printer duplicate —
|
||||
v1's P7 pattern) and non-empty `compatible_printers`, and must not declare an id. The
|
||||
C++ validator's OFL-aware `-f` (`PresetBundle.cpp:5674-5753`) already enforces the
|
||||
runtime consequence; the script check names the rename as the cause.
|
||||
- **New check 8 (triple integrity):** every id-declaring family resolves a complete,
|
||||
family-consistent triple; roots missing `filament_vendor`/`filament_type` error.
|
||||
- **New check 9 (succession integrity):** every retired entry's successor chain ends at a
|
||||
live tree id (or a documented cross-island hint target); no cycles; retired ids absent
|
||||
from the tree.
|
||||
- Snapshot mechanism, reserved spaces (`GF*`→BBL, `QD_*`→Qidi, `P`-hex/`null`→user-custom;
|
||||
v2's do-not-reserve-`OF*` note stands), and check 1/2/4/7 are unchanged.
|
||||
|
||||
## 4. Migration phases
|
||||
|
||||
**v3.0 — tooling + prerequisites (no profile changes).** New mint + triple resolver
|
||||
(reuse the flatten machinery), succession schema migration + C++ lookup helper wired into
|
||||
the §2 miss paths, Moonraker map → runtime lookup, checks 3/5/8/9, tests. Carry v2's W1
|
||||
client hardening (skip tray-wipe/temp-rewrite when a system preset holds the id; relax
|
||||
the `DeviceManager.cpp:5252` assert; guard the `PresetBundle.cpp:3717` deref) — it ships
|
||||
first regardless. **W3 type fixes land here**, *before* any re-mint: type is now a key
|
||||
component, so minting before fixing OFL `Generic PETG-CF`/`Generic PE-CF` would re-id
|
||||
those families twice.
|
||||
|
||||
**v3.1 — OFL re-mint.** Every OFL-declared id re-derives from its triple (mirrors like
|
||||
`OGFA00`, generics like `OGFL99`, blocks like `OEPLAB00` — all of it); each old shipped id
|
||||
gains a succession entry pointing at its replacement; the 26 GF-shaped ids OFL declares
|
||||
(measured at v3.0: only one of them, `GFOT001`, is also declared by BBL) are released to
|
||||
the BBL island space with hints at the re-minted families — two-island purity. Snapshot
|
||||
regenerated; full gate battery + fixture overlays (this phase touches preset-visibility
|
||||
machinery only via ids, but the fixtures are cheap insurance). Implementation notes
|
||||
(v3.1, executed): OFL generic ids relocate from the fdm_filament_* template bases onto
|
||||
the product-named "Generic X @System" presets first, so their triples carry the product
|
||||
name; `fdm_filament_pc` keeps a (transitional) declaration because 7 Prusa presets
|
||||
inherit it directly — the v3.2 Prusa worksheet re-homes them and deletes it.
|
||||
|
||||
**v3.2 — vendor bundles, worksheet-per-vendor (v1 machinery).** Three sub-cases:
|
||||
(a) the **391 unshipped v1 `OF*` mints** re-derive under the triple key — no succession
|
||||
entries (they never shipped; a documented one-time `--forget-never-shipped <list>` drops
|
||||
them from the ledger lineage instead of retiring them, since the ledger's rationale —
|
||||
ids live on in user presets and 3mfs — cannot apply to unreleased ids);
|
||||
(b) **true generic tunings** riding copied legacy ids (`GFL99`-class) drop their own id
|
||||
and re-point to the OFL generic family (the v1 Sovol pattern) — their old ids get
|
||||
cross-island hints where BBL owns them, succession entries otherwise;
|
||||
(c) remaining **shipped legacy ids** (numeric, name-shaped, pseudo-GF, the 57
|
||||
multi-vendor GF residue, the 10 P-hex — everything non-BBL/non-`QD_*`, ~800 ids)
|
||||
re-mint with succession entries. Retiring the 10 P-hex system ids also removes the last
|
||||
system ids from `check_ams_filament_valid`'s destructive P-gate.
|
||||
|
||||
**v3.3 — ongoing consolidation (optional, per-vendor, id-stable).** Hoist vendor-unique
|
||||
products into OFL where a family is genuinely multi-vendor material; thanks to the
|
||||
bundle-independent key this never changes ids, so it can proceed opportunistically.
|
||||
|
||||
## 5. Gates (every phase)
|
||||
|
||||
`python scripts/orca_extra_profile_check.py` exit 0; `assign_filament_ids.py --check`
|
||||
exit 0; unit tests green (existing 46 + new triple/succession/adoption tests); validator
|
||||
`-l 2` exit 0, `-f` tree-wide exit 0, `-r` BBL+Qidi exit 0; custom-preset fixture
|
||||
archives; config-equivalence — flattened effective configs differ only in `filament_id`
|
||||
(re-mints), `inherits`/`compatible_printers` (re-points, as prescribed per worksheet), and
|
||||
the W3 `filament_type` corrections. New for v3: a C++ test that a retired id resolves
|
||||
through the succession chain in the sync miss path, and a Moonraker test that the generic
|
||||
map lookup matches the shipped OFL presets. Manual AMS smoke test (tray set → old-id
|
||||
resolve → clear) stays a release-checklist item.
|
||||
|
||||
## 6. Accepted costs (explicit)
|
||||
|
||||
- **GF ↔ OFL divergence is permanent** for products in both catalogs (PolyLite PLA ≠
|
||||
`GFL00` outside BBL). The forward-looking fix is PR #12724-style filament-database
|
||||
upload, where Orca ids become first-class device artifacts.
|
||||
- **Renames/type-fixes re-id families** (by design); the succession ledger absorbs the
|
||||
device/user residue, but each one is still a ledger entry and a snapshot diff to review.
|
||||
- **User roots** keep whatever id they copied at creation; with succession lookup in
|
||||
`get_filament_by_filament_id` they now *resolve* instead of dangling — strictly better
|
||||
than v1's accepted residue.
|
||||
- **One-time field transition**: devices holding pre-v3 ids (AFC lanes, AMS trays, cali
|
||||
records) resolve via succession on updated clients; *older* Orca versions and
|
||||
BambuStudio never resolved OFL-only ids anyway (`?`/generic fallback — unchanged for
|
||||
them).
|
||||
|
||||
## 7. Open decisions
|
||||
|
||||
1. Whether v3.2(b)'s cross-island hints (`GFL99` → OFL generic) are wanted at launch or
|
||||
deferred (pure-miss-path feature; zero risk to BBL installs, small review surface).
|
||||
2. v3.3 pacing: per-vendor PRs opportunistically vs. a dedicated consolidation train.
|
||||
3. Whether to fold v2's W5 (P+md5 ids for inherited *user* presets, PR #13315) into v3.0's
|
||||
C++ work or keep it a separate PR (recommended: separate; W1 is its only prerequisite).
|
||||
|
||||
## 8. Evidence
|
||||
|
||||
Carried from v2 §8 (all re-verified this session), plus: `filament_vendor` audit — 49
|
||||
distinct strings tree-wide, `"Polymaker"` byte-consistent across all five PolyLite-PLA
|
||||
bundles; multi-vendor different-family GF residue = 57 ids; `MoonrakerPrinterAgent.cpp:
|
||||
608-658` = 23 hardcoded OFL ids; mint examples verified live (`Qidi/PolyLite PLA` →
|
||||
`OFceJcLf` under the v1 key — the fragmentation this plan removes; salt determinism
|
||||
`OF8afiMO`). Alias shadowing and the OFL id fallback verified at `Preset.cpp:3684-3714`
|
||||
and `PresetBundle.cpp:4842-5080` during the v1 audit; per-printer `-f` semantics at
|
||||
`PresetBundle.cpp:5674-5753`.
|
||||
224
filament_id_plan_v4.md
Normal file
224
filament_id_plan_v4.md
Normal file
@@ -0,0 +1,224 @@
|
||||
# filament_id plan v4: dissolve the Qidi `QD_*` island
|
||||
|
||||
Supersedes §0.2 of `filament_id_plan_v3.md` (the "`QD_*` island — untouched, forever"
|
||||
decision) and amends every v3 section that carved out `QD_*`. Everything else in v3 —
|
||||
the mint rule, the succession ledger, the BBL island, checks 1–9 — stands as
|
||||
implemented (v3.0–v3.2, all gates green at commit `f7c1b290fd`).
|
||||
|
||||
Decision driver: the island contradicts the catalog architecture v3 built. Qidi presets
|
||||
carry 204 `QD_<series>_<vendor>_<typeidx>` ids over 264 declarations (49 families,
|
||||
measured 2026-08-21) — one commercial product carries up to *five* ids (one per printer
|
||||
series: `QIDI PLA Rapido` = `QD_0_1_1` … `QD_4_1_1`), which is exactly the
|
||||
fragmentation v3 exists to remove. The island was frozen because Qidi's filament box
|
||||
composes these ids from device enums and requires exactly-matching presets
|
||||
(`QidiPrinterAgent.cpp:146-152`). But v3.0 shipped the machinery that makes freezing
|
||||
unnecessary: the succession ledger already translates retired ids on resolution miss.
|
||||
`QD_*` stops being a *preset id space* and becomes a *device protocol namespace*,
|
||||
translated once at the agent edge.
|
||||
|
||||
## 0. The architecture change
|
||||
|
||||
Two tiers, **one** frozen island:
|
||||
|
||||
1. **BBL island — untouched, unchanged.** All v3 reasoning holds (device/RFID/cloud
|
||||
contract is external and opaque).
|
||||
2. **Everything else converges on OFL product ids — now including Qidi.** All 204
|
||||
`QD_*` ids re-mint from their family triples and gain **retired** ledger entries
|
||||
(not cross-island hints: after dissolution there is no island to own them, and
|
||||
check 4's "never again" is exactly the guard we want against upstream re-adding
|
||||
them). The box keeps working because `QidiPrinterAgent` resolves its composed
|
||||
`QD_*` id through `resolve_filament_id_succession()` on miss — the same mechanism
|
||||
every other retired id already uses.
|
||||
|
||||
Why retire rather than hint (the one real design choice here): hints exist for ids a
|
||||
*foreign catalog* owns and may legitimately re-ship (`GF*`). Post-dissolution, nothing
|
||||
may ever re-ship a `QD_*` id in the profile tree — the device composes them at
|
||||
runtime, the tree translates them. Retired entries make CI enforce that permanently
|
||||
(`--update-snapshot` refuses resurrections, check 4 refuses occurrences); hints would
|
||||
permit re-shipping, which is now always a regression. The QD→family mapping is
|
||||
strictly 1:1 (verified: no `QD_*` id is claimed by more than one family), so the
|
||||
mode-rule successor is unambiguous for every entry.
|
||||
|
||||
## 1. What the dissolution consists of
|
||||
|
||||
Three independent work packages, ordered for bisectability:
|
||||
|
||||
- **(A) Re-converge the drifted tree** — prerequisite, not Qidi-specific. The
|
||||
2026-07 main merge (`f3fa3a34bd`) brought upstream vendor updates in pre-v3 style:
|
||||
`--check` currently exits with **243 errors** (123 unsanctioned new ids, 46 new
|
||||
instantiated own-key presets, 31 override drifts, 18 reserved-space claims, 5
|
||||
hint-keys re-declared — Qidi re-added `GFB99`/`GFG99`/`GFL99`, Snapmaker re-added
|
||||
`GFG96`/`GFU99` and even four *retired* ids incl. `OGFL99`, plus Snapmaker U1
|
||||
triple errors and a GreenGate3D rename). This is the standing WF-B maintenance
|
||||
pass; the dissolution's gates cannot go green on a red base.
|
||||
- **(B) C++ succession hook in the Qidi agent** — safe to land before any data
|
||||
changes (pure miss-path: while `QD_*` presets still exist, the hook never fires).
|
||||
- **(C) The dissolution proper** — tooling flip + Qidi data fixes + re-mint +
|
||||
snapshot/ledger regeneration, one vendor worksheet in the v3.2 mold.
|
||||
|
||||
## 2. Runtime translation (work package B)
|
||||
|
||||
`QidiPrinterAgent.cpp:183-192` currently: compose `setting_id` → keep it if a visible
|
||||
base preset declares it → else degrade to `filament_id_by_type(tray_type)` (i.e. every
|
||||
QIDI-brand box slot silently becomes Generic once the ids re-mint). Insert the
|
||||
succession walk between those two steps:
|
||||
|
||||
```cpp
|
||||
} else if (!setting_id.empty() && has_visible_base_preset(bundle->filaments, setting_id)) {
|
||||
tray.tray_info_idx = setting_id;
|
||||
} else {
|
||||
// Retired QD_* protocol ids forward to their minted successors via the shipped ledger.
|
||||
const std::string successor = setting_id.empty() ? std::string()
|
||||
: resolve_filament_id_succession(setting_id);
|
||||
if (!successor.empty() && has_visible_base_preset(bundle->filaments, successor))
|
||||
tray.tray_info_idx = successor;
|
||||
else
|
||||
tray.tray_info_idx = bundle->filaments.filament_id_by_type(tray.tray_type);
|
||||
}
|
||||
```
|
||||
|
||||
`resolve_filament_id_succession` is `Preset.hpp:119` (loads once, cycle-guarded,
|
||||
empty-safe) — no new includes needed beyond what the file already reaches through
|
||||
`PresetBundle`. This one hook covers both composition paths: the numeric-series
|
||||
`build_setting_id` lambda *and* the non-numeric fallback
|
||||
`map_filament_type_to_setting_id` (`:325-342`), whose four hardcoded returns
|
||||
(`QD_1_0_1`/`_11`/`_41`/`_50` = Generic PLA/ABS/PETG/TPU 95A) become ledger keys in
|
||||
package C. Keep that function as-is but extend its comment: the returned ids are
|
||||
retired ledger keys by design, and `scripts/tests/test_filament_id.py` parses the
|
||||
initializer (see §4 tests) — the Moonraker treatment (`MoonrakerPrinterAgent.cpp:
|
||||
619-627`) of replacing the table with name lookups was considered and not taken: the
|
||||
table already routes through the same ledger as the composed ids, and two translation
|
||||
mechanisms in one agent is worse than one.
|
||||
|
||||
Tests (same commit):
|
||||
|
||||
- `tests/libslic3r/test_filament_id_succession.cpp`: add a section asserting a
|
||||
`QD_`-shaped key forwards like any other (`{"QD_2_1_11", "OFnew001"}` resolves to
|
||||
`"OFnew001"`) — pins that the walk is prefix-agnostic.
|
||||
- `scripts/tests/test_filament_id.py`: new test parsing the four `QD_` literals out of
|
||||
`QidiPrinterAgent.cpp::map_filament_type_to_setting_id` (mirror the parser in
|
||||
`scripts/test_moonraker_lane_data.py`) and asserting each is a ledger key whose
|
||||
chain terminates at a live tree id. **Add it marked expected-fail/skipped until
|
||||
package C lands, then flip it on** — it is the permanent code↔ledger lockstep guard.
|
||||
|
||||
## 3. Tooling and validation flip (work package C, first commit)
|
||||
|
||||
All in `scripts/assign_filament_ids.py`; every touched line measured 2026-08-21:
|
||||
|
||||
- `is_island_declaration` (`:327-329`) → `return vendor == "BBL"`. This single change
|
||||
pulls every `QD_*` declarer into the triple bookkeeping (`:385`) and thus into
|
||||
checks 3 and 8, into `--remint`'s domain (`:1464`), and out of the hint-key
|
||||
tolerances (`:877`, `:1100`).
|
||||
- `reserved_space_owner` (`:596-604`): `QD_*` returns `(True, None)` — reserved,
|
||||
ownerless, exactly like the P-hex/user-custom space. Consequences, all wanted:
|
||||
check 6 refuses any future vendor claim; the `--update-snapshot` sanction gate
|
||||
(`:938-963`) refuses new `QD_*` ids outright; the vanish path (`:994`) routes
|
||||
`QD_*` to **retired** (owner `None` ≠ island), not released-with-hint. Update the
|
||||
two message sites that render `owner is None` as "reserved for user-custom presets"
|
||||
(`:628` docstring, `:958`, and check 6's copy) to name the space generically or
|
||||
special-case `QD_*` ("Qidi device protocol; dissolved island — retired, never
|
||||
declarable").
|
||||
- Check 1 (`:667-668`): delete the `vendor == "Qidi" and fid.startswith("QD_")`
|
||||
exemption.
|
||||
- Module docstring (`:27-45`): rewrite the `QD_*` bullet — reserved space stays
|
||||
listed, but as "device protocol namespace, translated via the succession ledger;
|
||||
dissolved as a catalog island in v4, may never be declared".
|
||||
- `scripts/tests/test_filament_id.py`: update the three island assertions —
|
||||
`reserved_space_owner("QD_X4_PLA")` → `(True, None)` (`:403`),
|
||||
`is_island_declaration("Qidi", "QD_X4_PLA")` → `False` (`:413`), and the
|
||||
reserved-space message case (`:570`).
|
||||
|
||||
No changes to the ledger schema, the C++ checks, `--retire` (post-flip it accepts
|
||||
`QD_*` olds automatically — they are non-island now), or the validator: check 3's
|
||||
"non-BBL, non-`QD_*`" phrasing in v3 §3 was always implemented as "non-island", so the
|
||||
flip *is* the spec change.
|
||||
|
||||
## 4. Migration phases
|
||||
|
||||
**v4.0 — re-converge the drifted tree (package A).** Per-vendor WF-B worksheets over
|
||||
the 243 errors: Snapmaker U1 (triple divergence `Generic|Snapmaker|snapmaker`, empty
|
||||
vendors, four resurrected retired ids — these force re-mints since retirement is
|
||||
permanent), BBL/addnorth `GF_AN*` overrides (BBL island: grandfather via snapshot,
|
||||
they are BBL-internal), Qidi/Snapmaker re-declared hint keys (re-mint those declarers,
|
||||
the check's own prescription), GreenGate3D rename, then `--update-snapshot` (new
|
||||
upstream `QD_*` ids sanction cleanly — the island is still intact in this phase) and
|
||||
the full v3 §5 gate battery. Bump `version` in every touched
|
||||
`resources/profiles/<Vendor>.json`. **Do not start v4.2 until `--check` exits 0.**
|
||||
|
||||
**v4.1 — the agent hook (package B).** §2 as written; `libslic3r_tests` +
|
||||
`scripts/tests/test_filament_id.py` green; behavior-neutral by construction (no `QD_*`
|
||||
ledger entries exist yet).
|
||||
|
||||
**v4.2 — the dissolution (package C).** One Qidi worksheet, v3.2 machinery:
|
||||
|
||||
1. Tooling flip commit (§3). `--check` now reports the Qidi island as
|
||||
non-conformant — expected, red only between commits of this phase.
|
||||
2. Data fixes, before any re-mint (the v3 "W3 lands first" lesson — type/vendor are
|
||||
key components): add `filament_vendor: ["QIDI"]` at each QIDI-brand family's
|
||||
inheritance apex so all declarers resolve it (39 of 49 families currently resolve
|
||||
none — check 8a would refuse the mint). Verify the six Generic families
|
||||
(`Generic PLA/ABS/PETG/PC/TPU 95A/PLA Silk`) resolve triples identical to their
|
||||
OFL counterparts (vendor `Generic`, OFL's `filament_type`) so they *converge onto
|
||||
the OFL ids* by triple math — the whole point; any mismatch is a W3-style data fix
|
||||
here, not a fork. No `inherits`/`compatible_printers` re-pointing anywhere: the
|
||||
series intermediates (`Generic PLA@Q2-Series` etc., all `instantiation: false`)
|
||||
simply keep declarations whose values become the OFL ids.
|
||||
3. `python scripts/assign_filament_ids.py --remint Qidi` — rewrites all 264
|
||||
declarations in place to their family mints (same triple ⇒ same id across a
|
||||
family's series intermediates and per-nozzle declarers; convergence with OFL ids
|
||||
is legal by design, `want_id` already permits same-triple collisions `:1447`).
|
||||
4. `--update-snapshot` — retires every vanished `QD_*` id with its mode-rule
|
||||
successor. **Audit the ledger diff: all ~204 new entries must be `QD_*`→non-null.**
|
||||
A null successor (possible only for a declared-only id with zero instantiated
|
||||
claims) gets an explicit `--retire "QD_x=OFy"` with the family's minted id.
|
||||
5. Un-skip the §2 lockstep test. Bump `resources/profiles/Qidi.json` version. Full
|
||||
gate battery (§5).
|
||||
|
||||
Known residue, accepted: `QIDI PC-ABS-FR` (series 1–2) vs `QIDI PC/ABS-FR`
|
||||
(series 3–4) are two preset-name families for one product → two ids. Renames were
|
||||
ruled out in v3 (`renamed_from` rejected for migrations); if upstream ever unifies the
|
||||
name, content-addressing re-ids and the ledger absorbs it — self-healing, no action
|
||||
now.
|
||||
|
||||
**v4.3 — OFL consolidation (unchanged).** v3.3 stays optional and id-stable; QIDI-brand
|
||||
families are vendor-unique and stay in the Qidi bundle.
|
||||
|
||||
## 5. Gates (per phase, delta from v3 §5)
|
||||
|
||||
Unchanged battery: `orca_extra_profile_check.py` exit 0, `assign_filament_ids.py
|
||||
--check` exit 0, `scripts/tests/test_filament_id.py` all green, `libslic3r_tests`
|
||||
green, validator `-l 2` tree-wide + `-f` tree-wide + `-v Qidi` exit 0, custom-preset
|
||||
fixture archives (v4.2 touches no preset visibility, but they are cheap insurance —
|
||||
run them for v4.0, which touches instantiation-adjacent upstream drift), flatten
|
||||
config-equivalence. New for v4.2: equivalence diff may contain **only** `filament_id`
|
||||
value changes (QD→OF) and the added `filament_vendor` keys on QIDI-brand families;
|
||||
ledger diff audit per §4.4; the map-literal lockstep test. Manual release-checklist
|
||||
item: Qidi box smoke test — slot holding a QIDI-brand material must surface the brand
|
||||
preset (not Generic) on an updated client, via the memory-documented local Klipper
|
||||
test rig.
|
||||
|
||||
## 6. Accepted costs (explicit, new relative to v3)
|
||||
|
||||
- **Every Qidi box slot resolves through the ledger miss-path forever** (one hash-map
|
||||
walk per slot per status poll — negligible, and structurally identical to how
|
||||
every retired id already resolves). The QD→OF translation table is maintained by
|
||||
the retirement machinery, not by hand.
|
||||
- **Older Orca clients** (pre-v4 profiles) paired with re-minted profile trees lose
|
||||
QIDI-brand slot matching (they look up `QD_*` and fall back generic-by-type — the
|
||||
degradation the hook removes for updated clients). Same one-time field-transition
|
||||
shape v3 §6 already accepted for AMS/AFC ids.
|
||||
- **Two ids for PC-ABS-FR** until upstream unifies the family name (§4 residue).
|
||||
|
||||
## 7. Evidence
|
||||
|
||||
Measured on this tree 2026-08-21 unless cited to v3: 204 distinct `QD_*` ids / 264
|
||||
declaring presets / 49 families, QD→family strictly 1:1, per-series id sets
|
||||
(`QD_0..4_1_1` = `QIDI PLA Rapido` etc.); 39 families resolve no `filament_vendor`;
|
||||
declarations live on `instantiation:false` series intermediates (Q2/Q2C/X5/X4) and
|
||||
per-nozzle X-Plus-4 presets; composition + miss-fallback at
|
||||
`QidiPrinterAgent.cpp:146-152, 183-192`, hardcoded fallback table `:325-342`;
|
||||
succession helpers `Preset.hpp:109-119`; ledger = 575 retired + 194 hints, zero `QD_*`
|
||||
entries; snapshot holds 160 of the 204 (the 44 newcomers are post-merge drift);
|
||||
`--check` = 243 errors, categorized in §1(A); island exemption mechanics at
|
||||
`assign_filament_ids.py:327-329, 385, 596-604, 667, 877, 994, 1464, 1514`; `--remint`
|
||||
same-triple convergence guard `:1447-1453`; retirement-permanence gate `:965-976`.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4142,10 +4142,10 @@ msgid "PA Profile"
|
||||
msgstr "Профіль PA"
|
||||
|
||||
msgid "Factor K"
|
||||
msgstr "Коеф. K"
|
||||
msgstr "Коэф. K"
|
||||
|
||||
msgid "Factor N"
|
||||
msgstr "Коеф. N"
|
||||
msgstr "Коэф. N"
|
||||
|
||||
msgid "Setting AMS slot information while printing is not supported"
|
||||
msgstr "Зміна інформації про слоти AMS під час друку не підтримується"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"filament_id": "GFB00_01",
|
||||
"filament_id": "OFLfywkp",
|
||||
"setting_id": "wAJTMxtCY7EoavRi",
|
||||
"name": "Afinia ABS+@HS",
|
||||
"from": "system",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"filament_id": "GFB00_01",
|
||||
"filament_id": "OFV5wEMe",
|
||||
"setting_id": "qCDnb2iBaz4hd4vX",
|
||||
"name": "Afinia ABS@HS",
|
||||
"from": "system",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"filament_id": "GFA00_01",
|
||||
"filament_id": "OF9HCdyQ",
|
||||
"setting_id": "N3sCgjdjvp6FTtw9",
|
||||
"name": "Afinia PLA@HS",
|
||||
"from": "system",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_tpu",
|
||||
"from": "system",
|
||||
"setting_id": "zUqTgAEbqTN1EdRl",
|
||||
"filament_id": "GFU01_01",
|
||||
"filament_id": "OFDJU6R3",
|
||||
"instantiation": "true",
|
||||
"filament_vendor": [
|
||||
"Afinia"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"filament_id": "GFB00_01",
|
||||
"filament_id": "OFXi59OX",
|
||||
"setting_id": "OxIiEYjbhEvSykaQ",
|
||||
"name": "Afinia Value ABS@HS",
|
||||
"from": "system",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"filament_id": "GFA00_01",
|
||||
"filament_id": "OFgHh8ly",
|
||||
"setting_id": "BASsUdyvElEVJ9AA",
|
||||
"name": "Afinia Value PLA@HS",
|
||||
"from": "system",
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
"name": "Anker Generic ABS @base",
|
||||
"inherits": "fdm_filament_abs",
|
||||
"from": "system",
|
||||
"filament_id": "GFB99",
|
||||
"filament_id": "OF3P0BQA",
|
||||
"instantiation": "false"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
"name": "Anker Generic ASA @base",
|
||||
"inherits": "fdm_filament_asa",
|
||||
"from": "system",
|
||||
"filament_id": "GFB98",
|
||||
"filament_id": "OFRiyes1",
|
||||
"instantiation": "false"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
"name": "Anker Generic PA @base",
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"filament_id": "GFN99",
|
||||
"filament_id": "OFMgJQCZ",
|
||||
"instantiation": "false"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Anker Generic PA-CF @base",
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"filament_id": "GFN98",
|
||||
"filament_id": "OF7uE5KB",
|
||||
"instantiation": "false",
|
||||
"filament_type": [
|
||||
"PA-CF"
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
"name": "Anker Generic PC @base",
|
||||
"inherits": "fdm_filament_pc",
|
||||
"from": "system",
|
||||
"filament_id": "GFC99",
|
||||
"filament_id": "OFGPJxnt",
|
||||
"instantiation": "false"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Anker Generic PETG @base",
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"filament_id": "GFG99",
|
||||
"filament_id": "OFgvOmM2",
|
||||
"instantiation": "false",
|
||||
"filament_type": [
|
||||
"PETG"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Anker Generic PETG-CF @base",
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"filament_id": "GFG98",
|
||||
"filament_id": "OF1daEUW",
|
||||
"instantiation": "false",
|
||||
"filament_type": [
|
||||
"PETG-CF"
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
"name": "Anker Generic PLA @base",
|
||||
"inherits": "fdm_filament_pla",
|
||||
"from": "system",
|
||||
"filament_id": "GFL99",
|
||||
"filament_id": "OFndmfJ1",
|
||||
"instantiation": "false"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Anker Generic PLA Silk @base",
|
||||
"inherits": "fdm_filament_pla",
|
||||
"from": "system",
|
||||
"filament_id": "GFL96",
|
||||
"filament_id": "OFXyyfX6",
|
||||
"instantiation": "false",
|
||||
"filament_cost": [
|
||||
"20"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Anker Generic PLA+ @base",
|
||||
"inherits": "fdm_filament_pla",
|
||||
"from": "system",
|
||||
"filament_id": "GFL95",
|
||||
"filament_id": "OFIYTy8S",
|
||||
"instantiation": "false",
|
||||
"filament_cost": [
|
||||
"25"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Anker Generic PLA-CF @base",
|
||||
"inherits": "fdm_filament_pla",
|
||||
"from": "system",
|
||||
"filament_id": "GFL98",
|
||||
"filament_id": "OFB0a3hT",
|
||||
"instantiation": "false",
|
||||
"filament_type": [
|
||||
"PLA-CF"
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
"name": "Anker Generic PVA @base",
|
||||
"inherits": "fdm_filament_pva",
|
||||
"from": "system",
|
||||
"filament_id": "GFS99",
|
||||
"filament_id": "OFsCbVbN",
|
||||
"instantiation": "false"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Anker Generic TPU @base",
|
||||
"inherits": "fdm_filament_tpu",
|
||||
"from": "system",
|
||||
"filament_id": "GFU99",
|
||||
"filament_id": "OF6tKa1Z",
|
||||
"instantiation": "false",
|
||||
"filament_retraction_speed": "90",
|
||||
"filament_deretraction_speed": "50",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_abs",
|
||||
"from": "system",
|
||||
"setting_id": "RDI26qeSRSTe0PDg",
|
||||
"filament_id": "GFB99",
|
||||
"filament_id": "OF223rZv",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ABS @Anycubic Kobra 3 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_abs",
|
||||
"from": "system",
|
||||
"setting_id": "Moc1cylP6mmSQjlb",
|
||||
"filament_id": "GFB99",
|
||||
"filament_id": "OF223rZv",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ABS @Anycubic Kobra 3 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_abs",
|
||||
"from": "system",
|
||||
"setting_id": "2xgfnUKyOUQwYWPa",
|
||||
"filament_id": "GFB99",
|
||||
"filament_id": "OF223rZv",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ABS @Anycubic Kobra 3 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
"inherits": "fdm_filament_abs",
|
||||
"from": "system",
|
||||
"setting_id": "NOiAgxA0BbvLhR1v",
|
||||
"filament_id": "GFB99",
|
||||
"filament_id": "OF223rZv",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ABS @Anycubic Kobra S1 0.4 nozzle"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Anycubic"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"0.95"
|
||||
],
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_abs",
|
||||
"from": "system",
|
||||
"setting_id": "MDWaiSjl89E6Edsn",
|
||||
"filament_id": "GFABS",
|
||||
"filament_id": "OF223rZv",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ABS @Anycubic Kobra S1 Max 0.25 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_abs",
|
||||
"from": "system",
|
||||
"setting_id": "wZjVYc7dBDSKRusJ",
|
||||
"filament_id": "GFABS",
|
||||
"filament_id": "OF223rZv",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ABS @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_abs",
|
||||
"from": "system",
|
||||
"setting_id": "AbB6JtoPRsNgmxyy",
|
||||
"filament_id": "GFABS",
|
||||
"filament_id": "OF223rZv",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ABS @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_abs",
|
||||
"from": "system",
|
||||
"setting_id": "exX565xnrLPkYkvu",
|
||||
"filament_id": "GFABS",
|
||||
"filament_id": "OF223rZv",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ABS @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_abs",
|
||||
"from": "system",
|
||||
"setting_id": "KeEk3yQZrKmJY9Q0",
|
||||
"filament_id": "GFABS",
|
||||
"filament_id": "OF223rZv",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ABS @Anycubic Kobra X 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "Anycubic Generic ASA",
|
||||
"from": "system",
|
||||
"setting_id": "U66DGcpZeZ24VfPe",
|
||||
"filament_id": "GFA99",
|
||||
"filament_id": "OF0yFLkY",
|
||||
"instantiation": "true",
|
||||
"filament_vendor": [
|
||||
"Anycubic"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_asa",
|
||||
"from": "system",
|
||||
"setting_id": "06j8OTuYw3Sh9BxL",
|
||||
"filament_id": "GFA99",
|
||||
"filament_id": "OF0yFLkY",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ASA @Anycubic Kobra 3 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_asa",
|
||||
"from": "system",
|
||||
"setting_id": "s2XJm0JghCSUDzhh",
|
||||
"filament_id": "GFA99",
|
||||
"filament_id": "OF0yFLkY",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ASA @Anycubic Kobra 3 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
"inherits": "fdm_filament_asa",
|
||||
"from": "system",
|
||||
"setting_id": "rf792xZNR7tRGKNg",
|
||||
"filament_id": "GFA99",
|
||||
"filament_id": "OF0yFLkY",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ASA @Anycubic Kobra S1 0.4 nozzle"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Anycubic"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"0.98"
|
||||
],
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
"inherits": "fdm_filament_asa",
|
||||
"from": "system",
|
||||
"setting_id": "wqK6AVf1mNkIOmnt",
|
||||
"filament_id": "GFASA",
|
||||
"filament_id": "OF0yFLkY",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ASA @Anycubic Kobra S1 Max 0.25 nozzle"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Anycubic"
|
||||
],
|
||||
"filament_type": [
|
||||
"ASA"
|
||||
],
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_asa",
|
||||
"from": "system",
|
||||
"setting_id": "aMgpooFosBBvlKKR",
|
||||
"filament_id": "GFASA",
|
||||
"filament_id": "OF0yFLkY",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ASA @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_asa",
|
||||
"from": "system",
|
||||
"setting_id": "Isk7NkdH7GxsEZkS",
|
||||
"filament_id": "GFASA",
|
||||
"filament_id": "OF0yFLkY",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ASA @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_asa",
|
||||
"from": "system",
|
||||
"setting_id": "Ew0Lg6u3e5Xj19Bz",
|
||||
"filament_id": "GFASA",
|
||||
"filament_id": "OF0yFLkY",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ASA @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_asa",
|
||||
"from": "system",
|
||||
"setting_id": "PEg6aLXcyUc70p9F",
|
||||
"filament_id": "GFASA",
|
||||
"filament_id": "OF0yFLkY",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic ASA @Anycubic Kobra X 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_abs",
|
||||
"from": "system",
|
||||
"setting_id": "az6wmXeWSCKcUEsK",
|
||||
"filament_id": "GFB99",
|
||||
"filament_id": "OF5Zk4e1",
|
||||
"instantiation": "true",
|
||||
"filament_flow_ratio": [
|
||||
"0.926"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_asa",
|
||||
"from": "system",
|
||||
"setting_id": "qKcef8t7nj8nBjPu",
|
||||
"filament_id": "GFB98",
|
||||
"filament_id": "OFI80Hct",
|
||||
"instantiation": "true",
|
||||
"filament_flow_ratio": [
|
||||
"0.93"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"setting_id": "j2PXsJyI9YyoE8lc",
|
||||
"filament_id": "GFN98",
|
||||
"filament_id": "OFPdhDlK",
|
||||
"instantiation": "true",
|
||||
"filament_type": [
|
||||
"PA-CF"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"setting_id": "xzI6EgoKa3DFYyoZ",
|
||||
"filament_id": "GFN99",
|
||||
"filament_id": "OFB1Tv1E",
|
||||
"instantiation": "true",
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"280"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pc",
|
||||
"from": "system",
|
||||
"setting_id": "3zgBtEkj1fQpDkxO",
|
||||
"filament_id": "GFC99",
|
||||
"filament_id": "OFWY6vBh",
|
||||
"instantiation": "true",
|
||||
"filament_max_volumetric_speed": [
|
||||
"12"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "CEd987NP90bPdkW7",
|
||||
"filament_id": "GFG99",
|
||||
"filament_id": "OFWzr7m0",
|
||||
"instantiation": "true",
|
||||
"reduce_fan_stop_start_freq": [
|
||||
"1"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pla",
|
||||
"from": "system",
|
||||
"setting_id": "9gFgyEJelaCIVwAH",
|
||||
"filament_id": "GFL98",
|
||||
"filament_id": "OFNcdCrm",
|
||||
"instantiation": "true",
|
||||
"filament_flow_ratio": [
|
||||
"0.95"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pla",
|
||||
"from": "system",
|
||||
"setting_id": "2MiX54GMiZjFzwBI",
|
||||
"filament_id": "GFL99",
|
||||
"filament_id": "OFKyCgaK",
|
||||
"instantiation": "true",
|
||||
"filament_flow_ratio": [
|
||||
"0.98"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pva",
|
||||
"from": "system",
|
||||
"setting_id": "I1GMbOsMYktU7EbM",
|
||||
"filament_id": "GFS99",
|
||||
"filament_id": "OFSGbf2I",
|
||||
"instantiation": "true",
|
||||
"filament_flow_ratio": [
|
||||
"0.95"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_tpu",
|
||||
"from": "system",
|
||||
"setting_id": "xrbLc7y1AInpumtv",
|
||||
"filament_id": "GFU99",
|
||||
"filament_id": "OFGKLoUm",
|
||||
"instantiation": "true",
|
||||
"filament_max_volumetric_speed": [
|
||||
"3.2"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"setting_id": "hcL5OHthGzApICTk",
|
||||
"filament_id": "GFPA",
|
||||
"filament_id": "OFzS7zt4",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PA @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"setting_id": "OJbFCKoG5DtVGT9J",
|
||||
"filament_id": "GFPA",
|
||||
"filament_id": "OFzS7zt4",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PA @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"setting_id": "6mMIVw8iheDn1OuV",
|
||||
"filament_id": "GFPA",
|
||||
"filament_id": "OFzS7zt4",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PA @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"setting_id": "epl6B2WNjV1dxG5Z",
|
||||
"filament_id": "GFPA6-CF",
|
||||
"filament_id": "OFQe7sAx",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PA6-CF @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"setting_id": "eMUXd3PFKHl41TIq",
|
||||
"filament_id": "GFPA6-CF",
|
||||
"filament_id": "OFQe7sAx",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PA6-CF @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"setting_id": "y9XYrUJrUYKcBhCI",
|
||||
"filament_id": "GFPA6-CF",
|
||||
"filament_id": "OFQe7sAx",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PA6-CF @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"setting_id": "nO6m8EaBKREWUi3f",
|
||||
"filament_id": "GFPAHT-CF",
|
||||
"filament_id": "OFaEuvNF",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PAHT-CF @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"setting_id": "ebKput7Vyn4IQez1",
|
||||
"filament_id": "GFPAHT-CF",
|
||||
"filament_id": "OFaEuvNF",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PAHT-CF @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pa",
|
||||
"from": "system",
|
||||
"setting_id": "jzrflGdwy9U8kl1c",
|
||||
"filament_id": "GFPAHT-CF",
|
||||
"filament_id": "OFaEuvNF",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PAHT-CF @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pc",
|
||||
"from": "system",
|
||||
"setting_id": "7F0I28djSlDopbIp",
|
||||
"filament_id": "GFPC",
|
||||
"filament_id": "OFZtkHRq",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PC @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pc",
|
||||
"from": "system",
|
||||
"setting_id": "wF10XxL2tNXh8C1p",
|
||||
"filament_id": "GFPC",
|
||||
"filament_id": "OFZtkHRq",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PC @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pc",
|
||||
"from": "system",
|
||||
"setting_id": "t3VfcIKMk0ELiPP7",
|
||||
"filament_id": "GFPC",
|
||||
"filament_id": "OFZtkHRq",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PC @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pc",
|
||||
"from": "system",
|
||||
"setting_id": "dOOXRvGwMe3NeUj0",
|
||||
"filament_id": "GFPC-CF",
|
||||
"filament_id": "OFeIyhUx",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PC-CF @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pc",
|
||||
"from": "system",
|
||||
"setting_id": "H0IECyfsMaCMdefe",
|
||||
"filament_id": "GFPC-CF",
|
||||
"filament_id": "OFeIyhUx",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PC-CF @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pc",
|
||||
"from": "system",
|
||||
"setting_id": "7nu7lbiAHMeFBIJc",
|
||||
"filament_id": "GFPC-CF",
|
||||
"filament_id": "OFeIyhUx",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PC-CF @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pc",
|
||||
"from": "system",
|
||||
"setting_id": "puSuSfNyKlYlmLjL",
|
||||
"filament_id": "GFPC-GF",
|
||||
"filament_id": "OFxJRuVF",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PC-GF @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pc",
|
||||
"from": "system",
|
||||
"setting_id": "1Qdmjm0MNJKU7aCD",
|
||||
"filament_id": "GFPC-GF",
|
||||
"filament_id": "OFxJRuVF",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PC-GF @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pc",
|
||||
"from": "system",
|
||||
"setting_id": "Z0qp7SdwN9luxLFO",
|
||||
"filament_id": "GFPC-GF",
|
||||
"filament_id": "OFxJRuVF",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PC-GF @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_tpu",
|
||||
"from": "system",
|
||||
"setting_id": "gmni9H2Du5nxBqQu",
|
||||
"filament_id": "GFU99",
|
||||
"filament_id": "OFUaHEO9",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PEBA 95A @Anycubic Kobra 3 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_tpu",
|
||||
"from": "system",
|
||||
"setting_id": "zCqTTjac3ydSAw3q",
|
||||
"filament_id": "GFPEBA",
|
||||
"filament_id": "OFjLAYgO",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PEBA @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_tpu",
|
||||
"from": "system",
|
||||
"setting_id": "1bCJcP2RcDlvIqEo",
|
||||
"filament_id": "GFPEBA",
|
||||
"filament_id": "OFjLAYgO",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PEBA @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_tpu",
|
||||
"from": "system",
|
||||
"setting_id": "5v6coSKjAl220Cnq",
|
||||
"filament_id": "GFPEBA",
|
||||
"filament_id": "OFjLAYgO",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PEBA @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "saRQ24o8KHgc1YnM",
|
||||
"filament_id": "GFPET-CF",
|
||||
"filament_id": "OFRhCTUg",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PET-CF @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "hYFR2CtiXab9KZUp",
|
||||
"filament_id": "GFPET-CF",
|
||||
"filament_id": "OFRhCTUg",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PET-CF @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "RCaf3c84JsWkuJzd",
|
||||
"filament_id": "GFPET-CF",
|
||||
"filament_id": "OFRhCTUg",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PET-CF @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "Anycubic Generic PETG",
|
||||
"from": "system",
|
||||
"setting_id": "qe2wYLf7CEMjmfxj",
|
||||
"filament_id": "GFG99",
|
||||
"filament_id": "OFo6n2pB",
|
||||
"instantiation": "true",
|
||||
"filament_vendor": [
|
||||
"Anycubic"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "uNktFymJ3RbGa7k0",
|
||||
"filament_id": "GFG99",
|
||||
"filament_id": "OFo6n2pB",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG @Anycubic Kobra 3 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "EaW663aw4torYXG8",
|
||||
"filament_id": "GFG99",
|
||||
"filament_id": "OFo6n2pB",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG @Anycubic Kobra 3 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "lgVEMmBHMen0sWsI",
|
||||
"filament_id": "GFG99",
|
||||
"filament_id": "OFo6n2pB",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG @Anycubic Kobra 3 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "uLRMTzyJIara4Hr2",
|
||||
"filament_id": "GFG99",
|
||||
"filament_id": "OFo6n2pB",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG @Anycubic Kobra S1 0.4 nozzle"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Anycubic"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"0.96"
|
||||
],
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "FAyFkKpV5w6G5dU2",
|
||||
"filament_id": "GFPETG",
|
||||
"filament_id": "OFo6n2pB",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG @Anycubic Kobra S1 Max 0.25 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "duduwoswLHk9I9sY",
|
||||
"filament_id": "GFPETG",
|
||||
"filament_id": "OFo6n2pB",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "b3GU7ytZPEYNNyne",
|
||||
"filament_id": "GFPETG",
|
||||
"filament_id": "OFo6n2pB",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "SrHKJh6prBzMz4Se",
|
||||
"filament_id": "GFPETG",
|
||||
"filament_id": "OFo6n2pB",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "HyTi93UGno6uAJEO",
|
||||
"filament_id": "GFPETG",
|
||||
"filament_id": "OFo6n2pB",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG @Anycubic Kobra X 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "ajFzrQq9AvGtZCui",
|
||||
"filament_id": "GFPETG-CF",
|
||||
"filament_id": "OF9UJOGF",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG-CF @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "VOV59iBwqwMtmi48",
|
||||
"filament_id": "GFPETG-CF",
|
||||
"filament_id": "OF9UJOGF",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG-CF @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "fdm_filament_pet",
|
||||
"from": "system",
|
||||
"setting_id": "L6GIF36jbXf5NVOw",
|
||||
"filament_id": "GFPETG-CF",
|
||||
"filament_id": "OF9UJOGF",
|
||||
"instantiation": "true",
|
||||
"filament_settings_id": [
|
||||
"Anycubic PETG-CF @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "Anycubic Generic PLA",
|
||||
"from": "system",
|
||||
"setting_id": "XIq1GeZdHqOl9Gtr",
|
||||
"filament_id": "GFL92",
|
||||
"filament_id": "OFmjN2bc",
|
||||
"instantiation": "true",
|
||||
"filament_vendor": [
|
||||
"Anycubic"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "Anycubic Generic PLA",
|
||||
"from": "system",
|
||||
"setting_id": "EaVdXQHAyocYUCez",
|
||||
"filament_id": "GFL99",
|
||||
"filament_id": "OFmjN2bc",
|
||||
"instantiation": "true",
|
||||
"filament_vendor": [
|
||||
"Anycubic"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "Anycubic Generic PLA",
|
||||
"from": "system",
|
||||
"setting_id": "UpC1Qut0kjYRD9po",
|
||||
"filament_id": "GFL92",
|
||||
"filament_id": "OFmjN2bc",
|
||||
"instantiation": "true",
|
||||
"filament_vendor": [
|
||||
"Anycubic"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"inherits": "Anycubic Generic PLA",
|
||||
"from": "system",
|
||||
"setting_id": "ELCOJflyY3DfpPAH",
|
||||
"filament_id": "GFL92",
|
||||
"filament_id": "OFmjN2bc",
|
||||
"instantiation": "true",
|
||||
"filament_vendor": [
|
||||
"Anycubic"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user