Conflicts:
- apps/lightcraft/src/native_menu.rs: upstream's item swapping (macOS keys
given up for real, Help menu not swapped, Settings / Quit tracked) with
KEY-GRID's keymap-aware rows. `Item.label` stays the text the row shows
(native_item_presentation), so `Item::native_label` reuses it instead of
formatting it again; Settings / Quit store theirs through
display_item_label, as upstream's native_label did. No early return after
a rebuild (upstream).
- crates/ui-egui/src/i18n.rs: upstream's tests (#2729: one test per check
across languages, gaps reported, never a failure) plus the batch's two new
ones (dropped-photos notice, Polish counts); production code as merged.
- grid.rs, keyword_list.rs, masking.rs: the translation tests #2729 removed
stay removed; the batch's new keyword and segmenter tests stay.
- cmd/library.rs, ui-egui/src/lib.rs: both test modules, each with its
#[cfg(test)].
- xtask/src/main.rs: #2302's test_selected and upstream's translation_gaps.
- docs: tracker / gap rows take both sides' edits, headers list both sides'
changes, history rows of both sides newest-first. What's New: one section
per date, newest first (the batch had 10-22 above 10-23, and second 10-21
and 10-19 sections); no line lost.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts:
- xtask/src/main.rs: upstream's runners (cargo test or nextest, no
examples, doctests apart, one wasm `cargo check --keep-going`) with
#2302's `ci --quick` on top: test_selected builds the same targets
(--lib --bins --tests), the wasm check takes the changed crates in one
call, the full test step is upstream's.
- apps/lightcraft/src/control_server.rs: upstream's `before` closure, with
the batch's no-delay sockets kept.
- docs/parity-checklist.md: LR-BEHAV-ACCESS from main (tests/it path),
LR-BEHAV-LOCALE / LR-BEHAV-LOCALIZE from the batch (Polish).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CI: dev profile keeps line tables for workspace crates and no debug info for dependencies
* Control server tests: persistent_requests_and_slow_replies_outlive_the_idle_read_timeout no longer races the idle timeout
Each request (and the closing half-shutdown) reaches the socket before the
worker reads, so on a slow machine only the reply waits outlast the 100 ms
idle timeout, as the test intends. The idle test sends its input the same
way, and the no-frames test allows 5 s instead of 2 s to give up.
* CI: one integration-test binary per crate
Each crate's tests/*.rs become modules of tests/it/main.rs (51 test files
into 13 binaries, plus 6 that stay their own). Inner #![cfg] attributes
move to the mod lines. Files that change state for the whole process keep
a binary of their own: codecs jxl_tail_heap and raw sr2_heap (dhat global
allocator), gpu shutdown, shutdown_first and memory, ui-egui shutdown.
Docs, comments and the GPU probe name the new paths and targets
(--test it <module>::); the CI report names an it binary's skips after
the crate.
* CI: tests under nextest, doctests apart, one wasm check
xtask ci runs the tests with cargo nextest run --lib --bins --tests when
cargo-nextest is installed, else cargo test with the same targets and a
one-line notice; doctests run after them with cargo test --workspace --doc.
The heif and hardware GPU steps use the same runner. Examples stay out of
the test build (clippy --all-targets still checks them). Concurrent tests
under nextest follow the RUST_TEST_THREADS cap (NEXTEST_TEST_THREADS).
The wasm check is one cargo check --keep-going over the same crates, and
clippy runs with --keep-going.
* CI: tests run under cargo test by default, nextest with LIGHTCRAFT_NEXTEST=1 (per-process scene cache)
Review follow-ups for the Reference lifecycle fix:
- photo.setReference refuses an id that is not a photo id instead of
pinning the active photo; only an absent or null id means the active one.
- A Recently Deleted photo is refused with a message that says to restore
it (setReference and view.reference); the grid menu item is disabled for
it and any refusal is shown as a toast, not dropped.
- Reference view with no live pin releases its panes (windows, region and
pane textures, full capacity) like other views.
- A successful library switch leaves Reference for the grid; the Compare
pair is now cleared only on success, like the reference pin.
- One compare::live helper replaces four copies of the "exists and not
deleted" check.
- whats-new entry moved to 2026-10-21; checklist and ui-parity dates bumped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lightroom Classic's F8 hides the right panel; F6 and F7 (filmstrip, left
panel) were bound but F8 did nothing. View > Right Panel (view.rightPanel,
F8 as a secondary key like F6 / F7) hides the right panel and shows the
same one again next time, or Edit when none was hidden. Hiding a tool
ends it, as closing its panel does.
Gap 28 listed rating [ ], flag cycling and F1 help as missing; they are
bound, so the entry now lists only filter-bar keys, Tab / Shift+Tab and F5.
GPU handles(): only output-device proofs stay on the CPU; Show All Masks now renders zoom windows (upstream); proof-boundary tolerance in the GPU equivalence test; device-profile draft test.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A right-click on a photo (or any widget) while its own context menu was open
flashed the menu at the new spot and closed it again on the same frame. egui's
`Popup::show` judges "was open last frame" by the popup's id, so the click that
reopened the menu at the pointer also counted as a click while open and closed
it under `CloseOnClick`. A right-click on a different widget was fine.
`widgets::context_menu` wraps `Popup::context_menu` and ignores clicks on the
frame of the right-click that opens or moves the menu; every context menu
(30 sites) goes through it, and `TextField` applies the same rule to its
close-on-click-outside menu (`widgets::context_menu_close`).
Tests: `right_clicking_elsewhere_moves_the_context_menu` (headless grid; failed
at the second frame before the fix) and `right_clicking_again_moves_the_menu`
(text field). docs/ui-parity.md: Context menus row and revision history.
Fixes#1877
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Visualize HDR (#1555) has no default key: ⇧H cycles the Tool Overlay (#1473, issue #224)
- CR3 tests (#1461, #1462) accept adaptive QP 131–175, as #1694 decodes; cr3.md says the R6 Mark II files decode
- English fallbacks in the Czech and Polish catalogs use → for the menu triangle; Polish in the keyword-label test
- canvas handle tests show pins (Tool Overlay Always); a focused handle keeps its pins shown in Auto
- the model-install test and demo deadlock guards wait on deadlines long enough for a busy machine
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Describe the new keys in the library shortcuts page, update the rows they
touch in the parity checklist and the UI parity page, and stop listing F6
and F7 as missing in the small-shortcuts gap now that they are bound.
View ▸ Increase / Decrease Grid Thumbnail Size (view.thumbSizeUp / view.thumbSizeDown)
step the bottom-bar slider by 30 pt within its 90–480 range in Photo Grid, Square
Grid and People, as Lightroom Classic's Library Grid keys do; + also enlarges.
Detail, Compare, Survey and Reference ignore the keys, text fields keep them, and
⌘= / ⌘− still zoom the photo. The slider's range is now shared constants.
photo.cycleFlag steps each selected photo's own flag unflagged -> pick ->
reject -> unflagged; photo.increaseFlag / photo.decreaseFlag move it up or
down reject < unflagged < pick without wrapping. One batch undo step, Compare
and Survey act on the active photo, Auto Advance follows, text fields keep
the key. Shown in Photo > Set Flag and Help > Keyboard Shortcuts.
The Remove tool's spot pins (Remove / Content-Aware / Heal / Clone) and the
mask pins now follow a Tool Overlay mode, saved with the UI state:
- Auto (default): shown while the pointer is over the photo (or a pin is
dragged), hidden while a new spot or brush stroke is painted
- Always: all of them
- Selected: only the selected spot's or mask's
- Never: none; the tool still works and a click paints a new spot
A hidden spot can't be grabbed. Mask pins also need Show Pins
(view.maskPins), which keeps its meaning and reply.
Command view.toolOverlay {mode?: auto|always|selected|never} (no mode steps
to the next), Shift+H (H stays Remove), View > Tool Overlay with the modes
and the cycle item, and a Tool Overlay dropdown in the Remove and Masking
panels. Headless tests cover each mode with the pointer over and away from
the photo, grabbing, the key, the command, the menu, the dropdown, mask pins
with Show Pins, and the ui.json round trip.
Visualize Spots, Point Color range and Visualize HDR are drawn on the
loupe's 1:1-8:1 window like mask overlays: the range and HDR views act
per pixel, the spots high pass reads within the window's margin. New
pipeline test: each overlay's window equals the whole-frame render's
pixels. The GPU finish kernel now soft-proofs output-space proofs
(destination and display gamut warnings) like the CPU; an output-device
profile's table still renders on the CPU. New GPU equivalence test.
Stacked on pr/zoom-detail (#1027).
Sources: own design.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
canvas_keys.rs gives every handle on the photo a focusable stand-in with
an AccessKit name and position: crop corners, edges and box (crop.drag),
spot targets and sources plus a New spot point (Return adds), radial and
linear gradient handles and mask pins. Arrows move by 0.5% (Shift 5%),
one undo step per press; the stand-in keeps arrows/Return/Space from the
shortcuts. The audit now counts any focusable or clickable node; ~50
hand-drawn icons, tiles and rows are announced as buttons. A test walks
Tab through the Edit/Crop/Remove/Masking panels top to bottom.
Sources: own design.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Soft proof is per-pixel, so the After window carries the proof like the
whole-frame render under it (the proof key is part of the tile's look).
New tests: a 1:1 window of a 24 MP photo equals the full-size export to
within one level; soft proofing at 1:1 is a canvas-sized frame plus a
native window. profile_slider_drag gains a soft-proof case. Gap 4 closed,
checklist row to done with measured Linux latencies.
Sources: own design.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
tests/accessibility.rs walks the AccessKit tree headless in every view,
Develop tool and 13 dialogs and fails on unnamed controls, sliders without
value/range and untitled dialogs. Fixes what it found: text fields are
named by caption or hint, develop sliders expose min/max/step/value text
and take Increment/Decrement, Tab-focused sliders take the arrow keys,
Auto Stack's slider is named. Also as_chunks in spots.rs for the newer
clippy lint. Docs: ui-parity audit section, checklist, gaps, ROADMAP.
Sources: own design.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Compare and Reference drew each pane from a whole-frame render of at most
2560 px, so 1:1 was a magnified preview and focus could not be checked.
Each pane now also renders the window on screen from the photo's own
pixels (Slot::CompareRegion), as the loupe does (#323). The media cache
keeps up to two full-size originals while either view is open, so one
pane's window does not evict the other's source.
Docs: gaps.md entry 4 shrinks to overlays and soft proofing; checklist
LR-VIEW-ZOOM / LR-VIEW-COMPARE and ui-parity zoom row updated.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UyHnpE9573a7nJFQqnGNex
Progress docs per craftrules standards/progress-docs.md: target-app parity, gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, model-by-model RAW coverage against Adobe's camera list (docs/raw/), and format, hardware, UI and localization parity docs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>