RT 2026-08-05 - area 15 - sonnet (Sonnet 5) - yield 3 #152
ms609-agent
announced in
15 · Legacy pure-R search API
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
sonnet (Sonnet 5)| effort: default | 2026-08-05 | first-ever review of this areaYield: 3 confirmed findings, 0 refuted of 5 candidates. Zero
sev:high.Filed: #125 (
sev:med), #126 (sev:low). Fixed inline, logged not filed: themaxIter = 0loop bound.Context — this was the sonnet arm of a tier-economics experiment
The question under test: is it cheaper to let sonnet find what sonnet can find and have opus find only the remainder, than to send opus first? Area 15 was chosen because it was the only never-visited area, so nothing had been pre-harvested and a first pass measured the cheap tier honestly. See the opus round for the answer — it is refuted; do not re-run.
The scope row's headline question was stale and would have burned the round
The row cited #16 (
TreeState::init_from_edgeOOB on multifurcating trees) as live, namingEdgeListScore()as a vulnerable entry point. #16 is closed — the boundary guard landed in PR #50 — so the brief reframed it before dispatch: the C++ boundary now rejects non-binary trees, so the live question is whether the pure-R layer hands it inputs it will now reject.Answer: no, and the seam is doubly guarded.
TreeSearch()/Ratchet()bothstop("tree must be bifurcating")on entry (R/CustomSearch.R:209,R/Ratchet.R:96), predating and independent of the C++ fix, andEdgeListScore()carries its owntabulate(parent)check (R/tree_length.R:611-618). A 600-iteration chained fuzz ofRootedNNI/RootedSPR/RootedTBRon the default random-move path, with structural-sanity checks, found zero corruption.Measured, not assumed — reopen if the C++ guard is relaxed or a new caller bypasses those entry checks.
The finding: a documented contract broken almost everywhere it is documented
man/NNI.Rd/man/TBR.RdpromiseedgeToBreak = -1returns "a complete list of all trees one step from the input tree". Six exported functions inherit that promise; one honours it.-1handlingNNI()R/NNI.R:65)RootedNNI()lapply(:196)SPR()stop()(R/SPR.R:101):102-107deadRootedSPR(),RootedSPRSwap()AllSPR()refs undefinedtreeTBR(),RootedTBR()-1branch at allThat
stop()atR/SPR.R:101is the key to the fix: this is one maintainer decision, not four bugs — refusing uniformly at the other five sites eliminates the silent class outright. No test anywhere passesedgeToBreak = -1to any of the six.Fixed inline, not filed
EdgeListSearch()loopedfor (iter in 1:maxIter).1:0isc(1, 0), somaxIter = 0performed two rearrangement iterations instead of none — and sinceRearrangeEdges()accepts any candidate scoring<= scoreToBeat, a caller asking for zero rearrangements could get a different tree back. Reachable fromBootstrap(),Jackknife(),Ratchet(). Fixed toseq_len(maxIter)withiter <- 0Lpre-initialised (load-bearing:iteris read after the loop). Pinned by a regression test using mocks that error if called.Verifier routing note
Candidates 1/2/3 were
sev:med, which the severity rule alone sends to haiku — but all three turn on R language/roxygen semantics, so they went peer-tier under "route by what decides the verdict". That paid: on theAllSPRfinding the peer verifier found that a global variable namedtreemasks the bug entirely, and produced a false negative that way before re-running clean. A cheap verifier would plausibly have refuted a real finding.Not chased
SuccessiveWeights()(R/SuccessiveApproximations.R:175-189) scores viaCharacterLength()rather than the kernel; agreement untraced. (Later found dead on arrival — see the opus round.)RearrangeEdges()callsTreeScorer()twice per iteration whenscoreToBeatis not supplied.MultiRatchet()/Ratchet()'sswappers=plusedgeToBreak = -1through...would reach the broken paths; no such call site in-repo, but the docs promise it.Re-verified, not re-filed
#119's
R/Bootstrap.Rsample()length-1 trap —deindexedCharscan have length 1 only when the whole dataset compresses to a single pattern of weight 1, so "unreachable with normal weights" holds. #83 confirmed still present; its two-path shape does not extend toSuccessiveApproximations(), which calls the kernel directly and has only one path.Seam status: still yielding (5 candidates, 5 confirmed, 0 refuted, on a first pass).
All reactions