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.

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