Say when a filament source is being ignored, and what a real failure looked like

Two things a real end-to-end run on the P1P taught, neither of them a fix.

`start_uploaded_file` silently discarded its `filament` argument for a bare
`.gcode`. That is protocol-correct - the v1 `gcode_file` request has only
`command` and `param`, with no `use_ams`/`ams_mapping` to put it in, so a
bare gcode draws whatever its own tool changes select. But the argument is
required, and a caller passing `FilamentSource::ams([3, ..])` would
reasonably believe it took effect. "A filament choice quietly overridden" is
the precise bug `FilamentSource` was introduced to stop, so this now warns
instead of dropping it.

The other is the whole-path confirmation, which is worth having written down
because it ended in a *physical* failure rather than a clean success. The
derivation read the project's one PETG/GFG99 filament and produced slot 3;
the printer echoed `tray_tar: 3`, so it agreed; 297,227 bytes went up with an
exact byte count; `IDLE -> PREPARE -> RUNNING`; it heated to 255C - and then
paused itself at stage 54 with `print_error: 0x07008003` and
`hms: [{attr: 0x07002300, code: 0x00020004}]`, a broken-filament fault on the
slot it was loading.

Every line of this code did the right thing and the print still did not
happen. That is the argument for the thing this commit documents rather than
changes: `command_outcome` can only report what the printer said about the
command, and "accepted" has now been shown to be three distinct steps away
from "printing". Anything that reports job status has to watch `gcode_state`,
`print_error` and `hms` after the fact - a job dispatcher that trusts the
start reply will report a successful print that never ran.

Also noted: `tray_now` is not a usable confirmation on its own. It went
255 -> 3 -> 254 over the run, so only the transition through the real slot
number is evidence; a single read can land on either sentinel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 22:37:28 +00:00
co-authored by Claude Opus 5
parent 790c951cb4
commit 35d2d96f05
+33
View File
@@ -384,6 +384,7 @@ pub const CHAMBER_LIGHT: &str = "chamber_light";
/// So this is a required argument rather than an option with a default.
/// There is no safe default: picking the wrong source draws the wrong
/// filament or none at all.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FilamentSource {
/// The external spool (`vt_tray`). `use_ams: false`, and
/// `ams_mapping` must be the empty *string* - the schema's trailing
@@ -1090,6 +1091,20 @@ impl BambuPrinter {
/// - **`url` spelling.** `ftp:///<name>` - empty host, triple slash,
/// resolved against the card's root - is accepted. `file:///` was
/// never needed and remains untested.
/// - **An accepted start is not a successful print, and the failure can
/// be physical.** Confirmed end to end on 2026-10-15 via
/// `upload_project_file`: the mapping derived correctly
/// (`ams_mapping` slot 3, and the printer echoed `tray_tar: 3`), the
/// upload matched byte for byte, the printer went
/// `IDLE -> PREPARE -> RUNNING`, heated to 255C - and then paused
/// itself at stage 54 with `print_error: 0x07008003` and
/// `hms: [{attr: 0x07002300, code: 0x00020004}]`, i.e.
/// `HMS_0700_2300_0002_0004`, which is a broken-filament fault on the
/// slot it was loading. Nothing in this code was wrong; the filament
/// was. Which is the point: `command_outcome` can only report what
/// the printer said about the *command*, so anything that wants to
/// know whether a print is actually running has to watch
/// `gcode_state`, `print_error` and `hms` afterwards.
/// - **`use_ams: false` / `ams_mapping: ""`.** Accepted by the printer -
/// and *wrong* on an AMS-equipped machine. Confirmed on a second run
/// the same day, against a project the owner had sliced in Bambu
@@ -1187,6 +1202,24 @@ impl BambuPrinter {
// things. Unverified - see this method's doc comment, which
// records what the hardware said about the `cache/` spelling.
body["param"] = serde_json::Value::String(format!("/{file_name}"));
// `filament` has nowhere to go here: `gcode_file` takes only
// `command` and `param` - no `use_ams`, no `ams_mapping` - so a
// bare gcode draws whatever its own tool changes select. That is
// correct, but it means this argument is silently discarded for
// half the inputs this method accepts, and "a filament choice
// quietly overridden" is precisely the bug `FilamentSource` was
// introduced to stop. So say so rather than letting a caller
// believe its mapping took effect.
if !matches!(filament, FilamentSource::ExternalSpool) {
tracing::warn!(
printer = %self.base.name,
file = file_name,
?filament,
"ignoring the filament source: a bare .gcode has no use_ams/ams_mapping \
field to put it in, so the gcode's own tool changes decide"
);
}
}
// A correlated `request`, not a fire-and-forget publish. This was