pam ▸ docs/generated/ralph_loop_2026-03-16_status_freshness_candidate_review_refresh.md
updated 2026-03-28

Ralph Loop 2026-03-16: Status Freshness Candidate Review Refresh

Why this change

python3 main.py research-status --json was hydrating a fresh live candidate_review packet, but the returned freshness block still preferred the older stored candidate_review_generated_at and latest_scan_finished_at timestamps from research/latest_state.json.

That made the handoff internally inconsistent:

  1. candidate_review.generated_at was fresh
  2. freshness.candidate_review_generated_at still pointed at the stale packet
  3. status_notes could still include candidate_review_is_stale even after the candidate-review packet had just been refreshed

This is a data-quality issue for PRD 003 and PRD 004 because Ralph uses the status handoff to decide whether live review quality is stale or current.

Change

Updated research/status.py so _build_freshness() now prefers the currently hydrated payload["candidate_review"] timestamps over the older stored freshness values when both are present.

Added a focused regression in tests/test_research_status.py covering the exact case:

  1. stale stored freshness timestamps
  2. fresh in-memory candidate-review refresh
  3. freshness block must follow the refreshed packet

Validation

  1. pytest -q tests/test_research_status.py Result: 11 passed in 0.13s
  2. python3 main.py research-status --json Result: - candidate_review.generated_at = 2026-03-16T19:19:50.890990+00:00 - freshness.candidate_review_generated_at = 2026-03-16T19:19:50.890990+00:00 - freshness.candidate_review_age_seconds = 0 - freshness.candidate_review_is_stale = false - status_notes no longer includes candidate_review_is_stale

Outcome

Status output now reports candidate-review freshness consistently after a live refresh, which makes stale-vs-current review quality visible without forcing Ralph to reconcile conflicting fields manually.