Files
bambuddy/backend/app
maziggy accafafa64 fix(backup): report the rows a failed K-profile step already committed (#2656)
`_apply` commits the database categories before the K-profile phase, and the
    comment there is right about why: `get_kprofiles` is 3 x 5 s per printer per
    nozzle and SQLite's `busy_timeout` is 15 s, so holding the writer across the
    MQTT phase would fail every concurrent writer in the app.

    But `run_restore`'s handler returns `{"success": False, ..., "results": {}}`
    for anything raised after that point, and the per-call guards inside
    `_restore_kprofiles` do not cover the whole phase. Two consequences, and the
    second is worse:

    * The user is told the restore failed and handed an empty `results` while the
      archive, spool and settings rows are durable on disk. The honest-reporting
      theme this whole feature is built on inverted on exactly the path where it
      matters most.
    * `_reconfigure_mqtt_relay` sits inside the same `try`, downstream of the
      raise. A restore that rewrote the mqtt_* rows left the relay pointed at the
      pre-restore broker until something else reconfigured it.

    `_apply` now contains the K-profile phase: fold the error into that category's
    tally as `failed` plus a `kprofilesStepFailed` note, and let the results it has
    already committed be returned and reported. Every profile the payload carried
    and the phase did not account for is counted failed — silence would have been
    the same lie in a smaller font. `_reconfigure_mqtt_relay` is reached again
    because `_apply` returns normally. The rollback in the handler discards only
    the phase's own read transaction, so a database error cannot leave the session
    in a state that turns the caller's commit into the very report this prevents.

    `kprofilesSendFailed` was the obvious note to reuse and is the wrong one: it
    names a nozzle, a printer and a serial that a phase-level failure does not
    have, and "failed to send" is untrue of a step that never got as far as
    sending. One new leaf x 13 locales instead.

    Belt-and-braces on the trigger that found this:
    `sum(len(c.get("profiles") or []) ...)` raises TypeError on a hand-edited or
    truncated backup whose `profiles` is not a list, and it runs before the guards.
    Counting defensively makes that a skipped category rather than an exception
    thrown over committed rows.

    Control kept explicit: a failure *before* the commit still rolls back, still
    reports nothing restored, and still does not touch the relay.

    Tests: +5 (280 -> 285 across the three restore files, 328 -> 337 across
    `-k github`). Fail-pre-fix 4 — 3 for the containment, 1 for the defensive
    count, checked separately. i18n parity 13 locales at 5771 leaves.

    Bundle rebuilt for the new leaf: index-CHCEEMgx.js -> index-DhOfNgMz.js. CSS
    hash unchanged.
2026-08-15 14:16:44 +02:00
..
…
…
…