Control channel: scope buffer page reads to referenced pool entries and attachments#85
Control channel: scope buffer page reads to referenced pool entries and attachments#85i-am-marvin wants to merge 6 commits into
Conversation
Paged sample-history reads from the realtime buffer (open_sample_history_from / open_sample_history_tail) previously loaded and parsed the sample's entire message pool, call pool, and every attachment body on every page request, making control-channel event polls O(sample) instead of O(page). SampleHistory pools are now position-keyed mappings; page-scoped reads collect the input_refs/call_refs positions and attachment hashes actually referenced by the page's events (including refs inside the loaded pool entries) and fetch only those rows. Full-history reads still load complete pools, and events_data (dense pools for .eval serialization) now guards against misuse on page-scoped histories. Pool-ref resolution accepts position-keyed mappings alongside dense lists. Fixes #80 Co-authored-by: Ransom Richardson <1209015+ransomr@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Reviewed the page-scoped pool/attachment loading. I verified the core invariants and found no correctness or security issues -- just two minor non-blocking nits, both around the What I checked:
Verification: |
|
🔎 Review complete. |
|
🤖 auto review rounds: 2 (cap 10). |
Replace the contiguity heuristic in SampleHistory.events_data with an explicit page_scoped field set by the construction site, so pages that reference a contiguous pool prefix also raise instead of returning truncated pools. Bind events_data to a local in eval_retry_error_from_history to avoid rebuilding the dense pools twice. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Re-reviewed at head 8632662 (round 2, after the previous review's nits were addressed). No correctness or security issues found, and no remaining nits. Both prior suggestions are correctly resolved:
What I verified this round:
|
|
🔎 Review complete — no outstanding suggestions. |
|
@ransomr 🤖 auto: the reviewer has no outstanding feedback — this PR has converged. auto never takes the final step (merge, or upstream promotion on the fork), so it's yours now; see the checks above for CI status. The |
Add POOL_REF_FIELDS in event._pool as the single registry of event fields carrying range-encoded pool refs, with collect_pool_ref_positions() replacing the hardcoded collector in the buffer database. A new test introspects the event models for *_refs fields and fails when one isn't registered, so page-scoped reads can't silently drop pool entries for a future ref field. Also add strict=True to the SampleHistory pool re-keying zips so a length mismatch raises instead of truncating. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@review full review please — latest push adds a shared POOL_REF_FIELDS registry (with an introspection test enforcing registration) and strict pool re-keying in SampleHistory. |
…-80-20260714-2155 # Conflicts: # CHANGELOG.md
ReviewReviewed the full diff (page-scoped pool/attachment loading for buffer page reads). No correctness or security issues found - two non-blocking documentation/maintainability nits posted inline. What I checked:
Verification run locally: If you want the nits addressed, reply with a top-level |
|
🔎 Review complete. |
… histories on the SampleBuffer interface Review round 2 feedback: move the export path's pool-ref remapping into event._pool as remap_pool_refs(), walking the POOL_REF_FIELDS registry so a newly registered ref field is remapped without a code change, and note on the abstract open_sample_history_tail/_from docstrings that they yield page-scoped histories (sparse pools, events_data raises). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ReviewI reviewed the full diff (page-scoped pool/attachment loading for buffer page reads, the position-keyed Position-recovery invariant — the No dense-pool consumer sees a sparse history — all Attachment scoping — collection walks both the page's event JSON and the loaded pool entries, which covers large message content stored as attachments inside pooled messages; hash queries are sample-scoped and chunked under the bound-parameter limit (500 + 2 fixed params stays under 999). Transaction consistency — all page-scoped queries execute eagerly inside the Export remap refactor — Verification run locally: |
|
🔎 Review complete — no outstanding suggestions. |
|
@claude open the upstream PR |
|
Claude finished @ransomr's task in 4m 8s —— View job Opening the upstream PR
What was doneThe branch is fully prepared for upstream promotion:
Why I couldn't open the PRI'm unable to create the upstream PR because both credentials available to this job are scoped to the To open it yourselfEverything is staged — either use the compare link or the one command below: Compare link: UKGovernmentBEIS/inspect_ai@main...meridianlabs-ai:inspect_ai:claude/issue-80-20260714-2155 Or via gh api repos/UKGovernmentBEIS/inspect_ai/pulls -X POST \
-f \
-f base="main" \
-f head="claude/issue-80-20260714-2155" \
-f head_repo="meridianlabs-ai/inspect_ai" \
-F body=@body.mdPrepared PR body (save as
|
|
Superseded by the upstream PR: UKGovernmentBEIS#4523 (now the system of record). |
This PR contains:
What is the current behavior? (You can also link to an open issue here)
Fixes #80
When a control-channel events page is served from the realtime sample buffer (
open_sample_history_from→_sample_history), the pagelimitonly bounds the event rows. Each page request also unconditionally loads andjson.loadsthe sample's entire message pool and call pool, and fetches every attachment body for the sample (tens of MB on image-heavy transcripts). Since the read runs synchronously on the eval's own event loop, a read-only monitor pollinginspect ctl eventsimposes repeated blocking pauses on in-flight samples.What is the new behavior?
Fix option 1 from the issue — page-scoped pool/attachment loading:
SampleHistorypools are now position-keyed mappings (dict[int, ...]) rather than dense lists. Full-history reads carry every entry (contiguous keys from 0); page reads carry only referenced positions._sample_history(page_scoped=True)collects theinput_refs/call_refspositional ranges and theattachment://hashes referenced by the page's event JSON (plus refs inside the loaded pool entries, since large message content is itself stored as an attachment), and loads only those rows (WHERE pos IN (...)viaROW_NUMBERrank,WHERE hash IN (...)scoped to the sample;INlists chunked under SQLite's bound-parameter limit).open_sample_history_fromandopen_sample_history_tail) are page-scoped;open_sample_history(full reads: streaming flush, recorder, retry errors) still loads complete pools._expand_refs/resolve_model_event_inputs/resolve_model_event_calls/materialize_pooled_eventsaccept position-keyed mappings alongside dense lists; the buffer transcript history provider resolves against the mappings.SampleHistory.events_data(dense pools for.evalserialization) became a property that raises on a page-scoped (sparse) history rather than silently misaligning refs.Does this PR introduce a breaking change? (What changes might users need to make in their application due to this PR?)
No — all changed interfaces are internal (
inspect_ai.log._recorders.buffer.*,inspect_ai.event._pool). Publicresolve_*helpers only widened their accepted parameter types.Other information:
Verification:
pytest tests/log tests/checkpoint tests/_control tests/_eval/test_retry_error_events.py(all passing),ruff check/ruff format, andmypyclean on changed files. New tests intests/log/test_sample_history.pycover page-scoped message/call pool loading, attachment scoping (event-level and pool-entry-level), end-to-end materialization throughBufferTranscriptHistoryProvider.events_from, and theevents_dataguard.The keyset-cursor option (#2 in the issue) is not included; the
ROW_NUMBERCTE still scans the sample's event rows per page, but no longer parses or ships unreferenced pool/attachment content.🤖 Generated with Claude Code