Overnight/test harness 2026 04 20#4
Merged
Conversation
Existing tests hit individual API endpoints but never the root "/" path that serves the embedded index.html. The HandleFunc registration alone doesn't trip Go coverage; only invoking the closure does. Add a test that GETs / and asserts a 200 with an HTML body. Server.Start 93% → 95.3%; package 97.7% → 97.9%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The pre-existing TestEncodeDecodeRoundTrip and
TestEncodeRejectsOversized both populate v.Hits before
encoding, so the `if v.Hits == nil { v.Hits = []KeywordHit{} }`
default-fill arm was never exercised. Pass a fully-zero
KeywordValue and verify the round trip works. EncodeValue 80%
→ 90%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Existing happy-path / non-200 / bad-URL tests covered most of httpGetClient.Get, but the `resp, err := g.c.Do(req)` transport- error arm stayed uncovered. Pre-cancel the context so http.Do returns context.Canceled immediately, exercising the wrapped return without depending on actual network state. Get 90% → 100%; package 96.4% → 96.7%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
All pre-existing tests passed an explicit fakeHTTPSClient, so
the `if client == nil { client = NewHTTPSFallbackClient(0) }`
arm stayed uncovered. New test passes nil + a pre-canceled
context so the substituted real client errors out immediately
without making a network call. FallbackToHTTPS 97.1% → 100%;
package 96.7% → 97.0%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The pre-existing tests covered the bad-pubkey early return and the happy-path round trip, but the `if err != nil` arm after MineRecordPoW was untested. Pass bits=41 so MineRecordPoW's "cost prohibitive" guard fires; verify the wrapped error surfaces and the Sig stays zero (signing skipped). SignAndMineRecord 88.9% → 100%; package 93.5% → 93.7%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The pre-existing tampered-leaf test triggers either the DecodeLeaf error path or the fingerprint-bytes mismatch — but the explicit `count != trailer.NumRecords` guard runs first and could mask either of those depending on the tampered byte. Add a test that inflates only the in-memory trailer's NumRecords claim (post-OpenBTree, no leaf mutation) so the fingerprint hash still matches — leaving the count guard as the only catch. VerifyFingerprint 81.5% → 85.2%; package 93.7% → 93.8%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Build a tree whose records carry tiny nonces (0..9) that don't satisfy any meaningful PoW threshold, then post-OpenBTree set the in-memory trailer's MinPoWBits to 20. Find must silently drop every record via VerifyRecordPoW's continue arm and return zero hits — verifies that the spam-defence threshold is actually enforced at query time, not just at trailer-decode. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Build a tree where one record's signature is corrupted before BuildBTree (the trailer signs the resulting fingerprint, so OpenBTree still succeeds). Find must drop the bad-sig record via the VerifyRecordSig continue arm rather than surface a bogus hit. Find 80.6% → 83.9%; package 93.8% → 93.9%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass an opts.Root that doesn't exist so the inner CreateTorrent fails on os.Stat; the wrapping CreateTorrentFile must surface the error without writing any file. Closes the propagation arm no other test reached. CreateTorrentFile 88.9% → 94.4%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Plant a 0o000 subdirectory under opts.Root so the pre-walk size pass's filepath.WalkDir receives a permission-denied ReadDir error. CreateTorrent must surface "stat tree:" without proceeding to BuildFromFilePath. Skipped when running as root. CreateTorrent 87.8% → 92.7%; engine package 84.1% → 84.4%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-cancel the context so getput.Get aborts immediately without contacting any peers, exercising the "dhtindex: get pointer ... %w" error wrap that no existing test reached. GetInfohashPointer 80% → 86.7%; package 94.4% → 94.7%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Apply the canceled-context pattern that closed GetInfohashPointer's traversal-error arm to every other DHT-bound entry point: PutInfohashPointer, AnacrolixPutter.Put, GetPPMI, and PutPPMI. Each of these wraps a getput.Put or getput.Get call whose error path was unreachable in CI without a real network. Pre-canceling the context aborts the traversal deterministically. Coverage shifts: - PutInfohashPointer: 85.0% → 90.0% - Put: 80.0% → 86.7% - GetPPMI: 80.0% → 100% - PutPPMI: 82.4% → 88.2% Package coverage: 94.7% → 95.1%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The function comment promises that passing reply=nil lets the
responder run through search without trying to send back a
result ("decode-only mode used in unit tests"), but no test
exercised that path. Add a test that drives a successful query
with nil reply and asserts the call completes without panic.
handleQuery 82.9% → 85.4%; package 96.1% → 96.2%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass a reply closure that returns an error and verify handleQuery completes without panic — the function debug-logs the send failure and returns rather than retrying. handleQuery 85.4% → 90.2%; package 96.2% → 96.4%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…y_err The pre-existing test passed an empty Records slice, which makes ApplyRecords succeed (no records to validate) and silently returns through the success path — never exercising the apply_err arm the comment claims. Replace with a record whose Pk is 5 bytes instead of 32 so ApplyRecords' "bad sizes" check fires and onSyncRecords takes the err return. onSyncRecords 84.6% → 100%; package 96.4% → 96.5%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a small pieceErrSource / leafFailSource pair of test fakes that wrap the real BytesPageSource and synthetically fail one piece. After OpenBTree completes (which only reads the trailer), swap the reader's source for the wrapper so Find's piece-fetch error arms fire deterministically: - TestFindRootPieceFetchError: piece 0 fetch fails - TestFindLeafPieceFetchError: a mid-walk leaf piece fails Find 83.9% → 87.1%; package 93.9% → 94.0%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
walkToLeaves and Find both fetch the same leaf piece; the existing TestFindLeafDecodeError corrupts the leaf bytes before any read so the walk's decodeHeader trips first and Find's outer DecodeLeaf arm stays uncovered. Same problem applied to TestFindLeafPieceFetchError this iteration — use a stateful source that returns the real bytes on the first call (walkToLeaves) and garbage on the second (Find's re-fetch). Find 87.1% → 93.5%; package 94.0% → 94.2%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two more fakes in the source-stub family — constPieceSource
returns custom bytes for piece 0 — let the remaining root-
validation arms in Find fire deterministically:
- TestFindRootHeaderDecodeError: piece 0 is zero-bytes so
decodeHeader's magic check fails.
- TestFindRootKindNotRoot: piece 0 is a syntactically valid
leaf-kind page so decodeHeader succeeds but the kind check
rejects.
Find 93.5% → 100%; package 94.2% → 94.4%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Submit a .txt file whose OpenReader returns an empty stream; the plaintext extractor produces no chunks, so handle takes the `len(chunks) == 0 → skipped++ + return` branch without calling IndexContent. handle 82.4% → 88.2%; package 94.2% → 94.7%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Build a tree, then substitute piece 1 (the leaf) with a valid trailer-kind page so the recursive walkToLeaves call decodes the header successfully but the kind check rejects since trailer is neither Interior nor Root nor Leaf. walkToLeaves 85.7% → 96.8%; package 94.4% → 94.5%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Close the index between Start and Submit so every IndexContent call returns "indexer: closed". Pipeline.handle still extracts text from the input but every chunk's index attempt fails, taking the `writeErrors == len(chunks) → Failed++` counter arm rather than `Extracted++`. handle 88.2% → 100%; package 94.7% → 95.7%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-plant a non-empty directory at companion.torrent.tmp so the second atomicWrite call (after the JSON payload writes successfully) fails on truncate-open. WriteCompanionFiles 80% → 85%; package 94.5% → 94.6%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Set EndorsementThreshold=10 so countStrongEndorsers with one endorser falls short, forcing the policy fallback. With bloom + tracker wired, the default unknown score of 0.5 clears the 0.3 threshold check inside bloomPolicy and admit fires via the "endorsed-bloom" label. IngestEndorsement 94.4% → 100%; package 97.0% → 97.3%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A single indexer returns two hits for the same infohash where
the first has empty Name and the second has a non-empty Name.
The merge loop processes hits in slice order, so the second
hit's name deterministically fills the initially-empty merged
entry — exercises the
`if lh.Name == "" && h.N != "" { lh.Name = h.N }` arm without
relying on cross-indexer goroutine ordering. legacyQuery
92.2% → 93.8%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extend the existing same-indexer two-hit test so the second hit also carries non-zero Size and Files, exercising the matching `lh.Size == 0 && h.Sz > 0` and `lh.Files == 0 && h.F > 0` fill arms that no other test reached. legacyQuery 93.8% → 96.9%; package 95.1% → 95.4%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A malformed indexer can publish a KeywordHit whose IH is not
exactly 20 bytes (the field is a plain []byte with no wire-
level length validation). The merge must skip such hits via
the `if len(ih) != 40 { continue }` guard. Add a test that
mixes a 19-byte IH with a valid 20-byte IH and asserts only
the latter survives. legacyQuery 96.9% → 98.4%; package 95.4%
→ 95.5%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NewTracker() returns an in-memory tracker with empty path;
Save's `if t.path == "" { return nil }` early-return arm let
callers construct ephemeral trackers for tests / experiments
without needing a backing file. No existing test exercised
this path. Save 85.7% → 92.9%; package 95.0% → 95.4%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two new tests use a counting failingWriter that succeeds for
the first N bytes then errors out:
- TestWriteBloomHeaderWriteError fails at byte 0 so the
header write returns immediately.
- TestWriteBloomBitsWriteError accepts the 24-byte header
then fails on the first bits-buffer write.
writeBloom 81.2% → 93.8%; package 95.4% → 96.0%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two new tests use hand-crafted bloom file headers:
- TestReadBloomBitsLenInconsistent declares bitsLen huge
relative to m so the size-consistency guard fires before
a billion-entry slice would be allocated.
- TestReadBloomBitsReadError truncates the body mid-bits
so io.ReadFull returns unexpected EOF on the second
iteration of the bits loop.
readBloom 90% → 100%; package 96.0% → 96.6%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Saturate every bit in a small filter (set bits to all-ones)
so popcount equals m and the `if x >= m { return Inf }`
guard fires. Without this test the +Inf saturation path of
the cardinality estimator was unexercised. EstimatedItems
90.9% → 100%; package 96.6% → 96.9%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass a 100-byte pieceSize so even a normally-sized record (~270 bytes encoded) overflows the page on its own. packLeaves must surface the "record too large" error rather than silently truncating. packLeaves 85.7% → 95.2%; package 94.7% → 94.9%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A record with Kw at the 64-byte keyword limit plus max-width Pow (uint64-max → 20 digits) and T (int64-max → 19 digits) encodes to ~258 bytes once you sum the bencoded fixed fields (pk:38, ih:26, sig:70 etc.) — just over the 256-byte MaxRecordBytes ceiling. Verifies that the post-marshal size guard catches such records before they reach the leaf encoder. EncodeRecord 81.8% → 90.9%; package 94.9% → 95.0%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three new tests round out the VerifyFingerprint error paths:
- TestVerifyFingerprintFetchError: piece-fetch fails
mid-walk via the pieceErrSource wrapper.
- TestVerifyFingerprintHeaderDecodeError: piece 1 returns
zero-bytes via constPieceSource so decodeHeader rejects
on bad magic.
- TestVerifyFingerprintHashMismatch: tamper with the
in-memory trailer's TreeFingerprint after OpenBTree so
the reconstructed hash and the claim diverge — count
guard passes, fingerprint comparison catches.
VerifyFingerprint 85.2% → 96.3%; package 95.0% → 95.3%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two new tests round out ProduceSymbols:
- TestProduceSymbolsWrongPhase calls in PhaseIdle (fresh
session, no Begin called) so the phase guard fires.
- TestProduceSymbolsCountClamping exercises both
count <= 0 (falls back to MaxSymbolsPerMessage default)
and count > MaxSymbolsPerMessage (capped).
ProduceSymbols 86.4% → 100%; package 96.4% → 96.7%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- TestApplyNeedTxIDMismatch passes a SyncNeed whose TxID
diverges from the session's so the txid guard fires.
- TestApplyNeedTooManyIDs passes IDs of length
MaxNeedIDsPerMessage+1 so the per-message cap rejects.
ApplyNeed 86.7% → 100%; package 96.7% → 96.9%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bencode-marshal a payload that round-trips into a valid SyncBegin struct but carries MsgTypeSyncEnd as msg_type so the discriminator-mismatch guard fires. DecodeSyncBegin 87.5% → 100%; package 96.9% → 97.0%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EncodeSyncRecords enforces the same MaxRecordsPerMessage cap as DecodeSyncRecords, so the round-trip path can't exercise the decoder-side guard. Bencode-marshal the struct directly to bypass the publisher-side check, then verify DecodeSyncRecords catches a 501-record payload. DecodeSyncRecords 88.9% → 100%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EncodeSyncNeed substitutes an empty slice for a nil IDs slice before bencoding so the wire form always has an explicit (possibly empty) list rather than nothing. No existing test exercised that fall-through. Round trip a nil-IDs SyncNeed and verify the encoder + decoder both succeed. EncodeSyncNeed 88.9% → 100%; package 97.0% → 97.1%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drive the session past Begin so the phase gate accepts, then pass MaxNeedIDsPerMessage+1 ids to trip the cap. NeedFrame 92.3% → 100%; package 97.1% → 97.2%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Plug in a sender that errors every Send call so the fan-out loop counts every error and asked stays at 0. Query must return an empty response without waiting for replies. Query 92.5% → 98.1%; package 97.2% → 97.3%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EncodePeerAnnounce rejects oversized endorsement lists at publish time, so a round-trip test can only exercise the at-cap case. Hand-marshal a peer_announce payload with MaxEndorsedPerAnnounce+5 entries to bypass that check, then verify the decoder trims to the cap rather than blowing out memory or surfacing an error. DecodePeerAnnounce 92.3% → 100%; package 97.3% → 97.4%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous commit accidentally added .claude/scheduled_tasks.lock which is local workspace state. Untrack it and add .claude/ to .gitignore so future Claude Code sessions don't pick it up either. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two new tests:
- TestDecodeSyncSymbolsBadDataXORLen hand-marshals a frame
whose first symbol carries a 5-byte DataXOR (must be 32);
the post-decode validation loop rejects.
- TestEncodeSyncRecordsNilRecordsDefault passes a nil
Records slice through Encode + Decode to exercise the
"substitute empty slice" default-fill arm.
DecodeSyncSymbols 92.3% → 100%; EncodeSyncRecords 92.3% →
100%; package 97.4% → 97.6%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Existing tests covered every decode-error arm but not the happy-path forwards for SyncRecords and SyncEnd. Add direct tests that pass valid frames from a capability-marked peer and assert no misbehavior is charged. handleSyncFrame 94.1% → 100%; package 97.6% → 97.8%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dhtindex.Lookup.Query rejects queries that tokenise to nothing. Pass a stopword-only query "the of" — Bleve's local search handles it (returns no hits, no error) but Tokenize returns empty and Lookup.Query surfaces "no tokens". handleSearch must still respond 200 with the error string in the dht.error field. handleSearch 87.0% → 88.9%; package 97.9% → 98.2%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire a fixedHitGetter that returns a populated KeywordValue
and register an indexer on the Lookup. Lookup.Query goes
through its happy path with one hit, and handleSearch's
`for _, h := range out.Hits { dhtResp.Hits = append(...) }`
arm fires. handleSearch 88.9% → 90.7%; package 98.2% → 98.4%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A session manifest entry with QueueOrder higher than the engine's nextQueueOrder counter must lift that counter so torrents added after restore get fresh slots above the restored set. restoreEntry 89.8% → 91.8%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drive the session past Begin so the phase guard accepts, then SetBudgets(2, 1024) and feed a 3-symbol frame so the `symbolsIn + len(Symbols) > maxSymbols` check fires. ApplySymbols 94.1% → 100%; package 97.7% → 97.8%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire-level decoders (ApplyRecords + DecodeSyncRecords) already filter out records with wrong field lengths, but ingestSyncRecords is also called from cache-restore-style flows that may not go through the wire path. Bypass the wire layer by calling ingestSyncRecords directly with a 5-byte Pk so the per-record skip arm fires; sink + observer must both remain empty. ingestSyncRecords 95.5% → 100%; package 97.8% → 97.9%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When a node has Capabilities.Publisher > 0 and a 32-byte publisher pubkey set via SetPublisherPubkey, the announce it sends after a peer handshake must: - flip BitLayerDPublisher in the services bitmap, and - carry the 32-byte pubkey in pa.Pubkey. A recordingHandshakeSender catches the goroutine-emitted PeerAnnounce; the test asserts both arms fire. OnRemoteHandshake 94.6% → 100%; package 97.9% → 98.1%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass a record with an empty keyword so the per-record EncodeRecord call inside EncodeLeaf's loop returns an error; EncodeLeaf must surface it rather than producing a leaf with a half-written payload. EncodeLeaf 88% → 92%; package 95.3% → 95.4%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A magnet handle has no metadata until GotInfo fires; with DHT disabled and no peers, that never happens, so sampleRate must take the early return rather than call t.Stats() on a half- initialized torrent. sampleRate 90% → 93.3%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Close the engine then call restoreEntry directly (inside-
package test) so the `if e.closed { return error }` guard
fires before any torrent.Client state is touched.
restoreEntry 91.8% → 95.9%; engine package 84.5% → 84.8%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two new tests:
- TestLoadSessionMkdirFails plants a regular file at
<dataDir>/torrents so MkdirAll can't make it a directory.
- TestLoadSessionReadFileFails plants a directory at
session.json so os.ReadFile fails with EISDIR (a non-
ErrNotExist error that the existing NoFileYetReturnsEmpty
test deliberately doesn't cover).
loadSession 90.9% → 100%; engine package 84.5% → 84.9%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Construct an engine with BloomPath and ReputationPath set so
the spam-resistance subsystems are wired in. Close then runs
the `if e.bloom != nil { e.bloom.Save() }` and matching
tracker save arms; verify both files exist on disk afterwards.
Engine.Close 80% → 84%; package 84.9% → 85.4%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two new tests:
- TestDecodeTrailerBadKind: hand-build a leaf-kind page and
pass it to DecodeTrailer; the kind guard rejects.
- TestDecodeTrailerWrongPayloadLength: build a trailer-kind
page whose header claims a 32-byte payload (not the fixed
TrailerPayloadSize); the size guard rejects before any
body byte is read.
DecodeTrailer 93.8% → 100%; package 95.4% → 95.7%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass a record with empty keyword so packLeaves rejects; BuildBTree must propagate the error rather than continue with a half-built tree. BuildBTree 93.4% → 94.5%; package 95.7% → 95.8%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
claudenstein
pushed a commit
that referenced
this pull request
Jul 19, 2026
First 0-HIGH round since the GUI surface opened. The r8-regression and html-xml-walker finders returned zero. Three of four fixes are neutralize-to- fail pinned; the LOW #4 fix is structurally verified (see below). - MED (gui): the Status tab ran indexer.Stats() (full-corpus scan under the index lock) synchronously on the Fyne UI thread every 2s, freezing the whole GUI on a real corpus. Compute render() off the UI thread; only SetText on it. - MED (swarmsearch): handlePeerAnnounce (async worker) unconditionally created a p.peers entry, so a frame processed after the synchronous OnPeerClosed resurrected a zombie -> unbounded, remote-triggerable memory leak (no reaper). Update-only now: NotePeerAdded already creates the entry synchronously before any message, so a missing entry means the peer is gone -> skip. - LOW (gui): the Search tab gated rendering on the LIVE checkbox, so toggling Swarm/DHT off mid-search dropped already-fetched hits. Gate on res.Swarm/res.DHT (what was queried; nil when not). - LOW (engine): SetFilePriority on a queued torrent could download outside the max-active-downloads cap (queued torrents were gated only by None priorities). Add the anacrolix-level gate pause uses: DisallowDataDownload on queue, AllowDataDownload on promotion. Structurally verified (the flag is unexported; the full queue/promote/pause suite passes with no regression). Convergence: r2=2 HIGH, r3-4=0, r5=1, r6=0, r7=1, r8=1, r9=0. Strongest signal yet — GUI + follow-ups swept, shared-walker + r8-regression dry. See DECISIONS. 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.