Stop a frame getting stuck as a half-frame diptych - #874
Merged
marcinz606 merged 2 commits intoAug 17, 2026
Conversation
An RGB Scan triplet, a stitch or an HDR merge could render as a half-frame diptych — split down the middle, each side run through the pipeline on its own — whenever the file it is built around had been worked on as two halves earlier. The frame came out half its width. Composites are now refused, as they already were by the split itself. A composite asset is its primary plus the extra paths, so it carries the primary's plain content hash. Discovery already declined to split those, but the other entry point claims a whole scan on the sole evidence that `<hash>marcinz606#1` or `<hash>marcinz606#2` edits exist, and a stale pair from an earlier half-frame session still matched. One predicate, `is_composite`, now answers for both.
Turning Half Frame on and straight back off left the frame that happened to be open stuck as a diptych, never having been edited. Auto-measured bounds no longer file a settings row for a half that has none. Rendering a half meters it, and the measured bounds are persisted so navigating back is stable. Under a half's hash that write created `<hash>marcinz606#1` out of nothing, and the mere existence of that row is what says the scan is a diptych. The row held no decision of the user's — only the metering, and whatever the sticky defaults were at the time. A half that carries a real edit already has a row, so its bounds keep tracking and it still returns as a diptych.
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.
A frame could be stuck rendering as a half-frame diptych — split down the middle, each side run through the pipeline on its own — when the user had never edited a half. Turning Half Frame on and straight back off was enough, and so
was assembling an RGB triplet from a file that had been split earlier. Two independent causes, both of which let a scan be claimed as a diptych on evidence that records no decision of the user's.
A scan is a diptych when the database holds a settings row under #1 or #2. That is the right test for "this half was worked on" only if such a row means an edit. It did not.
Rendering a half meters it, and _on_metrics_updated persists the measured normalization bounds so that navigating back is stable. Under a half's hash that write created the row out of nothing: selecting a half, which happens the
moment Half Frame goes on, was enough to file one. On a clean database, toggling Half Frame on and off with no edits at all leaves #1 behind for whichever frame was open, holding the metering and whatever the sticky defaults
were at that instant. Auto-measured bounds may now update a half's row but never create one (_may_persist_measured_bounds), so a half that was only looked at leaves no trace. A half carrying a real edit already has a row, its bounds
keep tracking, and it still returns as a diptych.
The second cause is the composite hash again, the same shape as #857. An RGB-Scan triplet is {**red, green_path, blue_path}, so it carries the red exposure's plain content hash; a stitch and an HDR merge do the same with their
primary. Discovery already refused to split composites — _expand_half_frames calls the combination unsupported — but the other entry point had no matching test, and claimed the assembled frame whenever the primary happened to have
half edits from an earlier session. The frame then came out half its width. The rule is now one predicate, is_composite, that discovery and both diptych readers share, so the two cannot drift; _mark_diptychs also stamps diptych =
False on composites rather than leaving the key absent, so the filmstrip badge and the read-only panel agree.
Verified by driving the app on a folder of camera scans. Before the change, Half Frame on and off with no edits leaves the open frame flagged diptych: True and active_roi at half the width; a triplet seeded with stale #1/#2 edits on
its red exposure renders at (0, 1067, 0, 784) of a 1600px preview. After it, both come back whole, and autocrop on the triplet returns the correct (64, 1031, 79, 1530). The positive control still holds: edit a half for real, turn
Half Frame off, and the scan returns as a diptych as documented.
The user guide overstated what counted as work ("turning Half Frame off does not lose the work") and said nothing about composites; both are corrected.
Note for anyone who hit this before the fix: the stale row survives the upgrade, so an affected frame keeps showing as a diptych until that row is removed. No migration here — the bug is new enough that the blast radius is small, and
deleting a half's edits is not something to do behind the user's back.