TASK_ID = RF001A_OTA_CAPTURE_004 TASK_TITLE = Start hardened RF-001A common-clock OTA capture SOURCE_BRANCH = video-development EXPECTED_HEAD = 168e03d9e778ab2ec63502552d385ec7be3ef677 REQUIRES_APPROVAL = YES HARDWARE_ACCESS = YES RF_RX = YES RF_TX = NO ALLOW_COMMIT = NO ALLOW_PUSH = RX_RESULT_ONLY RISK_LEVEL = YELLOW --- # RF-001A RX capture 004 This file is the authoritative current task for the RX laptop. Read `RX_NODE_STATE.md` first. If chat history conflicts with these files or the current Git HEAD, stop and report the conflict. This task is prepared only. A previous approval does not apply to this new TASK_ID. Do not access HackRF until the user approves this exact YELLOW task. ## 1. Software and Git gates 1. Run `git pull --ff-only origin video-development`. 2. Require branch `video-development` and a clean tracked worktree. 3. Require local HEAD to equal `origin/video-development`; `EXPECTED_HEAD` must be its ancestor. 4. Confirm the historical channel-test READY and COMPLETE acknowledgements from `origin/tx-node` through the RX watcher. 5. Before opening HackRF, run the authenticated no-change publication check: python -B tools/rx_agent_watcher.py --check-result-write --result-branch rx-node Require `RX-NODE WRITE PREFLIGHT = PASS`. This command fetches the branch, performs `git push --dry-run` of its existing HEAD to the same ref, and confirms that the remote HEAD did not change. It creates no commit and no production READY event. 6. Run the targeted tests, Ruff, Pyright and `git diff --check` according to the tracked project instructions. 7. Validate `configs/rf/rf001a_truth_metadata.json`: waveform SHA256, seed, PHY settings, 100 sequence numbers and 100 packet hashes must agree with `configs/rf/rf001a_common_clock.json`. If any gate fails, do not open HackRF and stop. In particular, a failed Git write preflight blocks the hardware task. ## 2. Optional offline check of capture 003 If the existing `RF001A_OTA_CAPTURE_003` file is present locally, analyze it read-only with the streaming cs8 decoder before starting new hardware work: python -B -X utf8 tools/qpsk_rf_rx.py --iq-file \rf001a_ota_capture.cs8 --iq-format cs8 --truth-metadata configs/rf/rf001a_truth_metadata.json --report \capture003_streaming_report.json No RF-001A transmission occurred during capture 003. The expected exact packet count is 0. CRC-valid background candidates must not be reported as exact unless their complete packet SHA256 matches the tracked truth metadata. The analysis must use memmap/chunks and must not materialize the full 1.92 GB capture as complex64. If capture 003 is unavailable, report `CAPTURE_003 ANALYSIS = NOT_RUN` and continue only after all mandatory gates pass. ## 3. Hardware preflight after YELLOW approval 1. Run `hackrf_info` and require RX serial `000000000000000097c063dc2e5327d3`. 2. With `MASTER CLKOUT -> SLAVE CLKIN` connected, run: hackrf_clock.exe -d 000000000000000097c063dc2e5327d3 -i 3. Require `CLKIN status: clock signal detected`. 4. Repeat the Git write preflight immediately before the finite RX command. 5. Require antennas connected, approximately 2 m distance, clear LOS, and video disabled. 6. Require at least 1500000000 free bytes on the capture volume and record the measured value. Do not reconfigure clocks. If CLKIN or the second Git preflight fails, stop before capture. ## 4. Finite RX capture Use a unique directory outside Git. Never overwrite an earlier capture. RX serial = 000000000000000097c063dc2e5327d3 center frequency = 1400000000 Hz sample rate = 8000000 samples/s RX LNA = 24 dB RX VGA = 24 dB RF amp = OFF antenna bias = OFF duration = 60 s sample count = 480000000 complex samples hardware format = cs8 expected file size = 960000000 bytes Use these fixed `hackrf_transfer.exe` arguments: -d 000000000000000097c063dc2e5327d3 -r \rf001a_ota_capture.cs8 -f 1400000000 -s 8000000 -n 480000000 -l 24 -g 24 -a 0 -p 0 -B Use `tools/capture_process_runner.ps1` as a controlled background process. Preserve its complete stdout, stderr, start JSON and result JSON outside Git. The runner must start exactly one finite child, record the actual child PID and UTC start time, set the expected end to start plus 60 seconds, wait for that exact process, record its integer exit code, size and duration, and calculate SHA256 after the output file closes. Never retry the capture automatically. Within five seconds require the runner and child to be alive and the file to exist and grow. Otherwise publish no READY and stop. ## 5. READY publication Create the strict schema-version-1 READY JSON outside Git for TASK_ID `RF001A_OTA_CAPTURE_004`. Use the actual child PID and UTC timestamps, `expected_capture_end = capture_started_at + 60 s`, current source HEAD, `common_clock_verified = true`, `rf_tx = 0`, and null final result fields. Publish it once with: python -B tools/rx_agent_watcher.py --publish-result --result-branch rx-node The publisher creates one immutable READY commit. On a recognized transient network or authentication failure it checks the remote branch and may retry the exact same commit once. It never creates a second READY commit or changes the payload between attempts. If the remote already contains that commit, the publication is successful. A second failure means: READY publication = FAIL RX READY FOR TX = NO RF TX = 0 Do not publish READY after the capture window has ended. After the process exits, publish only a `CAPTURE_COMPLETE` result with the actual exit code, size, duration and error counters, including nonzero failure values. After the remote HEAD confirms the READY commit, immediately print: TASK_ID = RF001A_OTA_CAPTURE_004 RX CAPTURE STARTED = YES RX READY FOR TX = YES CAPTURE PID = CAPTURE PATH = CAPTURE START TIME = EXPECTED CAPTURE END = RX RESULT HEAD = RF TX = 0 Return control without waiting for capture completion. ## 6. Completion and offline decode After the child exits, record exact exit code, actual size, duration, overruns, USB errors, file-write errors and SHA256. A complete capture is exactly 960000000 bytes; a smaller file is incomplete. Run the CLKIN check again and require detected status. Publish an honest schema-version-1 COMPLETE result with final values. Keep IQ, stdout, stderr and large logs outside Git. After `origin/tx-node` contains `TX_STARTED` and `TX_COMPLETE` for `RF001A_OTA_TX_004`, run the streaming decoder with RX/TX timestamps: python -B -X utf8 tools/qpsk_rf_rx.py --iq-file \rf001a_ota_capture.cs8 --iq-format cs8 --truth-metadata configs/rf/rf001a_truth_metadata.json --capture-started-at --tx-started-at --tx-finished-at --report \rf001a_streaming_report.json The decoder uses a two-second margin before and after the timestamped burst. Without complete timestamps it uses the streaming power locator. Chunk overlap is derived from the real 256-byte RF-001 waveform and duplicate detections from overlap are suppressed. ## 7. Prohibited actions RF TX, firmware update, CPLD update, Zadig, USB driver changes, clock reconfiguration, commit or push to `video-development`, repeated capture, raw IQ/video/waveform publication and large-log publication are forbidden. Final report: TASK_ID = RF001A_OTA_CAPTURE_004 RX-NODE WRITE PREFLIGHT = PASS / FAIL COMMON CLOCK = VERIFIED / NOT_VERIFIED RX CAPTURE COMPLETE = YES / NO CAPTURE SIZE = CAPTURE DURATION = RX OVERRUNS = USB ERRORS = FILE WRITE ERRORS = RAW IQ SHA256 = STREAMING DECODE = PASS / FAIL / NOT_RUN EXACT RF001A PACKETS = PEAK ANALYSIS MEMORY = RF TX = 0 STOP.