feat: let a size rejection be waived

A release below §5.5's floor was rejected with no way through, so a
policy wrong about one title left three Rick and Morty S09 packs
visible and none grabbable.

`allow_below_floor` relaxes the floor for one title into a soft fail,
never a pass: the release is waived, so automatic grabbing still skips
it and the import records a §5.7 waiver. The deck offers the one click
on a rejected row where the rule has an override, which is exactly what
§9.3's override is for.

Stored verdicts are re-derived when a title's overrides change — the
deck and the daemon's grab gate both read that column, so without it
the row the operator just acted on would keep reading `rejected`.

Closes #210

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Miguel Palhas
2026-08-24 22:15:14 +01:00
co-authored by Claude Opus 5
parent 405358bf24
commit 9fee07f080
16 changed files with 1098 additions and 20 deletions
@@ -0,0 +1,182 @@
{
"db_name": "SQLite",
"query": "\n SELECT s.overrides AS \"overrides!: String\",\n r.id AS \"root_id!: i64\",\n r.kind AS \"root_kind!: String\",\n r.audience AS \"root_audience!: String\",\n r.path AS \"root_path!: String\",\n p.id AS \"policy_id!: i64\",\n p.name AS \"policy_name!: String\",\n p.required_audio AS \"required_audio!: String\",\n p.dub_blacklist AS \"dub_blacklist!: String\",\n p.hdr_rules AS \"hdr_rules!: String\",\n p.size_bands AS \"size_bands!: String\",\n p.resolution_pref AS \"resolution_pref!: String\",\n p.source_weights AS \"source_weights!: String\",\n p.score_weights AS \"score_weights!: String\"\n FROM series s\n JOIN roots r ON r.id = s.root_id\n JOIN policies p ON p.id = r.policy_id\n WHERE s.id = ?\n ",
"describe": {
"columns": [
{
"name": "overrides!: String",
"ordinal": 0,
"type_info": "Text",
"origin": {
"Table": {
"table": "series",
"name": "overrides"
}
}
},
{
"name": "root_id!: i64",
"ordinal": 1,
"type_info": "Integer",
"origin": {
"Table": {
"table": "roots",
"name": "id"
}
}
},
{
"name": "root_kind!: String",
"ordinal": 2,
"type_info": "Text",
"origin": {
"Table": {
"table": "roots",
"name": "kind"
}
}
},
{
"name": "root_audience!: String",
"ordinal": 3,
"type_info": "Text",
"origin": {
"Table": {
"table": "roots",
"name": "audience"
}
}
},
{
"name": "root_path!: String",
"ordinal": 4,
"type_info": "Text",
"origin": {
"Table": {
"table": "roots",
"name": "path"
}
}
},
{
"name": "policy_id!: i64",
"ordinal": 5,
"type_info": "Integer",
"origin": {
"Table": {
"table": "policies",
"name": "id"
}
}
},
{
"name": "policy_name!: String",
"ordinal": 6,
"type_info": "Text",
"origin": {
"Table": {
"table": "policies",
"name": "name"
}
}
},
{
"name": "required_audio!: String",
"ordinal": 7,
"type_info": "Text",
"origin": {
"Table": {
"table": "policies",
"name": "required_audio"
}
}
},
{
"name": "dub_blacklist!: String",
"ordinal": 8,
"type_info": "Text",
"origin": {
"Table": {
"table": "policies",
"name": "dub_blacklist"
}
}
},
{
"name": "hdr_rules!: String",
"ordinal": 9,
"type_info": "Text",
"origin": {
"Table": {
"table": "policies",
"name": "hdr_rules"
}
}
},
{
"name": "size_bands!: String",
"ordinal": 10,
"type_info": "Text",
"origin": {
"Table": {
"table": "policies",
"name": "size_bands"
}
}
},
{
"name": "resolution_pref!: String",
"ordinal": 11,
"type_info": "Text",
"origin": {
"Table": {
"table": "policies",
"name": "resolution_pref"
}
}
},
{
"name": "source_weights!: String",
"ordinal": 12,
"type_info": "Text",
"origin": {
"Table": {
"table": "policies",
"name": "source_weights"
}
}
},
{
"name": "score_weights!: String",
"ordinal": 13,
"type_info": "Text",
"origin": {
"Table": {
"table": "policies",
"name": "score_weights"
}
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false
]
},
"hash": "1f67ae5af28115d22ad5e2fde1df8ee0f4aeb615e1d29c9cae03a589c7a6bdd4"
}
@@ -0,0 +1,74 @@
{
"db_name": "SQLite",
"query": "\n SELECT r.id AS \"id!: i64\",\n r.size AS \"size!: i64\",\n r.parsed AS \"parsed!: serde_json::Value\",\n r.verdict,\n r.rejected_rule\n FROM releases r\n WHERE r.id IN (\n SELECT er.release_id\n FROM episode_releases er\n JOIN episodes e ON e.id = er.episode_id\n JOIN seasons se ON se.id = e.season_id\n WHERE se.series_id = ?\n UNION\n SELECT sr.release_id\n FROM season_releases sr\n JOIN seasons se ON se.id = sr.season_id\n WHERE se.series_id = ?\n )\n ",
"describe": {
"columns": [
{
"name": "id!: i64",
"ordinal": 0,
"type_info": "Integer",
"origin": {
"Table": {
"table": "releases",
"name": "id"
}
}
},
{
"name": "size!: i64",
"ordinal": 1,
"type_info": "Integer",
"origin": {
"Table": {
"table": "releases",
"name": "size"
}
}
},
{
"name": "parsed!: serde_json::Value",
"ordinal": 2,
"type_info": "Text",
"origin": {
"Table": {
"table": "releases",
"name": "parsed"
}
}
},
{
"name": "verdict",
"ordinal": 3,
"type_info": "Text",
"origin": {
"Table": {
"table": "releases",
"name": "verdict"
}
}
},
{
"name": "rejected_rule",
"ordinal": 4,
"type_info": "Text",
"origin": {
"Table": {
"table": "releases",
"name": "rejected_rule"
}
}
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false,
false,
true,
true
]
},
"hash": "7fe60916664f3552cd111e45586c58997079821e2521a196174f4182e41531ad"
}
@@ -0,0 +1,26 @@
{
"db_name": "SQLite",
"query": "SELECT original_language FROM series WHERE id = ?",
"describe": {
"columns": [
{
"name": "original_language",
"ordinal": 0,
"type_info": "Text",
"origin": {
"Table": {
"table": "series",
"name": "original_language"
}
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
true
]
},
"hash": "869e17a01bcf8710bb533dbe428af062e73659ee89ab4387e0a28b7d546f5be4"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "UPDATE releases SET verdict = ?, rejected_rule = ? WHERE id = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "ad652cad9ca76a349b9257f7036e4af24a93f62b5c04b1a67ad8704f31c39d62"
}
@@ -0,0 +1,74 @@
{
"db_name": "SQLite",
"query": "\n SELECT r.id AS \"id!: i64\",\n r.size AS \"size!: i64\",\n r.parsed AS \"parsed!: serde_json::Value\",\n r.verdict,\n r.rejected_rule\n FROM releases r\n JOIN movie_releases mr ON mr.release_id = r.id\n WHERE mr.movie_id = ?\n ",
"describe": {
"columns": [
{
"name": "id!: i64",
"ordinal": 0,
"type_info": "Integer",
"origin": {
"Table": {
"table": "releases",
"name": "id"
}
}
},
{
"name": "size!: i64",
"ordinal": 1,
"type_info": "Integer",
"origin": {
"Table": {
"table": "releases",
"name": "size"
}
}
},
{
"name": "parsed!: serde_json::Value",
"ordinal": 2,
"type_info": "Text",
"origin": {
"Table": {
"table": "releases",
"name": "parsed"
}
}
},
{
"name": "verdict",
"ordinal": 3,
"type_info": "Text",
"origin": {
"Table": {
"table": "releases",
"name": "verdict"
}
}
},
{
"name": "rejected_rule",
"ordinal": 4,
"type_info": "Text",
"origin": {
"Table": {
"table": "releases",
"name": "rejected_rule"
}
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
true,
true
]
},
"hash": "e5b93151521f2d49a1f9e3c5b7ab1618554de74b444f28a89af92cde6abb47e5"
}