Skip to content

A15-02: SuccessiveApproximations() runs without the sectorial/fuse/pool escape machinery and its documentation never says so #126

Description

@ms609

Severity: sev:low · Area: 15 (Legacy pure-R search API)

Red-team candidate A15-4. This closes out a lead the 2026-08-04 area-13 round explicitly handed to this area.

What area 13 asked

That round traced the constraint/fuse/sector/pool machinery and left this untraced:

Resample.R/SuccessiveApproximations.R also call .PrepareConstraint (R/Resample.R:311, R/SuccessiveApproximations.R:71) and route to ts_resample_search/ts_parallel_resample/ts_successive_approx — not traced this round for whether they carry the fuse/sector/pool gates at all.

Answer: they do not, and the entry point cannot carry them

R/SuccessiveApproximations.R:88–109 builds searchArgs from only saK, maxSAIter, maxReplicates, targetHits, tbrMaxHits, ratchetCycles, min_steps, concavity, the xpiwe* group, plus .KernelConstraintArgs(consArgs) and the profile args.

Cross-checked against the kernel signature at src/ts_rcpp.cpp:2778–2803, ts_successive_approx()'s formals are exactly that list plus ratchetPerturbProb and driftCycles. No sectorMinSize, sectorMaxSize, fuseInterval, fuseAcceptEqual, poolMaxSize, or any other sectorial/pool parameter exists on this entry point at all — unlike the kernel calls MaximizeParsimony() makes (R/MaximizeParsimony.R:349, :365, :388).

So SuccessiveApproximations() is a self-contained ratchet + drift + TBR loop with none of the sectorial or tree-fusing escape machinery the main search relies on to get off local optima on larger or harder datasets.

Why this is filed as a documentation gap, not a bug

The reduced algorithm may well be intentional — successive approximations is Farris's (1969) procedure, and a lighter search per weighting round is a defensible design. Nothing here computes a wrong number.

The problem is that nothing tells the user. SuccessiveApproximations()'s roxygen uses @inheritParams MaximizeParsimony, and because the R signature does not accept the sectorial parameters they simply never appear in the generated man/SuccessiveApproximations.Rd — there is no note, no @section, nothing distinguishing "this parameter is not applicable here" from "this search is materially weaker on hard data". A user reaching for SuccessiveApproximations() to do a custom k-weighted analysis on a nontrivial matrix would reasonably expect search quality comparable to MaximizeParsimony(), and would have no way to learn otherwise short of reading src/ts_rcpp.cpp.

Suggested fix

A short @section (or a sentence in @details) stating that this function runs a ratchet/drift/TBR search without the sectorial-search, tree-fusing and pool machinery available through MaximizeParsimony(), and pointing users with hard datasets at the latter.

Worth deciding at the same time whether the gap itself should close — but that is a separate, larger question and should not block the doc fix.

Adjacent, not chased

SuccessiveWeights() (R/SuccessiveApproximations.R:175–189) calls CharacterLength() rather than the kernel. Whether its scoring agrees with the C++ kernel's for the same tree and weights was not traced this round; given #83's finding that TreeLength() and EdgeListScore() already disagree by default on extended IW, it is a reasonable next thread. Note that SuccessiveApproximations() itself is not exposed to #83's two-path divergence — it builds contrast/tip_data/weight directly from the dataset attributes and calls the kernel itself, so it has only the one path.

Verification

Confirmed REAL by an independent verifier against trunk tip e0629be61: argument lists and the C++ signature read directly, and the absence of any warning in the generated .Rd confirmed.

Found by /red-team area 15, 2026-08-05, sonnet (Sonnet 5) — the first review this area has ever had.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:15Red-team focus area 15red-teamFiled by the /red-team rotationsev:lowP3: robustness / polish

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions