Commit Graph
2769 Commits
Author SHA1 Message Date
David MannandClaude Opus 5.5 8ef5337c29 Measurement Scale: large pixel lengths print their real value (#7016) (#7017)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 03:06:59 -04:00
David MannandClaude Opus 5.5 13bbf0eefe Custom filter: in CMYK a positive offset brightens (#7076) (#7077)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 03:06:54 -04:00
David MannandClaude Opus 5.5 f3a9b81b1f Duotone: view and flat export clamp ink density like the Multichannel conversion (#6854) (#6855)
Duotone::render used the raw curve output, so ink curves above 100 % pushed the
simulated print out of gamut (red + blue at full density showed green instead of black).

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 03:06:49 -04:00
David MannandClaude Opus 5.5 7d166edb2a Lens Flare: don't darken 32-bit pixels above 1.0 (#5785) (#5786)
Screen as 1 - (1 - c)(1 - a) pulls a 32-bit value above white down
towards 1.0 (2.0 with a = 0.5 became 1.5, the core became 1.0). Add
a·max(1 - c, 0) instead: the same result for c <= 1, unchanged above.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 03:06:45 -04:00
David MannandClaude Opus 5.5 363d385114 Trap: refuse locked layers (#5623) (#5624)
Image > Trap wrote the active layer's pixels without checking locks, so a
layer under Lock All or the pixel lock (its own or its group's) was trapped
anyway. Check check_pixels_unlocked before writing, like the fill commands.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 03:06:40 -04:00
Korg1ch 36d6b669d4 test(engine): Content-Aware Fill with an empty sampling area is refused and changes nothing (#6532) 2026-10-18 09:46:18 +03:00
Korg1ch 0f12ac151f fix(engine): refuse a Content-Aware Fill with nothing to sample instead of filling black (#6532) 2026-10-18 09:19:41 +03:00
skylar taylor-barrick 3794e6fbbe Merge pull request #7118 from nicolasfalesy/perf/stack-mode-moments
perf(stack): one loop per statistic, up to 2.2× faster, bit for bit the same
2026-10-17 23:28:16 -06:00
Nicolas FalesyandClaude Opus 5.5 9ff27ec204 perf(stack): one loop per statistic, 1.3–2.2× faster on one thread
#6462 left Mean, Variance, Standard Deviation, Skewness and Kurtosis 5–15%
slower than the old serial loop on one thread. The cause: `stat` matched on
the mode three times per pixel inside one shared loop. `combine` now picks
the statistic once and hands `combine_with` a closure with a constant mode,
so each statistic gets its own loop with the match folded away. The sample
buffers are sized to the layer count and filled by index instead of `push`,
which re-checked the capacity per sample.

Every output is bit for bit the same (121 hashes match main).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUAqfMqVHdoeDa2y68KQQw
2026-10-18 06:54:53 +02:00
skylar taylor-barrick 2d0f3b61cf Merge pull request #2376 from Unemars/content-aware-workspace
Content-Aware Fill workspace, as Photoshop's
2026-10-17 22:50:54 -06:00
skylar taylor-barrick 8c30a41e06 Merge pull request #7126 from dotCooCoo/fix/stack-statistics-same-bits-on-windows
Stack Mode: Kurtosis and Skewness give the same bits on Windows and Linux
2026-10-17 21:08:12 -06:00
Michael HigginsandClaude Opus 5.5 4d9f163c61 Linux: Reveal never hands xdg-open a file (#7166) (#7168)
Reveal in Finder on Linux opens the linked file's parent with xdg-open,
which launches whatever it is given. A link stored as `tool.jar/a.png`
names a file as its parent, so Reveal launched that file. Reveal now
refuses a parent that is not a folder.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 20:53:59 -06:00
skylar taylor-barrick ceb85009c7 perf(canvas): a Properties-panel adjustment drag refreshes only the view (#6839) (#7155)
`damage_since` had a case for the Image > Adjustments dialog but none for the
Properties panel's `live_adjust` preview, so every parameter change returned no
damage and recomposited the whole document — `gpu-full` at 24.0 MP.

That is what made #5778 a latency regression at 100 % zoom: it correctly stops
CPU-compositing a 1.5 MP proxy, but the full-size GPU composite replacing it is
per-pixel work and 24 MP of it costs more. The Properties path now gets what the
dialog had: a session-tagged key, the layer's area as damage, and of that only
what the view shows, catching up as the view moves.

Intel UHD P630, 24 MP document, 12 changes, medians:

  v0.9.0    70.3 ms   1.5 MP CPU proxy
  main     203.1 ms   gpu-full, 24.0 MP
  this      47.8 ms   gpu-rect, 1.10 MP

Byte-identical to the full-refresh base on all 12 changes and across a pan.
25 % zoom and PHOTOCRAFT_CPU_COMPOSE are unchanged.

`live_region` does not narrow by the layer's mask: a reveal-all mask keeps its
coverage in the default pixel and reports empty content bounds, which emptied
the damage and froze the preview. Every adjustment layer has one.
2026-10-17 20:21:51 -06:00
Brandon ThomasandClaude Opus 5.5 8407d9ccb1 Release 0.10.0 (#7192)
* Release 0.10.0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Cargo.lock: photocraft-ipp at 0.10.0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
v0.10.0
2026-10-17 21:28:00 -04:00
UnemarsandClaude Fable 5.1 66c0e4ce13 Content-Aware Fill workspace: review follow-ups (#2376)
Testing on a 6000 × 4000 document found the proxy's sampling state computed
per pixel against every stroke segment: each stroke got slower, and an undo
tested 1.7 M pixels × 3000 segments on the UI thread, blocking it for over a
minute. The proxy is now painted as the engine paints the full-resolution
mask: the option's area and the fill area are sampled once at the proxy's
pixel centres (set_base), and each stroke is painted over them in order,
visiting only its own pixels (paint, restate_all), so a dab costs its segment
and a rebuild costs the strokes' areas.

Also from the same review:
- `edit.contentAwareFill {"ui": …}` with the workspace closed is an error
  instead of a fill with the defaults (an agent polling the state after an
  Esc added a fill per poll).
- The view sends one Down per press: the press is the stroke's first point
  and the frames before egui's drag threshold are its next ones, instead of
  drag_started() beginning the stroke over (the lasso lost its first points
  the same way; the Zoom tool zoomed on every frame the button was held).
- The preview texture is box-averaged to the device's max_texture_side when
  the plan's rectangle exceeds it (a 17000 px wide plan gave a validation
  error every frame).
- A preview that fails counts as shown for that state (Preview::finish), so
  it is reported once instead of restarting on every repaint.
- The view shows the document's visible layers composited (an Apply to a new
  layer shows); the engine's limits on strokes, lasso edits and points hold
  at the brush with a message instead of failing Apply; the footer is
  Photoshop's reset, OK, Apply, Cancel on every platform; a leftover
  `let _ = i;` is gone.

Tests: strokes painted once and equal to the engine's sampling area; `ui`
with the workspace closed; the first points of a stroke and a lasso through
egui_kittest; the preview texture at a 2048 limit; a failing preview
reported once; the view after Apply to a new layer; the limits at the brush.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-18 02:20:20 +02:00
skylar taylor-barrick ead6d2197f Package: report its paths with / on Windows too (#7184)
`file.package` absolutised the caller's `dir` and then built `folder`, `document`
and every `links` entry on it with `join`, which always writes `/`. On Windows
that left one string spelt both ways:
`C:\Users\...\pkg/Print Me/Links/art.png`. The control channel takes `/` and
rejects alternate separators, so a reported path could not be handed back to it.

Spell the absolutised directory with `/` as well, keeping a leading `\\`
(verbatim and UNC prefixes, where Win32 does not accept `/`) intact.
2026-10-17 19:20:33 -04:00
skylar taylor-barrick f8cd3e7982 chore: clear the rustc 1.96 clippy lint that fails CI
Unrelated to this branch's change; main already fails clippy --all-targets -- -D warnings
without it, which is what failed the Windows integration job here. One
clippy::nonminimal_bool site in canvas.rs, taking clippy's own rewrite: the
negation stays outside, so the is_finite guards and their NaN behaviour are
unchanged. A sweep of all 30 workspace members found no other site.
2026-10-17 17:08:37 -06:00
Diego Chagas 235e7578f3 Print through CUPS over IPP and the print portal, so File › Print works in the Flatpak (#2728) (#3017)
Main prints through craft-print, which runs `lp`; a Flatpak has no `lp`,
so File › Print fails there. This keeps craft-print as the route wherever
`lp` is on the path (and on Windows) and adds two more behind it:

- `photocraft-ipp`, a pure-Rust IPP client (CUPS-Get-Printers/Classes/
  Default, Print-Job over HTTP/1.1) that talks to CUPS over its socket or
  TCP; the Flatpak manifests grant --socket=cups for it. A `printServer`
  named in the request always takes this route. `file.print.printers`
  lists the queues.
- The XDG Print portal as the app's spooler (`Session::print_spooler`),
  for a sandbox without the CUPS socket or a system without a printer:
  the system print dialog, seeded with copies, paper and orientation.
  PHOTOCRAFT_PRINT_PORTAL=1 prefers it, =0 removes it.

A route that exists but fails (unknown printer, refused job) is an error;
only a missing route moves on. Results gain `backend` (lp, windows, ipp,
portal). docs/printing.md describes the routes.
2026-10-17 15:55:54 -06:00
Michael HigginsandClaude Opus 5.5 1d65bd605b Web: Place Embedded and canvas drops place images (#5749) (#5817)
* Web: Place Embedded and canvas drops place images (#5749)

File > Place Embedded was disabled in the browser (the engine command reads a
path), though the menu path reads the picked file's bytes. Files dropped on
the canvas were always opened as new documents. The web shell now tracks the
drag position, and drops on the canvas are placed from their bytes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Format (cargo fmt)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Narrow to the web canvas-drop half: Place Embedded enablement landed in #5585

Drop the picker test that covered the part #5585 now owns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:20:44 -07:00
skylar taylor-barrick 06ad0d5c95 Merge pull request #2863 from 1Git2Clone/ci-panic-hunt
CI: run panic_hunt in the Linux test job
2026-10-17 12:14:20 -06:00
skylar taylor-barrick 039b86f8f6 Merge pull request #7149 from skylartaylor/linked-path-checks
Follow linked paths only on this computer or the document's share
2026-10-17 12:13:47 -06:00
skylar taylor-barrick 482fd899cf Build: take craft-docpath from the merged craft-libs rev
craft-libs#169 is merged, so the fork pin is no longer needed. Pinned to
storytold/craft-libs 82a24b006eefa036b43c09a67fb9a3fbd17ffe63 (main after the merge) rather than the older 12281d07,
which predates resolve_absolute and the Windows colon refusal.
2026-10-17 12:02:56 -06:00
Gert Pellin - GPE ba40454b18 Logging: a second launch leaves the running instance's log alone (#6432) (#6478)
logging::rotate renamed photocraft.log up the chain on every start without
knowing whether another instance still wrote to it. The running instance
kept its handle, so after a second launch its live log was .1.log, after a
third .2.log, and a fourth launch deleted it.

The instance that writes photocraft.log now holds an exclusive lock on
photocraft.lock until it exits (a separate file, since Windows locks are
mandatory and would keep the log itself from being opened). A start that
finds that lock held leaves the chain alone and writes
photocraft-<pid>.log, marked by photocraft-<pid>.lock. Those side-by-side
logs are pruned to the newest KEEP once their instances have exited; a
held one is never touched. Rotation and pruning run under rotate.lock so
two starts at once can't interleave. On a file system without locks every
start rotates as before.
2026-10-17 11:57:39 -06:00
Khawar Zamman WaniandClaude Opus 5.5 378231214a Desktop app: photocraft --help prints usage; unknown options are usage errors (#6431) (#6435)
* fix(desktop): `photocraft --help` prints usage; unknown options are usage errors (#6431)

The desktop binary's argument loop took every argument it didn't know as
a file, so `photocraft --help`, `-h` or a typo such as `--safegpu`
opened the window and logged "Couldn't open --help".

- `--help` / `-h` print the usage (every option and environment
  variable) and exit 0.
- Any other argument starting with `-` (except macOS `-psn_`) is named
  on stderr and the launch exits 2 before the log file or window, along
  with any bad `--control` port (`control_args_exit_code` becomes
  `usage_exit_code`).
- `--` ends the options, so a file whose name starts with `-` opens.
- `--help` and `--version` write without `println!`, so a closed pipe
  (`photocraft --help | head -1`) can't panic.

Tests: apps/photocraft/tests/command_line_usage.rs runs the binary with
no display; 4 of its 6 tests fail on the old code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(desktop): usage tests exit before the window opens; fmt smart_filter_authorization

`arguments_after_double_dash_are_files` and `macos_process_serial_number_is_still_ignored`
passed only valid arguments, so the app went on to open its window. Removing DISPLAY makes
that fail fast on Linux, but Windows runners have a desktop and both tests hung until
nextest's 600 s timeout. They now add a bad `--control` value so the launch always fails
with the usage errors, and assert stderr names only that error (no "unknown option").

Also `cargo fmt` crates/automation/tests/smart_filter_authorization.rs, left unformatted
on main by #5684, which failed the Format step of every PR's ubuntu test job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:57:27 -06:00
ZuujisandClaude Opus 5.5 796ee3b103 Image Assets: two layers naming the same file no longer overwrite each other (#6614) (#6668)
* Image Assets: two layers naming the same file no longer overwrite each other (#6614) [WIP]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Image Assets: two layers naming the same file no longer overwrite each other (#6614)

generate_assets wrote every requested asset, so two layers (or two
default variants) naming one file silently replaced each other and the
result listed the file twice. Each file is now written once per run:
layers go top first, as the Layers panel lists them, the first writer
keeps the name, and later ones are reported in errors. Names are
compared ignoring case, since Logo.png and logo.png are one file on
Windows and macOS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:55:54 -06:00
David MannandClaude Opus 5.5 589941a536 Save: refuse to replace a read-only file (#6600) (#6643)
Saving writes a temporary file and renames it over the destination. A
rename only needs the folder to be writable, so on Linux and macOS a
read-only (chmod 444) file was silently replaced, while on Windows the
rename failed with a vague "locked or read-only" access error.

atomic_write now asks the AtomicFs whether the existing destination is
read-only (new `is_readonly`, false by default for other implementors)
and refuses before anything is written: "cannot save <file>: the file
is read-only; the original file was not changed". New files and
writable files save as before. Photoshop refuses the same way; the
user saves a copy with Save As.

Tests: a fake AtomicFs reporting read-only gets the error with nothing
written or renamed; a real file marked read-only keeps its bytes and
mode and gets the clear message on every platform.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 11:55:43 -06:00
David MannandClaude Opus 5.5 c9899e9c29 Duotone: ink curve points must be finite (#7049) (#7050)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:55:31 -06:00
Marco Arnulfo e196d8e47c Opening a file that is already open shows its tab instead of a second copy (fixes #6598) (#6630) 2026-10-17 11:53:21 -06:00
ZuujisandClaude Opus 5.5 1dcaa28b96 Quick Export: Same Folder asks before replacing the document's own file (#6599) (#6632)
With Export Preferences › Location = Same Folder, Quick Export wrote
<name>.<format> beside the document's file with no check, so a document
opened from photo.png was exported over photo.png itself. The app now
opens the save dialog for that case, and file.export.quickExport refuses
it without a `path`. Overwriting an earlier export beside a PSD is kept.

Adds file_cmds::same_file (text, dev+inode on Unix, case-insensitive
canonical path on Windows).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:53:10 -06:00
David MannandClaude Opus 5.5 193f495e5a Perspective Crop and Rotate Arbitrary keep the Background opaque (#7138)
Both filled the Background's uncovered area with the background colour
including its alpha (tools.setColors accepts one), leaving see-through
pixels on a Background. They now use alpha 1, as crop_doc does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 19:44:29 +02:00
Nicolas FalesyandClaude Opus 5.5 4b660fcffa perf(camera-raw): Shadows/Highlights 1.5× faster, bit for bit the same
The fast local Laplacian filter upsampled every remapped level in full for
every reference (up to 96), but each pixel reads that level for at most two
references. `llf` now samples it only where the weight is nonzero, with
`up_at` (same terms, same order as `up`; row taps found once per row,
`mirror` only near the edges). `quantile` selects its element instead of
sorting the whole work copy (5 sorts per render, serial).

36 MP dialog, all cores: Shadows 252 -> 168 ms, Highlights 275 -> 184 ms,
all 14 sliders 627 -> 411 ms. Output hashes match main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUAqfMqVHdoeDa2y68KQQw
2026-10-17 13:18:21 -04:00
skylar taylor-barrick 8c12449819 Save: keep the replaced file's metadata (#6603, #7073, #7094, #7095, #7096)
Saving writes a temporary file and renames it over the target, so everything
attached to the old file went with the file that was unlinked. Several of those
are security decisions, so a save quietly undid them: a download lost its Mark
of the Web, an explicit ACL fell back to whatever the folder hands down.

New crates/format/src/atomic/meta.rs, reached from atomic_write through two
AtomicFs methods (copy_permissions became copy_metadata; replace_existing is new
and defaults to rename, so the failure-injecting test file systems are
unchanged):

- Extended attributes (#6603): flistxattr/fgetxattr/fsetxattr through safe
  rustix, per attribute, best effort. macOS Finder tags, com.apple.quarantine
  (the Mark of the Web's macOS counterpart) and Linux user.* all ride along.
  Attributes the system owns refuse to be written and are skipped;
  com.apple.decmpfs is skipped deliberately, since it describes storage the new
  bytes do not have.
- macOS ACL (#7073): a new macOS-only exacl dependency (MIT).
  fcopyfile(COPYFILE_ACL) is an unsafe fn and fclonefileat(CLONE_ACL) is
  APFS-only and would mean writing every save as clone-then-truncate; the
  reasoning is in docs/decisions.md. A file with no ACL is left alone.
- Windows (#7094, #7096): ReplaceFileW through winsafe's kernel feature (MIT,
  no dependencies, a safe wrapper; the workspace forbids writing the FFI call
  here). One call keeps the destination's DACL, its named streams including
  Zone.Identifier, and its creation time.
- Automation write path (#7095): AuthorizedWorkspace::write copies the replaced
  file's attributes through the two cap-std descriptors, never a path, so a
  request path still cannot escape the write root. Permissions there remain
  #4963; ReplaceFileW is path-based and so is not used on that path.

The order inside copy_metadata matters: attributes and ACL first, permission
bits last. Writing an attribute needs the destination open for writing, so
copying a 0444 mode onto the temporary file first locks you out of your own
temporary file. Covered by a regression test.

Atomicity is not weakened. The metadata step runs on the temporary file before
the swap, never touches bytes, and never fails a save. Windows is the one place
the swap itself changed, and a backup file name is passed because it is a
correctness requirement, not an option: ReplaceFileW without one documents
ERROR_UNABLE_TO_MOVE_REPLACEMENT as leaving the replaced file deleted and the
replacement under its temporary name, which is a failed save that loses the
user's document. With a backup name the same failure leaves both files alone.
ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, the one error that does move things, is
unwound by hand; every other error falls back to the plain rename, i.e. to the
previous behaviour.

THE WINDOWS PATHS ARE UNVERIFIED ON WINDOWS. They were written and reviewed on
a Mac. The #[cfg(windows)] tests -- Zone.Identifier, a second named stream,
icacls output, creation time -- have never executed. They do compile and pass
clippy -D warnings against x86_64-pc-windows-msvc, which is as far as a Mac
gets. CI's Windows job is the first real run, and #7094 in particular (Mark of
the Web surviving a replace) is the whole point of the change and is the part
no one has observed working.

Tested on macOS: a real chmod +a entry and a real Finder tag both survive a
save (checked with ls -le and xattr, and as unit tests), plus a 64 KiB
attribute value, a read-only file, the mode, and the automation path.

Still open: Linux POSIX ACLs are not carried over (system.posix_acl_access is
not reported by listxattr, so it needs its own step; not part of these issues),
and macOS creation time is still reset by a save (that half of #6603 needs
setattrlist, which has no safe wrapper here).
2026-10-17 10:43:09 -06:00
David MannandClaude Opus 5.5 b6f18820c6 Merge main into fix/pcraft-load-nonfinite
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 18:26:31 +02:00
David MannandClaude Opus 5.5 e30cedbb2a Merge main into fix/transform-fill-cache
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 18:24:17 +02:00
David MannandClaude Opus 5.5 cdf7f2c7fe Merge main into fix/gradient-offset-resize
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 18:13:04 +02:00
itsF4LCON 3bca0123b0 Type: the blink-phase test finds the caret by its strokes
arrow_keys_reset_caret_blink_phase (#5512) looked for a 1.5-wide line, the old caret. The caret is now CARET_STROKES (a 3 pt white halo and a 1 pt black line), so the test matches those.
2026-10-17 18:12:29 +02:00
itsF4LCON 6d521c2d3e Merge remote-tracking branch 'upstream/main' into fix/6085-text-caret-contrast 2026-10-17 18:04:21 +02:00
dotCooCoo 074d4b08b6 Stack Mode: Kurtosis and Skewness give the same bits on Windows and Linux
`stat` raised each deviation from the mean to a power with `f32::powi`,
with the exponent passed through the moment closure. On
x86_64-pc-windows-msvc that call goes to the C runtime's `powf`, whose
cubes and fourth powers can differ from repeated multiplication in the
last bit. On Linux the same call gives the bits of repeated squaring, as
compiler-builtins' `__powisf2` computes it. Kurtosis
came out one ULP higher on Windows in two values of the test fixture, and
`stack::tests::statistics_are_bit_identical_to_the_serial_implementation`
failed there.

The moments and Skewness's `sd³` now use `ipow`, which multiplies by
repeated squaring: `x·x²` for the cube and `x²·x²` for the fourth power.
Results on Linux do not change, and the recorded bits stay as they are.
2026-10-17 08:58:44 -07:00
IvanandClaude Opus 5.5 a4fe4ffbed Contributors: add 1Git2Clone
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 18:37:13 +03:00
IvanandClaude Opus 5.5 45afd2e9d7 CI: run panic_hunt in the Linux test job
The full-registry fuzz (AGENTS.md Rule 9) is #[ignore]d and no workflow ran it, so nothing
enforced "must stay green". The new step reruns the Test step's nextest selection with
--run-ignored only, filtered to the panic_hunt binary, so nothing rebuilds; the ci profile
terminates it if it hangs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 18:37:12 +03:00
David MannandClaude Opus 5.5 3096e456dd Merge main into fix/preset-group-rename-unique
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 17:24:08 +02:00
David Mann dc71c6440c Merge origin/main into fix/gif-delay-below-1fps 2026-10-17 17:00:12 +02:00
David Mann f8c7955699 Merge origin/main into fix/artboards-to-files-marks 2026-10-17 16:59:38 +02:00
Hamza Naveed efa1edd079 algo: gate the recorded-hash test's helpers with the test (#7053)
`blocks` and `fnv` exist only for `harris_and_describe_hashes_recorded_from_the
_serial_code`, which is `#[cfg(all(target_os = "linux", target_arch =
"x86_64"))]` because the hashes it compares against go through the platform's
hypot / ln / cos / atan2 / sin_cos. Everywhere else the test is compiled out and
the two helpers are left unused, so `-D warnings` fails on `dead_code`:

    error: function `blocks` is never used   crates/algo/src/features.rs:704
    error: function `fnv` is never used      crates/algo/src/features.rs:708

They now carry the same cfg as the only thing that calls them.

CI's matrix is ubuntu-latest and windows-latest and runs clippy on both, so this
fails the Windows leg as much as a local run on macOS: `target_os = "linux"` is
false for both.
2026-10-17 08:39:15 -06:00
Josephand00xJ0 351149f0df Fix the build: restore export_presets in load_presets_json (#5344 x #5616) (#6906)
#5344 added the export_presets field to Persisted; #5616 rewrote load_presets_json to read each set with take() and its Persisted initializer lacked the new field, so main stopped compiling (E0063 at presets/mod.rs:180). Read export_presets the same way as the other sets; the existing load step and round-trip test cover it.

Co-authored-by: 00xJ0 <56056764+00xJ0@users.noreply.github.com>
2026-10-17 08:32:54 -06:00
David MannandClaude Opus 5.5 7ebaa94a82 Render Video: GIF frame delay follows timelines under 1 fps (#7045)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 15:44:43 +02:00
David MannandClaude Opus 5.5 fd2c10bba8 Artboards to Files: paths, notes, slices and marks move with the board (#7010)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 15:12:17 +02:00
NetterSilver 158dcc6731 Fix engine compile error: load export presets from presets JSON
Fixes #6911

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
(cherry picked from commit bb7a5f2309)
2026-10-17 13:34:00 +03:00
PerchAnton 120cfe19a2 Merge origin/main into fix/finite-command-parameters
Resolve Color to Alpha validation conflict while preserving the upstream array guards and finite color parsing.
2026-10-17 13:34:00 +03:00
itsF4LCON 85aa10b16d Merge remote-tracking branch 'upstream/main' into fix/6085-text-caret-contrast 2026-10-17 11:01:10 +02:00