diff --git a/docs/service-apis.md b/docs/service-apis.md index 44469d7..9f96f06 100644 --- a/docs/service-apis.md +++ b/docs/service-apis.md @@ -42,8 +42,8 @@ and exported-metainfo data, keeps the qB-local hash separately, and calculates: - normalized selected and selected-complete file-index sets; - torrent runtime state; - canonical path flag and content revision; -- a save-path fingerprint based on validated path mapping, never a leaked - absolute host path. +- a validated qBittorrent `save_path`, retained only in the client's local + normalized observation. qBittorrent 5 may expose a pure-v2 or hybrid torrent under the first 20 bytes of its v2 hash while separately advertising full `infohash_v1` and @@ -56,6 +56,23 @@ All entries retain qBittorrent's stable torrent file index. Renamed/noncanonical content paths are rejected in v1 because they cannot be transported and merged without ambiguity. +### Per-torrent local content roots + +`save_path` is not inventory, placement, or protocol data. It is qBittorrent +metadata used only by the daemon that queried qBittorrent. Before staging a +source, merging into an existing target, applying post-recheck permissions, or +evicting files, that daemon maps the torrent's API-visible `save_path` through +`qbittorrent.api_root`/`local_root`. The most-specific +`qbittorrent.local_path_overrides` mapping wins when a nested path is exposed +through a distinct client container mount. + +An ordinary nested qBittorrent path such as `/media/Data/Downloading` needs no +per-resource configuration: it resolves beneath the configured root. A path +outside that root, an unmapped distinct mount, or a mapped local path that is +not a visible real directory fails the affected job before filesystem mutation. +This check is intentionally per resource; an unrelated malformed qBittorrent +entry cannot prevent normal resources from being staged or transferred. + ### Verification guard The client captures transfer counters and state before recheck, issues recheck, diff --git a/src/archive_clients/resources.py b/src/archive_clients/resources.py index f15f54b..bc74052 100644 --- a/src/archive_clients/resources.py +++ b/src/archive_clients/resources.py @@ -19,6 +19,14 @@ class ResourceError(ValueError): @dataclass(frozen=True) class NormalizedResource: + """A normalized qB observation for protocol data and local file work. + + ``save_path`` is qBittorrent's API-visible per-torrent content root. It + is deliberately local-only: clients resolve it through their qB path + mapping immediately before filesystem work, and it is never serialized in + inventory, placements, or control protocol messages. + """ + summary: resource_pb2.ResourceSummary files: tuple[resource_pb2.TorrentFile, ...] metainfo: Metainfo