Bring script headers onto the template and close safeguard gaps
Headers claimed protections the code never had, and several destructive paths had no guard against a collapsed config value.
This commit is contained in:
@@ -39,7 +39,8 @@
|
||||
# age gate an entry the arr cannot even name is not going to import: if the
|
||||
# title is in the library and monitored, clearing it lets the arr search a
|
||||
# copy it can actually parse; if it is not in the library, nothing is
|
||||
# tracking it and it is dead weight either way. Guarded — see safeguard 6
|
||||
# tracking it and it is dead weight either way. Guarded — see Non-Empty
|
||||
# Library Requirement below
|
||||
# HELD — IMPORTABLE entries the arr keeps refusing (XEM-blocked, season-span
|
||||
# files), and everything skipped by a guard → report only, human call
|
||||
#
|
||||
@@ -47,27 +48,114 @@
|
||||
# there is no way to tell tracked from orphaned, and guessing means deleting active imports.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Classify Before Acting
|
||||
# Every entry is placed in exactly one class before anything is deleted, and each class
|
||||
# has its own justification. Nothing is removed because it merely looked unwanted — it is
|
||||
# removed because it matched a category whose deletion rationale is written down above.
|
||||
#
|
||||
# The Queue Is the Source of Truth
|
||||
# Tracked-vs-orphaned is decided by the arr's own queue, never inferred from filenames or
|
||||
# timestamps. If the queue cannot be read, the arr is skipped entirely rather than
|
||||
# falling back to a weaker signal — a guess here deletes an active import.
|
||||
#
|
||||
# Deleting Is Recoverable, Deleting Wrong Is Not
|
||||
# The classes that get deleted are ones the arr can re-acquire: junk it could never
|
||||
# import, content the library already has, and entries it cannot even name. Anything
|
||||
# whose loss would be permanent or ambiguous is held and reported for a human instead.
|
||||
#
|
||||
# Abnormal Volume Means Broken Input
|
||||
# The delete cap exists because the realistic failure mode is bad input, not bad logic —
|
||||
# a partial queue fetch classifies live downloads as orphans, and the only visible
|
||||
# symptom is an unusually large delete total. The cap turns that into a stop.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
# 1. DOWNLOAD_ORPHAN_CLEANER_ENABLED master toggle
|
||||
# 2. Download dir must exist and live under /mnt/ — refuses to walk anything else
|
||||
# 3. Queue fetch must succeed (see above)
|
||||
# 4. Age gate — nothing under DOWNLOAD_ORPHAN_AGE days is touched
|
||||
# 5. Deletion only for JUNK, parse-verified REDUNDANT, and UNMATCHED — never for
|
||||
# IMPORTABLE or anything a guard has held
|
||||
# 6. UNMATCHED deletes require the arr to report a non-empty library. An empty or
|
||||
# restoring database answers every parse with "no match", which would condemn the
|
||||
# entire download dir; the library is queried directly rather than inferred from the
|
||||
# run's own matches, since a small batch that is legitimately all-unmatched is normal
|
||||
# once daily runs have caught up and would otherwise read as a broken database
|
||||
# 7. Run total over DOWNLOAD_ORPHAN_MAX_DELETE_GB aborts the delete pass and notifies —
|
||||
# a queue fetch that returned partial data would classify live downloads as orphans,
|
||||
# and an abnormally large delete total is the visible symptom of exactly that
|
||||
# (--i-know-what-im-doing overrides, e.g. for a first run against a known backlog)
|
||||
# Root Enforcement
|
||||
# Download folders are written by container users; removing them requires root.
|
||||
#
|
||||
# Lock Acquisition
|
||||
# acquire_lock "wait" with an EXIT trap releasing all locks, so an interrupted run never
|
||||
# strands a lock and the daily orchestrator is never silently skipped.
|
||||
#
|
||||
# Host Detection
|
||||
# detect_hosts() runs before any HOST*_-prefixed download dir is resolved.
|
||||
#
|
||||
# DOWNLOAD_ORPHAN_CLEANER_ENABLED Toggle
|
||||
# Master switch — exits cleanly when disabled.
|
||||
#
|
||||
# Download Path Restriction
|
||||
# The download dir must exist and live under /mnt/. Anything else is refused rather
|
||||
# than walked, so a blank or malformed path can never point the scan at the filesystem
|
||||
# root or a system directory.
|
||||
#
|
||||
# Queue Fetch Hard Gate
|
||||
# The arr is skipped entirely if its queue cannot be read. Without the queue there is no
|
||||
# way to distinguish tracked from orphaned, and guessing deletes active imports.
|
||||
#
|
||||
# Age Gate
|
||||
# Nothing under DOWNLOAD_ORPHAN_AGE days is touched, so an entry mid-import is never a
|
||||
# deletion candidate regardless of how it classifies.
|
||||
#
|
||||
# Deletion Class Restriction
|
||||
# Only JUNK, parse-verified REDUNDANT and UNMATCHED are deleted. IMPORTABLE entries and
|
||||
# anything a guard has held are reported, never removed.
|
||||
#
|
||||
# Non-Empty Library Requirement
|
||||
# UNMATCHED deletions require the arr to report a non-empty library. An empty or
|
||||
# restoring database answers every parse with "no match", which would condemn the whole
|
||||
# download dir. The library is queried directly rather than inferred from this run's own
|
||||
# match rate — a small batch that is legitimately all-unmatched is normal once daily runs
|
||||
# have caught up, and would otherwise read as a broken database.
|
||||
#
|
||||
# Delete Volume Cap
|
||||
# A run total over DOWNLOAD_ORPHAN_MAX_DELETE_GB aborts the delete pass and notifies.
|
||||
# --i-know-what-im-doing overrides it for a deliberate first run against a known backlog.
|
||||
#
|
||||
# Dry Run Support
|
||||
# --dry-run classifies everything and reports, deleting and importing nothing.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# USAGE
|
||||
# CONFIGURATION
|
||||
# ==============================================================================================
|
||||
#
|
||||
# host*.conf (resolved per host after detect_hosts())
|
||||
#
|
||||
# HOST*_SONARR_DOWNLOAD_DIR / HOST*_RADARR_DOWNLOAD_DIR
|
||||
# Host-side path to the arr's completed-download folder. Absent means that arr's
|
||||
# cleanup is skipped, not an error.
|
||||
#
|
||||
# HOST*_SONARR_DOWNLOAD_CONTAINER_DIR / HOST*_RADARR_DOWNLOAD_CONTAINER_DIR
|
||||
# The same folder as the arr container sees it — used when triggering the
|
||||
# DownloadedEpisodesScan / DownloadedMoviesScan path.
|
||||
#
|
||||
# SONARR_URL / SONARR_API_KEY / RADARR_URL / RADARR_API_KEY
|
||||
# Aliased by detect_hosts(). A missing URL or key skips that arr.
|
||||
#
|
||||
# master.conf
|
||||
#
|
||||
# DOWNLOAD_ORPHAN_CLEANER_ENABLED
|
||||
# Master toggle (default: true)
|
||||
#
|
||||
# DOWNLOAD_ORPHAN_AGE
|
||||
# Days before an entry is eligible at all — younger entries may be mid-import
|
||||
# (default: 7)
|
||||
#
|
||||
# DOWNLOAD_ORPHAN_MIN_VIDEO_MB
|
||||
# An entry with no video file above this size is JUNK (default: 50)
|
||||
#
|
||||
# DOWNLOAD_ORPHAN_MAX_DELETE_GB
|
||||
# Abort the delete pass if the run total exceeds this (default: 100)
|
||||
#
|
||||
# SONARR_EXTENSIONS / RADARR_EXTENSIONS
|
||||
# Video extensions used to decide whether an entry contains real media
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# arr_download_orphan_cleaner.sh — daily orchestrator entry
|
||||
|
||||
Reference in New Issue
Block a user