mask.applyEffect, saveEffect and updateEffect read an `id` that isn't a
mask id as the selected mask (applyEffect {"id": "1"} changed mask 2);
mask.update, mask.component and mask.refineDetail cast `component` with
as-casts and fell back to component 0 or the last selection. They share
the strict opt_mask_id / opt_index helpers now.
photo.label read its label with str_param, which is None both when the
label is missing and when it isn't a string, and None meant "none": so
photo.label {} or {"label": 3} cleared the colour label of every selected
photo. Only "none" or null clear now; anything else that isn't a known
label is an error. Every caller in the app already passes a label.
mask_id read `id` with `as_u64().map(|v| v as u32)`, so text fell back to
the selected mask (mask.delete {"id": "1"} deleted it) and an id past
u32 wrapped onto another mask (4294967297 as u32 is 1). spot_index and
spot.select did the same with `index`, and a colour range's `component`
fell back to the first colour range part. They now refuse such values,
as the photo ids do; a missing or null value still means the selection.
Several commands read their photo parameters leniently. An `ids` that
wasn't a list of whole numbers (`"ids": 3`, `["3"]`) fell back to the
selection or the active photo, and an `id` that wasn't a whole number
(`"id": "5"`) fell back to the active photo, so a call meant for one
photo acted on another:
- ids: album.addPhotos / removePhotos / toggleTarget, library.select,
develop.set, denoise.queue, faces.index, mask.applyEffect (mask ids)
and app.export;
- id: photo.relink (relinked the active photo to the file),
photo.removeRegion / setRegion, faces.setName, stack.setTop / moveUp /
moveDown / split, library.findSimilar, the photo queries,
denoise.cancel (cancelled every photo) / status and ui.render.
They now refuse such values with an error, as Session::targets already
does for the other commands (shared cmd::photo_ids / photo_id). A
missing or null value still means the selection or the active photo.
Found while testing crates/engine/src/cmd/cull.rs:17-20 (secs, used by the burst grouping at cull.rs:45)
Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/rename.rs:919 (start parsed at crates/engine/src/cmd/manage.rs:12)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The Print dialog's Page section gets Lightroom's Page Options for Single Image
and Contact Sheet: the page number at the bottom right, the print settings line
(sharpening, profile, resolution) at the bottom left, and crop marks at the
corners of each photo. They are `print.set {page: {pageNumbers, pageInfo,
cropMarks}}`, saved with templates, drawn in the preview and composed into the
PDF; marks and text turn white on a dark page.
Resolved against rb-base-36: Scanned keeps the base's rewrite flag next to magic and tag; Exif keeps the Panasonic lens fallback; locale catalogs merged (one duplicate key dropped).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>