The namer re-reads partial releases as the Rust window writes them
The pending namer's TypeScript re-index gave a file short of parts on the server to the range path's fragment rule, so a partial release the edge wrote (Bob's hex-named uploads in chello, ratcave, font, storage) never came out again: 10 of 148k named releases moved. RangeIndexer's partialFiles keeps such a file in its release, marked partial; tools/namer_check.ts replays sample rows from the corpus (10 of 10 found with it, 1 without). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0ccb850ea4
commit
8cf965af80
5 files changed
+102
-1
No files matched your search
@@ -123,6 +123,11 @@ export interface RangeIndexerOptions {
|
||||
* chunks seen so far), as uploads in busy groups spread over minutes.
|
||||
*/
|
||||
edgeArticles?: number
|
||||
/**
|
||||
* A file given up short of parts is a file of its release all the same (partial), as the Rust edge's window writes
|
||||
* it, not a fragment: the pending namer reads such a release again (LOG.md 2026-10-29 (121)).
|
||||
*/
|
||||
partialFiles?: boolean
|
||||
}
|
||||
|
||||
const MAX_CANDIDATES = 4
|
||||
@@ -274,6 +279,18 @@ export class RangeIndexer {
|
||||
else byFile.set(s.fileKey, [s])
|
||||
}
|
||||
for (const list of byFile.values()) {
|
||||
if (this.options.partialFiles) {
|
||||
// As the Rust window's files(): one article of a multi-part random file is no release.
|
||||
if (list.length === 1 && (list[0].number !== 1 || list[0].totalParts > 1) && isRandomFile(list[0].file.name)) {
|
||||
this.count('per-article', uploadTool(list[0].messageId), 1, 0)
|
||||
continue
|
||||
}
|
||||
// One segment per part (two copies of a file share its key here), the first article seen.
|
||||
const parts = new Map<number, EdgeSegment>()
|
||||
for (const s of list.sort((a, b) => a.articleNumber - b.articleNumber)) if (!parts.has(s.number)) parts.set(s.number, s)
|
||||
this.files([{ fileKey: list[0].fileKey, segments: [...parts.values()].sort((a, b) => a.number - b.number) }])
|
||||
continue
|
||||
}
|
||||
// One article of a "file" of many parts under a random name: a random subject per article, which
|
||||
// never completes from headers (99.8% of the boneless fragments; LOG.md 2026-10-09).
|
||||
if (list.length === 1 && isRandomFile(list[0].file.name)) {
|
||||
@@ -430,6 +447,7 @@ export function chunkOf(key: string, files: AggregatedFile<EdgeSegment>[], uploa
|
||||
lastArticle,
|
||||
readable: chunkFiles.some((f) => !isRandomFile(f.name)),
|
||||
hasPar2: chunkFiles.some((f) => /\.par2$/i.test(f.name)),
|
||||
partial: files.some((f) => f.segments.length < f.segments[0].totalParts),
|
||||
payload: encodeChunk(chunkFiles),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user