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

Ralph Loop 2026-03-16: Replay Event Stream Quality

Change

Expanded replay_prepare_done telemetry in research/continuous_loop.py so the step-level event stream now carries:

  1. pair_eventful_metadata_rows
  2. large_move_rows
  3. large_move_untagged_rows
  4. large_move_missing_eventful_metadata_rows
  5. large_move_zero_score_rows
  6. large_move_scored_untagged_rows
  7. large_move_unscored_untagged_rows
  8. review_signal_rows

Why

Ralph is instructed to read research/continuous_loop_events.jsonl, but that event stream previously reduced replay preparation to:

  1. replay_rows
  2. eventful_rows
  3. actionable_signal_rows

That was not enough to tell whether a zero-action loop was caused by:

  1. stale or missing eventful metadata
  2. genuine scanner zero scores
  3. sleeves having nothing reviewable to act on

The richer replay profile already existed in latest_state.json, but not in the operator-facing event log.

Validation

Commands:

pytest -q tests/test_continuous_loop.py tests/test_research_status.py tests/test_prepare_replay.py
python3 - <<'PY'
from research.continuous_loop import _replay_prepare_event_payload
summary = {
    "replay_rows": 1676,
    "profile": {
        "eventful_rows": 112,
        "pair_eventful_metadata_rows": 1648,
        "large_move_rows": 28,
        "large_move_untagged_rows": 28,
        "large_move_missing_eventful_metadata_rows": 28,
        "large_move_zero_score_rows": 0,
        "large_move_scored_untagged_rows": 0,
        "large_move_unscored_untagged_rows": 28,
        "actionable_signal_rows": 0,
        "review_signal_rows": 0,
    },
}
print(_replay_prepare_event_payload(24, summary))
PY

Results:

  1. 11 passed in 0.10s
  2. Helper smoke output included the new metadata-gap and zero-score split in the emitted event payload.

Interpretation

This is a bounded PRD 001 / PRD 004 improvement. Ralph can now inspect the event stream directly and distinguish:

  1. metadata gap: large_move_missing_eventful_metadata_rows
  2. scanner zero: large_move_zero_score_rows
  3. near-threshold miss: large_move_scored_untagged_rows
  4. no reviewable sleeve input: review_signal_rows=0

That makes the next loop decision less dependent on re-deriving replay diagnostics from larger artifacts.