Skip to content

The "enforced splits are protected from collapse" promise is implemented as an exact-match test, so under the DEFAULT collapse = TRUE the search returns trees that VIOLATE the user's constraint. #19

Description

@ms609

Severity: P2 · Area: 11 (Collapse), 13 (Constraint)

Location: src/ts_rcpp.cpp:2244-2269 (bit-identical comparison against canonicalised consSplitMatrix rows); consZero computed at R/MaximizeParsimony.R:134, :143, :153 and dropped from the returned list at :191-198; promise at :918-921

The flag is cleared only when a node's descendant bitset is bit-identical to a constraint row, and the kernel has no access to consZero, so any constraint split realised by a node that is not exactly the 1-group is unprotected. Verified REAL end-to-end, and worse than the finder framed it (opus verifier). Promise quoted verbatim from :918-921; names(cargs) confirmed at runtime to carry no consZero. Kernel-level, deterministic (only (g,h) supported, cons = c(a=1, b=1, c=0, d=0, e:h="?")): realising node {a,b} exactly -> protection fires, constraint still shown; realising node {a,b,e} -> (a,(b,c,d,e,f,(g,h))), not shown; realising node {a,b,e,f} -> same, not shown. End-to-end through the public API (8 taxa, 2 characters supporting (a,e) + 2 supporting (b,f), constrained optimum 4 from tree = (((a,e),(b,f)),(c,(d,(g,h))))): collapse = TRUE -> 20/20 returned trees violate the constraint (e.g. (a,(e,(c,d,g,h,(b,f)))) at score 4, where no split separates {a,b} from {c,d}); collapse = FALSE -> 0/20. So the defect is not merely a hidden grouping — the returned tree breaks a hard user-specified contract. This is the precise limit of the finder's own answer to key question 6. It correctly derived that collapse cannot violate a constraint in the min-length sense (contracting an edge replaces a resolution by a polytomy whose Fitch length is the min over resolutions, so no character's length can rise, and a "constraint characters at minimum length" constraint survives any contraction) — but in the displayed-split sense, which is what @param constraint promises the user, it does. Record both halves: the min-length argument is sound and should not be re-derived. Fix direction confirmed to match the mechanism: protect the MRCA of the 1-group when it excludes the 0-group, which requires plumbing consZero through .PrepareConstraint's return. P2 rather than P1 only because the regime is narrow — the constraint's realising split must be both unsupported and not exactly the 1-group; the case for P1 is that it silently breaks a hard contract on the default path.


Migrated 2026-08-04 from dev/red-team/findings.md; pre-tracker ID T-403. References to T-403 in source comments, dev/red-team/log.md, commit messages and PR bodies mean this issue — see dev/red-team/migration-map.tsv. Cross-repo references use the fully-qualified form agent-issues/TreeSearch#<n>; a bare #n means this repo.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:11Red-team focus area 11area:13Red-team focus area 13in-progressBeing fixed; claiming comment names the branchred-teamFiled by the /red-team rotationsev:medP2: wrong on edge input / search quality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions