CodeRabbit on #2689 (head 02743d187):
- crates/engine/src/cmd/library.rs: `cull` (#2327: a rating, flag or label
that takes the active photo out of the view) and `photo.delete` /
`photo.deletePermanently` moved the active photo without ending an open
interaction, unlike `step` and `library.select`: the drag stayed open with
no undo step. Each ends it now before its own change, so the drag is its
own undo step and comes first: undo brings the rating or the photo back,
with its edit, then the edit (Delete Permanently's undo restores the
edit too). Test an_open_edit_ends_before_the_selection_moves_on (rating,
delete, delete permanently) fails without the fix.
- docs/parity-checklist.md (LR-BEHAV-LOCALIZE) and docs/localization.md: list
every shipped language (Polish, and the others the row lacked; Italian in
the localization doc).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
tests_segment::a_failing_download_ends_with_an_error_and_never_blocks
checks that a second download request while one runs starts nothing. Its
local mirror answered 404 at once, so on a loaded runner the first
download could end before the second request, which then rightly started
a new one: the assertion failed (upstream's gate on #2689, 5223c8095). The
mirror's first answer now waits until the second request is made. A
300 ms pause between the two requests failed the test before and passes
now. Test code only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
doc_path::resolve uses craft_docpath::resolve_absolute; a path that resolves but is not absolute here is reported as not on this computer. Adds tests for Windows-form, GVFS-relative and colon-in-name paths, and a git-sources check in nix.yml and release.yml.
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)
The command sweep ran metadata.downloadPlaceNames with empty params, which
starts a real download from download.geonames.org into the settings folder.
The sweep now skips it (the command has its own loopback-server tests) and
asserts that no place names download was started.
Co-Authored-By: Claude <noreply@anthropic.com>
A colour-range mask compares every pixel against every sample, so
render and export cost is pixels x samples. The interactive sampler
stops at 5, but mask.add / mask.update (colorRange) passed their
`samples` array straight through, so a few hundred samples on a large
render turned into billions of operations and hung rendering and
export. The project already caps similar lists (MAX_STROKE_DABS,
MAX_DETAIL).
The samples list from automation is now capped at 64.
Test: a request with 1000 samples is cut to 64; a two-sample request is
unchanged.
Reported-by: BS.ehlas.cz
.avif has no AV1 decoder in any build and .heic/.heif only decode when
the codecs' heif feature is enabled, so listing them let web users pick
files import would immediately report as failed. accept_list() now mirrors
lightcraft_codecs::Format::Heif::can_decode() and never offers .avif.
EXTENSIONS itself is unchanged, so files on disk are still recognised and
imported-or-reported as before.
Two corpus tests fail on main with the CC0 corpus present (they skip without it, so no CI
has run them):
- camera_preview::tests::corpus_z8_uses_the_bundled_profile / corpus_z6ii_…: the test fitted
the camera look with `lens: None`. Since 1ee751ebd (Nikon's in-file distortion for the
Z 6II and Z 8, the same day as the tests) the camera's JPEG is matched through that warp,
which files.rs reads with `lens_geometry` and removes from the opcodes before binning the
proxy. The test now does the same; the app path was right all along.
- corpus_raw_decodes: coverage-1639.fff has no JPEG and hands on its 8-bit RGB image as a
baseline TIFF (`rgb_preview`, b5dc500c5); the test only accepted JPEG / JPEG XL previews.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Find Missing Photos took a missing photo's file name with Path::file_name,
which doesn't split on `\` on macOS or Linux, so a library made on Windows
had photos it could only find by content: those with no hash on record
(Lightroom-catalog imports, files edited since) were never found. Both the
missing photos and the files found on disk are now named by one rule: the
part after the last `/` or `\`, in lower case.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Japanese paper-size test exported only the canonical names and then
checked `print.set` with はがき, so the alias-to-MediaBox path was not
covered. Export はがき through `print.exportPdf` as well and read the
same 283.46 × 419.53 pt page as postcard.
Both sides' revision-history rows and change lines are kept (newest first);
print_view.rs auto-merged, so main's shared context_menu call sits beside the
PR's current_paper()/paper_name() punctuation and alias fixes.
# Conflicts:
# ROADMAP.md
# docs/gaps.md
# docs/parity-checklist.md
The paper-name normalisation promised punctuation-insensitive names but
dropped only whitespace, hyphens, underscores and parentheses, so `L判。`
did not resolve; keep letters and digits only instead. The Print dialog
also lower-cased the stored name without resolving it to a canonical
paper, so a paper set through an alias (`はがき`) showed `はがき in` and
selected no option; add `paper_name` and use it for the selector's
current value and option comparison.
Tests: the layout aliases test covers periods and Japanese punctuation,
and the Print view test covers the resolved current paper.
Keep the existing Inter and CJK export order and the UI font chain.
Defer Arabic export faces until joining and bidirectional ordering exist.
Restore main's headline documents and record remaining text-layout limits.
Found while testing crates/engine/src/sync.rs:851 (SyncStep::Remove; compare mark_deleted in crates/engine/src/cmd/library.rs:168)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Switches read "Show Focus Point ✓" next to "Filmstrip ✓"; now every switch
is named for the thing and the check mark says whether it is on (Focus
Point, Clipping, Photo Counts, Mask Overlay, All Mask Overlays, Mask Pins,
Layout Image). Show Original stays: it is a view, not a switch.
Names that meant two things: View ▸ Detail and the Edit section Detail
(Detail View now, like Reference View), Window ▸ Edit and the Edit menu
(Edit Panel), Compare and Compare Before and After (Before/After Side by
Side, next to Split and Top/Bottom), and Clear/Discard Preview Cache (one
command, now Discard Preview Cache everywhere). New labels in all 13
catalogs. Tests: no "Show …" switch; no two menu commands share a label or
a menu's name.
Co-Authored-By: Claude <noreply@anthropic.com>
A full count (AlbumTally::of, albums.list) keeps each loop-free smart album's photos for the pass and
answers "album is #N" from them, so an album tested by 51 others is worked out once instead of 52 times
per photo. Albums in or reaching a loop, or in a chain too deep for the depth limit, are evaluated by
their rules as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>