crates/engine/src/file_cmds.rs: batch keeps the save-point closure (takes the output path) and also copies the session's authorize hook into each scratch session, as main now does.
crates/raw/src/sensor.rs: both sides cap the memory of retained tiles; kept the existing retained_segment_bytes check (checked multiplication, same limit) and dropped main's duplicate inline loop.
Resolutions: CLI usage, flag lists and flag parsing carry both --tiff-compression (t15) and
--jpeg-format (t16); file.saveACopy, batch, imageProcessor and layersToFiles param specs carry
both tiffCompression and jpegFormat; file_cmds keeps tiff_compression_param and
jpeg_format_param; atn_cmds keeps flag_set/applies_at_canvas_bounds (t15) and UNHOLDABLE (t16),
edit.transform uses the pixel_target guard (t15) with layer_ref(p)? (t16); ui-egui open paths
build ImportOptions (t16) and apply raw_defaults (t15); docs headers/rows unioned; atn tests keep
both sides; tr.tsv "Keep Using CPU" kept once.
actions.load gave each imported action a unique name with a helper that
restarted suffix numbering at 2 and linearly scanned all accepted names
for every candidate. A file repeating one base name many times caused
cubic comparison work during load.
Replace it with a UniqueNames helper backed by a HashSet for membership
and a per-base-name next-suffix cache, preserving the name, name 2,
name 3 ... sequence and first-match behavior.
Finding: 9c7a5fdb-131e-4687-8175-58d72007b0c5 (CWE-407)
Conflicts:
docs/gaps.md: header line is ours plus the PR's missing change item (later Last updated date); change-log rows kept both, newest first
docs/file-format-parity.md: same
crates/engine/src/jobs.rs: kept both Running fields (recorded_by, pre_selected) and both initialisers; main's new_fx_target block and foreign-recording flush kept; after_command takes the PR's pre_selected argument at both call sites.
crates/engine/src/atn_cmds.rs: no `uncarried` macro arm; the four Select > Modify events (Feather, Expand, Contract, Smooth) use the existing `unless` arm with a new predicate `applies_at_canvas_bounds` (wraps the PR's `flag_set`). Helper fns kept both (`preserves_roundness`, `flag_set`).
crates/engine/src/atn_cmds/tests.rs: both sides' appended tests kept whole.
crates/engine/src/atn_cmds.rs (EVENTS): main builds adjustment events with adjustment_event!; kept main's Black & White macro line and used the PR's by-name Photo Filter (empty code) through the same macro, with the PR's comment.
crates/engine/src/atn_cmds.rs: kept main's helper block (SMART_BRUSH, Color Range, clipping events) whole and the PR's radial blur consts and fns after it.
crates/engine/src/atn_cmds/tests.rs: kept both sides' tests whole.
crates/engine/src/atn_cmds.rs: kept main's smartBrushWorkspace/autoCutout/ClrR events and comment; refineSelectionEdge uses the PR's refine_edge_to, which also refuses a step with sampleAllLayers (main's earlier inline check).
crates/engine/src/atn_cmds/tests.rs: kept both sides' tests whole.
crates/engine/src/atn_cmds.rs: the filter macro's to guard keeps both checks (pixel_target && !skip && holds_its_settings); kept main's preserves_roundness and the PR's UNHOLDABLE table and holds_its_settings.
crates/engine/src/atn_cmds/tests.rs: kept both sides' tests whole.
crates/engine/src/atn_cmds.rs: three hunks, kept both sides (the Mn menu-item mapping and zoom ids from main, the Dcmn offset mapping and document.activate id from the PR); the document.activate arm precedes main's menu-item fallback in select_to.
docs/gaps.md: header line kept from main with the PR's change entry prepended and the date 2026-10-19.
crates/engine/src/atn_cmds.rs: kept this PR's range-checked Kind::Long arm and main's Kind::ExactLong arm; dropped the PR's Group Layers explicit-layer refusal (#7236), as #7968 exports that layer by name.
crates/engine/src/atn_cmds/tests.rs: kept both sides' tests whole; dropped the PR's groupLayers layer:3 refusal case (#7236).
Save Actions wrote Photo Filter steps with the four-char event code PhtF.
Photoshop loads the file but stops on playback ("The command 'Photo
Filter' is not currently available"). The same descriptor runs under the
string event photoFilter (measured by the reporter in Photoshop 27.11 at
8 and 16 bits). PhtF is the adjustment's class, not an event.
- Photo Filter now exports by name (photoFilter), like Black & White,
Box Blur and Surface Blur since dfe94d6a. The descriptor is unchanged.
- Import still accepts PhtF through LEGACY_CODES, so actions PhotoCraft
saved before keep loading, and they re-save under the name.
- Tests: Photo Filter joins the by-name/legacy-code test (export id,
import by name and old code, near misses stay Photoshop steps). A new
test records the issue's exact step, saves it strictly with nothing
skipped, loads a Photoshop-authored step and an old PhtF step, re-saves
both as photoFilter, and plays both the same as a direct run at 8 and
16 bits. Both tests fail without the fix.
A `make` of a `Chnl` whose `At` reference has further items (the mask of
a named layer) was mapped to a layer.layerMask command, which acts on the
target layer. Such a step now stays a kept Photoshop step, reported as
unsupported.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PR stopped writing PhotoCraft's defaults for params a step leaves
out. Checked against Photoshop, that is fine for Fill opacity and mode,
Crop delete, Selective Color method, Channel Mixer monochrome, Paint
Bucket contiguous and Gradient Map reverse/dither, but Photoshop plays
other missing keys differently: Canvas Size anchors top left (PhotoCraft:
centre), Apply Image blends Normal (Multiply), Color Balance turns
preserve luminosity off (on), and a Paint Bucket step without a
tolerance doesn't play at all. Those, and the unverified Hue/Saturation,
Color Balance tone and Save for Web keys, are written again as before.
- `tools.setColors` exported only the foreground of a step that sets
both colours; such a step now doesn't export (the strict save refuses
it, as before the PR).
- `kind` on an imported `layer.setAdjustment` made Photoshop's "reset to
default" (`set` with an empty `T`) a no-op merge; it now joins only
params that edit something.
- `cargo xtask corpus --atn` (and `--all`) failed on Windows: the Bjango
archive has a macOS `Icon\r` file tar can't create there; it's skipped.
- `test-corpus --changed` now runs for `atn_cmds` changes, and the
`ALL` doc comment is back on `ALL`.
Tests: defaults_photoshop_plays_differently_are_written,
set_colors_exports_only_a_single_colour and
adjustment_layer_reset_still_resets fail without this commit; the psd
and engine .atn corpus tests still pass (16 files byte-identical; 513
kept Photoshop steps).
Co-authored-by: Fabio Lissi <3223836+FabioLissi@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fill_to (Paint Bucket export): keep main's `source` alias and explicit
colour (`Usng` = `Clr ` plus `Clr `, #7199) together with the PR's
optional `Tlrn`/`AntA`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>