fix(operator-trend): floor rererestore persistence magnitude (T3-2 phase 5)#80
Merged
Merged
Conversation
…ase 5) The rererestore persistence builder decremented per-event `magnitude` without the `max(0.0, ..)` floor its rebuild sibling applies. `magnitude` is per-event evidence strength (non-negative by concept; `sign` carries the direction), so an over-penalized confirmation event went negative and -- after `sign` -- counted against its own side, producing a spurious clearance-leaning persistence_score. Floor the 4 decrements to match rebuild. On the same structural input the two tiers now agree (persistence_score 0.31 == 0.31, was 0.31 vs 0.24), and the rerererestore wrapper that delegates to it no longer yields a spurious negative (-0.08 -> 0.09). The phase-4 composer golden caught this exactly: the regenerated golden diff is 3 score lines, and the anchor test flips from pinning the divergence to pinning the convergence (test_magnitude_floor_unifies_rebuild_and_rererestore_tiers). No existing test pinned the buggy value -- the negative-magnitude path was uncharacterized, which is why the bug survived.
saagpatel
added a commit
that referenced
this pull request
Jun 20, 2026
…trized base (T3-2 phase 6) (#82) The rebuild and rererestore persistence builders were ~190-line hand-clones of one algorithm -- proven identical by the phase-4 composer golden, the floor fix (#80), and a differential test over the net's corpus. Extract a single _persistence_for_target_base plus a _PersistenceTierSpec carrying the per-tier literals (status keys, status tokens, reason prose, output keys); both public builders become thin wrappers that pass their spec. Public signatures are unchanged, so the apply-chain wiring, the rerererestore delegation wrapper (which injects the rererestore builder), and all other callers are untouched. Net -121 lines (265 insertions, 386 deletions). The composer golden is byte-identical -- a correct collapse changes no output -- and the full suite (2539 passed) is green. Correctness is demonstrated, not assumed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
closure_forecast_reset_reentry_rebuild_reentry_restore_rererestore_persistence_for_targetdecremented per-eventmagnitudewithout themax(0.0, ..)floor that itsrebuildsibling applies:magnitudeis per-event evidence strength — non-negative by concept, withsign(±1 by side) carrying direction. Without the floor, an over-penalized confirmation event (mixed-age freshness + a reset signal) drives magnitude negative, andsign * magnitudethen makes that confirmation event count against its own side — a confirmation-side target can get a spurious clearance-leaningpersistence_score.The fix
Floor the 4 decrements (L5776/5778/5780/5788) to match
rebuild. On the same structural input the two tiers now agree, and thererererestorewrapper that delegates to this builder stops producing a spurious negative:persistence_score0.240.31(== rebuild)persistence_score-0.080.09Caught by the phase-4 net
The composer characterization golden (#79) caught this exactly: the regenerated golden diff is 3 score lines, and the anchor test flips from pinning the divergence to pinning the convergence (
test_magnitude_floor_unifies_rebuild_and_rererestore_tiers). No existing test pinned the buggy value — the negative-magnitude path was uncharacterized, which is precisely why the bug survived until the net drove it.Verification
2539 passed, 2 skipped) — zero mirror-test breakagemypyon the edited source clean;ruff check src/ tests/clean