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 <noreply@anthropic.com>
This commit is contained in:
LittleSam129
2026-08-10 14:34:58 +03:00
parent c9569164e0
commit c486039053
55 changed files with 63 additions and 62 deletions

View File

@@ -0,0 +1,153 @@
"""
Lab002, часть 2.
Повреждение одного бита пакета без контроля целостности.
Цель:
1. Сформировать цифровой пакет.
2. Намеренно изменить один бит полезной нагрузки.
3. Разобрать повреждённый пакет.
4. Убедиться, что без CRC повреждение не обнаруживается.
"""
import struct
# ============================================================
# Константы протокола
# ============================================================
SYNC_WORD = 0xAA55
PROTOCOL_VERSION = 1
MESSAGE_TYPE_TEXT = 1
HEADER_FORMAT = ">HBBHH"
# ============================================================
# Формирование исходного пакета
# ============================================================
message = "ПРИВЕТ SDR"
payload = message.encode("utf-8")
sequence_number = 1
message_type = MESSAGE_TYPE_TEXT
payload_length = len(payload)
header = struct.pack(
HEADER_FORMAT,
SYNC_WORD,
PROTOCOL_VERSION,
message_type,
sequence_number,
payload_length,
)
packet = header + payload
print("Исходное сообщение:")
print(message)
print("\nИсходный пакет:")
print(packet.hex(" "))
# ============================================================
# Имитация повреждения пакета
# ============================================================
# bytes нельзя изменять напрямую.
# Поэтому преобразуем пакет в изменяемый массив bytearray.
corrupted_packet = bytearray(packet)
header_size = struct.calcsize(HEADER_FORMAT)
# В строке "ПРИВЕТ SDR":
#
# "ПРИВЕТ" занимает 12 байтов UTF-8,
# пробел занимает 1 байт,
# буква S находится по индексу 13 внутри PAYLOAD.
payload_byte_index = 13
# Полный индекс внутри пакета:
packet_byte_index = header_size + payload_byte_index
original_byte = corrupted_packet[packet_byte_index]
# XOR с 0x01 изменяет младший бит:
#
# 0x53 = 01010011 = S
# 0x52 = 01010010 = R
corrupted_packet[packet_byte_index] ^= 0x01
corrupted_byte = corrupted_packet[packet_byte_index]
print("\nИзменяемый байт внутри пакета:")
print(
f"До повреждения: "
f"{original_byte:3d} "
f"= 0x{original_byte:02X} "
f"= {original_byte:08b}"
)
print(
f"После повреждения: "
f"{corrupted_byte:3d} "
f"= 0x{corrupted_byte:02X} "
f"= {corrupted_byte:08b}"
)
print("\nПовреждённый пакет:")
print(bytes(corrupted_packet).hex(" "))
# ============================================================
# Разбор повреждённого пакета
# ============================================================
received_header = corrupted_packet[:header_size]
received_payload = corrupted_packet[header_size:]
(
received_sync,
received_version,
received_type,
received_sequence,
received_length,
) = struct.unpack(HEADER_FORMAT, received_header)
# ============================================================
# Проверки структуры
# ============================================================
assert received_sync == SYNC_WORD
assert received_version == PROTOCOL_VERSION
assert received_type == MESSAGE_TYPE_TEXT
assert received_sequence == sequence_number
assert received_length == len(received_payload)
print("\nВсе проверки заголовка пройдены.")
restored_message = bytes(received_payload).decode("utf-8")
print("\nСообщение после повреждения:")
print(restored_message)
print("\nИсходное сообщение:")
print(message)
# ============================================================
# Проверка результата эксперимента
# ============================================================
assert restored_message != message
print("\nПовреждение данных произошло.")
print("Но заголовок и длина пакета остались правильными.")
print("Без CRC приёмник не смог определить ошибку.")