anneal_search (via stochastic_tbr_phase, src/ts_temper.cpp:297) screens candidate moves with
regraft_violates_constraint (a pre-move, min-Fitch heuristic) but has no post-move
map_constraint_nodes verification anywhere in the function — unlike every sibling phase (TBR
ts_tbr.cpp:2867-2883, drift ts_drift.cpp:741, spr_search, prune_reinsert, nni_perturb,
all of which map+verify+revert on every applied move). stochastic_tbr_phase only calls
update_constraint (metadata sync, not a compliance check) at :374.
src/ts_driven.cpp:518-521 then captures best_sa_tree = result.tree on any score improvement
with no compliance test at all — a fourth instance of the ungated-capture class already flagged
in issues #18/#1/#19.
Mitigating factors (why this is filed low, not high)
anneal_search is SPR-only (temper_apply_spr_move); the finder could not construct an
SPR-path false negative in the pre-move screen (see the round's "resolved negative" on Q3:
regraft_violates_constraint's straddle → UNCONSTRAINED branch is sound for SPR specifically,
because the clip's internal induced bipartitions don't change under relocation — this is only
unsound for TBR, which is exactly why the TBR/drift backstops exist).
annealCycles defaults to 0L — opt-in only.
So the pre-move screen probably does catch this case in practice today, but the missing backstop
is a real defence-in-depth gap consistent with the pattern every other phase already guards
against, and it would become live the moment regraft_violates_constraint's SPR-soundness
argument stops holding (e.g. if temper's move set is ever extended).
Fix direction
Add the same map+verify+revert pattern used by TBR/drift/spr_search/prune_reinsert/nni_perturb
to stochastic_tbr_phase's accepted-move path.
anneal_search(viastochastic_tbr_phase,src/ts_temper.cpp:297) screens candidate moves withregraft_violates_constraint(a pre-move, min-Fitch heuristic) but has no post-movemap_constraint_nodesverification anywhere in the function — unlike every sibling phase (TBRts_tbr.cpp:2867-2883, driftts_drift.cpp:741,spr_search,prune_reinsert,nni_perturb,all of which map+verify+revert on every applied move).
stochastic_tbr_phaseonly callsupdate_constraint(metadata sync, not a compliance check) at:374.src/ts_driven.cpp:518-521then capturesbest_sa_tree = result.treeon any score improvementwith no compliance test at all — a fourth instance of the ungated-capture class already flagged
in issues #18/#1/#19.
Mitigating factors (why this is filed low, not high)
anneal_searchis SPR-only (temper_apply_spr_move); the finder could not construct anSPR-path false negative in the pre-move screen (see the round's "resolved negative" on Q3:
regraft_violates_constraint'sstraddle → UNCONSTRAINEDbranch is sound for SPR specifically,because the clip's internal induced bipartitions don't change under relocation — this is only
unsound for TBR, which is exactly why the TBR/drift backstops exist).
annealCyclesdefaults to0L— opt-in only.So the pre-move screen probably does catch this case in practice today, but the missing backstop
is a real defence-in-depth gap consistent with the pattern every other phase already guards
against, and it would become live the moment
regraft_violates_constraint's SPR-soundnessargument stops holding (e.g. if temper's move set is ever extended).
Fix direction
Add the same map+verify+revert pattern used by TBR/drift/spr_search/prune_reinsert/nni_perturb
to
stochastic_tbr_phase's accepted-move path.