# Контекст для ИИ-агента Точка входа для агента, работающего с этим репозиторием. Читать первым, до любых правок. Остальные страницы — по ссылкам, содержимое здесь не дублируется. ## Правила работы **Корень работы — каталог этого репозитория.** Не читать и не изменять ничего за его пределами: родительские каталоги, домашний каталог, системные пути. Исключение — временные файлы в каталоге scratchpad. Пути в коде, командах и документации — относительно корня репозитория. **Документация правится вместе с кодом.** Изменили поведение — правьте соответствующую страницу `docs/` в том же наборе коммитов. Соответствие «что сделали → что править» — в [](../dev/adding-flowgraph.md#6-обновить-документацию). **Коммиты делает только человек.** Агент правит рабочее дерево и предлагает текст сообщений, но не вызывает `git commit`, `git push`, `git rebase` и прочие команды, меняющие историю. Готовые изменения агент оставляет незакоммиченными и показывает предлагаемое разбиение на коммиты. **Каждый коммит подписан.** `git commit -s`, заголовок в повелительном наклонении не длиннее 50 символов. Без трейлера `Signed-off-by:` CI блокирует слияние. См. [](../dev/contributing.md). ## Что это за проект Форк `satnogs-flowgraphs` (ветка `soniks`) — флоуграфы GNU Radio для наземных станций сети Соникс плюс Python-запускатор. `soniks-client-new` вызывает один бинарник `flowgraph_dispatcher --mode `, тот выбирает флоуграф, поднимает его и три ZMQ-подписчика, пишущих кадры, аудио и IQ. Фork добавил декодеры Geoscan и USP (Спутникс). Полная картина — [](../overview.md), сквозной путь данных — [](../dev/architecture.md). ## Карта репозитория | Путь | Что | Когда трогать | |---|---|---| | `generic/*.grc` | 11 флоуграфов общего назначения | новая модуляция или общий протокол | | `satellites/*.grc` | 9 декодеров под спутники, включая Geoscan и USP | новый спутник | | `test_flowgraphs/*.grc` | генераторы сигнала, **вне сборки** | отладка без эфира | | `tools/sync_frontend.py` | раскладка общего фронтенда из `generic/fm.grc` по остальным графам | любая правка приёмного тракта | | `tests/*.py` | инварианты `.grc` и контракт аргументов диспетчера | вместе с любой правкой кода | | `flowgraph_dispatcher/flowgraph_dispatcher.py` | таблицы режимов, разбор аргументов, управление процессами | новый режим или аргумент | | `flowgraph_dispatcher/zmq_*_sub.py` | запись кадров, IQ, аудио | формат выходных файлов | | `flowgraph_dispatcher/zmq_subs/helper_functions/` | общие разборщики, сигналы, метки времени | общая логика подписчиков | | `*/CMakeLists.txt` | **явные** списки собираемых файлов | добавление или удаление `.grc` | | `debian/` | метаданные пакета | изменение зависимостей | | `docs/` | эта документация | вместе с любым изменением поведения | Чего в проекте нет: Python-упаковки (`setup.py`, `pyproject.toml`), генерации API-доков, сборки пакета в CI. ## Инварианты Нарушение любого из них ломает сборку или проходит незаметно и ломает наблюдение. 1. **`.grc` — источник правды.** `generic/*.py` и `satellites/*.py` генерирует `grcc` при сборке; они в `.gitignore` и никогда не коммитятся. Правка сгенерированного `.py` исчезнет при следующей сборке. 2. **Имя параметра в `.grc` = имя аргумента в `client_argument_parser()`** (дефисы против подчёркиваний — единственное расхождение). Диспетчер передаёт всё как `--ключ=значение` вслепую, а `grcc` генерирует `parse_args()`, поэтому лишний аргумент завершает флоуграф с кодом 2. Проверяет `tests/test_dispatcher.py`. 3. **Списки в `CMakeLists.txt` явные, не по маске.** Новый `.grc`, не внесённый в `set(flowgraphs …)`, молча не соберётся. 4. **Порты ZMQ выводятся из одного числа.** В диспетчере это `--zmq-base-port` (по умолчанию 16887), во флоуграфе — параметр `zmq_base_port`. Кадры на `base`, IQ на `base + 1`, аудио на `base + 2`. Литеральных адресов `tcp://127.0.0.1:1688x` в `.grc` быть не должно — это проверяет `tests/test_flowgraphs.py`. 5. **Новый режим = две записи** в `SATNOGS_FLOWGRAPH_SCRIPTS` **и** `SATNOGS_FLOWGRAPH_MODES`, плюс строка в CMake. Одной недостаточно. 6. **Подписчики стартуют раньше флоуграфа.** ZMQ pub/sub не буферизует для неподключённых подписчиков — порядок в `run()` менять нельзя. 7. **Аудио-тракт обязан выдавать ровно 48000 Гц моно.** Подписчик пишет OGG с этой частотой жёстко и рассогласование не обнаруживает. 8. **`decoded_data_file_path`, `file_path`, `iq_file_path`, `enable_iq_dump` во флоуграфах ни к чему не подключены** — запись файлов живёт в подписчиках. Не «чинить» их внутри `.grc`. `doppler_correction_per_sec` снят 2026-09-12, диспетчер его обнуляет. 9. **Децимация не меньше 4.** Дальше по тракту есть `decimation // 2` и `decimation // sps`; без нижней границы получается ноль. 10. **Приёмный тракт до демодулятора — один на все графы, источник правды `generic/fm.grc`.** Править фронтенд (`soapy_source`, доплер-компенсация, водопад, IQ ZMQ, UDP) в другом файле бессмысленно: `tools/sync_frontend.py` перепишет его по золотому, а `test_frontend_matches_golden` не пропустит расхождение. У каждого графа свои только `out_samp_rate`/`samp_rate` водопада и `compensate` у `iq_receiver`. `dev_args` с 2026-09-12 живой: `--dev-args` доезжает до `soapy_source`. ## Частые задачи | Задача | Куда | |---|---| | Добавить декодер или режим | [](../dev/adding-flowgraph.md) | | Понять, что делает режим | [](../modes.md), затем [](../flowgraphs/index.md) | | Разобраться в конкретном `.grc` | [](../dev/grc-conventions.md) + страница семейства | | Изменить формат выходных данных | [](../outputs.md), правки в `zmq_*_sub.py` | | Диагностировать отсутствие кадров | [](../troubleshooting.md) | | Понять «почему так странно сделано» | [](../dev/known-issues.md) | | Решить, брать ли правку из апстрима | [](../dev/upstream.md) | ## Ловушки Проверенные расхождения между тем, как код выглядит, и тем, как он работает, собраны в [](../dev/known-issues.md). Самые дорогие по времени: - **иерархические блоки — мёртвый код**, правка не меняет поведение декодеров; - **у PHASMA нет аудиоветки** — OGG будет пустым, подписчик предупреждает; - **частота дискретизации IQ нигде не записана** — без параметров наблюдения файл бесполезен; - **аудио жёстко пишется на 48000 Гц** — тракт обязан выдавать ровно эту частоту. ## Проверка изменений Минимум перед коммитом: ```sh python3 tests/test_flowgraphs.py # инварианты .grc, без GNU Radio python3 tests/test_dispatcher.py # контракт аргументов, без GNU Radio flake8 flowgraph_dispatcher tests python3 tests/e2e_check.py # дерево процессов, без SDR; не в CI cd build && cmake .. && make # все .grc проходят grcc grcc satellites/my_decoder.grc -o /tmp && python3 /tmp/satnogs_my_decoder.py --help make -C docs html # документация собирается с -W ``` Первые три команды не требуют GNU Radio. В CI идут они плюс сборка через `grcc` (джоба `flowgraphs`, образ станции) и документация; `e2e_check.py` — нет. Прогон целиком без эфира — раздел «Собрать и проверить» в [](../dev/adding-flowgraph.md).