From c48603905355fc6ddf7dc2fd8f64409e3982dc56 Mon Sep 17 00:00:00 2001 From: LittleSam129 <1qwe432@gmail.com> Date: Mon, 10 Aug 2026 14:34:58 +0300 Subject: [PATCH] Split experiments from tests The tests/ directory held 50 laboratory programs and no tests. They model channels, run hundreds of repetitions and write CSV, PNG and reports; calling that a test suite blocked introducing a real one, because any pytest run would have collected the labs and re-executed every experiment. - move all 50 lab programs to experiments/ with git mv, preserving history - rewrite the 38 cross-imports between labs from tests.labNNN to experiments.labNNN - leave tests/ empty for actual fast checks of protocol/ - point quick_gate and the hook at the new layout and add experiments/ to the syntax sweep - update the paths quoted in the Lab042 specification and the verifier agent definition This also defuses the import-time work finding without touching 41 files: the labs still create directories and write files on import, but nothing imports them now except the gate, which does so deliberately. Gate passes: syntax clean, protocol imports, 15 lab modules import, 2 functional suites run. Co-Authored-By: Claude Opus 5 --- .claude/agents/verifier.md | 4 ++-- docs/lab042_hardware_loopback_spec.md | 12 ++++++------ experiments/__init__.py | 0 {tests => experiments}/lab001_text_bytes.py | 0 {tests => experiments}/lab001_utf8_russian.py | 0 {tests => experiments}/lab002_bit_corruption.py | 0 {tests => experiments}/lab002_packet_structure.py | 0 {tests => experiments}/lab003_crc32.py | 0 {tests => experiments}/lab004_protocol_module.py | 0 {tests => experiments}/lab005_virtual_channel.py | 0 {tests => experiments}/lab006_stop_and_wait_arq.py | 0 {tests => experiments}/lab007_image_fragmentation.py | 0 {tests => experiments}/lab008_image_transfer_arq.py | 0 {tests => experiments}/lab009_real_photo_estimate.py | 0 {tests => experiments}/lab010_image_optimization.py | 0 {tests => experiments}/lab011_scene_modes.py | 0 {tests => experiments}/lab012_color_vs_gray.py | 0 {tests => experiments}/lab013_bpsk_python.py | 0 {tests => experiments}/lab014_bpsk_ber_curve.py | 0 .../lab015_fragment_size_optimization.py | 0 .../lab016_adaptive_fragment_size.py | 0 {tests => experiments}/lab017_link_hysteresis.py | 0 {tests => experiments}/lab018_bpsk_radio_frame.py | 0 {tests => experiments}/lab019_bpsk_receiver.py | 0 .../lab020_bpsk_frame_error_rate.py | 0 .../lab021_frequency_offset_correction.py | 0 .../lab022_noise_and_frequency_offset.py | 0 .../lab023_guarded_cfo_correction.py | 0 {tests => experiments}/lab024a_pluto_rx_capture.py | 0 .../lab024b_pluto_welch_spectrum.py | 0 .../lab025_pluto_wfm_demodulation.py | 0 .../lab026_video_bitrate_benchmark.py | 0 .../lab026b_four_bit_video_benchmark.py | 0 .../lab027_roi_multiresolution_benchmark.py | 0 .../lab027_roi_temporal_preview.py | 0 .../lab027c_synchronous_roi_preview.py | 0 .../lab027d_fps_quality_preview.py | 0 .../lab027e_operator_view_preview.py | 0 {tests => experiments}/lab028_video_packetization.py | 0 .../lab029_packet_channel_simulation.py | 2 +- .../lab029b_time_based_burst_simulation.py | 4 ++-- {tests => experiments}/lab030_packet_erasure_fec.py | 6 +++--- {tests => experiments}/lab031_fec_interleaving.py | 8 ++++---- {tests => experiments}/lab032_fec_parameter_sweep.py | 8 ++++---- .../lab033_priority_channel_scheduler.py | 10 +++++----- {tests => experiments}/lab034_stale_video_drop.py | 10 +++++----- .../lab035_video_frame_admission.py | 6 +++--- .../lab036_long_duration_scheduler.py | 8 ++++---- {tests => experiments}/lab037_lossy_full_link.py | 10 +++++----- {tests => experiments}/lab038_control_failsafe.py | 10 +++++----- {tests => experiments}/lab039_two_stage_braking.py | 8 ++++---- .../lab040_persistent_emergency.py | 8 ++++---- .../lab041_session_restart_safety.py | 4 ++-- tests/__init__.py | 1 + tools/quick_gate.py | 6 +++--- 55 files changed, 63 insertions(+), 62 deletions(-) create mode 100644 experiments/__init__.py rename {tests => experiments}/lab001_text_bytes.py (100%) rename {tests => experiments}/lab001_utf8_russian.py (100%) rename {tests => experiments}/lab002_bit_corruption.py (100%) rename {tests => experiments}/lab002_packet_structure.py (100%) rename {tests => experiments}/lab003_crc32.py (100%) rename {tests => experiments}/lab004_protocol_module.py (100%) rename {tests => experiments}/lab005_virtual_channel.py (100%) rename {tests => experiments}/lab006_stop_and_wait_arq.py (100%) rename {tests => experiments}/lab007_image_fragmentation.py (100%) rename {tests => experiments}/lab008_image_transfer_arq.py (100%) rename {tests => experiments}/lab009_real_photo_estimate.py (100%) rename {tests => experiments}/lab010_image_optimization.py (100%) rename {tests => experiments}/lab011_scene_modes.py (100%) rename {tests => experiments}/lab012_color_vs_gray.py (100%) rename {tests => experiments}/lab013_bpsk_python.py (100%) rename {tests => experiments}/lab014_bpsk_ber_curve.py (100%) rename {tests => experiments}/lab015_fragment_size_optimization.py (100%) rename {tests => experiments}/lab016_adaptive_fragment_size.py (100%) rename {tests => experiments}/lab017_link_hysteresis.py (100%) rename {tests => experiments}/lab018_bpsk_radio_frame.py (100%) rename {tests => experiments}/lab019_bpsk_receiver.py (100%) rename {tests => experiments}/lab020_bpsk_frame_error_rate.py (100%) rename {tests => experiments}/lab021_frequency_offset_correction.py (100%) rename {tests => experiments}/lab022_noise_and_frequency_offset.py (100%) rename {tests => experiments}/lab023_guarded_cfo_correction.py (100%) rename {tests => experiments}/lab024a_pluto_rx_capture.py (100%) rename {tests => experiments}/lab024b_pluto_welch_spectrum.py (100%) rename {tests => experiments}/lab025_pluto_wfm_demodulation.py (100%) rename {tests => experiments}/lab026_video_bitrate_benchmark.py (100%) rename {tests => experiments}/lab026b_four_bit_video_benchmark.py (100%) rename {tests => experiments}/lab027_roi_multiresolution_benchmark.py (100%) rename {tests => experiments}/lab027_roi_temporal_preview.py (100%) rename {tests => experiments}/lab027c_synchronous_roi_preview.py (100%) rename {tests => experiments}/lab027d_fps_quality_preview.py (100%) rename {tests => experiments}/lab027e_operator_view_preview.py (100%) rename {tests => experiments}/lab028_video_packetization.py (100%) rename {tests => experiments}/lab029_packet_channel_simulation.py (99%) rename {tests => experiments}/lab029b_time_based_burst_simulation.py (99%) rename {tests => experiments}/lab030_packet_erasure_fec.py (99%) rename {tests => experiments}/lab031_fec_interleaving.py (99%) rename {tests => experiments}/lab032_fec_parameter_sweep.py (99%) rename {tests => experiments}/lab033_priority_channel_scheduler.py (99%) rename {tests => experiments}/lab034_stale_video_drop.py (99%) rename {tests => experiments}/lab035_video_frame_admission.py (99%) rename {tests => experiments}/lab036_long_duration_scheduler.py (99%) rename {tests => experiments}/lab037_lossy_full_link.py (99%) rename {tests => experiments}/lab038_control_failsafe.py (99%) rename {tests => experiments}/lab039_two_stage_braking.py (99%) rename {tests => experiments}/lab040_persistent_emergency.py (99%) rename {tests => experiments}/lab041_session_restart_safety.py (99%) diff --git a/.claude/agents/verifier.md b/.claude/agents/verifier.md index 6e1b085..0660215 100644 --- a/.claude/agents/verifier.md +++ b/.claude/agents/verifier.md @@ -7,7 +7,7 @@ model: sonnet Ты проверяешь чужую работу в проекте SDR Rover Link: учебно-исследовательский цифровой радиоканал для наземного ровера. Python, модули протокола в `protocol/`, -лабораторные работы в `tests/labNNN_*.py`, журнал проекта в `PROJECT_LOG.md`. +лабораторные работы в `experiments/labNNN_*.py`, журнал проекта в `PROJECT_LOG.md`. Ты не автор кода. Твоя ценность именно в том, что ты не участвовал в его написании. @@ -18,7 +18,7 @@ model: sonnet Если пересказ расходится с первоисточником — это находка, и часто самая важная. 2. **Запусти сам.** Быстрая проверка: `python tools/quick_gate.py`. - Полный прогон лабы: `python tests/labNNN_имя.py`. Не верь чужому «тесты проходят». + Полный прогон лабы: `python experiments/labNNN_имя.py`. Не верь чужому «тесты проходят». 3. **Пересчитай ключевые числа независимым способом.** Это главный инструмент. Симуляция BER проверяется аналитической формулой, счётчик отброшенных пакетов — diff --git a/docs/lab042_hardware_loopback_spec.md b/docs/lab042_hardware_loopback_spec.md index 549d142..6efbd64 100644 --- a/docs/lab042_hardware_loopback_spec.md +++ b/docs/lab042_hardware_loopback_spec.md @@ -22,16 +22,16 @@ | Звено | Где взять | |---|---| -| Разбиение JPEG на фрагменты и сборка обратно | `protocol/image_fragments.py`, примеры в `tests/lab007_image_fragmentation.py` | +| Разбиение JPEG на фрагменты и сборка обратно | `protocol/image_fragments.py`, примеры в `experiments/lab007_image_fragmentation.py` | | Пакет с CRC32, кодирование и разбор | `protocol/packet.py` | -| Подбор размера и качества JPEG | `tests/lab010_image_optimization.py`, готовые профили в `data/processed/lab010` | -| Формирование радиокадра с преамбулой и маркером | `build_radio_frame` в `tests/lab018_bpsk_radio_frame.py` | +| Подбор размера и качества JPEG | `experiments/lab010_image_optimization.py`, готовые профили в `data/processed/lab010` | +| Формирование радиокадра с преамбулой и маркером | `build_radio_frame` в `experiments/lab018_bpsk_radio_frame.py` | | Фильтр приподнятого косинуса | `root_raised_cosine_taps` там же | | Модуляция BPSK | `bpsk_modulate` там же | -| Поиск кадра в потоке отсчётов | `find_radio_frame` в `tests/lab019_bpsk_receiver.py` | +| Поиск кадра в потоке отсчётов | `find_radio_frame` в `experiments/lab019_bpsk_receiver.py` | | Оценка и коррекция ухода частоты | `estimate_carrier_parameters`, `correct_phase_and_frequency` там же | | Демодуляция и разбор кадра | `bpsk_demodulate`, `decode_radio_frame` там же | -| Работа с Pluto на приём | `tests/lab024a_pluto_rx_capture.py` | +| Работа с Pluto на приём | `experiments/lab024a_pluto_rx_capture.py` | **Единственное, чего нет в проекте — передача.** Это и есть основной объём работы. @@ -250,7 +250,7 @@ - Параметры тракта из раздела 5 не менять. - Все константы вынести в начало файла с указанием источника, как это сделано в Lab041. - Никаких вписанных руками результатов: каждое число в отчёте должно вычисляться из измерений текущего запуска. Это отдельно проверяется при приёмке. -- Файл лабораторной: `tests/lab042_pluto_image_loopback.py`, запуск через `python -m tests.lab042_pluto_image_loopback` из корня проекта. +- Файл лабораторной: `experiments/lab042_pluto_image_loopback.py`, запуск через `python -m experiments.lab042_pluto_image_loopback` из корня проекта. --- diff --git a/experiments/__init__.py b/experiments/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/lab001_text_bytes.py b/experiments/lab001_text_bytes.py similarity index 100% rename from tests/lab001_text_bytes.py rename to experiments/lab001_text_bytes.py diff --git a/tests/lab001_utf8_russian.py b/experiments/lab001_utf8_russian.py similarity index 100% rename from tests/lab001_utf8_russian.py rename to experiments/lab001_utf8_russian.py diff --git a/tests/lab002_bit_corruption.py b/experiments/lab002_bit_corruption.py similarity index 100% rename from tests/lab002_bit_corruption.py rename to experiments/lab002_bit_corruption.py diff --git a/tests/lab002_packet_structure.py b/experiments/lab002_packet_structure.py similarity index 100% rename from tests/lab002_packet_structure.py rename to experiments/lab002_packet_structure.py diff --git a/tests/lab003_crc32.py b/experiments/lab003_crc32.py similarity index 100% rename from tests/lab003_crc32.py rename to experiments/lab003_crc32.py diff --git a/tests/lab004_protocol_module.py b/experiments/lab004_protocol_module.py similarity index 100% rename from tests/lab004_protocol_module.py rename to experiments/lab004_protocol_module.py diff --git a/tests/lab005_virtual_channel.py b/experiments/lab005_virtual_channel.py similarity index 100% rename from tests/lab005_virtual_channel.py rename to experiments/lab005_virtual_channel.py diff --git a/tests/lab006_stop_and_wait_arq.py b/experiments/lab006_stop_and_wait_arq.py similarity index 100% rename from tests/lab006_stop_and_wait_arq.py rename to experiments/lab006_stop_and_wait_arq.py diff --git a/tests/lab007_image_fragmentation.py b/experiments/lab007_image_fragmentation.py similarity index 100% rename from tests/lab007_image_fragmentation.py rename to experiments/lab007_image_fragmentation.py diff --git a/tests/lab008_image_transfer_arq.py b/experiments/lab008_image_transfer_arq.py similarity index 100% rename from tests/lab008_image_transfer_arq.py rename to experiments/lab008_image_transfer_arq.py diff --git a/tests/lab009_real_photo_estimate.py b/experiments/lab009_real_photo_estimate.py similarity index 100% rename from tests/lab009_real_photo_estimate.py rename to experiments/lab009_real_photo_estimate.py diff --git a/tests/lab010_image_optimization.py b/experiments/lab010_image_optimization.py similarity index 100% rename from tests/lab010_image_optimization.py rename to experiments/lab010_image_optimization.py diff --git a/tests/lab011_scene_modes.py b/experiments/lab011_scene_modes.py similarity index 100% rename from tests/lab011_scene_modes.py rename to experiments/lab011_scene_modes.py diff --git a/tests/lab012_color_vs_gray.py b/experiments/lab012_color_vs_gray.py similarity index 100% rename from tests/lab012_color_vs_gray.py rename to experiments/lab012_color_vs_gray.py diff --git a/tests/lab013_bpsk_python.py b/experiments/lab013_bpsk_python.py similarity index 100% rename from tests/lab013_bpsk_python.py rename to experiments/lab013_bpsk_python.py diff --git a/tests/lab014_bpsk_ber_curve.py b/experiments/lab014_bpsk_ber_curve.py similarity index 100% rename from tests/lab014_bpsk_ber_curve.py rename to experiments/lab014_bpsk_ber_curve.py diff --git a/tests/lab015_fragment_size_optimization.py b/experiments/lab015_fragment_size_optimization.py similarity index 100% rename from tests/lab015_fragment_size_optimization.py rename to experiments/lab015_fragment_size_optimization.py diff --git a/tests/lab016_adaptive_fragment_size.py b/experiments/lab016_adaptive_fragment_size.py similarity index 100% rename from tests/lab016_adaptive_fragment_size.py rename to experiments/lab016_adaptive_fragment_size.py diff --git a/tests/lab017_link_hysteresis.py b/experiments/lab017_link_hysteresis.py similarity index 100% rename from tests/lab017_link_hysteresis.py rename to experiments/lab017_link_hysteresis.py diff --git a/tests/lab018_bpsk_radio_frame.py b/experiments/lab018_bpsk_radio_frame.py similarity index 100% rename from tests/lab018_bpsk_radio_frame.py rename to experiments/lab018_bpsk_radio_frame.py diff --git a/tests/lab019_bpsk_receiver.py b/experiments/lab019_bpsk_receiver.py similarity index 100% rename from tests/lab019_bpsk_receiver.py rename to experiments/lab019_bpsk_receiver.py diff --git a/tests/lab020_bpsk_frame_error_rate.py b/experiments/lab020_bpsk_frame_error_rate.py similarity index 100% rename from tests/lab020_bpsk_frame_error_rate.py rename to experiments/lab020_bpsk_frame_error_rate.py diff --git a/tests/lab021_frequency_offset_correction.py b/experiments/lab021_frequency_offset_correction.py similarity index 100% rename from tests/lab021_frequency_offset_correction.py rename to experiments/lab021_frequency_offset_correction.py diff --git a/tests/lab022_noise_and_frequency_offset.py b/experiments/lab022_noise_and_frequency_offset.py similarity index 100% rename from tests/lab022_noise_and_frequency_offset.py rename to experiments/lab022_noise_and_frequency_offset.py diff --git a/tests/lab023_guarded_cfo_correction.py b/experiments/lab023_guarded_cfo_correction.py similarity index 100% rename from tests/lab023_guarded_cfo_correction.py rename to experiments/lab023_guarded_cfo_correction.py diff --git a/tests/lab024a_pluto_rx_capture.py b/experiments/lab024a_pluto_rx_capture.py similarity index 100% rename from tests/lab024a_pluto_rx_capture.py rename to experiments/lab024a_pluto_rx_capture.py diff --git a/tests/lab024b_pluto_welch_spectrum.py b/experiments/lab024b_pluto_welch_spectrum.py similarity index 100% rename from tests/lab024b_pluto_welch_spectrum.py rename to experiments/lab024b_pluto_welch_spectrum.py diff --git a/tests/lab025_pluto_wfm_demodulation.py b/experiments/lab025_pluto_wfm_demodulation.py similarity index 100% rename from tests/lab025_pluto_wfm_demodulation.py rename to experiments/lab025_pluto_wfm_demodulation.py diff --git a/tests/lab026_video_bitrate_benchmark.py b/experiments/lab026_video_bitrate_benchmark.py similarity index 100% rename from tests/lab026_video_bitrate_benchmark.py rename to experiments/lab026_video_bitrate_benchmark.py diff --git a/tests/lab026b_four_bit_video_benchmark.py b/experiments/lab026b_four_bit_video_benchmark.py similarity index 100% rename from tests/lab026b_four_bit_video_benchmark.py rename to experiments/lab026b_four_bit_video_benchmark.py diff --git a/tests/lab027_roi_multiresolution_benchmark.py b/experiments/lab027_roi_multiresolution_benchmark.py similarity index 100% rename from tests/lab027_roi_multiresolution_benchmark.py rename to experiments/lab027_roi_multiresolution_benchmark.py diff --git a/tests/lab027_roi_temporal_preview.py b/experiments/lab027_roi_temporal_preview.py similarity index 100% rename from tests/lab027_roi_temporal_preview.py rename to experiments/lab027_roi_temporal_preview.py diff --git a/tests/lab027c_synchronous_roi_preview.py b/experiments/lab027c_synchronous_roi_preview.py similarity index 100% rename from tests/lab027c_synchronous_roi_preview.py rename to experiments/lab027c_synchronous_roi_preview.py diff --git a/tests/lab027d_fps_quality_preview.py b/experiments/lab027d_fps_quality_preview.py similarity index 100% rename from tests/lab027d_fps_quality_preview.py rename to experiments/lab027d_fps_quality_preview.py diff --git a/tests/lab027e_operator_view_preview.py b/experiments/lab027e_operator_view_preview.py similarity index 100% rename from tests/lab027e_operator_view_preview.py rename to experiments/lab027e_operator_view_preview.py diff --git a/tests/lab028_video_packetization.py b/experiments/lab028_video_packetization.py similarity index 100% rename from tests/lab028_video_packetization.py rename to experiments/lab028_video_packetization.py diff --git a/tests/lab029_packet_channel_simulation.py b/experiments/lab029_packet_channel_simulation.py similarity index 99% rename from tests/lab029_packet_channel_simulation.py rename to experiments/lab029_packet_channel_simulation.py index e1ad0ca..87f9e2f 100644 --- a/tests/lab029_packet_channel_simulation.py +++ b/experiments/lab029_packet_channel_simulation.py @@ -27,7 +27,7 @@ from protocol.video_packet import ( PacketCRCError, VideoPacketError, ) -from tests.lab028_video_packetization import ( +from experiments.lab028_video_packetization import ( EncodedComposite, SOURCE_VIDEO_PATH, VideoMetadata, diff --git a/tests/lab029b_time_based_burst_simulation.py b/experiments/lab029b_time_based_burst_simulation.py similarity index 99% rename from tests/lab029b_time_based_burst_simulation.py rename to experiments/lab029b_time_based_burst_simulation.py index 038d78d..57dbbec 100644 --- a/tests/lab029b_time_based_burst_simulation.py +++ b/experiments/lab029b_time_based_burst_simulation.py @@ -32,14 +32,14 @@ from protocol.video_packet import ( ObjectType, decode_packet, ) -from tests.lab028_video_packetization import ( +from experiments.lab028_video_packetization import ( COMPOSITE_FPS, EncodedComposite, SOURCE_VIDEO_PATH, VideoMetadata, load_video_profile, ) -from tests.lab029_packet_channel_simulation import ( +from experiments.lab029_packet_channel_simulation import ( PAYLOAD_SIZES, PreparedProfile, prepare_profiles, diff --git a/tests/lab030_packet_erasure_fec.py b/experiments/lab030_packet_erasure_fec.py similarity index 99% rename from tests/lab030_packet_erasure_fec.py rename to experiments/lab030_packet_erasure_fec.py index e57ff8e..c485d13 100644 --- a/tests/lab030_packet_erasure_fec.py +++ b/experiments/lab030_packet_erasure_fec.py @@ -44,18 +44,18 @@ from protocol.video_packet import ( ObjectType, decode_packet as decode_inner_packet, ) -from tests.lab028_video_packetization import ( +from experiments.lab028_video_packetization import ( COMPOSITE_FPS, SOURCE_VIDEO_PATH, EncodedComposite, VideoMetadata, load_video_profile, ) -from tests.lab029_packet_channel_simulation import ( +from experiments.lab029_packet_channel_simulation import ( PreparedProfile, prepare_profiles, ) -from tests.lab029b_time_based_burst_simulation import ( +from experiments.lab029b_time_based_burst_simulation import ( BAD_TIME_FRACTION, CONTROL_STREAM_BITRATE_BPS, CONTROL_STREAM_BITRATE_KBPS, diff --git a/tests/lab031_fec_interleaving.py b/experiments/lab031_fec_interleaving.py similarity index 99% rename from tests/lab031_fec_interleaving.py rename to experiments/lab031_fec_interleaving.py index 67c2b6a..6111172 100644 --- a/tests/lab031_fec_interleaving.py +++ b/experiments/lab031_fec_interleaving.py @@ -36,18 +36,18 @@ from protocol.video_packet import ( CompositeReassembler, decode_packet as decode_inner_packet, ) -from tests.lab028_video_packetization import ( +from experiments.lab028_video_packetization import ( COMPOSITE_FPS, SOURCE_VIDEO_PATH, EncodedComposite, VideoMetadata, load_video_profile, ) -from tests.lab029_packet_channel_simulation import ( +from experiments.lab029_packet_channel_simulation import ( PreparedProfile, prepare_profiles, ) -from tests.lab029b_time_based_burst_simulation import ( +from experiments.lab029b_time_based_burst_simulation import ( BAD_TIME_FRACTION, CONTROL_STREAM_BITRATE_BPS, CONTROL_STREAM_BITRATE_KBPS, @@ -55,7 +55,7 @@ from tests.lab029b_time_based_burst_simulation import ( generate_bad_intervals, percentile, ) -from tests.lab030_packet_erasure_fec import ( +from experiments.lab030_packet_erasure_fec import ( FECBlockPlan, FECMode, FunctionalTestResult, diff --git a/tests/lab032_fec_parameter_sweep.py b/experiments/lab032_fec_parameter_sweep.py similarity index 99% rename from tests/lab032_fec_parameter_sweep.py rename to experiments/lab032_fec_parameter_sweep.py index 59a4777..4d9f673 100644 --- a/tests/lab032_fec_parameter_sweep.py +++ b/experiments/lab032_fec_parameter_sweep.py @@ -34,18 +34,18 @@ from protocol.video_packet import ( CompositeReassembler, decode_packet as decode_inner_packet, ) -from tests.lab028_video_packetization import ( +from experiments.lab028_video_packetization import ( COMPOSITE_FPS, SOURCE_VIDEO_PATH, EncodedComposite, VideoMetadata, load_video_profile, ) -from tests.lab029_packet_channel_simulation import ( +from experiments.lab029_packet_channel_simulation import ( PreparedProfile, prepare_profiles, ) -from tests.lab029b_time_based_burst_simulation import ( +from experiments.lab029b_time_based_burst_simulation import ( BAD_TIME_FRACTION, CONTROL_STREAM_BITRATE_BPS, CONTROL_STREAM_BITRATE_KBPS, @@ -53,7 +53,7 @@ from tests.lab029b_time_based_burst_simulation import ( generate_bad_intervals, percentile, ) -from tests.lab030_packet_erasure_fec import ( +from experiments.lab030_packet_erasure_fec import ( FECBlockPlan, FECMode, FunctionalTestResult, diff --git a/tests/lab033_priority_channel_scheduler.py b/experiments/lab033_priority_channel_scheduler.py similarity index 99% rename from tests/lab033_priority_channel_scheduler.py rename to experiments/lab033_priority_channel_scheduler.py index f7b5cb5..ac6be0f 100644 --- a/tests/lab033_priority_channel_scheduler.py +++ b/experiments/lab033_priority_channel_scheduler.py @@ -47,21 +47,21 @@ from protocol.video_packet import ( CompositeReassembler, decode_packet as decode_inner_packet, ) -from tests.lab028_video_packetization import ( +from experiments.lab028_video_packetization import ( COMPOSITE_FPS, SOURCE_VIDEO_PATH, EncodedComposite, VideoMetadata, load_video_profile, ) -from tests.lab029_packet_channel_simulation import prepare_profiles -from tests.lab030_packet_erasure_fec import ( +from experiments.lab029_packet_channel_simulation import prepare_profiles +from experiments.lab030_packet_erasure_fec import ( FECBlockPlan, SourcePacket, TransmissionUnit, prepare_source_packets, ) -from tests.lab032_fec_parameter_sweep import ( +from experiments.lab032_fec_parameter_sweep import ( SweepMode, build_parameter_units, ) @@ -994,7 +994,7 @@ def write_report( "8. Созданные файлы и итоговый Git status", "- protocol/link_packet.py", "- protocol/priority_scheduler.py", - "- tests/lab033_priority_channel_scheduler.py", + "- experiments/lab033_priority_channel_scheduler.py", "- data/processed/lab033/lab033_summary.csv", "- data/processed/lab033/lab033_class_metrics.csv", "- data/processed/lab033/lab033_report.txt", diff --git a/tests/lab034_stale_video_drop.py b/experiments/lab034_stale_video_drop.py similarity index 99% rename from tests/lab034_stale_video_drop.py rename to experiments/lab034_stale_video_drop.py index f42414e..c4c7265 100644 --- a/tests/lab034_stale_video_drop.py +++ b/experiments/lab034_stale_video_drop.py @@ -34,10 +34,10 @@ from protocol.video_age_policy import ( schedule_with_video_age, ) from protocol.video_packet import CompositeReassembler, decode_packet as decode_inner_packet -from tests.lab028_video_packetization import COMPOSITE_FPS -from tests.lab029_packet_channel_simulation import prepare_profiles -from tests.lab030_packet_erasure_fec import SourcePacket, prepare_source_packets -from tests.lab033_priority_channel_scheduler import ( +from experiments.lab028_video_packetization import COMPOSITE_FPS +from experiments.lab029_packet_channel_simulation import prepare_profiles +from experiments.lab030_packet_erasure_fec import SourcePacket, prepare_source_packets +from experiments.lab033_priority_channel_scheduler import ( CHANNEL_RATES_KBPS, STREAM_VIDEO, VIDEO_PAYLOAD_SIZE, @@ -982,7 +982,7 @@ def write_report(lab033, continuous, aligned, results, tests): ]) lines.extend(f"- {'PASS' if item.passed else 'FAIL'} {item.name}: {item.detail}" for item in tests) lines.extend(["", "8. Созданные файлы"]) - lines.extend(f"- {path.as_posix()}" for path in (Path("protocol/video_age_policy.py"), Path("tests/lab034_stale_video_drop.py"), SUMMARY_CSV_PATH, VIDEO_CSV_PATH, CONTROL_CSV_PATH, REPORT_PATH, *PLOT_PATHS)) + lines.extend(f"- {path.as_posix()}" for path in (Path("protocol/video_age_policy.py"), Path("experiments/lab034_stale_video_drop.py"), SUMMARY_CSV_PATH, VIDEO_CSV_PATH, CONTROL_CSV_PATH, REPORT_PATH, *PLOT_PATHS)) lines.extend([ "", "9. Итоговый Git status", diff --git a/tests/lab035_video_frame_admission.py b/experiments/lab035_video_frame_admission.py similarity index 99% rename from tests/lab035_video_frame_admission.py rename to experiments/lab035_video_frame_admission.py index 98ed805..8b2ec88 100644 --- a/tests/lab035_video_frame_admission.py +++ b/experiments/lab035_video_frame_admission.py @@ -25,8 +25,8 @@ from protocol.video_frame_scheduler import ( schedule_video_frames, ) from protocol.video_packet import CompositeReassembler, decode_packet as decode_inner_packet -from tests.lab028_video_packetization import COMPOSITE_FPS -from tests.lab034_stale_video_drop import ( +from experiments.lab028_video_packetization import COMPOSITE_FPS +from experiments.lab034_stale_video_drop import ( PolicyDefinition as Lab034Policy, build_aligned_workload, build_lab033_workload, @@ -721,7 +721,7 @@ def write_report(aligned,results,tests): lines.extend(["","5. Интерпретация","- Реактивная Lab034 начинает кадр без гарантии завершения, затем удаляет остаток: уже переданные байты становятся бесполезными, а обновление не публикуется.","- Удаление до первого пакета исключает бесполезную передачу; обслуживание целыми кадрами гарантирует, что начатый кадр будет опубликован.","- Политика самого свежего уменьшает задержку ожидающих данных, но удаляет больше промежуточных кадров; очередь из двух кадров сохраняет больше последовательных обновлений ценой возраста.","- Прогноз полного завершения учитывает весь размер кадра и будущую периодическую высокоприоритетную нагрузку, поэтому полезнее проверки только текущего возраста.","- В модели точно известны команды 20 Гц, телеметрия 10 Гц и аварийная команда 10,0 с; неизвестные будущие дискретные события не моделируются и в реальной системе потребовали бы запаса.","- При устойчивой перегрузке невозможно одновременно сохранить все кадры, исходное JPEG-качество и малую задержку; требуется уменьшить частоту, качество или заранее пропускать кадры.","- Частота обновления, возраст изображения и длительность отсутствия нового изображения оцениваются одновременно: оптимизация одного показателя может ухудшить остальные.","","6. Допущения","- Ошибки и помехи отсутствуют; один общий абстрактный ресурс, форматы Lab028-Lab034 неизменны, активный пакет не прерывается.","- Прогноз не изменяет настоящую очередь; для допущенных кадров сохраняются только агрегированные ошибки, без подробного журнала.","- Политика автоматически не выбирается.","","7. Функциональные проверки"]) lines.extend(f"- {'PASS' if item.passed else 'FAIL'} {item.name}: {item.detail}" for item in tests) lines.extend(["","8. Созданные файлы"]) - lines.extend(f"- {path.as_posix()}" for path in (Path("protocol/video_frame_scheduler.py"),Path("tests/lab035_video_frame_admission.py"),SUMMARY_CSV_PATH,VIDEO_CSV_PATH,CONTROL_CSV_PATH,PREDICTION_CSV_PATH,REPORT_PATH,*PLOT_PATHS)) + lines.extend(f"- {path.as_posix()}" for path in (Path("protocol/video_frame_scheduler.py"),Path("experiments/lab035_video_frame_admission.py"),SUMMARY_CSV_PATH,VIDEO_CSV_PATH,CONTROL_CSV_PATH,PREDICTION_CSV_PATH,REPORT_PATH,*PLOT_PATHS)) lines.extend(["","9. Итоговый Git status","- Lab035 не добавлена в индекс и не закоммичена.","",git_status]) REPORT_PATH.write_text("\n".join(lines)+"\n",encoding="utf-8") diff --git a/tests/lab036_long_duration_scheduler.py b/experiments/lab036_long_duration_scheduler.py similarity index 99% rename from tests/lab036_long_duration_scheduler.py rename to experiments/lab036_long_duration_scheduler.py index 0f95b46..5e0186c 100644 --- a/tests/lab036_long_duration_scheduler.py +++ b/experiments/lab036_long_duration_scheduler.py @@ -31,12 +31,12 @@ from protocol.packet_erasure_fec import ( from protocol.video_age_policy import AgePolicyPacket from protocol.video_frame_scheduler import FramePolicy, VideoFrameGroup from protocol.video_packet import decode_packet as decode_inner_packet -from tests.lab028_video_packetization import ( +from experiments.lab028_video_packetization import ( COMPOSITE_FPS, EncodedComposite, packets_for_composite, ) -from tests.lab033_priority_channel_scheduler import ( +from experiments.lab033_priority_channel_scheduler import ( STREAM_CONTROL, STREAM_EMERGENCY, STREAM_TELEMETRY, @@ -44,7 +44,7 @@ from tests.lab033_priority_channel_scheduler import ( build_workload as build_lab033_workload, deterministic_payload, ) -from tests.lab034_stale_video_drop import parity_for_partial +from experiments.lab034_stale_video_drop import parity_for_partial OUTPUT_DIRECTORY = Path("data/processed/lab036") @@ -1318,7 +1318,7 @@ def write_report( f"- CRC-проверено общих пакетов: {workload.crc_packets_checked}; FEC-блоков: {workload.crc_blocks_checked}.", "", "7. Созданные файлы", - "- tests/lab036_long_duration_scheduler.py", + "- experiments/lab036_long_duration_scheduler.py", "- data/processed/lab036/lab036_summary.csv", "- data/processed/lab036/lab036_video_metrics.csv", "- data/processed/lab036/lab036_control_metrics.csv", diff --git a/tests/lab037_lossy_full_link.py b/experiments/lab037_lossy_full_link.py similarity index 99% rename from tests/lab037_lossy_full_link.py rename to experiments/lab037_lossy_full_link.py index 4183c35..782d084 100644 --- a/tests/lab037_lossy_full_link.py +++ b/experiments/lab037_lossy_full_link.py @@ -42,8 +42,8 @@ from protocol.packet_erasure_fec import ( from protocol.video_packet import decode_packet as decode_inner_packet from protocol.video_frame_scheduler import VideoFrameGroup from protocol.video_age_policy import AgePolicyPacket -from tests.lab028_video_packetization import COMPOSITE_FPS, EncodedComposite, packets_for_composite -from tests.lab033_priority_channel_scheduler import ( +from experiments.lab028_video_packetization import COMPOSITE_FPS, EncodedComposite, packets_for_composite +from experiments.lab033_priority_channel_scheduler import ( STREAM_CONTROL, STREAM_EMERGENCY, STREAM_TELEMETRY, @@ -51,7 +51,7 @@ from tests.lab033_priority_channel_scheduler import ( build_workload as build_lab033_workload, deterministic_payload, ) -from tests.lab034_stale_video_drop import parity_for_partial +from experiments.lab034_stale_video_drop import parity_for_partial OUTPUT_DIRECTORY = Path("data/processed/lab037") @@ -1186,13 +1186,13 @@ def write_report( "", "Созданные файлы", "- protocol/control_repetition.py", - "- tests/lab037_lossy_full_link.py", + "- experiments/lab037_lossy_full_link.py", *[f"- {path.as_posix()}" for path in (SUMMARY_CSV_PATH, COMMAND_CSV_PATH, VIDEO_CSV_PATH, EMERGENCY_CSV_PATH, REPORT_PATH, *PLOT_PATHS)], "", "Итоговый git status", "?? data/processed/lab037/", "?? protocol/control_repetition.py", - "?? tests/lab037_lossy_full_link.py", + "?? experiments/lab037_lossy_full_link.py", "", "Двоичные пакеты, JPEG, подробные пакетные журналы и дампы не сохранялись.", "Режим защиты автоматически не выбирается: все три режима представлены отдельно.", diff --git a/tests/lab038_control_failsafe.py b/experiments/lab038_control_failsafe.py similarity index 99% rename from tests/lab038_control_failsafe.py rename to experiments/lab038_control_failsafe.py index 3b814c0..968b722 100644 --- a/tests/lab038_control_failsafe.py +++ b/experiments/lab038_control_failsafe.py @@ -43,12 +43,12 @@ from protocol.packet_erasure_fec import ( decode_outer_symbol, ) from protocol.video_packet import decode_packet as decode_inner_packet -from tests.lab033_priority_channel_scheduler import ( +from experiments.lab033_priority_channel_scheduler import ( STREAM_CONTROL, STREAM_EMERGENCY, deterministic_payload, ) -from tests.lab037_lossy_full_link import ( +from experiments.lab037_lossy_full_link import ( BAD_TIME_FRACTION, CHANNEL_RATES_KBPS, DURATION_SECONDS, @@ -1577,7 +1577,7 @@ def write_report( created = ( Path("protocol/control_failsafe.py"), Path("protocol/emergency_ack.py"), - Path("tests/lab038_control_failsafe.py"), + Path("experiments/lab038_control_failsafe.py"), SUMMARY_CSV_PATH, COMMAND_CSV_PATH, EMERGENCY_CSV_PATH, @@ -1596,8 +1596,8 @@ def write_report( "?? protocol/control_failsafe.py", "?? protocol/control_repetition.py", "?? protocol/emergency_ack.py", - "?? tests/lab037_lossy_full_link.py", - "?? tests/lab038_control_failsafe.py", + "?? experiments/lab037_lossy_full_link.py", + "?? experiments/lab038_control_failsafe.py", "", "Lab038 не добавлен в Git и не закоммичен. Двоичные пакеты, JPEG, дампы и подробные пакетные журналы не сохранялись.", ] diff --git a/tests/lab039_two_stage_braking.py b/experiments/lab039_two_stage_braking.py similarity index 99% rename from tests/lab039_two_stage_braking.py rename to experiments/lab039_two_stage_braking.py index 3c6f68e..25e353b 100644 --- a/tests/lab039_two_stage_braking.py +++ b/experiments/lab039_two_stage_braking.py @@ -24,9 +24,9 @@ from protocol.two_stage_failsafe import ( forced_stop, integrate_kinematics, ) -from tests.lab033_priority_channel_scheduler import STREAM_EMERGENCY -from tests.lab037_lossy_full_link import bad_intervals -from tests.lab038_control_failsafe import ( +from experiments.lab033_priority_channel_scheduler import STREAM_EMERGENCY +from experiments.lab037_lossy_full_link import bad_intervals +from experiments.lab038_control_failsafe import ( DURATION_SECONDS, EMERGENCY_SPREAD_US, MASTER_SEED, @@ -1776,7 +1776,7 @@ def write_report( lines.extend(f"- {'PASS' if item.passed else 'FAIL'} {item.name}: {item.detail}" for item in tests) created = ( Path("protocol/two_stage_failsafe.py"), - Path("tests/lab039_two_stage_braking.py"), + Path("experiments/lab039_two_stage_braking.py"), SUMMARY_CSV_PATH, WATCHDOG_CSV_PATH, DISTANCE_CSV_PATH, diff --git a/tests/lab040_persistent_emergency.py b/experiments/lab040_persistent_emergency.py similarity index 99% rename from tests/lab040_persistent_emergency.py rename to experiments/lab040_persistent_emergency.py index 8230d5d..27989b5 100644 --- a/tests/lab040_persistent_emergency.py +++ b/experiments/lab040_persistent_emergency.py @@ -37,9 +37,9 @@ from protocol.two_stage_failsafe import ( TwoStageFailsafe, integrate_kinematics, ) -from tests.lab033_priority_channel_scheduler import STREAM_CONTROL, STREAM_EMERGENCY -from tests.lab037_lossy_full_link import bad_intervals -from tests.lab038_control_failsafe import DURATION_SECONDS, Frame, Unit, Workload, build_workload, packet_is_lost +from experiments.lab033_priority_channel_scheduler import STREAM_CONTROL, STREAM_EMERGENCY +from experiments.lab037_lossy_full_link import bad_intervals +from experiments.lab038_control_failsafe import DURATION_SECONDS, Frame, Unit, Workload, build_workload, packet_is_lost OUTPUT_DIRECTORY = Path("data/processed/lab040") @@ -1650,7 +1650,7 @@ def write_report( created = ( Path("protocol/persistent_emergency.py"), Path("protocol/safe_reset.py"), - Path("tests/lab040_persistent_emergency.py"), + Path("experiments/lab040_persistent_emergency.py"), SUMMARY_CSV, EMERGENCY_CSV, RESET_CSV, diff --git a/tests/lab041_session_restart_safety.py b/experiments/lab041_session_restart_safety.py similarity index 99% rename from tests/lab041_session_restart_safety.py rename to experiments/lab041_session_restart_safety.py index bc13792..3e84116 100644 --- a/tests/lab041_session_restart_safety.py +++ b/experiments/lab041_session_restart_safety.py @@ -94,7 +94,7 @@ VIDEO_OFFERED_LOAD_KBPS = 243.39286666666666 TELEMETRY_OFFERED_LOAD_KBPS = 7.68 # Параметры торможения взяты из профиля "nominal" Lab039, а не подобраны заново. -# tests/lab039_two_stage_braking.py: DecelerationProfile("nominal", 1.0, 3.0). +# experiments/lab039_two_stage_braking.py: DecelerationProfile("nominal", 1.0, 3.0). # Оценка пути ниже одноступенчатая и потому консервативнее двухступенчатой # модели Lab039: она не учитывает предварительное замедление Stage1. LAB039_NOMINAL_STAGE2_MPS2 = 3.0 @@ -1417,7 +1417,7 @@ def write_report( created = ( Path("protocol/control_messages.py"), Path("protocol/session_state.py"), - Path("tests/lab041_session_restart_safety.py"), + Path("experiments/lab041_session_restart_safety.py"), SUMMARY_CSV, SESSION_CSV, REJECTION_CSV, diff --git a/tests/__init__.py b/tests/__init__.py index e69de29..b9fafd7 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Быстрые автоматические проверки ядра протокола.""" diff --git a/tools/quick_gate.py b/tools/quick_gate.py index b110806..962efdc 100644 --- a/tools/quick_gate.py +++ b/tools/quick_gate.py @@ -24,7 +24,7 @@ import sys import traceback PROJECT_ROOT = Path(__file__).resolve().parent.parent -CHECKED_DIRECTORIES = ("protocol", "tests", "tools") +CHECKED_DIRECTORIES = ("protocol", "tests", "experiments", "tools") def check_syntax() -> list[str]: @@ -81,13 +81,13 @@ def check_functional_tests() -> tuple[list[str], int, int]: executed = 0 skipped = 0 - for path in sorted((PROJECT_ROOT / "tests").glob("lab*.py")): + for path in sorted((PROJECT_ROOT / "experiments").glob("lab*.py")): source = path.read_text(encoding="utf-8") if "def run_functional_tests" not in source: continue - module_name = f"tests.{path.stem}" + module_name = f"experiments.{path.stem}" try: module = importlib.import_module(module_name)