Skip to content

Stop a frame getting stuck as a half-frame diptych - #874

Merged
marcinz606 merged 2 commits into
marcinz606:mainfrom
seanharding:fix/half-frame-stuck-diptych
Aug 17, 2026
Merged

Stop a frame getting stuck as a half-frame diptych#874
marcinz606 merged 2 commits into
marcinz606:mainfrom
seanharding:fix/half-frame-stuck-diptych

Conversation

@seanharding

Copy link
Copy Markdown
Contributor

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.

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.
@marcinz606
marcinz606 merged commit c0ba5cd into marcinz606:main Aug 17, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants