Files
bambuddy/backend
maziggy 920c6d1549 Read a print's destination from the report topic, not just the request one (issue #1820)
current_project_url was assigned in exactly one place, _handle_request_message,
    and _on_message calls that only for the request topic. A print started from the
    printer's own screen publishes nothing there, so the field stayed None for the
    one case the storage verdict exists for: the file is already in the printer's
    model library under /userdata/model/history/, which port 990 does not serve.

    The verdict then fell through to the sdcard flag, and @ojimpo's H2S reports that
    flag true -- its "card" is the internal eMMC -- so every such print ran the full
    sweep before giving up. He measured one: 16 filename-and-directory attempts over
    22 FTPS connections, 18 of them refused, 6.4 seconds, then a fallback archive
    holding a name and nothing else.

    The printer does announce where the file lives, as an unsolicited project_file
    *response* on the report topic about two seconds before gcode_state reaches
    PREPARE. _process_message now reads the url off it, gated on result SUCCESS and
    a non-empty value so a refused dispatch cannot name a file that was never
    written. Reading it there rather than only at the request topic also covers an
    install neither of us had in view: some brokers refuse the request-topic
    subscription, and on those no print of any kind had ever populated the field.

    The new branch captures state and nothing else. The "External project_file
    payload" diagnostic stays with the request-topic handler: our own dispatch is
    echoed on both topics, the request-topic echo lands first and clears
    _own_project_file_key, so reusing the diagnostic here would have logged every
    Bambuddy-started print as somebody else's. A test pins that.

    What the print names is now what gets tried -- the five directories a copy could
    be in, rather than the ~110 connections that cannot succeed. The probe is still
    worth running: an H2S keeps recently used jobs under /cache and archives them in
    full while they last, which is why the reporter's two prints on the same day
    behaved differently. Slicer-sent prints are unchanged.

    The banner no longer describes a step that never happened. With no reason
    recorded, a blank archive fell back to the original wording -- "Store sent files
    on external storage" is off in your slicer -- which on that printer is on, and
    which the internal-storage wording from #2780 already explains would not help on
    an H2. The archive that most needed that explanation was the only one that could
    not be given it.

    So file:///userdata/ now earns its own reason, internal_history, separate from
    the brtc://emmc dispatch case. A dispatch chose internal storage and can be
    aimed elsewhere; a print of a file that was already there had no dispatch at
    all, and telling that operator to pick External in Send names a dialog they
    never opened. The banner and the connection diagnostic both read the verdict's
    reason rather than a fixed one, so the two surfaces cannot give the same printer
    different advice. Thirteen locales, and a wiki section the banner links to.

    -----

    Read the K-profile selection when the mutation runs, not when it is captured

    Configure Slot sends cali_idx from selectedKProfile, and the mutation read it
    through its own closure. React Query hands a mutation its options from an
    effect, so a click landing between a commit and that effect flushing runs the
    previous render's mutationFn -- one that captured the selection as it was before
    the K-profile query resolved. The payload then carries cali_idx -1 and the
    printer binds the default 0.020 instead of the calibrated K, while the dialog
    shows the right profile selected throughout.

    It surfaced as an intermittent failure of the per-nozzle K-profile test, about
    one full-suite run in six. Reproducing it with staggered query resolution showed
    the divergence directly: the select element held the correct profile immediately
    before and after the click, and the payload still carried -1. That test's slot is
    the most exposed case in the file -- a right-hotend slot carrying the left
    hotend's index, where the "keep showing the active profile" safety net cannot
    repair an empty recompute.

    The selection now goes through a ref written during render, so the mutation
    resolves it at execute time. An effect would have inherited the same flush
    ordering this exists to escape. The K value and the profile's ids travel in the
    same payload and had the same exposure, so they move with it.

    Measured over a staggered-resolution grid: 2 failures in 15 runs before, 0 in 12
    after. api.getSlicerPrinterModels was also missing from the test file's mock, so
    that query ran with no query function and rejected in all 37 tests -- mocked now,
    though on its own it changed nothing, which is how the ref was confirmed as the
    fix rather than assumed.
2026-08-26 10:18:12 +02:00
..