Ralph Loop: latest-state candidate-review refresh
Problem:
- research/latest_state.json was still carrying a legacy candidate-review packet shape even after the code learned to name disabled sleeve blockers specifically.
- Example from the stored handoff before refresh:
- top_review_candidate_invalidation_reasons=[["sleeve_disabled", 1], ["heuristic_direction=neutral", 1]]
- top_review_candidate_disabled_sleeves=null
- top review candidate invalidation_reasons=["sleeve_disabled"]
- A live status recomputation already produced the better packet:
- top_review_candidate_invalidation_reasons=[("sleeve_disabled:politics_midprice_reversal", 1), ...]
- top_review_candidate_disabled_sleeves=[("politics_midprice_reversal", 1)]
Bounded change:
- Updated research/status.py so persist_latest_state=True refreshes the candidate-review cluster and freshness block even when those keys already exist in latest_state.json.
- Left other hydrated fields on the existing “fill missing fields” behavior to avoid broad persistence churn.
- Added a regression test proving that a legacy stored packet is rewritten with the specific disabled-sleeve blocker labels and disabled-sleeve concentration fields.
Validation:
- pytest -q tests/test_research_status.py tests/test_continuous_loop.py tests/test_candidate_review.py
- Result: 23 passed in 0.10s
- Manual status snapshot check:
- current recomputed top review blockers: ('sleeve_disabled:politics_midprice_reversal', 1), ('heuristic_direction=neutral', 1)
- current recomputed review disabled sleeves: ('politics_midprice_reversal', 1)
- current recomputed top review candidate blockers: ['sleeve_disabled:politics_midprice_reversal']
Outcome:
- A status refresh can now repair stale candidate-review handoffs instead of leaving raw latest_state.json consumers on the old blocker format.