fix(files): file registration records the proc-fd link size (64 bytes) instead of the real file length - #901
kevinheneveld wants to merge 1 commit into
Conversation
…) instead of the real file length Since Listenarrs#717, file registration reads sizes from the lease's metadata path, which on Linux is a /proc/self/fd magic link. FileSystemInfo.Length reads the link inode itself (lstat), and proc magic symlinks report a constant st_size of 64 — so every file registered through a pinned lease persists Size = 64 regardless of the actual file. The UI then shows 0 KB wherever sizes are rendered (duplicate comparison, library size totals, quality scoring inputs). Open the metadata path instead and take the stream length: opening follows the magic link to the exact pinned object the lease holds, so the length is read from the real file without reintroducing the rename race the metadata path exists to avoid. Applies to both initial registration and physical-generation replacement snapshots (the latter falls back to the prior recorded size when the open fails). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fd link (PR Listenarrs#901) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common.
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 2af63b9)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 0d4e045)
…ts beside Listenarrs#901 No behaviour change. The gate and its reasoning move from EnsureAudiobookFileCoreAsync into QualifiesAsAudioContent in a new AudiobookFileService.ContentGate.cs, following the six partials this class already uses. The call site is four lines. Why it matters beyond tidiness. BackendArchitectureTests.ActiveProductionSourceFiles_RemainFocused fails any production file over 500 lines. AudiobookFileService.cs is 469 on canary, so there are 31 lines of headroom and two open PRs are spending them: canary 469 Listenarrs#901 alone 494 passes this branch before 487 passes both together 512 FAILS Measured by merging this branch onto Listenarrs#901 head 58adddd: 3141 passed, 130 skipped, and that one architecture test failed. Each PR passes the guard alone and the pair does not, so whoever merged second would have hit a failure they could not see from their own branch. This branch's footprint in the shared file drops from 18 lines to 5, which puts the combination at 499. Suite unchanged at 3142 passed / 0 failed / 130 skipped, and the application project rebuilds at zero warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 0d4e045)
…ts beside Listenarrs#901 No behaviour change. The gate and its reasoning move from EnsureAudiobookFileCoreAsync into QualifiesAsAudioContent in a new AudiobookFileService.ContentGate.cs, following the six partials this class already uses. The call site is four lines. Why it matters beyond tidiness. BackendArchitectureTests.ActiveProductionSourceFiles_RemainFocused fails any production file over 500 lines. AudiobookFileService.cs is 469 on canary, so there are 31 lines of headroom and two open PRs are spending them: canary 469 Listenarrs#901 alone 494 passes this branch before 487 passes both together 512 FAILS Measured by merging this branch onto Listenarrs#901 head 58adddd: 3141 passed, 130 skipped, and that one architecture test failed. Each PR passes the guard alone and the pair does not, so whoever merged second would have hit a failure they could not see from their own branch. This branch's footprint in the shared file drops from 18 lines to 5, which puts the combination at 499. Suite unchanged at 3142 passed / 0 failed / 130 skipped, and the application project rebuilds at zero warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit e68f6db)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 0d4e045)
…ts beside Listenarrs#901 No behaviour change. The gate and its reasoning move from EnsureAudiobookFileCoreAsync into QualifiesAsAudioContent in a new AudiobookFileService.ContentGate.cs, following the six partials this class already uses. The call site is four lines. Why it matters beyond tidiness. BackendArchitectureTests.ActiveProductionSourceFiles_RemainFocused fails any production file over 500 lines. AudiobookFileService.cs is 469 on canary, so there are 31 lines of headroom and two open PRs are spending them: canary 469 Listenarrs#901 alone 494 passes this branch before 487 passes both together 512 FAILS Measured by merging this branch onto Listenarrs#901 head 58adddd: 3141 passed, 130 skipped, and that one architecture test failed. Each PR passes the guard alone and the pair does not, so whoever merged second would have hit a failure they could not see from their own branch. This branch's footprint in the shared file drops from 18 lines to 5, which puts the combination at 499. Suite unchanged at 3142 passed / 0 failed / 130 skipped, and the application project rebuilds at zero warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit e68f6db)
…ests Review nit on item 236 (Listenarrs#901): both new tests already assert MetadataPath looks like a real /proc/<pid>/fd/<n> link, but nothing checked that lstat (FileInfo.Length) on that path actually disagrees with the real file, the way the removed DivergentDescriptorFixture control did. Without that, a runtime change that made lstat follow the link -- so the 64-byte bug simply stopped reproducing -- could make either test pass without TryGetRegisteredFileLength doing anything, since both stat and open would already agree. Added the same control inline: Assert.NotEqual between the real byte count and new FileInfo(MetadataPath).Length, right after the /proc path shape assertion and before the registration/refresh call. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 0d4e045)
…ts beside Listenarrs#901 No behaviour change. The gate and its reasoning move from EnsureAudiobookFileCoreAsync into QualifiesAsAudioContent in a new AudiobookFileService.ContentGate.cs, following the six partials this class already uses. The call site is four lines. Why it matters beyond tidiness. BackendArchitectureTests.ActiveProductionSourceFiles_RemainFocused fails any production file over 500 lines. AudiobookFileService.cs is 469 on canary, so there are 31 lines of headroom and two open PRs are spending them: canary 469 Listenarrs#901 alone 494 passes this branch before 487 passes both together 512 FAILS Measured by merging this branch onto Listenarrs#901 head 58adddd: 3141 passed, 130 skipped, and that one architecture test failed. Each PR passes the guard alone and the pair does not, so whoever merged second would have hit a failure they could not see from their own branch. This branch's footprint in the shared file drops from 18 lines to 5, which puts the combination at 499. Suite unchanged at 3142 passed / 0 failed / 130 skipped, and the application project rebuilds at zero warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit e68f6db)
…t a two-file double The carried-forward test (dc84254, from our own narrower fix) modeled the lease's MetadataPath as a second, independent 64-byte file standing in for a /proc/<pid>/fd/<n> magic link. That is faithful to a fix that reads size through the lease's own OpenMetadataReadStream(), which is what our fix did. Listenarrs#901 does not call that: TryGetRegisteredFileLength opens MetadataPath itself. A real magic link, opened directly, resolves to the pinned file's real bytes; only lstat'ing it (FileInfo.Length, the original bug) reports a constant 64. A second, unrelated file at MetadataPath cannot happen with a real lease, so the two-file double doesn't exercise what Listenarrs#901 actually does, and both of its behavioural tests still failed (64 instead of the real length) with Listenarrs#901's fix applied -- not because the bug persists, but because the double isn't the bug. Replaced with two tests built on the production PinnedAudiobookFileRegistrationLease.Open(), already used elsewhere in this file, so MetadataPath is a real /proc/<pid>/fd/<n> link on this Linux box: one for EnsureAudiobookFileAsync (the original AudiobookFileService.cs site) and one for RefreshPhysicalGenerationAsync (the PhysicalGeneration.cs site Listenarrs#901 also touches, which had no dedicated size test before). Measured fail-first on canary-m4bard without Listenarrs#901 (both report 64, matching the real FileInfo/lstat bug on this box), and pass with Listenarrs#901's fix applied. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> (cherry picked from commit f279b5f)
…ests Review nit on item 236 (Listenarrs#901): both new tests already assert MetadataPath looks like a real /proc/<pid>/fd/<n> link, but nothing checked that lstat (FileInfo.Length) on that path actually disagrees with the real file, the way the removed DivergentDescriptorFixture control did. Without that, a runtime change that made lstat follow the link -- so the 64-byte bug simply stopped reproducing -- could make either test pass without TryGetRegisteredFileLength doing anything, since both stat and open would already agree. Added the same control inline: Assert.NotEqual between the real byte count and new FileInfo(MetadataPath).Length, right after the /proc path shape assertion and before the registration/refresh call. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> (cherry picked from commit 6e3e188)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 0d4e045)
…ts beside Listenarrs#901 No behaviour change. The gate and its reasoning move from EnsureAudiobookFileCoreAsync into QualifiesAsAudioContent in a new AudiobookFileService.ContentGate.cs, following the six partials this class already uses. The call site is four lines. Why it matters beyond tidiness. BackendArchitectureTests.ActiveProductionSourceFiles_RemainFocused fails any production file over 500 lines. AudiobookFileService.cs is 469 on canary, so there are 31 lines of headroom and two open PRs are spending them: canary 469 Listenarrs#901 alone 494 passes this branch before 487 passes both together 512 FAILS Measured by merging this branch onto Listenarrs#901 head 58adddd: 3141 passed, 130 skipped, and that one architecture test failed. Each PR passes the guard alone and the pair does not, so whoever merged second would have hit a failure they could not see from their own branch. This branch's footprint in the shared file drops from 18 lines to 5, which puts the combination at 499. Suite unchanged at 3142 passed / 0 failed / 130 skipped, and the application project rebuilds at zero warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit e68f6db)
…t a two-file double The carried-forward test (dc84254, from our own narrower fix) modeled the lease's MetadataPath as a second, independent 64-byte file standing in for a /proc/<pid>/fd/<n> magic link. That is faithful to a fix that reads size through the lease's own OpenMetadataReadStream(), which is what our fix did. Listenarrs#901 does not call that: TryGetRegisteredFileLength opens MetadataPath itself. A real magic link, opened directly, resolves to the pinned file's real bytes; only lstat'ing it (FileInfo.Length, the original bug) reports a constant 64. A second, unrelated file at MetadataPath cannot happen with a real lease, so the two-file double doesn't exercise what Listenarrs#901 actually does, and both of its behavioural tests still failed (64 instead of the real length) with Listenarrs#901's fix applied -- not because the bug persists, but because the double isn't the bug. Replaced with two tests built on the production PinnedAudiobookFileRegistrationLease.Open(), already used elsewhere in this file, so MetadataPath is a real /proc/<pid>/fd/<n> link on this Linux box: one for EnsureAudiobookFileAsync (the original AudiobookFileService.cs site) and one for RefreshPhysicalGenerationAsync (the PhysicalGeneration.cs site Listenarrs#901 also touches, which had no dedicated size test before). Measured fail-first on canary-m4bard without Listenarrs#901 (both report 64, matching the real FileInfo/lstat bug on this box), and pass with Listenarrs#901's fix applied. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> (cherry picked from commit f279b5f)
…ests Review nit on item 236 (Listenarrs#901): both new tests already assert MetadataPath looks like a real /proc/<pid>/fd/<n> link, but nothing checked that lstat (FileInfo.Length) on that path actually disagrees with the real file, the way the removed DivergentDescriptorFixture control did. Without that, a runtime change that made lstat follow the link -- so the 64-byte bug simply stopped reproducing -- could make either test pass without TryGetRegisteredFileLength doing anything, since both stat and open would already agree. Added the same control inline: Assert.NotEqual between the real byte count and new FileInfo(MetadataPath).Length, right after the /proc path shape assertion and before the registration/refresh call. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> (cherry picked from commit 6e3e188)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 0d4e045)
…ts beside Listenarrs#901 No behaviour change. The gate and its reasoning move from EnsureAudiobookFileCoreAsync into QualifiesAsAudioContent in a new AudiobookFileService.ContentGate.cs, following the six partials this class already uses. The call site is four lines. Why it matters beyond tidiness. BackendArchitectureTests.ActiveProductionSourceFiles_RemainFocused fails any production file over 500 lines. AudiobookFileService.cs is 469 on canary, so there are 31 lines of headroom and two open PRs are spending them: canary 469 Listenarrs#901 alone 494 passes this branch before 487 passes both together 512 FAILS Measured by merging this branch onto Listenarrs#901 head 58adddd: 3141 passed, 130 skipped, and that one architecture test failed. Each PR passes the guard alone and the pair does not, so whoever merged second would have hit a failure they could not see from their own branch. This branch's footprint in the shared file drops from 18 lines to 5, which puts the combination at 499. Suite unchanged at 3142 passed / 0 failed / 130 skipped, and the application project rebuilds at zero warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit e68f6db)
…t a two-file double The carried-forward test (dc84254, from our own narrower fix) modeled the lease's MetadataPath as a second, independent 64-byte file standing in for a /proc/<pid>/fd/<n> magic link. That is faithful to a fix that reads size through the lease's own OpenMetadataReadStream(), which is what our fix did. Listenarrs#901 does not call that: TryGetRegisteredFileLength opens MetadataPath itself. A real magic link, opened directly, resolves to the pinned file's real bytes; only lstat'ing it (FileInfo.Length, the original bug) reports a constant 64. A second, unrelated file at MetadataPath cannot happen with a real lease, so the two-file double doesn't exercise what Listenarrs#901 actually does, and both of its behavioural tests still failed (64 instead of the real length) with Listenarrs#901's fix applied -- not because the bug persists, but because the double isn't the bug. Replaced with two tests built on the production PinnedAudiobookFileRegistrationLease.Open(), already used elsewhere in this file, so MetadataPath is a real /proc/<pid>/fd/<n> link on this Linux box: one for EnsureAudiobookFileAsync (the original AudiobookFileService.cs site) and one for RefreshPhysicalGenerationAsync (the PhysicalGeneration.cs site Listenarrs#901 also touches, which had no dedicated size test before). Measured fail-first on canary-m4bard without Listenarrs#901 (both report 64, matching the real FileInfo/lstat bug on this box), and pass with Listenarrs#901's fix applied. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> (cherry picked from commit f279b5f)
…ests Review nit on item 236 (Listenarrs#901): both new tests already assert MetadataPath looks like a real /proc/<pid>/fd/<n> link, but nothing checked that lstat (FileInfo.Length) on that path actually disagrees with the real file, the way the removed DivergentDescriptorFixture control did. Without that, a runtime change that made lstat follow the link -- so the 64-byte bug simply stopped reproducing -- could make either test pass without TryGetRegisteredFileLength doing anything, since both stat and open would already agree. Added the same control inline: Assert.NotEqual between the real byte count and new FileInfo(MetadataPath).Length, right after the /proc path shape assertion and before the registration/refresh call. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> (cherry picked from commit 6e3e188)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 0d4e045)
…ts beside Listenarrs#901 No behaviour change. The gate and its reasoning move from EnsureAudiobookFileCoreAsync into QualifiesAsAudioContent in a new AudiobookFileService.ContentGate.cs, following the six partials this class already uses. The call site is four lines. Why it matters beyond tidiness. BackendArchitectureTests.ActiveProductionSourceFiles_RemainFocused fails any production file over 500 lines. AudiobookFileService.cs is 469 on canary, so there are 31 lines of headroom and two open PRs are spending them: canary 469 Listenarrs#901 alone 494 passes this branch before 487 passes both together 512 FAILS Measured by merging this branch onto Listenarrs#901 head 58adddd: 3141 passed, 130 skipped, and that one architecture test failed. Each PR passes the guard alone and the pair does not, so whoever merged second would have hit a failure they could not see from their own branch. This branch's footprint in the shared file drops from 18 lines to 5, which puts the combination at 499. Suite unchanged at 3142 passed / 0 failed / 130 skipped, and the application project rebuilds at zero warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit e68f6db)
…t a two-file double The carried-forward test (dc84254, from our own narrower fix) modeled the lease's MetadataPath as a second, independent 64-byte file standing in for a /proc/<pid>/fd/<n> magic link. That is faithful to a fix that reads size through the lease's own OpenMetadataReadStream(), which is what our fix did. Listenarrs#901 does not call that: TryGetRegisteredFileLength opens MetadataPath itself. A real magic link, opened directly, resolves to the pinned file's real bytes; only lstat'ing it (FileInfo.Length, the original bug) reports a constant 64. A second, unrelated file at MetadataPath cannot happen with a real lease, so the two-file double doesn't exercise what Listenarrs#901 actually does, and both of its behavioural tests still failed (64 instead of the real length) with Listenarrs#901's fix applied -- not because the bug persists, but because the double isn't the bug. Replaced with two tests built on the production PinnedAudiobookFileRegistrationLease.Open(), already used elsewhere in this file, so MetadataPath is a real /proc/<pid>/fd/<n> link on this Linux box: one for EnsureAudiobookFileAsync (the original AudiobookFileService.cs site) and one for RefreshPhysicalGenerationAsync (the PhysicalGeneration.cs site Listenarrs#901 also touches, which had no dedicated size test before). Measured fail-first on canary-m4bard without Listenarrs#901 (both report 64, matching the real FileInfo/lstat bug on this box), and pass with Listenarrs#901's fix applied. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> (cherry picked from commit f279b5f)
…ests Review nit on item 236 (Listenarrs#901): both new tests already assert MetadataPath looks like a real /proc/<pid>/fd/<n> link, but nothing checked that lstat (FileInfo.Length) on that path actually disagrees with the real file, the way the removed DivergentDescriptorFixture control did. Without that, a runtime change that made lstat follow the link -- so the 64-byte bug simply stopped reproducing -- could make either test pass without TryGetRegisteredFileLength doing anything, since both stat and open would already agree. Added the same control inline: Assert.NotEqual between the real byte count and new FileInfo(MetadataPath).Length, right after the /proc path shape assertion and before the registration/refresh call. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> (cherry picked from commit 6e3e188)
…rrs#901 This PR fixed two things behind the same /proc descriptor link: the probe's extension guard rejecting the candidate, and FileInfo reporting the link's own 64 bytes instead of the file's length. Listenarrs#901 fixes the size half, and fixes it better. It opens the metadata path and takes the stream length unconditionally. The version here read the length through the lease's generation-bound stream but fell back to FileInfo on the metadata path when the lease did not expose one, which on Linux is the original 64-byte bug again. That half also had no test of its own here; both test files in this branch cover the scan boundary. So the size change is dropped and the two shared files go back to canary. What remains is the half Listenarrs#901 does not touch: the scan passed the lease's metadata path as both the byte source and the media identity, and on Linux that path is an extensionless /proc link, so the audio-extension guard rejected the candidate before ffprobe ever ran. Passing the candidate as the identity alongside the metadata path as the byte source keeps the guard working on the real filename. The two PRs no longer touch a file in common. (cherry picked from commit 0d4e045)
…ts beside Listenarrs#901 No behaviour change. The gate and its reasoning move from EnsureAudiobookFileCoreAsync into QualifiesAsAudioContent in a new AudiobookFileService.ContentGate.cs, following the six partials this class already uses. The call site is four lines. Why it matters beyond tidiness. BackendArchitectureTests.ActiveProductionSourceFiles_RemainFocused fails any production file over 500 lines. AudiobookFileService.cs is 469 on canary, so there are 31 lines of headroom and two open PRs are spending them: canary 469 Listenarrs#901 alone 494 passes this branch before 487 passes both together 512 FAILS Measured by merging this branch onto Listenarrs#901 head 58adddd: 3141 passed, 130 skipped, and that one architecture test failed. Each PR passes the guard alone and the pair does not, so whoever merged second would have hit a failure they could not see from their own branch. This branch's footprint in the shared file drops from 18 lines to 5, which puts the combination at 499. Suite unchanged at 3142 passed / 0 failed / 130 skipped, and the application project rebuilds at zero warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit e68f6db)
…t a two-file double The carried-forward test (dc84254, from our own narrower fix) modeled the lease's MetadataPath as a second, independent 64-byte file standing in for a /proc/<pid>/fd/<n> magic link. That is faithful to a fix that reads size through the lease's own OpenMetadataReadStream(), which is what our fix did. Listenarrs#901 does not call that: TryGetRegisteredFileLength opens MetadataPath itself. A real magic link, opened directly, resolves to the pinned file's real bytes; only lstat'ing it (FileInfo.Length, the original bug) reports a constant 64. A second, unrelated file at MetadataPath cannot happen with a real lease, so the two-file double doesn't exercise what Listenarrs#901 actually does, and both of its behavioural tests still failed (64 instead of the real length) with Listenarrs#901's fix applied -- not because the bug persists, but because the double isn't the bug. Replaced with two tests built on the production PinnedAudiobookFileRegistrationLease.Open(), already used elsewhere in this file, so MetadataPath is a real /proc/<pid>/fd/<n> link on this Linux box: one for EnsureAudiobookFileAsync (the original AudiobookFileService.cs site) and one for RefreshPhysicalGenerationAsync (the PhysicalGeneration.cs site Listenarrs#901 also touches, which had no dedicated size test before). Measured fail-first on canary-m4bard without Listenarrs#901 (both report 64, matching the real FileInfo/lstat bug on this box), and pass with Listenarrs#901's fix applied. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> (cherry picked from commit f279b5f)
…ests Review nit on item 236 (Listenarrs#901): both new tests already assert MetadataPath looks like a real /proc/<pid>/fd/<n> link, but nothing checked that lstat (FileInfo.Length) on that path actually disagrees with the real file, the way the removed DivergentDescriptorFixture control did. Without that, a runtime change that made lstat follow the link -- so the 64-byte bug simply stopped reproducing -- could make either test pass without TryGetRegisteredFileLength doing anything, since both stat and open would already agree. Added the same control inline: Assert.NotEqual between the real byte count and new FileInfo(MetadataPath).Length, right after the /proc path shape assertion and before the registration/refresh call. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> (cherry picked from commit 6e3e188)
|
I ran part of this today against our own fork's build, carrying this PR's commit alongside other unrelated fork patches, not a stock canary instance. What I have below is evidence of how real the underlying bug is, plus a test-double finding, not confirmation that the fix itself works end to end on a live install. More on why further down. As far as I can tell the diagnosis is specific and the fix matches it: reading the metadata path instead of lstat'ing it is exactly what's needed once you know a On the backfill question the PR body already flags: rows written before this fix was in place currently carry I wasn't able to finish the other half of the check this pass, whether a freshly scanned file gets the correct size going forward. That's blocked by something unrelated to this PR on this particular install, not a problem with the fix itself. One thing on the test side: we wrote our own regression test for this on our branch, and the first version modeled the lease's Unless I'm missing something, this looks solid. Does the backfill behavior for existing rows match what you'd expect, or is there a migration or re-scan path already planned for those? Disclosure: drafted with Claude Code at my direction; I read the cited code at the stated commit and reviewed this before posting. |
The bug
Since #717,
AudiobookFileServicereads the registered file's size from the lease's metadata path (new FileInfo(metadataPath).Length). On Linux that path is a/proc/self/fd/<n>magic link, andFileSystemInfostats the link inode itself — proc magic symlinks report a constantst_sizeof 64. Result: every file registered through a pinned lease persistsSize = 64, regardless of the real file.Live evidence from my instance (v1.3.0): 361 of 27,912
AudiobookFilesrows haveSize = 64exactly — every one created after the deploy that brought in #717 (sources:download,LibraryScan,MetadataRescan). The UI shows "0 KB" wherever sizes render (the duplicate-ASIN comparison table is where I caught it).The fix
Open the metadata path and take the stream length. Opening follows the magic link to the exact pinned object the lease holds open, so the size is read from the real file without reintroducing the rename race the metadata path exists to avoid. Applied at both write sites:
AudiobookFileService.cs— initial registration (Size = nullwhen the open fails, as before)AudiobookFileService.PhysicalGeneration.cs— generation-replacement snapshots (falls back to the previously recorded size)Notes
ExtractMetadataAsync's cache key usesLastWriteTimeUtcof the same metadata path, which has the same lstat behavior on Linux (the link's mtime, not the file's). It only weakens cache invalidation — the key still includes the physical object identity — so I left it out of scope here; happy to fold it in if you'd like.Size = 64stay wrong until re-registered; on my instance I'm backfilling them from disk. If you want, a follow-up startup reconciliation could repairSize = 64rows whose path resolves, but I didn't want to bundle that policy decision into this fix.🤖 Generated with Claude Code