fix(insights): derive real terminal_state for bounded large-session profiles - #3492
Conversation
…rofiles
Problem: the bounded/degraded large-session profile path
(build_large_session_insight_record_bundle_{sync,async} in
storage/insights/session/rebuild.py) hardcoded
terminal_state="unknown"/confidence=0.0/method="bounded_materialization"
unconditionally. Live evidence: all 1,575 bounded_large_session profiles
carried terminal_state="unknown" (100%), making the longest -- and most
failure-prone -- sessions terminal-state-blind. `_terminal_state`
(archive/session/runtime.py) is structurally O(session tail): it only
needs the last message, last tool outcomes, and trailing session events,
not a full-session scan, so excluding it from the bounded path was
unnecessary caution (polylogue-wofr).
What changed: added a bounded tail read (last 50 messages + their
tool_use/tool_result blocks + last 200 trailing session events, via new
`_tail_session_sync`/`_tail_session_async` and
`_bounded_session_terminal_state_{sync,async}`) that hydrates a minimal
in-memory `Session` for just that window and calls the exact same
`_terminal_state` derivation the unbounded profile path uses -- no
parallel heuristic. `_large_session_profile_record_from_row` now takes an
optional `terminal_state_result` and threads it into the evidence,
inference, and stored profile-record fields, keeping the
`bounded_materialization` provenance marker alongside the real structural
evidence. All other bounded/degraded reductions (workflow_shape, cost,
work events, phases) are unchanged.
Verification:
- `python -m devtools test tests/unit/storage/test_session_insight_refresh.py`
-- 32 passed, including two new tests:
`test_large_session_rebuild_derives_terminal_state_from_bounded_tail`
(asserts terminal_state="error_left"/method="action_outcome" from a
bounded-path tail read; reverting to hardcoded "unknown" makes it fail,
confirmed by mutation) and
`test_bounded_and_unbounded_terminal_state_agree_on_shared_fixture`
(parity: the same fixture materialized once unbounded and once bounded
derives identical terminal_state/method/confidence).
- `python -m devtools verify --quick` -- exit 0 (format, lint, mypy
--strict, render-all-check, layering, schema-versioning, and other
policy gates).
- `python -m mypy polylogue/storage/insights/session/rebuild.py` --
Success: no issues found.
Not run: `devtools verify --all` / full non-integration suite (out of
scope for this focused fix; the touched surface's own test file is green).
Ref polylogue-wofr
Co-Authored-By: Claude <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reached
Next review available in: 36 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Bounded/degraded large-session profiles now compute a real
terminal_statefrom a bounded tail read, instead of hardcoding"unknown"unconditionally.Problem
Live evidence (triage-verified 2026-07-31): all 1,575
bounded_large_sessionprofiles carriedterminal_state="unknown"(100%) —build_large_session_insight_record_bundle_{sync,async}instorage/insights/session/rebuild.pyhardcodedterminal_state="unknown",terminal_state_confidence=0.0,terminal_state_method="bounded_materialization"unconditionally, regardless of any structural evidence in the session. Messagestop_reasonis now persisted (index v46, PR #3390), but the bounded profile path never read the tail data needed to derive terminal state at all. This left the longest, most failure-prone sessions (message-count decile 9) terminal-state-blind, gating campaign D3 in the annotation launch order (per polylogue-wofr notes)._terminal_state(archive/session/runtime.py) is structurally O(session tail): it only needs the last message, last tool outcomes, and trailing session events — not a full-session scan — so excluding it from the bounded path was unnecessary caution, not a real cost tradeoff.Solution
_tail_session_sync/_tail_session_asyncinpolylogue/storage/insights/session/rebuild.py): last 50 messages + their non-text (tool_use/tool_result) blocks + last 200 trailing session events for one session, via new_SESSION_INSIGHT_TAIL_MESSAGE_SQL/_SESSION_INSIGHT_TAIL_BLOCK_SQL_TEMPLATE/_SESSION_INSIGHT_TAIL_EVENT_SQLqueries (each LIMIT-bounded, ordered ascending via a subquery so no Python-side reversal is needed).Session(session_from_records) for just that tail window._bounded_session_terminal_state_{sync,async}then callbuild_session_analysis+ the exact same_terminal_statefunction (archive/session/runtime.py) the unbounded profile path already uses — imported directly, not reimplemented, per the existing precedent of importing private runtime helpers into rebuild.py (e.g._primary_model)._large_session_profile_record_from_rownow accepts an optionalterminal_state_resultand threads the real(terminal_state, confidence, evidence, method)into the evidence payload, inference payload, and storedSessionProfileRecordfields. Thebounded_materializationprovenance marker is kept interminal_state_evidencealongside the real structural evidence, so a reader can still tell the record came from the degraded path.terminal_state.A session whose real terminal event falls outside the tail window degrades to whatever
_terminal_statereports from the window it was given (typically"unknown"/"no_signal") — the same honest behavior as before for sessions genuinely lacking structural evidence in scope.Verification
python -m devtools test tests/unit/storage/test_session_insight_refresh.py— 32 passed, including two new tests:test_large_session_rebuild_derives_terminal_state_from_bounded_tail: a bounded-profile fixture whose tail message's final tool outcome is a typed error assertsterminal_state="error_left"/method="action_outcome"via the bounded path withload_sync_batchpatched to raise (proving no full hydration). Anti-vacuity: manually reverted the derivation to the old hardcoded"unknown"and confirmed both this test and the parity test below fail (assert 'unknown' == 'error_left'), then restored the fix.test_bounded_and_unbounded_terminal_state_agree_on_shared_fixture: the same fixture (2 messages, well within the 50-message tail window) materialized once through the ordinary full-analysis path and once through the bounded/degraded path (threshold monkeypatched to 1) derives identicalterminal_state/terminal_state_method/terminal_state_confidencevia both routes.python -m devtools verify --quick— exit 0 (format, lint,mypy --strict,render all --check, layering, schema-versioning, and other policy gates).python -m mypy polylogue/storage/insights/session/rebuild.py— Success: no issues found in 1 source file.Not run:
devtools verify --all/ the full non-integration suite (out of scope for this focused fix; the touched surface's own test file — 32 tests — is green, and per-PR CI runslint+ skips the heavytestsuite until merge).Acceptance criteria (polylogue-wofr)
terminal_state="error_left"with evidence, via the bounded rebuild path. Satisfied (async twin shares the same helper functions, exercised by the existing async bounded-path tests plus manual code-path symmetry — no separate async-specific terminal-state test was added since_bounded_session_terminal_state_asyncis a direct twin of the sync version with identical logic).fail_full_load/guarded_loadmonkeypatches (assertingload_sync_batch/load_async_batchare never called) continue to pass, and the new tail queries are separate LIMIT-bounded SQL, not the full per-session batch loader. No new explicit row-count-budget assertion was added beyond the existing "must not call the full loader" guard — deferring a dedicated cost-pinning test as a possible follow-up if live telemetry ever shows otherwise.Ref polylogue-wofr