feat(release): parse_release returns (ParsedRelease, ParseReport)

Wire the scoring foundations into the parser entry point. parse_release
now returns a tuple — the structural ParsedRelease and a diagnostic
ParseReport carrying confidence (0-100), road
(EASY / SHITTY / PATH_OF_PAIN), the residual UNKNOWN tokens, and the
list of critical fields that couldn't be filled.

EASY is decided structurally (a group schema matched), independently
of the score. SHITTY vs PATH_OF_PAIN is decided by score against the
60 cutoff from scoring.yaml. Malformed names (forbidden chars) emit a
zero-confidence PoP report and short-circuit to parse_path=AI as
before.

ParsePath stays as-is (DIRECT / SANITIZED / AI) — it records *how* we
tokenized, not how confident we are. The two dimensions are now
properly separated.

Call sites propagated:
- alfred/application/filesystem/resolve_destination.py (4 occurrences)
- alfred/agent/tools/filesystem.py
- tests/domain/test_release.py
- tests/domain/test_release_fixtures.py
- tests/application/test_detect_media_type.py

New tests/domain/release/test_parser_v2_scoring.py (22 cases) locks
ParseReport validation, compute_score arithmetic, decide_road
thresholding, the collector helpers, and the end-to-end tuple contract.
This commit is contained in:
2026-05-20 01:21:30 +02:00
parent 98c688f29b
commit b4c9efd13b
7 changed files with 336 additions and 22 deletions
+6 -3
View File
@@ -28,11 +28,14 @@ _KB = YamlReleaseKnowledge()
def _parsed(media_type: str = "movie"):
"""Build a ParsedRelease with the requested media_type via the real parser."""
if media_type == "tv_show":
return parse_release("Show.S01E01.1080p-GRP", _KB)
parsed, _ = parse_release("Show.S01E01.1080p-GRP", _KB)
return parsed
if media_type == "movie":
return parse_release("Movie.2020.1080p-GRP", _KB)
parsed, _ = parse_release("Movie.2020.1080p-GRP", _KB)
return parsed
# "unknown" / other — feed a name the parser can't classify
return parse_release("randomthing", _KB)
parsed, _ = parse_release("randomthing", _KB)
return parsed
# --------------------------------------------------------------------------- #