Policy filter and verdict pipeline #54
Reference in New Issue
Block a user
Delete Branch "issue/10-policy-engine"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds the pure pre-grab/post-download policy pipeline in
arr-core.Rules preserve unknown evidence, classify failures inside the engine, and reduce hard failures before soft waivers. Resolution filtering,
only_4k, and the CAM/telesync/screener source filters are included. Parsed releases usearr-parseclaims directly; language, HDR, and scoring remain separate rule extensions.Closes #10
Verification
just ci(50 tests)arr-coredependency tree contains no axum, sqlx, or reqwestReviewed
ba180ec. Two behaviour findings on the pipeline, two smaller ones inline.Two remarks with no line to sit on:
Rule::ResolutionUnknownandRule::SourceUnknownare added toRule, which is the typeVerdictandMediaFile.waivername. Neither variant can ever reach either, since Unknown never decides a verdict. They only exist insideEvaluation.rules. A separate type for report entries would keepRulemeaning "a rule that decided something".pub use arr_parse::NameClaims as ParsedReleaseputsarr_parsetypes intoarr-core's public surface, soRelease.parsednow storesarr_parse::Resolution/Sourceand every consumer converts at each use, asCandidatedoes per call. Works, and it removes the duplicate struct; worth being deliberate about since it is the stored shape.@@ -112,5 +112,5 @@pub size_bands: BTreeMap<Resolution, SizeBand>,pub resolution_preference: Vec<Resolution>,pub source_weights: BTreeMap<Source, i32>,}HdrClaimhas no users left in the workspace afterParsedReleasebecame an alias forNameClaims, which carriesarr_parse::HdrMarkerinstead. Drop it, or leave it for the HDR rule issue knowing it now duplicatesHdrMarker.@@ -0,0 +104,4 @@/// Reduce an ordered set of policy rules to a verdict.////// The first hard failure decides rejection. If none exists, the first soft/// failure decides the waiver. Unknown evidence never becomes a pass.The doc says "Unknown evidence never becomes a pass", but a candidate where every rule is Unknown reduces to
Verdict::Eligible, which is the pass.missing_pre_grab_evidence_stays_unknownasserts exactly that.Pre-grab that is the right call. Post-download it is not: a
ProbedMediawithsource: NoneorSource::Othercomes backEligiblewith no waiver, so a caller onevaluate()cannot tell "passed every rule" from "had no evidence for any of them". Issue #10 asks for unknown rather than pass, and onlyevaluate_with_reportpreserves it.Either make post-download Unknown produce a waiver, or reword the doc to say Unknown abstains and the verdict alone does not carry it.
@@ -0,0 +144,4 @@&& (!context.overrides.only_4k || resolution == Resolution::R2160p);let outcome = if accepted {RuleOutcome::Pass} else if context.candidate.phase() == EvaluationPhase::PostDownload {A disallowed resolution post-download is SoftFail unconditionally, so every case imports with a waiver.
DESIGN §5.7 names one soft case: 1080p while
only_4kwas set. §5.6's whole premise is that names lie — grab a release claiming 2160p, ffprobe reports 480p, and this waives it and imports the file. That is a hard fail under §5.7 ("useless... blacklist the release, grab the next candidate"), not a waiver.Suggest splitting: soft when the resolution is in
policy.resolution_preferenceand onlyonly_4kexcluded it, hard when it is outside the root policy entirely.@@ -0,0 +422,4 @@Candidate::PostDownload(&media),);assert_eq!(report.rules[1].outcome, RuleOutcome::Unknown);The name says "not treated as a pass", but the assertion only checks
rules[1].outcome. The verdict here isVerdict::Eligibleand the test passes anyway. Assert the verdict too, so whatever is decided for the first finding is pinned by this test.Addressed in
3a303e2. Post-download resolutions outside the root policy now hard-fail; only anonly_4koverride mismatch is soft.evaluatenow returns the full report so unknown evidence cannot be discarded accidentally, and report-only rule identities no longer inhabitRule. The unusedHdrClaimtype is removed.Release.parseddeliberately remains the completearr_parse::NameClaimsshape. Converting it to the old core struct would discard title, year, codec, edition, group, and marker distinctions; conversion to probed domain values stays at rule evaluation.Verification
just ci— 50 tests passed.Reviewed
3a303e2. All four earlier findings are addressed: resolution now hard-fails post-download unlessonly_4kis the sole reason,RuleEvaluationcarries the concreteRuleonly where one exists,evaluatereturns the report so the verdict can no longer hide an Unknown, andHdrClaimis gone.One leftover inline.
@@ -0,0 +53,4 @@/// A rule's result before the pipeline reduces all results to one verdict.#[derive(Clone, Copy, Debug, Eq, PartialEq)]pub enum RuleOutcome {RuleOutcomeandRuleEvaluation::outcome()have no callers left after the refactor — reduction now matches onRuleEvaluationdirectly and the tests compare variants. Same shape as theHdrClaimleftover: drop both, or keep them knowing they are public API with no user yet.Reviewed
4e1876d. No findings.