Overnight/test harness 2026 04 20#5
Merged
Conversation
Two new tests:
- TestPauseTorrentIdempotent calls PauseTorrent twice on
the same torrent; the second call must take the
`if already { return nil }` fast path.
- TestRemoveTorrentUnknownInfoHashErrors passes an
unrecognised infohash so the handleByHex error propagates
cleanly rather than panicking.
PauseTorrent 93.3% → 100%; RemoveTorrent 92.9% → 100%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass an unregistered infohash so the inner handleByHex call returns an error; SetFilePriority must surface that without attempting to call into anacrolix on a nil handle. SetFilePriority 92.9% → 100%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mark a peer capable, plug in a scriptedSender that synthesises a Result with one hit via HandleMessage on the fake reply path. The HTTP /search response must carry the hit translated into a SwarmHit (Name, Size, Seeders, etc.). handleSearch 90.7% → 100%; package 98.4% → 99.5%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds two manifest tests in a single file: load a manifest whose JSON has 'entries' set to null (Unmarshal leaves m.Entries nil → exercises the rebuild guard) and a Save where the parent dir loses write permission so os.WriteFile on the tmp path fails. LoadOrCreateManifest 94.7%→100%. Save remains 92.9% — the residual gap is the json.MarshalIndent error which is unreachable for the manifest's struct shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… arms
Two reachable archive.go gaps:
- claims-by-extension switch: Dispatch normally pre-fills MIME from
filepath.Ext, so the .zip/.tar/.tgz/.tar.gz arms were dead. Pass
MIME='application/octet-stream' to bypass mimeFromPath and force
the extension switch to fire.
- zipMemberNames: archive/zip lets a writer create an entry with
name "", which surfaces as f.Name=="" on read and must be
filtered out before joining names. The existing 'skip directory'
test claimed to cover empty names but didn't actually plant one.
zipMemberNames 90.9%→100%, init 81.8%→100%, archive.go Extract steady
at 90.5% (residual is io.ReadAll error on a real reader, unreachable).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…F arms
Five reachable branches across the docx and exif extractors:
- docx empty document.xml (whitespace-only text run): exercises
the 'TrimSpace(text) == \"\"' early-return.
- docx malformed XML: drives extractDocumentText to surface a
decode error rather than returning empty text.
- exif JPEG with no APP1 segment: hits the
findExifTIFF !found arm (returns nil, nil).
- exif APP1 with TIFF whose byte-order marker is neither II nor
MM: drives parseTIFF's bad-BOM error through Extract.
- exif APP1 with valid TIFF but zero entries: emits no known
tags so the assembled text is empty and Extract returns nil.
docx Extract 77.8%→85.2%, exif Extract 78.6%→89.3%, parseTIFF
93.3%→95.5%, parseIFD 95.0%→96.7%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EPUB Extract whitespace-only-chapters arm: an EPUB whose every
chapter body is empty/whitespace returns (nil, nil) rather than a
chunk holding empty text.
RTF control-word arms: one synthesised body chains \\par, \\line,
\\sect, \\page, \\tab, \\emdash, \\endash, \\lquote, \\rquote,
\\ldblquote, \\rdblquote, \\bullet, \\'a9 hex escape, plus the
literal \\\\ \\{ \\} escapes. Each glyph appearing in the output
proves its switch arm fired.
Plus the application/rtf MIME-claim path (text/rtf is owned by
the plaintext extractor first, so this hits the application/rtf
half of the OR).
EPUB Extract 84.8%→87.0%, RTF Extract 69.8%→92.1%, RTF init
83.3%→100%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rrors
Five reachable arms across chunker.go and subtitle.go:
- chunkText with targetBytes <= 0 falls back to
DefaultChunkTargetBytes (compared head-to-head with an
explicit-default call).
- chunkText two-paragraph join: with target sized so both
paragraphs fit, the WriteString("\\n\\n") arm fires.
- chunkByLine flush-before-oversized-line: a paragraph whose
later line exceeds maxChunk after content was already
buffered triggers the cur.Reset() flush arm.
- subtitle dialog line that is entirely markup
(e.g. "<i></i>") strips to empty and gets skipped.
- subtitle scanner.Err() propagation: an io.Reader that errors
after returning valid bytes surfaces as an Extract error.
chunkText 93.8%→100%, chunkByLine 93.3%→100%, subtitle Extract
92.6%→100%, package coverage 87.4%→89.0%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Plant a regular file at the index path before calling OpenWithLogger; Bleve's create call fails (the path exists as non-index data) so the wrapped error propagates. OpenWithLogger 77.3%→81.8%. Residual gaps are the schema- rebuild's intermediate Close/RemoveAll/re-create failures, which require corrupting state mid-rebuild and aren't deterministic. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two reachable guards:
- companion.OpenBTree's RootPieceIndex != 0 check: build a real
signed tree, decode the trailer, mutate RootPieceIndex to 1,
re-sign with the same key, splice the doctored trailer back
in. OpenBTree must reject after VerifyTrailerSig passes.
- swarmsearch.BuildRecordsFrame's len(recs) > MaxRecordsPerMessage
cap: pass MaxRecordsPerMessage+1 records and expect the
'exceeds cap' error rather than an oversize wire frame.
OpenBTree 93.8%→100%, BuildRecordsFrame 92.9%→100%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HandleMessage's routing path catches malformed bencode at peekHeader, so the inner DecodeQuery err arm in handleQuery is unreachable from the public entry point. The internal test calls handleQuery directly with non-bencode bytes; the function must return cleanly without panicking and without invoking the reply closure. handleQuery 90.2%→95.1%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
engine.New treats failures from reputation.LoadOrCreateBloom and LoadOrCreateTracker as non-fatal — the engine still comes up without the spam-resistance state. The two err arms log a Warn and continue; both were uncovered. Plant a directory at the bloom and reputation paths (each containing a blocker file so ReadFile fails with a non-NotExist error). engine.New must succeed. engine.New 73.3%→74.8%, engine package 85.5%→85.7%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two more non-fatal warn arms in engine.New:
- loadSession with corrupt JSON: plant '{not json' at the
canonical session.json path; engine.New must continue with
an empty session rather than fail.
- identity.LoadOrCreate with a directory at the identity path:
LoadOrCreate's IsDir guard fires; engine.New's warn arm
swallows the error so the engine still starts (just without
DHT publisher capability).
engine.New 73.3%→77.0%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Default tests leave HTTPUserAgent empty so the
'if cfg.HTTPUserAgent != \"\" { tc.HTTPUserAgent = ... }' branch
in engine.New stays cold. Pass a custom UA in cfg and verify the
engine boots cleanly. No public accessor for the resulting
torrent.Client UA, so a clean New + Close is enough proof.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Six previously-uncovered FLAC arms now exercised by hand-crafted
fLaC payloads:
- parseVorbisComment len(b) < 4 short-circuit
- vendor length overruns the vorbis body
- per-comment length overruns the body
- per-comment branches: missing '=', empty value, unknown
Vorbis field name (vorbisLabel returns ""), known field
(TITLE) surfaces in output
- VORBIS_COMMENT block whose declared bodyLen exceeds the
bytes that actually follow → readFull error
- non-VORBIS block whose declared bodyLen exceeds the bytes
that follow → br.Discard error
flac.Extract 78.6%→93.8%, parseVorbisComment 75%→100%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A JPEG containing a comment (COM) segment followed by EOI takes findExifTIFF's 'i = bodyEnd' advance branch — the segment fits but isn't EXIF, so the loop must skip past its body and continue checking. Without this case the only path through findExifTIFF either matched an EXIF APP1 immediately or bailed out on a truncated segment. findExifTIFF 87.5%→91.7%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
writeTorrentCopy is a best-effort persistence step in AddTorrentFile — if it fails, the engine logs a warn and the add still succeeds. Force the failure by chmod 0o500 on the torrents/ subdirectory after engine.New has created it; the subsequent AddTorrentFile must still return a non-nil handle. Skipped on Windows and as root (chmod semantics). AddTorrentFile 90.0%→93.3%, engine package 85.5%→86.2%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The existing partial-failure test (failNth=4) trips on the SECOND IndexTorrent call, which exercises the IndexTorrent err arm but not the IndexContent err arm. failNth=2 trips on the first IndexContent call instead so the inner content-loop error path fires. subscriber.ingest 96.0%→100%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both Save calls in Close are non-fatal — failures are logged and Close still completes. Strip write permission on the bloom file's and reputation file's parent directories AFTER engine.New has wired them up; the in-Close Save then fails on tmp WriteFile, exercising the previously-uncovered warn arms. Skipped on Windows + as root. engine.Close 84.0%→92.0%, engine package 85.7%→86.3%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AllTorrentDocs pages through results 1000 at a time. With <1000
docs in the index the second-iteration logic ('from += batch')
never fires. Index 1001 torrent docs and verify the returned
slice is complete; this exercises both the 1000-doc first batch
and the 1-doc tail.
Skipped under -short because indexing 1001 Bleve docs takes
~20s on the test box.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Bytes arms
Four reachable Extract arms in zim.go:
- dir entry mimeIdx == zimRedirectMime/zimDeletedMime: use a
helper to patch a built ZIM's dir entry mimeIdx to 0xFFFF
(redirect) and verify the loop's IsRedirect skip fires.
- dir entry mimeIdx >= len(mimes): same helper writes an
out-of-range mimeIdx; bounds-check skip arm fires.
- non-extractable MIME (image/png): the only article's MIME
fails zimIsExtractableMime → no chunks returned.
- empty decoded text: a whitespace-only article body decodes
to "" via zimDecodeArticle and is skipped.
- emitted >= maxBytes break: small cap below the first
article's length prevents the second from being emitted.
zim Extract 68.6%→78.4%, readZimDirEntry 66.7%→75.0%, package
coverage 89.6%→89.9%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three more reachable arms in zim.go:
- dispatch ext fallback: pass MIME='application/octet-stream'
so the registered claim function reaches the
'EqualFold(filepath.Ext(c.Path), \".zim\") return true' arm
rather than matching the MIME-prefix check above.
- cluster type 4 (XZ/LZMA2): patch a built ZIM's cluster type
byte; readZimCluster surfaces the 'not supported in v1'
error which Extract swallows via continue.
- unknown cluster type (e.g. 6): patch byte to value outside
{1, 2, 4} so readZimCluster's default-arm error fires.
zim init 83.3%→100%, readZimCluster 48.8%→53.5%, package
89.6%→90.2%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ApplyNeed accepts up to MaxNeedIDsPerMessage (1000) IDs, but BuildRecordsFrame's record cap is MaxRecordsPerMessage (500). A sync_need that resolves to 501+ records reaches the overflow arm in onSyncNeed and the function must return without sending sync_records. Build 501 distinct LocalRecords, register a responder session, and dispatch the sync_need: assert reply is never invoked. onSyncNeed 84.6%→100%, swarmsearch coverage 98.2%→98.4%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When cfg.SeedListPath is set, engine.New calls
tr.LoadSeedList and surfaces a log.Info on n>0 plus a warn for
each per-entry parse error. Default tests leave SeedListPath
empty so both arms are cold.
Plant a seed list with one valid 32-byte pubkey and one
'not-hex' bad entry. The valid one imports (n=1 fires the
'engine.seed_list_loaded' info), the bad one routes through
the warn loop ('engine.seed_list_err').
engine.New 77.0%→81.5%, engine package 86.3%→86.7%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same shape as bloom/reputation/identity load tolerance: plant a directory at cfg.TrustPath so trust.LoadOrCreate fails on a non-NotExist read. engine.New must continue with TrustStore=nil. engine.New 81.5%→82.2%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The arm fires when the FIRST ContentDoc for a file has empty FilePath but a LATER ContentDoc for the same FileIndex has a non-empty one. Bleve's ContentDocsForInfoHash returns docs in non-deterministic order, so a black-box test can't pin the sequence. Switch to an internal test that calls collectFileRecords directly with the exact ordered slice. collectFileRecords 96.4%→100%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The existing pause tests add via magnet (no metadata), so the pre-metadata branch covers `paused`; the post-metadata switch arm stays cold. Use AddTorrentMetaInfo so metadata is present immediately, pause the torrent, and verify the snapshot reports Status="paused". snapshotOf 86.2%→89.7%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Six getZimBlob err arms were uncovered. Internal tests pass hand-crafted cluster bytes directly so each guard can fire independently: - empty cluster (len < 1) → 'missing type byte' - body shorter than offsetSize → 'body shorter than first offset' - first offset 0 or non-aligned → 'bad first offset' - blobNum >= blobCount → 'blob N out of range' - claimed offset entry past cluster end - startOff > endOff or endOff > body length → 'offsets invalid' Plus a happy-path extended-cluster test exercising the 8-byte offset width. getZimBlob 67.7%→100%, zim Extract 78.4%→80.4%, package coverage 90.2%→90.8%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
readZimDirEntry's `case zimDeletedMime: return zimDirEntry{IsDeleted: true}`
arm was untested — the previous redirect test only covered the
zimRedirectMime/zimLinkTargetMime case. Patch a dir entry's
mimeIdx to zimDeletedMime; Extract's IsDeleted skip arm fires
and the deleted entry is filtered out.
readZimDirEntry 75.0%→83.3%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The arm `if t.BytesMissing() <= 0 { continue }` skips fully
verified torrents from the active-downloads count. To exercise
it, the data file must already exist where anacrolix's storage
backend looks for it (DataDir/<torrent-name>) so VerifyData
runs synchronously and BytesMissing drops to 0 quickly.
Place the source file directly under the engine's DataDir,
AddTorrentMetaInfo, poll until BytesMissing == 0, then add a
magnet. The magnet's queueOrActivate triggers
countActiveDownloads — the seeding torrent is skipped per the
arm under test.
countActiveDownloads 93.3%→100%, engine package 86.7%→87.2%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire an index, place a .txt file inside DataDir so the plaintext extractor matches once VerifyData fires file-complete events, AddTorrentMetaInfo, then poll the index until at least one content document appears. The pipeline calls the OpenReader closure inside ingestFileEvents (lines 1669-1681) which reads the file and feeds chunks into Bleve. ingestFileEvents 47.1%→88.2%, engine package 87.5%→88.0%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After AddTorrentMetaInfo wires up the file tracker but before
VerifyData fires, flip the per-torrent indexing flag OFF via
SetTorrentIndexing. ingestFileEvents drains the file events
but the `if !h.IsIndexing() { continue }` arm skips the
pipeline submit instead of indexing.
ingestFileEvents 88.2%→94.1%, engine package 88.0%→88.4%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire identity + DHT enabled (with a dead-end bootstrap addr so the embedded server doesn't leak to the public mainline) so engine.New's startPublisher hits the publisher worker, lookup, and pointer-putter/getter constructors instead of returning at the 'no identity' / 'no DHT server' guards. Asserts each handle is non-nil after engine.New. startPublisher 9.5%→78.6%, engine package 88.4%→90.7%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DisableDHTPublish=true is the documented 'leech-only DHT' mode — suppresses the keyword publisher worker but keeps lookup + pointer putter/getter wired so the node can still subscribe to other publishers' BEP-46 pointers and BEP-44 keyword indexes. Adds the second startPublisher test that asserts: - Publisher() is nil - Lookup(), PointerPutter(), PointerGetter() are non-nil startPublisher 78.6%→81.0%, engine package 90.7%→91.0%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adding a torrent + sleeping briefly lets the autoIndex goroutine
catch up and call pub.Submit on the active publisher. Covers
the previously-cold `if pub != nil { pub.Submit(...) }` arm in
autoIndex.
autoIndex 84.6%→92.3%, engine package 91.0%→91.1%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AddInfoHash starts an upgradeMagnetSession goroutine that blocks on GotInfo. Hand the same infohash's metainfo to the engine via AddTorrentMetaInfo — anacrolix's registerLocked dedupes by infohash, so metadata flows to the existing handle and GotInfo fires. The goroutine then writes DataDir/torrents/<ih>.torrent and updates the session entry. Polls for the .torrent file's appearance to avoid asserting on internal session state. upgradeMagnetSession 39.1%→69.6%, engine package 91.0%→91.7%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same shape as the happy-path test but chmod 0o500 on the torrents/ subdirectory after engine.New so writeTorrentCopy's WriteFile fails when upgradeMagnetSession runs. Logs warn and returns rather than panicking. upgradeMagnetSession 69.6%→78.3%, engine package 91.7%→91.8%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hand metainfo into the engine first via AddTorrentMetaInfo so the AddInfoHash inside FetchCompanionTorrent reuses the same handle; GotInfo fires immediately, the file is single-file and already verified on disk so the BytesCompleted poll loop exits on the first iteration. Returns an absolute path under DataDir. FetchCompanionTorrent 36.4%→86.4%, engine package 91.9%→92.8%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…m + min-score The DHT-enabled full-path test now also wires: - cfg.Regtest=true → exercises the RegtestPublisherOptions arm - cfg.ReputationPath → lookup.SetTracker arm - cfg.BloomPath → lookup.SetBloom arm - cfg.MinIndexerScore=0.25 → lookup.SetMinIndexerScore arm startPublisher 81.0%→90.5%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Plant a directory at cfg.PublisherManifest so
LoadOrCreateManifest fails on the read of an unreadable path.
startPublisher's `if err != nil { return }` arm fires; engine.New
swallows the error after a warn (publisher_start_err) and the
engine still comes up with Publisher() == nil.
startPublisher 90.5%→92.9%, engine package 92.7%→93.3%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire two engines on loopback, place identical content under both DataDirs, AddTorrentMetaInfo on each, then connect with AddTrustedPeerEngine in both directions. Anacrolix dials over loopback and the LTEP handshake fires the previously-cold callback bodies in engine.New: PeerConnAdded, ReadExtended- Handshake, PeerConnReadExtensionMessage, PeerConnClosed. The test itself is timing-tolerant — even partial connection setup triggers the callbacks the cover tool needs to mark covered. engine.New 82.2%→91.1%, engine package 93.3%→94.3%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The piece-event arm in file_tracker.run only fires when pieces complete AFTER the tracker subscribes — i.e., during a real download, not on a torrent that's already verified. Wire two engines on loopback where the leech (B) starts with NO data on disk; the seed (A) feeds it pieces, the leech's tracker processes them via the `case ev, ok := <-sub.Values` arm, and remaining[fi] decrements until it dispatches the file-complete event. file_tracker.run 79.4%→91.2%, engine package 94.3%→95.1%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire two engines with attached indices, seed a torrent doc on the responder, establish an LTEP handshake via AddTrustedPeerEngine, then issue a swarmsearch query from one to the other. The responder's HandleMessage invokes the reply closure inside engine.New's PeerConnReadExtensionMessage callback (lines 688-700) which queues the result payload for WriteExtendedMessage on the connection. engine.New 91.1%→95.6%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Strip write on DataDir but keep DataDir/torrents writable so writeTorrentCopy succeeds (writes to torrents/) but the following session.update fails (saveLocked's WriteFile on DataDir/session.json.tmp). Logs warn, returns cleanly. upgradeMagnetSession 78.3%→82.6%, engine package 95.1%→95.3%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds TestFetchCompanionTorrentCtxCancelMidPoll: builds metainfo from a file outside DataDir so VerifyData reports BytesCompleted=0, no peers means it never advances, and a 250ms ctx times out inside the polling loop, exercising the previously-cold ctx.Done() arm. FetchCompanionTorrent coverage 86.4% → 95.5%.
Adds four loadPrivKey tests in cmd/swartznet: - explicit-path happy path with round-trip equality - explicit-path failure (planted directory) - default-path happy path (HOME isolated to a tmpdir) - default-path failure (empty HOME → UserHomeDir err) loadPrivKey 33.3% → 91.7%; defaultIdentityPath 75.0% → 100%.
Adds TestBloomSaveWriteBloomKTooLarge: hand-builds a BloomFilter with k = 70_000 so writeBloom's `k > math.MaxUint16` guard fires, exercising Save's writeBloom-error cleanup path (f.Close + tmp remove). Internal test so the private fields are reachable. BloomFilter.Save 73.7% → 84.2%.
Three new branch tests for readZimCluster:
- cluster-num-out-of-range: patch dir entry's ClusterNum to 99
so the `num >= ClusterCount` guard fires
- end-leq-start: patch cluster ptr past ChecksumPos so end ≤ start
- size-exceeds-cap: bump header ChecksumPos so the implied
cluster size > 64 MiB cap
readZimCluster 65.1% → 72.1%.
Adds TestOpenWithLoggerSchemaRebuildRemoveAllError: chmod the
parent dir to 0o500 between the stale-sentinel poke and the
re-open so os.RemoveAll(path) fails — exercising the
`return fmt.Errorf("indexer: remove stale index: %w", err)`
arm of the schema-rebuild branch.
OpenWithLogger 81.8% → 86.4%.
Adds TestPromoteQueuedLockedBreaksAtCap: starts with cap=1, adds three torrents (one active + two queued), then raises cap to 2 so promoteQueuedLocked enumerates the queue, promotes one torrent, hits active >= cap, and breaks before reaching the third — exercising the previously-cold cap-limited loop body and break. promoteQueuedLocked 73.7% → 100%.
Adds four error-path tests: - bad flag → flag.Parse err → exitUsage - missing positional args → NArg != 2 → exitUsage - missing file → os.ReadFile err → exitRuntime - non-btree bytes → companion.OpenBTree err → exitRuntime cmdAggregateFind 66.7% → 87.9%.
Adds four cmd_crawl_probe tests:
- bad-flag → flag.Parse err → exitUsage
- bad-addr → ResolveUDPAddr err → exitUsage
- explicit-hex --target round-trips through the responder
(previously only the random-target branch was covered)
- dead loopback peer + short timeout → SampleInfohashes err →
exitRuntime
cmdCrawlProbe 80.6% → 90.3%.
Adds two PDF Extract branch tests:
- iotest.ErrReader → io.ReadAll err → wrapped error returned
- PDF whose Tj draws only whitespace → TrimSpace strips it →
`return nil, nil` empty-text arm
PDFExtractor.Extract 73.9% → 82.6%.
Adds four readRecords branch tests: - happy path with blank lines (covers the empty-line continue) - missing file → os.Open err - empty kw → "empty kw" err - oversized line → scanner.Err propagates bufio.ErrTooLong readRecords 82.1% → 96.4%.
Adds four iotest.ErrReader-driven branch tests for the io.ReadAll(io.LimitReader(...)) arm in each office Extractor. ODP 81.5 → 85.2%; ODT 85.2 → 88.9%; DOCX 85.2 → 88.9%; PPTX 87.9 → 90.9%.
Adds four hand-built MKV branch tests, each declaring a body length the bytes can't satisfy: - EBML body truncated → Discard err - no Segment header after EBML → second readEBMLHeader err - Info child body truncated → readFull err - unknown-child body truncated → default-case Discard err MKVExtractor.Extract 81.1% → 91.9%.
Five more iotest.ErrReader-driven branch tests for the io.ReadAll(io.LimitReader(...)) arm. Archive 95.2 → 100%; MOBI 93.8 → 95.8%; EXIF 89.3 → 92.9%; EPUB 87.9 → 90.9%; MP4 84.2 → 89.5%; package total 94.9 → 95.2%.
claudenstein
pushed a commit
that referenced
this pull request
Jul 19, 2026
Closes the round-4 adversarial backlog; each fix has a regression test that fails when the fix is neutralized. All touched packages race-clean. - #10 companion: put the new BEP-46 pointer BEFORE dropping the old seed, so a failed put keeps the still-advertised infohash fetchable. - #7 dhtindex: TOCTOU between off-lock aggregate Refresh and a concurrent Retract — added a gen counter + post-distribute re-check so a retracted tree isn't left published for a full refresh interval. - #9 indexer/httpapi/daemon: a malformed query string is now a typed ErrBadQuery → HTTP 400 (client fault), not 500; classified at the daemon seam via a LocalBadRequest flag (httpapi imports no indexer types). - #5 companion: publisher GeneratedAt is now strictly monotonic across content changes, so a backward wall-clock step no longer trips the follower's replay guard and drops legitimate new content. - #11 companion: an Unfollow racing an in-flight Sync no longer resurrects the dedup maps — per-publisher Forget epoch, re-checked under lock in commitDedup. - #4 engine: persistAdd runs after Add releases e.mu; a racing RemoveTorrent could be resurrected — updateGuarded(abort) + Handle.isRemoved() make the create happens-before-correct (RemoveTorrent closes h.removed before its lock-guarded remove); persistSeedAdd DataPath refinement → updateExisting. - #8 swarmsearch: initiator/responder txid collision deferred with a fix sketch (needs a wire direction bit + the unwired StartSync path) — see DECISIONS T3-8. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.