Fix repeat ownership and close out capture evidence

Start each repeat after its own manifest entry, refuse packets from a restarted
or stopped camera, keep a simulated repeat from reading as recorded evidence,
and decide completeness from the writer report. Add the operator summary (four
files plus an atomic pointer) and read-only video review of a hold window.

Verified with the full Autocal suite (567 passed), the shared recorder/playback
files (57 passed), the lint gate and the documentation gate; the two pre-existing
panel_check layout failures also fail on a clean HEAD worktree.
This commit is contained in:
ykcheungab
2026-10-17 10:44:30 +08:00
parent d7540f52ec
commit 19426c3c4a
32 changed files with 5461 additions and 191 deletions
@@ -0,0 +1,149 @@
"""The review dialog that shows the recorded pictures beside the curve."""
from __future__ import annotations
import pytest
from review_test_helpers import wait_review
from evidence_helpers import multipoint_session
from orisys_autocal.session_review import review_session
@pytest.fixture
def reviewed(tmp_path):
root = multipoint_session(
tmp_path / "rec", sites=("P1",), repeats=1, levels=(5.0, 10.0))
return root, review_session(root)
def _window(review: dict) -> dict:
return review["sites"][0]["windows"][1]
def test_the_dialog_shows_the_first_frame_of_the_selected_window(qt_app, reviewed):
from orisys_autocal.ui.video_review_dialog import VideoReviewDialog
root, review = reviewed
window = _window(review)
dialog = VideoReviewDialog(
root, review, trial_id=window["trial_id"], step_index=int(window["step_index"]))
try:
wait_review(dialog)
assert dialog.video is not None
assert dialog.location.frame_id > 0
assert dialog.image.pixmap() is not None and not dialog.image.pixmap().isNull()
assert "frame" in dialog.position.text().lower() or "帧" in dialog.position.text()
assert dialog.slider.maximum() == dialog.video.frame_count - 1
finally:
dialog.close()
assert dialog.video is None
def test_stepping_moves_one_recorded_frame(qt_app, reviewed):
from orisys_autocal.ui.video_review_dialog import VideoReviewDialog
root, review = reviewed
window = _window(review)
dialog = VideoReviewDialog(
root, review, trial_id=window["trial_id"], step_index=int(window["step_index"]))
try:
wait_review(dialog)
start = dialog.index
dialog._step(1)
wait_review(dialog)
assert dialog.index == start + 1
dialog._step(-1)
wait_review(dialog)
assert dialog.index == start
finally:
dialog.close()
def test_a_stale_frame_request_is_dropped(qt_app, reviewed):
from orisys_autocal.ui.video_review_dialog import VideoReviewDialog
root, review = reviewed
window = _window(review)
dialog = VideoReviewDialog(
root, review, trial_id=window["trial_id"], step_index=int(window["step_index"]))
try:
wait_review(dialog)
dialog._request(0)
dialog._request(1)
wait_review(dialog)
assert dialog.index == 1
assert dialog.video.frame_count >= 2
finally:
dialog.close()
def test_a_recording_without_video_explains_itself(qt_app, tmp_path):
from orisys_autocal.ui.video_review_dialog import VideoReviewDialog
root = multipoint_session(
tmp_path / "rec", sites=("P1",), repeats=1, levels=(5.0,), with_capture=False)
review = review_session(root)
window = review["sites"][0]["windows"][1]
dialog = VideoReviewDialog(
root, review, trial_id=window["trial_id"], step_index=int(window["step_index"]))
try:
wait_review(dialog)
assert dialog.video is None
assert not dialog.play_button.isEnabled()
assert dialog.image.text()
assert "no" in dialog.image.text().lower() or "没有" in dialog.image.text()
finally:
dialog.close()
def test_the_hold_review_dialog_offers_the_video_for_the_selected_window(qt_app, reviewed):
from orisys_autocal.ui.session_review_dialog import SessionReviewDialog
from orisys_autocal.ui.video_review_dialog import VideoReviewDialog
root, review = reviewed
dialog = SessionReviewDialog(root, review=review)
try:
assert dialog.video_button.isEnabled()
opened = dialog._video()
assert isinstance(opened, VideoReviewDialog)
wait_review(opened)
opened.close()
finally:
dialog.close()
def test_the_record_overview_offers_the_video_action(qt_app, reviewed):
from orisys_autocal.ui.record_overview_dialog import RecordOverviewDialog
from orisys_autocal.ui.video_review_dialog import VideoReviewDialog
root, review = reviewed
dialog = RecordOverviewDialog(root, review=review)
try:
actions = [action.objectName() for action in dialog.tools.menu().actions()]
assert "overview_video" in actions
dialog.table.clearSelection()
dialog.table.setCurrentCell(-1, -1)
assert dialog._video() is None
assert dialog.notice.text()
dialog.table.selectRow(0)
opened = dialog._video()
assert isinstance(opened, VideoReviewDialog)
wait_review(opened)
opened.close()
finally:
dialog.close()
def test_an_unclosed_trial_does_not_offer_the_video(qt_app, tmp_path):
from orisys_autocal.ui.session_review_dialog import SessionReviewDialog
root = multipoint_session(
tmp_path / "rec", sites=("P1",), repeats=1, levels=(5.0,), trial_status="incomplete")
review = review_session(root)
dialog = SessionReviewDialog(root, review=review)
try:
assert dialog._video() is None
assert dialog.message.text()
finally:
dialog.close()