Repository navigation
fix: treat a confirmed dialog as confirmed, and stop pinning a prepared model - #38
Merged
Merged
Conversation
QMessageBox.question returns a plain int, not a StandardButton member: on PySide6 6.10.3 pressing Yes yields 16384, and `16384 is StandardButton.Yes` is False while `==` is True. Four call sites compared the answer with `is`, so every confirmation in the application was read as a refusal. The dialog appeared, the user pressed Yes, and nothing happened at all: no removal, no download, no message, no error. Affected: removing one model weight, Delete outdated, Re-download outdated, and deleting a pinned cut set. All four now compare with equality, and the one that reads least obviously carries a comment saying why, so it does not get tidied back into an identity check. The suite could not have caught this. Every test monkeypatched QMessageBox.question to return the canonical enum member, for which identity does hold, so the stub asserted the opposite of what Qt does. The stubs now return int(StandardButton.Yes), which is what Qt returns, and one test drives a real QMessageBox to completion by finding the active modal window and clicking its YesRole button. That test needs no stub at all and guards the whole class rather than these four instances. Closes #37 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A model prepared for one preview stayed the session's active model for the rest of the run: _active_spec is cleared only in close(), which runs at application shutdown. Removing that weight raised MODEL_IN_USE and the button stayed dead, so the default model could never be deleted without first preparing a different one. Nothing in the interface said so. The guard was stricter than the thing it protects. The segmentation child builds its session from the model bytes and holds no handle on the file afterwards, and prepare() returns the cached result for the same model without reading the file again. Deleting the active weight breaks nothing that is running; the next switch away and back downloads it, which the maintainer accepted as the consequence. Removal now refuses only while the model is in the cleanup set, the post-failure state where the child is not known to be healthy, and the error says that rather than naming an active session. The manager's active-model check is gone from the dialog's guard too; the refusal while a job runs is what covers a preparation actually in flight. A blocked click now puts the reason in the status line instead of returning in silence, as the neighbouring actions already do. jobs/models/session.py shrinks from 439 to 437 lines; the baseline records it. Closes #36 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #37
Closes #36
Summary
Two defects in the same area, found while investigating a report that models could not be deleted. The first is the one that blocked the user.
#37: every confirmation in the application was ignored.
QMessageBox.question()returns a plainint, not aStandardButtonmember. Measured on PySide6 6.10.3 by clicking the real dialog:Four call sites compared with
is, so pressing Yes was read as a refusal: removing a model weight, Delete outdated, Re-download outdated, and deleting a pinned cut set. The dialog appeared, the user pressed Yes, and nothing happened at all — no action, no message, no error.#36: a model prepared once could never have its weight deleted again.
_active_specis cleared only inclose(), which runs at application shutdown, so the default model was locked for the whole run and the refusal showed up only as a dead button with a tooltip.Why the suite did not catch #37
Every test monkeypatched
QMessageBox.questionto returnQMessageBox.StandardButton.Yes, the canonical enum member, for which identity does hold. The stub returned something Qt never returns, so the tests asserted the opposite of production. My own first four reproductions passed for exactly the same reason; it only reproduced once a real modal dialog was driven to completion.The stubs now return
int(QMessageBox.StandardButton.Yes), and one new test uses no stub at all: it opens the real confirmation, finds the active modal window, clicks the button whose role isYesRole, and asserts the weight is gone. Deliberately reverting one source fix makes that test fail, which was checked rather than assumed.The #36 guard, narrowed rather than removed
The guard was stricter than the thing it protects. The segmentation child builds its session from the model bytes and holds no handle on the file afterwards, and
prepare()returns the cached result for the same model without reading the file again, so deleting the active weight breaks nothing that is running. The next switch away and back downloads it, which the maintainer accepted as the consequence.Removal now refuses only while the model is in the cleanup set — the post-failure state where the child is not known to be healthy — and the error names that state. The dialog's guard drops its active-model check as well; refusing while a job runs is what covers a preparation actually in flight. A blocked click now puts its reason in the status line instead of returning in silence.
jobs/models/session.pyshrinks from 439 to 437 lines; the baseline records it.Test plan
uv run ruff check . && uv run mypy src && QT_QPA_PLATFORM=offscreen uv run pytest -q: 1620 passed, 4 skipped.MODEL_IN_USE; a blocked click reports its reason.🤖 Generated with Claude Code