Skip to content

Inspector parameters persist forever with no way to reset them, so the pre-#27 wheel-scroll damage is permanent #56

Closed

Description

@sensitron

Context

#27 fixed the cause of the wheel-scroll bug: until then, scrolling the inspector panel changed the
value of whatever field the pointer passed over. #40's Notes recorded the damage from a single
such session — an edge treatment nobody chose, 11 fps, and a 0.4 % alpha threshold.

The cause is fixed. The damage is not. Inspector parameters are persisted in QSettings and there
is no way for a user to put them back. Anyone who scrolled past a field before #27 keeps those
values in every future session, on every future clip, with nothing in the UI to undo it.

Found 2026-09-05 on Windows while manually verifying #40 — the values below are still live on
that machine, months after the session that set them.

Current State (verified 2026-09-05)

Live contents of HKEY_CURRENT_USER\Software\MatteLoop\MatteLoop\parameters on a machine
affected by the pre-#27 bug, next to the defaults in
src/matteloop/core/parameters.py:48-62:

Key Persisted Default
fps 11 15 scrolled
alpha_threshold 0.4 2.0 scrolled
stretch_x 1.2 1.0 scrolled
padding 1 0 scrolled
edge_mode decontaminate_colors standard set deliberately during #40
model_id birefnet-portrait birefnet-portrait default
execution_provider CPUExecutionProvider CPUExecutionProvider default

The full persisted set (_KEYS in src/matteloop/ui/preferences.py) is model_id, edge_mode,
execution_provider, fps, trim, alpha_threshold, padding, stretch_x,
output_directory, output_filename and max_mib. The transform is not persisted.

There is no reset. Searched the whole UI for a reset, restore, defaults or clear path:

Looked for Result
Reset/Defaults button for parameters none
Menu bar or context menu the app has neither
Preferences dialog none
CLI flag only --version, --providers, --smoke-test (src/matteloop/app.py:253-265)
Settings schema version that would discard old values none

The two "Reset" buttons that do exist are scoped elsewhere and do not touch these values:
src/matteloop/ui/inspector.py:500 ("Reset Crop") and src/matteloop/ui/timeline.py:248
("Reset Range").

Validation does not rescue the user. parameters_from_values
(src/matteloop/core/parameters.py:351-376) does range-check every persisted value —
fps to 1..240, alpha_threshold to 0..100, padding to >= 0, stretch_x to > 0 — and falls
back to the default per key when a value is invalid. Every scrolled value above is inside those
ranges. They are legal values that the user did not choose, which is exactly the case validation
cannot detect.

The only escape today is deleting the registry key by hand. That is not something to ask a user
to do, and it is not discoverable.

Why This Matters

The persisted set is not cosmetic. fps and alpha_threshold change what is rendered; a
0.4 % alpha threshold keeps nearly every faintly-transparent pixel, and stretch_x 1.2 distorts
the output geometry. A user in this state gets subtly wrong results forever and has no reason to
suspect the settings — they never chose them, so they have no memory of setting them.

It also makes every future bug report from an affected user harder to read: their output differs
from a clean install for reasons neither side can see.

Proposed Change

Add a user-reachable reset for the inspector parameters.

  1. A "Reset to defaults" action in the inspector, scoped to the persisted parameter set
    (model_id, edge_mode, fps, trim, alpha_threshold, padding, stretch_x, max_mib),
    restoring the ParameterState defaults and writing them through to QSettings. Placement should
    match the existing "Reset Crop" / "Reset Range" affordances so it reads as the same kind of
    control.
  2. Do not reset what the user is working on: the loaded source, the crop, the timeline range
    and the transform are separate concerns with their own controls. This action is about the
    inspector parameters only.
  3. execution_provider is excluded from the reset. It is persisted with the same set, but it
    is a machine capability choice rather than a creative parameter: resetting it to the
    recommendation would move a user back onto hardware they deliberately left. On the machine
    where this was found, that means being put back on DirectML and a GPU that hangs on the
    default model. The UI must state that the provider is not affected.
  4. output_directory and output_filename are excluded too. They are a button and a line
    edit, so the wheel could never have changed them, and they are file choices the user made on
    purpose. Their "default" (next to the source, named after it) is reachable by clearing them.

Acceptance Criteria

  1. A user can restore the inspector parameters to their defaults without leaving the app.
  2. After the reset, the persisted QSettings values match ParameterState()'s defaults for every
    key in scope — verified by reading the settings back, not just the widgets.
  3. The reset does not change the loaded source, crop, timeline range, transform, output
    directory or output filename.
  4. The reset is reflected in the inspector widgets immediately, without a restart.
  5. The reset leaves execution_provider untouched, and the UI says so.
  6. A user with out-of-range persisted values still gets per-key fallback as today — this change
    does not replace parameters_from_values' validation.
  7. uv run ruff check . && uv run mypy src && QT_QPA_PLATFORM=offscreen uv run pytest -q green,
    plus uv run python scripts/check_guardrails.py.

Testing Plan

Layer What Count
Unit reducer event restores every in-scope key to its default and leaves the rest alone +2
Integration persist -> reset -> re-read QSettings yields defaults +1
UI the action is reachable, updates the widgets, and does not disturb crop/range/transform +2

Files Reference

File Change
src/matteloop/core/parameters.py a ParametersReset event in the ParameterEvent union (:151-164), reduced by reduce_parameters (:167) from the ParameterState defaults (:48-62), invalidating the preview like the other parameter events
src/matteloop/ui/inspector.py the button itself, alongside the existing reset affordances (see :500), emitting the event through command_requested like "Reset Crop"

No change to src/matteloop/ui/preferences.py or src/matteloop/ui/controller.py:
Controller._dispatch_parameter (controller.py:462-480) already routes every ParameterEvent
to the store and calls persist_parameters with the full resulting state, so a reset event is
persisted the moment it is reduced. (_dispatch_parameter also re-applies _working_provider
when the persisted provider is the one that failed — the reset must not touch that path, which
follows from leaving execution_provider alone.)

Out of Scope

Rollback

Revert the PR. The change adds an action; it does not alter the stored format, so a revert leaves
existing settings readable.

Effort Estimate

~1 h reducer event + ~1 h UI wiring + ~1 h tests.

Related

Activity

  1. added
    bugSomething isn't working
    on Sep 6, 2026
  2. self-assigned this
    on Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions