Files
dl-organizer/docs/TECHNICAL_REVIEW.md
T

7.7 KiB
Raw Blame History

Technical review: video-library-manager

Metadata

Field Value
Repository path dl-organizer (package vlm)
Verification date (UTC) 2026-04-06
Git revision verified ea21e15
Test run uv run pytest -q496 passed

Scope

  • Source: src/vlm/**/*.py, tests/
  • Config: pyproject.toml
  • Assumption: single-user local library; artifacts semi-trusted; no formal threat model in repo.

Executive summary

Architecture and tests are solid. Verified gaps: no library_root check on move/rename source in executor; by_quality falls back to index 0 without surfacing reason; quarantine raises ValueError for unsupported category while execute_plan has no per-operation try/except, so one bad op can abort the run; duplicate join uses exact string path keys; find non-zero exit still consumes stdout.

Weighted score (010): 8.0.

Score rubric

Criterion Score Notes
Module boundaries / pipeline 8.5 Commands → domain modules; scan→parse→analyze→plan→execute is explicit.
Execution safety (filesystem) 7.0 Destination under root checked; source not checked for move/rename.
Planning / duplicate logic 7.5 Multiple strategies; string path identity; silent by_quality fallback; unknown strategy → keep index 0 (duplicate_resolve.py:48).
Data I/O & validation 8.0 io.py validates identities/analysis/plan shapes; validated objects remain dict-typed at boundaries (type: ignore in places).
Error handling consistency 7.5 Quarantine: raise vs OperationResult mismatch on category rejection.
Test signal 8.5 Broad tests/; path safety and resolver covered (test_path_safety.py, test_duplicate_resolve.py, etc.).
Dependencies 9.0 Runtime: click, pyyaml only (pyproject.toml:79).

Findings

F1 [High] Move/rename: source not constrained to library_root

Evidence: ExecutionEngine._perform_operation checks destination with is_within_root(..., self.config.library_root) then calls operation.source_path.rename(...) without checking the source (executor.py:354377).

Impact: Malformed or hand-edited plan.json can rename from any path the process can access into the library tree. QuarantineManager.quarantine_file instead requires file_path.relative_to(self.config.library_root) (quarantine.py:133137).

Recommendation: For move / rename, require is_within_root(operation.source_path, self.config.library_root) (after Path resolution policy is defined). Fail with OperationResult(success=False). Optional config gate for deliberate “import from outside,” default off. Add test alongside tests/test_path_safety.py:76103.


F2 [Medium] by_quality: silent fallback to first item

Evidence: choose_keep_indexif quality_comparison is None or len(quality_comparison) != len(items): return 0 (duplicate_resolve.py:4042).

Impact: Behavior equals input order, not quality, with no structured flag in plan metadata from this function alone.

Recommendation: Return None and skip auto-quarantine for that group, or require CLI/plan failure when duplicate_keep == by_quality and rows misaligned, or write explicit metadata / summary line when fallback occurs.


F3 [Medium] Duplicate group ↔ identities join: exact path strings

Evidence: path_to_index = {str(vf.path): i for ...} and indices = [path_to_index[p] for p in paths if p in path_to_index] (planner.py:108111). Analysis files must match str(VideoFile.path) byte-for-byte.

Impact: Symlinks, differing normalization between analysis writer and identities loader, or OS case rules can drop files from duplicate resolution.

Recommendation: Normalize keys (e.g. utils.canonical_path_str) at both analysis emission and plan consumption; document contract; regression test if symlinks are in scope.


F4 [LowMedium] Quarantine: ValueError vs OperationResult

Evidence: Unsupported category path does raise ValueError(error_msg) after logging (quarantine.py:116129). Other failure modes return OperationResult.

Evidence: execute_plan loop calls execute_operation with no try/except (executor.py:110112).

Impact: One invalid quarantine operation (e.g. manual plan) can abort the whole execute pass instead of recording a single failed result.

Recommendation: Return failed OperationResult for unsupported category; reserve exceptions for invariant violations only.


F5 [Low] find non-zero exit: stdout still parsed

Evidence: On process.returncode != 0, code logs stderr if present, then always parses stdout into paths (scanner.py:178192).

Impact: Partial or stale listing possible without hard failure.

Recommendation: Document behavior; optionally fail if returncode != 0 and empty result, or add --strict-scan.


F6 [Low] Optional dependencies: textual in both dev and tui

Evidence: pyproject.toml:1316 (dev), 1819 (tui).

Impact: Install surface ambiguity only.

Recommendation: Document that dev includes Textual for TUI-related tests, or slim dev if CI wants fewer deps.


F7 [Informational] Validated JSON remains dict-typed at I/O edge

Evidence: validate_plan_json returns dict (io.py:224251); constructors may still bridge dict ↔ dataclass elsewhere.

Impact: Field drift between validator and models.py possible over time.

Recommendation: Single factory path: validated dict → domain objects for hot paths.


F8 [Informational] Unknown duplicate_keep strategy string

Evidence: After strategy checks, choose_keep_index falls through to return 0 (duplicate_resolve.py:48).

Impact: Config typo keeps first duplicate like first_seen without failing load.

Recommendation: Validate duplicate_keep in config.py / validate_config against an allowlist; reject unknown values.

Verified strengths

Claim Evidence
find invoked without shell string argv list: subprocess.Popen(command, ...) (scanner.py:171172, 164169).
Path component sanitization sanitize_path_component strips controls and separators (utils.py:6575); planner uses it before templates (planner.py:301, 419).
Destination under library in planner is_within_root(destination, config.library_root) (planner.py:321, 440).
Quarantine manifest two-phase Pending manifest write before rename (quarantine.py:221268 region).
JSON artifact validation _validate_parsed_identities_json, _validate_analysis_json, validate_plan_json (io.py:157251).
Parallel ffprobe ThreadPoolExecutor when include_video_metadata and more than one path (scanner.py:85101).

Priority order

  1. F1
  2. F2
  3. F4
  4. F3
  5. F8, F5, F6, F7

Verification log (document vs codebase)

Statement in this doc Checked against
F1 source not under root guard executor.py:321377
F2 by_quality fallback duplicate_resolve.py:4043
F3 path_to_index planner.py:108111
F4 raise + no try in loop quarantine.py:116129, executor.py:110112
F5 find returncode scanner.py:178192
F6 pyproject optional pyproject.toml:1220
F7 validate_plan_json returns dict io.py:224251
F8 unknown strategy duplicate_resolve.py:3648
Strengths table scanner.py, utils.py, planner.py, quarantine.py, io.py as cited
496 tests passed uv run pytest -q on 2026-04-06

This document is evidence-based against the paths above; behavior not re-listed here is not claimed verified.