RT 2026-07-27 - area 9 - opus (Opus 5) - yield 8 #165
ms609-agent
announced in
09 · Wagner & addition trees
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.
opus (Opus 5) | effort: unrecorded | 2026-07-27
Migrated record. This round predates the move to Discussions; it is reproduced
verbatim below from
dev/red-team/log.md, which is now closed to new entries. It isposted here so this area has a round record whose
createdAtorders correctly againstthe other areas' — the backfill ran oldest-first for that reason. All fourteen posting
timestamps are later than the rounds they describe; the real date is in the title and
in the
date:field.area: 9 (Wagner & addition trees)
reviewed_by: opus finder + opus verifier (4 correctness claims) + haiku verifier (6 low-sev batch) + orchestrator re-verification of three cruxes
date: 2026-07-27
tier: opus (Opus 5)
yield: 8 filed (T-364 P1, T-365 P2, T-366/367/368/369/370/371 P3) + 3 fixed inline, from 10 candidates; 0 refuted, but 3 of the 10 had a severity or sub-claim corrected in verification
notes: Re-visit at the same rung after the 2026-06-16 opus-4.8 round yielded; the version had also moved 4.8 to 5, but a yielding seam re-visits at the same tier anyway, so no version-bump-revisit brief was used. THE BRIEF AIMED AT THE INCIDENTAL CHURN, AND THAT IS WHERE THE P1 CAME FROM.
src/ts_wagner.cpphad changed in exactly four commits since the last round (78b74147,00d73d6a,c9ea624e,521f125b) and every one is titled for work in another area — an ASAN sweep, a TBR perf change, a sector guard, a TBR test. The Wagner kernel edits were made by sessions whose attention was elsewhere. The brief pasted the full diff and named five specific things to decide on the code rather than from the comments; the round's two highest-severity findings both came out of that region or the constraint machinery it touches. Recommend making "diff the scope files against the last round's commit, and check whether the intervening commits were about this area" a standing first step for every re-visit.T-364 (P1) — the headline, and it is reproducible from the repo's own test suite.
AdditionTree(constraint = ...)silently returns a constraint-violating tree whenever the un-filtered 3-taxon base puts the constraint's inside-LCA at the root:wagner_map_constraint_nodesthen hascn == root, andts_wagner.cpp:410skips that split entirely on every subsequent insertion. The load-bearing sub-claim is monotonicity —cncan only move rootward, because grafting a leaf preserves ancestor relations among existing nodes — so the split is never re-enforced. Verified two ways. (a) The verifier enumerated the base-triple arrangements on a 10-taxon single-split case: 3 of 4 givecn == root, and in those the returned tree was byte-identical to the unconstrained tree. (b) It makestests/testthat/test-AdditionTree.R:66-83latently fail: over 400 seeds the test's own assertion fails 35/400 = 8.75%, seed 23 returning((a,(d,(b,(c,f)))),e);witheandfapart, silently, no warning. The orchestrator re-ran (b) independently rather than taking the verdict — same 35/400, same seed-23 tree. The test passes today only because its two un-seeded assertions inherit a benign RNG state fromset.seed(1)at:6; nothing pins that. Severity is P1 because a documented exported argument is silently not honoured on ordinary input at ~1-in-11 odds; theMaximizeParsimony()path is shielded by the 100-retry posthoc check, so this is not a search-correctness P1, and no reachability figure was claimed for the related T-324 (that remains the HPC question). Repro gotcha worth remembering:build_constraintcanonicalizes so tip 0 is always outside, flipping the mask — three verifier attempts failed on exactly this before it was spotted.FIXED INLINE (4, in four commits, all named-file staging on a branch with live concurrent sessions). (1)
32435fd4— deadinappLevel <- which.max(inapp)inLengthAdded(); worth removing rather than ignoring becausewhich.max()on an all-FALSE logical returns 1L, so a future reader who started using it would get a wrong answer, not an error. (2)d3500aa1—AdditionTree()'s@returnpromised a tree "rooted onsequence[1]", which was never true (build_three_taxon_treemakesorder[0]a grandchild of the root); verified on three differentsequence[1]values, none root-adjacent, and confirmed doc-only because the score is rooting-invariant (TreeLength 86 both as returned and afterRootTree(., 1)). Also documented thenTaxa < 4Learly return, which silently ignoressequenceandconstraint..Rdhand-edited to match rather than re-running roxygen, to avoid touching unrelated generated files. (3)3c19b6b3— removed the deadew_scoreaccumulation and corrected the two comments that asserted a false invariant; both files passg++ -fsyntax-only -Wall -Wextrawith no new warnings. (4)9fc2b6e3— pinnedset.seed(1)on the two un-seeded assertions intest-AdditionTree.R:66-83, with a comment recording T-364's mechanism, the 8.75% failure rate, seed 23's tree, and the instruction to drop the pin for a multi-seed loop once T-364 lands. This does not hide the bug (T-364 is filed P1 with a standalone repro); it stops a 1-in-11 random red landing on an unrelated PR with a signal pointing nowhere near the cause, and makes a pass that was previously luck into a pass that is intentional.T-364 WAS CONSIDERED FOR AN INLINE FIX AND DELIBERATELY LEFT FILED. The tempting fix — detect
cn == rootat step 3 and reshuffle, mirroringrandom_wagner_tree/biased_wagner_tree(:770-779,:809-822) — does not transplant. Those own their shuffle, so they can redraw;AdditionTreeassembles a complete order in R (user prefix plussample(unlisted),R/AdditionTree.R:68) and calls the kernel once, so C++ cannot tell a user-pinned prefix from a filled tail and has nothing safe to reshuffle. A retry therefore belongs in the R layer and brings real design decisions with it (retry count; what to do when the whole order is pinned; warn versus error; the added cost on every constrainedAdditionTreecall). Nor is base-triple permutation sufficient on its own: it fixes the "exactly two of three inside" arrangements, but not "all three inside", and with nested splits no permutation of a fixed triple satisfies every split simultaneously. Maintainer's call, so filed rather than half-fixed.THE MOST IMPORTANT INLINE FIX IS A COMMENT.
ts_prune_reinsert.cpp:453stated "wagner_incremental_rescoremaintains bothprelimandfinal_". Thefinal_half is false (T-367), and this is precisely the comment that would walk the next author back into the wrong-cost bug that existed before the edge-set rewrite. Replaced with an explicit "do NOT extend this tofinal_" note explaining the Phase-1/Phase-2 mismatch. Equally: thefitch_scorecall atts_wagner.cpp:449now carries a DO-NOT-DELETE note, because the obvious-looking cleanup (the variable it initialised was dead) would silently break the seeding of thei == 3insertion step.VERIFICATION CHANGED THE RECORD ON THREE OF TEN — the value here was precision, not filtering. Nothing was refuted outright, but: (1) T-365 down, P1 to P2 — every demonstrated
concavity = "profile"failure is a loudRcpp::exception, and the verifier actively searched for a silent-wrong-numbers path and could not construct one, so the finder's implication of corrupted output is unsupported. The verifier also found a third failing variant the finder missed. (2) T-364 up — the finder scoped it as a T-324 mechanism note; the verifier found it silently breaks the publicAdditionTree()entry point and flunks an existing test. (3) T-366 down, med to P3 — the mechanism is real, butpruneReinsertCycles = 0Lin both defaults with no preset override, so the path is opt-in and off everywhere shipped. T-367's most quotable claim was REFUTED in magnitude and must not be recorded: "stalefinal_made every edge below the break point cost the fullactive_mask" is wrong, becausesimd::any_hit_reduce3unions the two endpoint finals, so one stale-zero endpoint degrades the state set without zeroing it. Stalefinal_is a plausible contributor to the historical "+30% Wagner trees", not the explanation — an attribution error that would have entered the project's record unchallenged. The verifier also narrowed the finder's four "false comment" citations to the two that genuinely assert the invariant, one of them#ifdef-gated.ORCHESTRATOR RE-VERIFIED THREE CRUXES RATHER THAN TAKING A VERDICT. (a) T-364's 35/400 flaky-test rate — the single fact deciding P1 versus P3. (b) T-369's
identical()topology claim, which the haiku verifier had confirmed by reasoning about the placement path rather than executing the repro it was asked to run; re-run, 6/6 identical. (c) T-368's call-site count, where my own first grep found one call and both agents cited two — they were right and the grep was too narrow, because both calls route through thewagner_update_constraintwrapper. Pattern: a verifier that reasons its way to the right answer still leaves the falsifiable core unexecuted, and the orchestrator is the last chance to run it.ENVIRONMENT DEFECT FOUND WHILE SETTING UP REPROS — costs every future round time if not fixed. The R that plain
Rscriptresolves to here is R-devel 4.7, and its library contains aTreeSearch/directory holding onlylibs/— noDESCRIPTION, noR/, noMeta/. Solibrary(TreeSearch)fails outright under the default R. This is adev/build-fast.Rresidue (it hot-swaps the DLL and nothing else). The only loadable installs are R 4.6's (2.0.0.9000, built 2026-06-01) and R 4.5's (2.0.0, built 2026-07-07), both stale relative to the worktree — a sharper form of [[stale-local-treesearch-lib]] than that memory currently records, since the default interpreter cannot load the package at all. Workarounds used this round:pkgload::load_all(compile = FALSE)(verifier) and R 4.5 plus a per-file git-log staleness check (orchestrator —R/AdditionTree.Rlast changed78b74147, 2026-06-19, so the 07-07 install is current for that file). Always discharge the staleness caveat per file, by git log, before trusting an R-level repro. The finder's own basis was in fact unusable and it did not notice; its findings survived only because the verifier redid them underload_all.RULED OUT WITH EVIDENCE — do not re-derive.
tw = tree.total_wordsversusds.total_wordsstride divergence: impossible,wagner_treealways callsinit_wagner_statefirst (:27). Stale-slot reads from the non-zeroingedge_set/edge_set_up/edge_set_prereuse: impossible, write-before-read is complete and there is already a debug assert atsrc/ts_fitch.cpp:610-634.have_words == falseleavingbest_above/best_below == -1: cannot happen unconstrained, and constrained it falls through to the:560-564root-edge fallback, which warns.split_root[]sentinel needing the same guard elsewhere: only two readers, both guarded.r == 1node-budget OOB write inrandom_constrained_tree: the arithmetic hole is real but UNREACHABLE —build_constraintcanonicalizes tip 0 outside, so tip 0 is always a root-level item, forcingr >= 2; also confirmed empirically with all-ones andn-1-ones constraint matrices. Notebuild_constraint_from_r(src/ts_rcpp.cpp:275+) does no split-size validation, so the R-layer filter is the only guard. Caller-scope check:ts_wagner_treehas exactly one R caller (R/AdditionTree.R:117),ts_random_wagner_treeis tests-only, andbiased_wagner_treeis C++-only — no caller outside the scope row, unlike area 7's stale scope.FOR THE NEXT ROUND (strongest lead first). (1)
expand_and_reinserttakes aConstraintData* cdand never reads it — surfaced as a pre-existing-Wunused-parameterwarning atsrc/ts_prune_reinsert.cpp:353while warning-checking an unrelated edit. If prune-reinsert genuinely reinserts tips without consulting the constraint, that is a T-324-shaped gap on another path. Unverified — I did not chase it, and it should not be treated as a finding until someone does. Also recorded asescalation-backlog.mditem 6, because it is cross-area (area 9 found it, areas 3/13 own it) and this round established that a cross-area note left only here is read by nobody — the first application of that rule. (2) Park for area 13:build_constraint's canonicalization uses the complement including ambiguous tips, whereas.PrepareConstraint's four-gamete gate (R/MaximizeParsimony.R:165-181) uses only the explicit 0-group excluding them — so passing the R gate does not guarantee the canonical masks are laminar, andrandom_constrained_tree'sis_strict_subsetnesting model can be handed crossing splits whenever tips are?for a constraint character. Posthoc verify catches the tree, so the symptom is retry churn, not a wrong answer — another T-324 contributor. (3)wagner_incremental_rescorenow has three callers with three differentprelim-seeding conventions (ts_wagner.cpp:449andts_sector.cpp:917usefitch_score;ts_prune_reinsert.cpp:396usesscore_tree), and that contract is undocumented ints_wagner.h— a one-line precondition would have prevented T-366 and will prevent the next instance. (4)softmax_sample_order(:681-751) numerics under extremetemperaturewere not audited; only thetotal == 0andr <= cumdegenerate paths were checked. (5) Neithertest-ts-wagner.Rnortest-PolEscapa.Rhas aconcavity = "profile"case — one test would have caught both T-365 and T-369's profile asymmetry.Seam status: STILL YIELDING, emphatically — 8 filed including a P1, from a seam that has now yielded at opus on three consecutive visits. Next area-9 visit stays at opus, fresh agent. Next area: 10 (Alternative scoring kernels) — which also owns the orphaned inapplicable-IW residual recovered into
escalation-backlog.mditem 5(a) this round (commit9d3c6566): the 2026-06-16 area-9 signal that Wagner NA+IW scores 3.003497 on Vinther2008 whileTreeLengthreturns 2.974744 had been sitting in a log entry and nowhere else for six weeks, invisible totidybecausetidyreconciles filed findings. Carry it.All reactions