* CRW-LIB: decode Canon CRW through the shared craft-crw crate
LightCraft decodes Canon CRW (the CIFF raws of the EOS D30, D60, 10D, 300D and the
PowerShot G1/G6) through craft-libs' `craft-crw`, the clean-room decoder derived and
verified on the `clean-room-crw-format-decode` branch and moved there with its frozen
tables and derivation record. `crates/raw/src/vendor/crw.rs` is now the adapter: it maps
the crate's header and samples onto `RawImage` (CFA, levels, active area, orientation,
as-shot white balance, the make/model/time records a CRW keeps instead of Exif) and
converts the capture time through chrono. The dependency is a local path
(`../craft-libs/crates/crw`) until the craft-libs branch merges; then it becomes a git
revision.
Everything LightCraft-side from that branch comes along unchanged: `probe_bytes` fills
metadata gaps from the decoder's records so CRW imports name their camera; the EOS D60
bundled camera profile and its chart-measured dual-illuminant matrices (`chart_table.rs`,
`spectral::Camera` carries its illuminant pair) give the D60 a Kelvin white-balance scale;
CRW joins the JPEG-fitted starting look, the catalog's raw formats and `lightcraft-cli
calibrate`; `RENDER_CACHE_VERSION` 71; the CC0 CRW corpus entries for `cargo xtask corpus`;
coverage, parity, gaps, raw-parity, target-app-parity and ROADMAP updates. The G5 stays
preview-only (the crate refuses it with the reason) and the robustness test keeps its CRW
sample.
What does not come along: the decoder, its tables and `crw_oracle.rs` (now craft-crw's
digest-pinned sample test) and the derivation record, which lives in craft-libs
`crates/crw/clean-room/`. `clean-room/crw/` here keeps only the EOS D60 chart-calibration
document and its capture list, with a README pointing at the record.
Gates: fmt, clippy -D warnings (raw all targets; engine, catalog, cli), lightcraft-raw tests
(475 + 134, the corpus files decoding through the adapter), catalog tests, engine lib tests
(1,300 pass; the two failures, `tests_import::recursive_discovery_…` and
`originals::tests::write_targets_pin_absent_paths_…`, are in files unchanged from main),
`cargo xtask parity`, `assets`, `layers`, `coverage.py --check`.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* no message
* no message
* Update documentation after moving code to craft-libs
* Review coment fixes
* CRW: pin craft-crw f3b62ec, a truncated entropy stream is Corrupt
craft-libs #472 makes craft_crw::decode refuse a stream that ends more than
Limits::max_stream_end_fill (64 samples, one block) before the frame does,
instead of filling the rest with predictor values and returning success.
The adapter already maps craft_crw::Error::Corrupt to RawError::Corrupt;
a regression test proves a truncated CRW now fails at this boundary (it
decoded as a flat frame on the old pin) while its header still reads.
Only craft-crw moves; craft-ui/docpath/update/window stay on c5a1cbf.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Code review comment fix
* Add some tests
---------
Co-authored-by: Robert Woldberg <314159+rwoldberg@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The old version's cached installer is missing, so Windows cannot remove it.
Re-caching it with msiexec /fv on the same-version MSI fixes both updating
and uninstalling (reproduced and verified on Windows 11, #3254).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Camera profile: Sony ILCE-7RM5 (α7R V)
* Camera profile: register the bundled ILCE-7RM5 profile
* Camera profile: attribution for the ILCE-7RM5 profile
* Camera profile: list ILCE-7RM5 among the built-in profiles in the README
* Camera profile: list ILCE-7RM5 in the Simplified Chinese README
* Camera profile: list ILCE-7RM5 in the Traditional Chinese README
* Camera profile: ILCE-7RM5 calibration set used the Standard creative style only
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)
Conflicts:
- README.md, docs/localization.md: language lists keep every language, Finnish appended
- assets/ATTRIBUTION.md: union of rows
- crates/ui-egui/src/i18n.rs, crates/ui-egui/src/menus.rs: language table and commands keep sv and fi
- crates/ui-egui/src/panels/keyword_list.rs: code list gains fi; Locale::ALL.len() is 16
- docs/localization-parity.md: header keeps the newer date and both changes; revision rows are the union
Conflicts:
- README.md, docs/localization.md: language lists keep every language, Swedish appended
- assets/ATTRIBUTION.md: union of rows
- crates/ui-egui/src/i18n.rs: language table and command test list keep it, ka and sv; both tests kept
- crates/ui-egui/src/menus.rs: language commands keep it, ka and sv
- crates/ui-egui/src/panels/keyword_list.rs: code list gains sv; Locale::ALL.len() is 15
Adds Finnish catalogs (fi.json, fi-formats.json), the language table entry
and menu command, Finnish tests, docs and an attribution row. What's New text
stays English, as in most catalogs.
AI-assisted translation (Claude Code), reviewed by a native Finnish speaker.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Review on #1468: main's #2099 split out text_matches() and lets unknown field
prefixes fall back to plain text. On top of it, text_matches() now also matches
Photo::people(); the free-text token is unquoted before text_matches(); an
unknown field's quoted value is unquoted in the fallback (`10:"30 am"` is the
text `10:30 am`); and the field split keeps the !t.starts_with('"') guard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- .github/workflows/ci.yml: the full `cargo xtask ci` on every pull request and push to main
(Linux x64, craft-fonts, rust-cache for dependencies), so it becomes the merge gate.
- `cargo xtask ci --quick [--base REF]`: fmt, clippy, the changed packages' tests, layers and
assets, plus heif / parity / wasm when the changes touch them, measured against the merge base
with origin/main (xtask/src/ci_quick.rs). Workspace-wide files test everything.
- A machine-wide lock (xtask/src/ci_lock.rs): a second `ci`, from another worktree, waits and
names the run it waits for. LIGHTCRAFT_CI_SLOTS=N, LIGHTCRAFT_CI_LOCK=off|<dir>.
- README, CLAUDE.md quality gate, gaps.md gap 9, target-app-parity.md stability note.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add README.zh-hant.md alongside the existing English and Simplified
Chinese READMEs, translated from the current README.md and aligned
with the in-app zh-hant terminology (crates/ui-egui/locales/zh-hant.json).
Cross-link all three README files in their language switchers.
Both sides added code at the same places: main's Prepared filter struct next to
search_tokens()/unquote() in query.rs, its touched_since test next to the
people-search test in tests.rs, and its 2026-10-14 What's New sections next to
this one. All kept.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Align feature descriptions, counts, exports and language options with the
current code. Distinguish model-dependent features and implemented Print
and slideshow workflows from their remaining gaps.
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Georgian next to Italian in the language table, menus, catalogs list and docs; ka-formats.json lists the format
strings other PRs added, in English until translated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds Swedish (Svenska) as an interface language: 2707 strings, written from the English source.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stacked on rb/1592: LOOK_VERSION 8 -> 9; the PR's corpus-profile helper is the base's corpus_uses_the_bundled_profile.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds Georgian (ქართული, code ka, system tags ka / ka-GE / ka_GE) with
complete plain and formats catalogs, the Edit > Language command and the
Settings choice. Sentence-cased messages go through i18n::upper_first,
which leaves Georgian letters alone (upper-casing Mkhedruli would turn it
into Mtavruli). The Settings language choices wrap now that eleven
endonyms no longer fit on one line, and the face-model Remove button goes
through tr().
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YMTAbGNRxnMEzRvYnQGphF