{ "source": "fresh GitHub GraphQL and REST reads", "captured_at": "2026-10-29T02:24:09.464811+00:00", "count": 108, "prs": [ { "number": 9703, "title": "Fix adjustment layer name clicks targeting masks", "url": "https://github.com/storytold/photocraft/pull/9703", "body": "Fixes #9694\n\nClicking an adjustment layer's name now selects its contents instead of its mask, including when that same layer's pixel or vector mask was previously selected. Explicit mask-thumbnail clicks and new-layer creation keep their existing behavior. Fill-layer row targeting and rasterization prompts, and ordinary raster-layer row behavior, are unchanged.\n\nRegression coverage uses actual native UI clicks at 1x and 2x, checks the selected content-thumbnail brackets, and preserves the existing #3369 Properties/creation regression. The new regression fails on the base revision and passes with this fix. An actual Fill-black regression verifies that adjustment content is preserved and only its mask changes. Pixel painting on adjustment layers retains its existing mask fallback.\n\nValidation:\n- 29 mask-thumbnail tests pass; independent code review found no blocker.\n- Strict all-target UI Clippy, formatting, layering, and WebAssembly checks pass.\n- Full UI library run: 4,013 passed, 26 failed, 18 ignored. Integration: 132 passed, 1 failed, 1 ignored. All 27 failures are missing-glyph panics in egui 0.37 with the fonts available in this local build; the full suite is not green. Doctests pass (0 tests).\n- Native macOS offscreen screenshots rendered and visually inspected. Windows/Linux UI has not been manually tested.\n\nBefore (mask thumbnail selected after clicking the name):\n\n![Before](https://raw.githubusercontent.com/vanvo/photocraft/d879000b88edd76743a7774a0517b5bcd2e63ebd/before.png)\n\nAfter (content thumbnail selected after the same click):\n\n![After](https://raw.githubusercontent.com/vanvo/photocraft/d879000b88edd76743a7774a0517b5bcd2e63ebd/after.png)\n\n[Image attribution and licenses](https://raw.githubusercontent.com/vanvo/photocraft/d879000b88edd76743a7774a0517b5bcd2e63ebd/ATTRIBUTION.md)", "state": "OPEN", "isDraft": false, "merged": false, "headRefOid": "3605d30c38294c4d970e52f4a02f44f97e8bc1a9", "baseRefName": "main", "files": { "nodes": [ { "path": "crates/ui-egui/src/mask_thumbs_ui/tests.rs" }, { "path": "crates/ui-egui/src/panels.rs" } ], "pageInfo": { "hasNextPage": false } }, "commits": { "nodes": [ { "commit": { "statusCheckRollup": { "state": "SUCCESS", "contexts": { "nodes": [ { "name": "select platforms", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095607/job/121682358085" }, { "name": "sonarcloud / Plan coverage shards", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095888/job/121681757819" }, { "name": "sonarcloud / Build instrumented test archive", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095888/job/121681861941" }, { "name": "gate / gate (ubuntu-24.04)", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095607/job/121682358927" }, { "name": "sonarcloud / Tests ${{ matrix.shard }}/${{ inputs.shards }}", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095888/job/121681862838" }, { "name": "test (without heif)", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095607/job/121682358648" }, { "name": "corpus tests", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095607/job/121682359068" }, { "name": "sonarcloud / SonarCloud Scan", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095888/job/121681860253" }, { "name": "fuzz (${{ matrix.target.crate }}/${{ matrix.target.name }})", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095607/job/121682361404" }, { "name": "test (windows-latest, unit)", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095607/job/121682729957" }, { "name": "test (windows-latest, integration)", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095607/job/121682729898" }, { "name": "web build and wasm size gate", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40354095607/job/121682729794" }, { "context": "CodeRabbit", "state": "SUCCESS", "targetUrl": null } ], "pageInfo": { "hasNextPage": false } } } } } ] }, "approval": { "state": "APPROVED", "submittedAt": "2026-10-26T17:06:00Z", "url": "https://github.com/storytold/photocraft/pull/9703#pullrequestreview-5655990760", "body": "Reviewed at SHA 3605d30.\n\nFixes #9694: clicking an adjustment layer's name in the Layers panel now selects its content, not its mask (`ui.maskTarget` false), including when that layer's pixel or vector mask was selected before. In `layer_row` the old `content_less` rule (adjustment and fill rows default to the mask) is split: fills with a mask keep the mask default; adjustments take the `maskTarget false` branch (`on_thumb || adjustment || !row.primary`). Clicking a mask thumbnail still targets that mask, the vector mask thumbnail still targets the vector mask, and creating a layer keeps its existing behaviour.\n\nChecked: the whole `panels.rs` change (the branch order is unchanged, only the conditions); the edited expectation in the existing #3369 test (fill rows still target the mask, adjustments do not, no vector mask target); the new test across two adjustment kinds at 1x and 2x: mask thumbnail clicks, name click after each, bracket on the content thumbnail, another-layer-then-name, `paint_target` still \"mask\", and Fill black editing the mask and not the adjustment content.\nNote: this is a deliberate behaviour change for adjustment rows, whereas fill rows keep the old default; it is covered by the tests and matches the issue, but it is a product choice I did not check against the other app.\nNot verified: I did not run the tests; the author reports 29 mask-thumbnail tests passing and a local failure set of font-glyph panics that predates this change, which I did not reproduce.\n", "commit": { "oid": "3605d30c38294c4d970e52f4a02f44f97e8bc1a9" }, "author": { "login": "FredApps" } }, "manual_status": "NOT RUN", "subsystem": "UI and workflow", "new_test_names": [ "adjustment_names_target_contents_instead_of_masks" ], "regression_source": "https://github.com/storytold/photocraft/pull/9703" }, { "number": 9651, "title": "perf(algo): row-parallel local_sharpen with fast-path protect_detail (#5426)", "url": "https://github.com/storytold/photocraft/pull/9651", "body": "Refs #5426. Follow-up to #5499.\n\n## Problem\n\n#5499 parallelized `local_blur` and the per-dab mix in `DabTool::Focus`, but `local_sharpen` (`crates/algo/src/retouch.rs`) stayed single-threaded. `protect_detail` also recomputed boundary clamping and strided lookups for the 8-neighbour window inside the per-channel loop, for every pixel in the dab. With large brushes (500–2500 px) interactive strokes lagged badly and stalled the application.\n\n## Change\n\n- `local_sharpen` processes window rows in parallel (`out.par_chunks_mut(stride)`), with a `wasm32` serial fallback like `local_blur`.\n- `protect_detail` computes the 3×3 neighbourhood offsets once, outside the channel loop.\n- Interior pixels (`x > 0 && x + 1 < w && y > 0 && y + 1 < h`) use direct stride offsets and skip boundary clamping, which covers over 99.9% of pixels in large dabs.\n- New `retouch_sharpen_exact` integration test compares against the frozen scalar oracle bit for bit across layouts, edges and channels.\n- New `bench_sharpen_tool` example, matching `bench_blur_tool`.\n\n## Timings\n\nGitHub Actions `rc-bench`, 4 vCPU AMD EPYC 9V45. Output is bit-identical at every size (fingerprint `96d1f22de93b16ec` at 8-bit, `9282e5cfc9e3ec48` at 16-bit).\n\n| Depth | Brush | Before | After | Less time |\n| --- | ---: | ---: | ---: | ---: |\n| 8-bit | 100 px | 40.75 ms | 27.37 ms | 33% |\n| 8-bit | 500 px | 214.14 ms | 153.37 ms | 28% |\n| 8-bit | 1000 px | 738.67 ms | 571.52 ms | 23% |\n| 16-bit | 100 px | 39.94 ms | 27.42 ms | 31% |\n| 16-bit | 500 px | 196.86 ms | 134.26 ms | 32% |\n| 16-bit | 1000 px | 597.21 ms | 447.68 ms | 25% |\n\n## Tests\n\n- `cargo test -p photocraft-algo --test it -- retouch_sharpen_exact` (2 passed)\n- Bit-identical fingerprints between base and this PR at every depth and size.\n- Wasm size gate and clean `cargo clippy`.", "state": "OPEN", "isDraft": false, "merged": false, "headRefOid": "67666bdf72a58066df868868cef82e5b9cc838de", "baseRefName": "main", "files": { "nodes": [ { "path": "crates/algo/src/retouch.rs" }, { "path": "crates/algo/tests/it/main.rs" }, { "path": "crates/algo/tests/it/retouch_sharpen_exact.rs" }, { "path": "crates/engine/examples/bench_sharpen_tool.rs" } ], "pageInfo": { "hasNextPage": false } }, "commits": { "nodes": [ { "commit": { "statusCheckRollup": { "state": "SUCCESS", "contexts": { "nodes": [ { "name": "select platforms", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40562083384/job/122393509820" }, { "name": "select platforms", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40304685201/job/121510766804" }, { "name": "sonarcloud / Plan coverage shards", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40304685377/job/121510767326" }, { "name": "gate", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40562083384/job/122393597582" }, { "name": "sonarcloud / Build instrumented test archive", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40304685377/job/121510848043" }, { "name": "gate / gate (ubuntu-24.04)", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40304685201/job/121510766978" }, { "name": "test (without heif)", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40562083384/job/122393508322" }, { "name": "sonarcloud / Tests ${{ matrix.shard }}/${{ inputs.shards }}", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40304685377/job/121510849890" }, { "name": "test (without heif)", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40304685201/job/121510766972" }, { "name": "corpus tests", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40562083384/job/122393560877" }, { "name": "corpus tests", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40304685201/job/121510766515" }, { "name": "sonarcloud / SonarCloud Scan", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40304685377/job/121510847640" }, { "name": "fuzz (${{ matrix.target.crate }}/${{ matrix.target.name }})", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40304685201/job/121510769284" }, { "name": "fuzz (${{ matrix.target.crate }}/${{ matrix.target.name }})", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40562083384/job/122393509224" }, { "name": "selection-morphology", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40562083384/job/122393564915" }, { "name": "test (windows-latest, ${{ matrix.part }})", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40304685201/job/121510958391" }, { "name": "selection-morphology-quick-perf", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40562083384/job/122393558240" }, { "name": "web build and wasm size gate", "status": "COMPLETED", "conclusion": "SUCCESS", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40304685201/job/121510956808" }, { "name": "test (windows-latest, ${{ matrix.part }})", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40562083384/job/122393511108" }, { "name": "web build and wasm size gate", "status": "COMPLETED", "conclusion": "SKIPPED", "detailsUrl": "https://github.com/storytold/photocraft/actions/runs/40562083384/job/122393511236" }, { "context": "CodeRabbit", "state": "SUCCESS", "targetUrl": null } ], "pageInfo": { "hasNextPage": false } } } } } ] }, "approval": { "state": "APPROVED", "submittedAt": "2026-10-26T11:38:57Z", "url": "https://github.com/storytold/photocraft/pull/9651#pullrequestreview-5651366614", "body": "Reviewed at SHA 67666bd.\n\nWhat it does: `local_sharpen` in `algo/src/retouch.rs` is now row-parallel with rayon (a sequential `chunks_mut` on wasm32). For `protect_detail` it computes the 3x3 neighbour offsets once per pixel, using a branch-free fast path for interior pixels and the old clamped lookup at the edges. An empty window or zero channels returns an empty Vec early (#5426).\n\nChecked: each output row is a disjoint `stride = ow*ch` chunk, so the rows are independent. The interior test (`x>0 && x+10 && y+1