Severity: P3 · Area: 10 (HSJ/XFORM kernels), 6 (R<->C++ interface)
Location: src/ts_rcpp.cpp:1836-1864 (the skipped branch at :1849); kernel read at src/ts_hsj.cpp:390; wrapper default at R/ts-driven-compat.R:64, :196-201
hierarchy_blocks, hsj_alpha and scoring_mode = HSJ are set unconditionally, but ds.tip_labels / ds.n_orig_chars only inside the hsjTipLabels-present-and-non-NULL branch. list(hsjTipLabels = NULL) keeps the name (verified), so containsElementNamed passes while Rf_isNull skips the branch -- leaving HSJ enabled with an empty tip_labels, and score_hierarchy_block then evaluates tip_labels[t * 0 + block.primary_char] on an empty vector. Verified REAL -- segfault reproduced, exit 139, by two independent routes (opus verifier, build at bbab0f7c): the grouped interface with hsjConfig$hsjTipLabels present-but-NULL, and the compat wrapper's own default (ts_driven_search(..., hierarchyBlocks = <blocks>, hsjAlpha = 1, hsjAbsentState = 0, ...) with hsjTipLabels simply left at its NULL default). ts_hsj_score cannot reach this state because tip_labels_r is a required argument -- hence the two paths validate values equivalently but not presence, exactly as claimed. This is the live instance of a gap a prior round recorded as hypothetical. The 2026-07-28 round cleared isfinite(concavity) vs scoring_mode as unreachable from the public API but wrote: "R/ts-driven-compat.R builds the same configs without those guards -- check it if that wrapper is ever widened or promoted." It did not need widening. The wrapper does shadow R/RcppExports.R:196 (Collate line 120 after 118, confirmed at runtime) and tests drive it. Held at P3 because no current caller omits hsjTipLabels (R/MaximizeParsimony.R:1537, R/Resample.R:88-91, tests/testthat/test-ts-resample-hierarchy.R:315-319, test-ts-t330-collapse-hsj-xform.R:66-70 all supply it), so it is live code with a dead gap rather than a live crash -- but a segfault behind a one-argument omission on a test-driven internal wrapper is a P2 as a frozen-shape inconsistency, and the fix is one Rf_error. The same-site sub-claim (neither path bounds-checks primary/secondaries against n_orig_chars, :1840-1841 and :3172-3174) is a true code fact but unreachable: ValidateHierarchy bounds indices to [1, nChar], and neither taxon-dropping nor .Recompress() changes nChar.
Migrated 2026-08-04 from dev/red-team/findings.md; pre-tracker ID T-398. References to T-398 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.
Severity: P3 · Area: 10 (HSJ/XFORM kernels), 6 (R<->C++ interface)
Location:
src/ts_rcpp.cpp:1836-1864(the skipped branch at:1849); kernel read atsrc/ts_hsj.cpp:390; wrapper default atR/ts-driven-compat.R:64,:196-201hierarchy_blocks,hsj_alphaandscoring_mode = HSJare set unconditionally, butds.tip_labels/ds.n_orig_charsonly inside thehsjTipLabels-present-and-non-NULL branch.list(hsjTipLabels = NULL)keeps the name (verified), socontainsElementNamedpasses whileRf_isNullskips the branch -- leaving HSJ enabled with an emptytip_labels, andscore_hierarchy_blockthen evaluatestip_labels[t * 0 + block.primary_char]on an empty vector. Verified REAL -- segfault reproduced, exit 139, by two independent routes (opus verifier, build atbbab0f7c): the grouped interface withhsjConfig$hsjTipLabelspresent-but-NULL, and the compat wrapper's own default (ts_driven_search(..., hierarchyBlocks = <blocks>, hsjAlpha = 1, hsjAbsentState = 0, ...)withhsjTipLabelssimply left at itsNULLdefault).ts_hsj_scorecannot reach this state becausetip_labels_ris a required argument -- hence the two paths validate values equivalently but not presence, exactly as claimed. This is the live instance of a gap a prior round recorded as hypothetical. The 2026-07-28 round clearedisfinite(concavity)vsscoring_modeas unreachable from the public API but wrote: "R/ts-driven-compat.Rbuilds the same configs without those guards -- check it if that wrapper is ever widened or promoted." It did not need widening. The wrapper does shadowR/RcppExports.R:196(Collate line 120 after 118, confirmed at runtime) and tests drive it. Held at P3 because no current caller omitshsjTipLabels(R/MaximizeParsimony.R:1537,R/Resample.R:88-91,tests/testthat/test-ts-resample-hierarchy.R:315-319,test-ts-t330-collapse-hsj-xform.R:66-70all supply it), so it is live code with a dead gap rather than a live crash -- but a segfault behind a one-argument omission on a test-driven internal wrapper is a P2 as a frozen-shape inconsistency, and the fix is oneRf_error. The same-site sub-claim (neither path bounds-checksprimary/secondariesagainstn_orig_chars,:1840-1841and:3172-3174) is a true code fact but unreachable:ValidateHierarchybounds indices to[1, nChar], and neither taxon-dropping nor.Recompress()changesnChar.Migrated 2026-08-04 from
dev/red-team/findings.md; pre-tracker ID T-398. References toT-398in source comments,dev/red-team/log.md, commit messages and PR bodies mean this issue — seedev/red-team/migration-map.tsv. Cross-repo references use the fully-qualified formagent-issues/TreeSearch#<n>; a bare#nmeans this repo.