From 3466a597352bf277fe5f11d4d47e2dde967aab20 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 2 Jul 2026 17:37:09 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/bolt.md | 3 +++ media_shrinker.py | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 63607c3..4aafd40 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -60,3 +60,6 @@ ## 2026-06-25 - [Optimize Path.exists() when paired with stat()] **Learning:** Checking `Path.exists()` before `Path.stat()` introduces a redundant system call because `exists()` internally uses `stat()`. **Action:** Rely on catching the `OSError` from `Path.stat()` to simultaneously check for existence and retrieve file attributes, saving measurable I/O overhead on large filesystems. +## 2024-07-02 - [Avoid pathlib.Path.resolve() in performance critical paths] +**Learning:** `pathlib.Path.resolve()` is significantly slower than `os.path.realpath()` because it instantiates a new `Path` object and resolves symlinks explicitly. In tight loops or batch processing involving thousands of files, this overhead is noticeable. +**Action:** Use `os.path.realpath(path_str)` directly instead of `pathlib.Path(path_str).resolve()` when performance is a priority and you only need the resolved path string. Convert to a `Path` object only when necessary. diff --git a/media_shrinker.py b/media_shrinker.py index 7f38dd7..0dee447 100644 --- a/media_shrinker.py +++ b/media_shrinker.py @@ -193,7 +193,7 @@ def find_candidates( """ root = Path(root) - excluded = tuple(Path(item).resolve() for item in exclude_paths) + excluded = tuple(Path(os.path.realpath(item)) for item in exclude_paths) excluded_prefixes = tuple(prefix.casefold() for prefix in exclude_dir_prefixes) candidates: list[tuple[Path, int]] = [] @@ -755,7 +755,7 @@ def convert_file( resolved_sources = resolved_protected_sources if resolved_sources is None: - resolved_sources = frozenset(Path(item).resolve() for item in protected_sources) + resolved_sources = frozenset(Path(os.path.realpath(item)) for item in protected_sources) return [ _convert_segment( @@ -1257,7 +1257,7 @@ def _execute_conversions( workers = choose_worker_count(args.workers) ffmpeg_threads = args.ffmpeg_threads if args.ffmpeg_threads >= 0 else None - resolved_candidates = frozenset(Path(item[0]).resolve() for item in candidates) + resolved_candidates = frozenset(Path(os.path.realpath(item[0])) for item in candidates) protected_sources = [c[0] for c in candidates] def process_candidate(candidate_tuple: tuple[Path, int]) -> list[ConversionResult]: @@ -1413,7 +1413,7 @@ def _ensure_not_protected_source_path( protected_sources: frozenset[Path], output: Path ) -> None: """Raise MediaShrinkerError if output would overwrite a protected source.""" - resolved_output = output.resolve() + resolved_output = Path(os.path.realpath(output)) if resolved_output in protected_sources: raise MediaShrinkerError( f"Refusing to use protected source path as generated output: {output}" @@ -1609,7 +1609,7 @@ def _execute_plan( def _ensure_not_source_path(source: Path, output: Path) -> None: """Reject generated paths that would overwrite or delete the source file.""" - if source.resolve() == output.resolve(): + if os.path.realpath(source) == os.path.realpath(output): raise MediaShrinkerError( f"Refusing to use source path as generated output: {output}" ) From 3ea9808082cf32043ae41a1b7a766eca1b7bacec Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 2 Jul 2026 23:19:19 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0]?= =?UTF-8?q?=20-=20Fix=20review=20feedbacks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/bolt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 4aafd40..3c3f76a 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -60,6 +60,6 @@ ## 2026-06-25 - [Optimize Path.exists() when paired with stat()] **Learning:** Checking `Path.exists()` before `Path.stat()` introduces a redundant system call because `exists()` internally uses `stat()`. **Action:** Rely on catching the `OSError` from `Path.stat()` to simultaneously check for existence and retrieve file attributes, saving measurable I/O overhead on large filesystems. -## 2024-07-02 - [Avoid pathlib.Path.resolve() in performance critical paths] +## 2026-07-02 - [Avoid pathlib.Path.resolve() in performance critical paths] **Learning:** `pathlib.Path.resolve()` is significantly slower than `os.path.realpath()` because it instantiates a new `Path` object and resolves symlinks explicitly. In tight loops or batch processing involving thousands of files, this overhead is noticeable. **Action:** Use `os.path.realpath(path_str)` directly instead of `pathlib.Path(path_str).resolve()` when performance is a priority and you only need the resolved path string. Convert to a `Path` object only when necessary. From c0822cbd855e2c29232acb5025b21d22a6e2978a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 7 Jul 2026 11:04:45 +0900 Subject: [PATCH 3/5] chore: re-trigger CI to run CodeQL (ruleset code_scanning requirement) Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CJRVbDrp1vGYkJgNHMGPpG From 31311eb523f4f5e11384333b73228358963056d6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 7 Jul 2026 13:50:01 +0900 Subject: [PATCH 4/5] chore: re-trigger required workflows (single, uncontended) Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CJRVbDrp1vGYkJgNHMGPpG From 40474aacf74505f2e860b69f070c990de757ebd5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 7 Jul 2026 15:25:47 +0900 Subject: [PATCH 5/5] chore: re-trigger workflows (opencode-review hung on prior head) Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CJRVbDrp1vGYkJgNHMGPpG