# Отладка исходников: реализация и результаты Дата: 2026-09-16. План: [mame-source-debug.md](mame-source-debug.md). Реализованы сборка/карта, проверенный транспорт, базовая C-сессия, постоянный session server, DAP MVP, VS Code launch/build task и первый stdio MCP-адаптер C-уровня. Эксклюзивное владение CPU между клиентами, безопасный restart и расширенная отладка ещё не готовы. Этапы плана не считаются завершёнными целиком по одному успешному репро. ## Статус платформ - **macOS:** текущий end-to-end цикл проверен, включая backend `sdbg` и одновременную работу VS Code со штатным `osx` debugger MAME. Новый `MAME.HT/sprinter` (0.289, Holub/Tolik) прошёл живой DAP launch с прежними ROM/DSS: prompt на строке 22, `false_hits=0`, остановка в `hello.c:17` (`main`, PC `0x8224`). У него уже были те же исходники `sdbg` и `mamebridge`; рецепты сборки перенесены с новым именем бинарника. - **Linux:** ожидается работа через `sdbg`, `qt` или `imgui`, но полный живой прогон ещё не выполнен. - **Windows:** весь функционал пока работать не будет. Provider `debugger: "windows"` открывает штатный debugger MAME, однако host-часть использует `fcntl`, Unix domain sockets и Unix launcher. Native Windows launch/attach из VS Code официально не поддерживается до реализации переносимого транспорта, блокировки, запуска и end-to-end тестов. ## Доступно сейчас - `bin/sprinter-cc --src-debug` и повторяемый `--src-debug-file FILE`. - `app.mk`: `SRC_DEBUG=1` либо `SRC_DEBUG_FILES=...`; выбор интерпретатора через `PYTHON` в make и `SPRINTER_PYTHON` у обёртки. В проекте используется local pyenv Python 3.12 (`.python-version`); личный путь не зашит в код. - Уникальные имена CDB-позиций и TU, включая повторные метки внутри одного модуля. Публичные C/asm-символы и инструкции не переименовываются. - Сборка в отдельном временном каталоге с проверкой пакета перед публикацией. Ошибка compiler/linker/парсера сохраняет предыдущие EXE и пакет. Конкурентные debug-сборки одного output сериализованы; одновременная обычная и debug-сборка одного output пока не поддерживается. - Manifest: build ID, хеш EXE/артефактов/исходников/включённых заголовков, сохранённые исходники, параметры памяти, команды, версия SDCC и выбранные TU. Зависимости собираются также для TU без карты в пер-модульном режиме. - Проверяемый JSON-индекс `.sdbg.json`, offline CLI функций, переменных, символов и соответствия C/asm/адресов. Банковые адреса учитывают секцию и окно huge/big; банк данных не трактуется как резидентная память. - Пересборка make при смене команды/содержимого зависимостей. Быстрая правка заголовка не зависит от секундной точности mtime; повторный make без изменений не вызывает compiler. - Отдельный плагин `toolchain/mcp/sdbgbridge`, загружаемый непосредственно из репозитория через pluginspath. Он не заменяет существующий mamebridge и не требует копирования изменённых файлов в игнорируемое дерево MAME. - Версия протокола, ID сессии, generation, атомарные файловые ответы, ограниченный журнал событий, stopped snapshots, чтение logical memory с отключёнными side effects, pause/continue/instruction step и точки с проверкой владения. FileBridge запрещает повтор mutations после timeout. - `DebugSession` проверяет EXE, Intel HEX и исполняемые байты реально загруженного resident/current-bank образа перед интерпретацией PC. Он читает `_bank_pages`, отвергает нули/дубликаты и учитывает, что state MAME хранит старшие флаги над 8-битным значением page-port. - Точки по строке и функции, удаление логической группы, `where` и чтение поддержанных 1/2/4-байтных global/static. Банковская точка получает условие по I/O page-port (`ib@e2==...` для W3), формируемое самим plugin; произвольная debugger expression через этот вызов не принимается. Resident-объект или bank-data не читается, если его физическая страница сейчас закрыта. - Bootstrap живого теста не держит entry-breakpoint во время загрузки DSS. Он активирует единственную service-точку перед вводом команды запуска, сверяет сигнатуру/образ на `main`, а исходные точки ставит после attach. Банковые пользовательские точки нельзя безопасно активировать до заполнения `_bank_pages`, поэтому они намеренно создаются после runtime init. - `sdbg_server.py` — единственный долгоживущий владелец backend. Локальный Unix JSON-RPC допускает несколько клиентов, сериализует команды, хранит логические группы и события. `set_source_breakpoints` и `set_function_breakpoints` создают новый disabled-набор, при ошибке удаляют его, затем заменяют прежний набор и активируют точки. - Session server проверяет `snapshot` и при остановленном CPU раз в 0,5 с: reset/state load инвалидирует сессию, потеря MAME приводит к закрытию после ограниченного timeout backend. Если выполнение продолжено из родного окна debugger MAME, server сообщает DAP смену состояния. Закрытая сессия всегда выдаёт DAP `terminated`, даже если событие `invalidated` выпало из журнала. - DAP MVP и минимальное VS Code-расширение: attach к session server, source/function breakpoints, один достоверный frame, registers, поддержанные globals/statics, evaluate одного имени, continue/pause и instruction step. F11 идёт до другой C-позиции, F10 использует MAME `over`, Shift+F11 выходит через bank trampoline до C-позиции caller. Автомат имеет предел 512 машинных операций и сохраняет приоритет пользовательской точки. Длинный вызов с ожиданием внешнего ввода не блокирует DAP; Pause доступен. Неподдержанные setVariable, disassemble, restart/terminate не рекламируются либо возвращают явную ошибку. - Собственное расширение является обязательной Sprinter-частью интеграции: готовые C/C++ или clangd можно добавить для редактирования, но они не знают source-debug package, DSS, банки и MAME DAP. Версия 0.2.0 даёт TaskProvider для приложений с `app.mk`, команду Build Active Project и автоматическую debug-сборку перед F5. Она использует `make SRC_DEBUG=1` и local Python 3.12; ошибки SDCC с файлом/строкой попадают в Problems. Код сборки проверяется самим расширением: при ошибке MAME не запускается. VSIX 0.2.0 собран и проверен в отдельном workspace SprPoP. Run-команда, расширенные linker/assembler diagnostics и выбор profile/EXTRA_DATA остаются следующими шагами. - DAP `logMessage` без пересборки: разрешены литералы, `{{`/`}}` и только подстановки `{variable}`. Session server читает типизированное значение, отправляет `output` и продолжает CPU. Совпавшая обычная точка имеет приоритет остановки, поэтому logpoint её не проглатывает. Произвольные выражения, format specifier и conversion намеренно отвергаются. - ``: `SDBG_LOG(tag, "total={total}")` и ограниченный `SDBG_LOGIF(tag, flag, "...")` создают нулевые asm-якоря только в выбранном debug-TU. Метаданные приходят из активного препроцессорного потока; package содержит связанный адрес/причину unverified. Session server автоматически ставит эти точки после attach, зеркалирует текст в MAME debugger console и DAP Debug Console, затем продолжает CPU. Совпавшая пользовательская точка по-прежнему останавливает исполнение. Локальные, C-выражения и printf-форматы пока не доступны; значения читаются из поддержанных global/static объектов, исходное приложение не печатает в DSS. DAP event ring ограничен 1024 событиями; если клиент отстал, Debug Console показывает число пропущенных событий. Частые logpoints останавливают CPU при каждом попадании, их overhead пока не измерен. DAP хранит точный UTF-8 текст; MAME `printf` получает безопасную проекцию: кавычки заменяются апострофом, управляющие символы — пробелами. Практический контракт и таблица типов — [руководство по SDBG_LOG](sdbg-log-macros.md). Decimal/hex formatter, форматированный адрес и значение по ненулевому указателю — задачи финального этапа, сейчас не поддерживаются. Для него `char *` задан как строка, `int8_t *`/`uint8_t *` — как один 8-битный объект; текущий CDB не различает `char *` и `uint8_t *`, поэтому нужна metadata declared type. - `sdbg_launcher.py` реализует VS Code launch: создаёт временную дискету, копию системного HDD и отдельные state-каталоги, показывает окно Sprinter, ждёт DSS, ставит только service-точку `main`, вводит `a:\\NAME.EXE`, проверяет сигнатуру entry и запускает session server. Закрытие DAP завершает только созданные им server/MAME, удаляет временный каталог и свой Unix socket (с проверкой inode, чтобы не удалить новый сеанс). - `sdbg_mcp.py` предоставляет 29 инструментов через официальный MCP SDK 2.x поверх того же session server: статус, C-позиция, регистры, logical memory, переменные, события/логи, личные точки и команды исполнения. MCP-точки имеют owner ID и не могут удалить точки VS Code; при обычном закрытии MCP-клиента они очищаются. Живой совместный прогон проверил структурированные ответы, отказ на удаление чужой точки и последующее срабатывание точки DAP с provider `sdbg` и `osx`. Отдельный WAITKEY-прогон подтвердил удаление личной точки при running CPU и дальнейшее завершение шага после клавиши. Повторный запуск на том же фиксированном socket после прежнего stale-файла прошёл; после Stop путь удалён. В автономном режиме доступен 31 инструмент: официальный MCP-клиент запустил `hello`, ввёл `x` через публичный `press_key` во время `getchar()` и остановился на следующей C-строке. Остальные raw-возможности ввода перечислены в [матрице](mcp-capability-matrix.md). Контракт запуска и ограничения — в [руководстве по MCP](sdbg-mcp.md). ## Использование карты В shell без инициализированных pyenv shims используйте `pyenv exec`: ```sh pyenv exec make -C tests/hello SRC_DEBUG=1 pyenv exec python toolchain/sdbg.py --build tests/hello/.sprinter-cc-hello verify pyenv exec python toolchain/sdbg.py --build tests/hello/.sprinter-cc-hello map pyenv exec python toolchain/sdbg.py --build tests/hello/.sprinter-cc-hello vars pyenv exec python toolchain/sdbg.py --build tests/hello/.sprinter-cc-hello line2addr hello.c 33 ``` `addr2line` принимает адрес **линковщика** с префиксом `0x`, например `0x1c00c`, а не логический PC без информации о банке. Ответ включает logical_address, bank, window, функцию, инструкцию `.asm` и все найденные исходные позиции. Неизвестный адрес возвращает unknown. Неоднозначности не скрываются; изменённый исходник имеет stale-статус, сохранённый текст собранной версии остаётся в пакете. Для одной TU: `pyenv exec make -C tests/banked SRC_DEBUG_FILES=bank1.c`. Режимы all/selected взаимоисключающие. `--debug` по-прежнему означает runtime DEBUG_RT и не включает карту C. Низкоуровневый live CLI работает с уже запущенным `sdbgbridge`; его IPC и session ID должны совпадать с окружением процесса MAME: ```sh pyenv exec python toolchain/sdbg_session.py \ --build tests/hello/.sprinter-cc-hello \ --ipc "$SDBG_IPC_DIR" --session "$SDBG_SESSION_ID" attach ``` Доступны `where`, `step`, `continue`, `break-line`, `break-function`, `read-variable`, `activate-breakpoints` и `deactivate-breakpoints`. Это диагностический однооперационный CLI: логические ID групп точек живут только внутри процесса. Для долгой работы и DAP используйте общий session server ниже. Предпочтительный режим для нескольких клиентов — один server: ```sh pyenv exec python toolchain/sdbg_server.py \ --build tests/hello/.sprinter-cc-hello \ --ipc "$SDBG_IPC_DIR" --session "$SDBG_SESSION_ID" \ --socket /tmp/sprinter-sdbg.sock pyenv exec python toolchain/sdbg_client.py \ --socket /tmp/sprinter-sdbg.sock status ``` VS Code-расширение находится в отдельном репозитории `../VSCode-Sprinter`. В Extension Development Host используется attach-конфигурация: ```json { "type": "sprinter-mame", "request": "attach", "name": "Sprinter MAME: Attach", "socket": "/tmp/sprinter-sdbg.sock" } ``` В VS Code расширение `0.2.0` находит SDK через `sprinterDebugger.sdkRoot`, а Python 3.12 — через local pyenv shim или установленную pyenv-версию. Это устраняет зависимость от `PATH` процесса VS Code, открытого из Dock, и позволяет отлаживать приложение из отдельного workspace. Выбранные пути видны в Output → `Sprinter MAME Debug`; при раннем сбое launcher сообщает stderr и последние строки MAME log. Интегрированный запуск: ```json { "type": "sprinter-mame", "request": "launch", "name": "Sprinter MAME: Launch", "build": "${workspaceFolder}/tests/hello/.sprinter-cc-hello" } ``` Launcher читает text-mode descriptors из VRAM и ждёт стабильный пустой prompt `X:…>` 0,25 секунды. `dssTimeout` по умолчанию равен 30 эмулируемым секундам; `launchAt` теперь только необязательная нижняя граница. Перед вводом launcher сохраняет снимок DSS. Пошаговый запуск development-расширения описан в [vscode-sprinter-debug.md](vscode-sprinter-debug.md). ## Воспроизводимые проверки ```sh pyenv exec python -m unittest discover -s tests/sdbg -v pyenv exec python tests/sdbg/run_mame_probe.py pyenv exec python tests/sdbg/run_mame_probe.py --bridge pyenv exec python tests/sdbg/run_mame_probe.py --bridge --banked pyenv exec python tests/sdbg/run_mame_probe.py --bridge --banked --server pyenv exec python tests/sdbg/run_mame_probe.py --banked --bridge --server --lifecycle-exit pyenv exec python tests/sdbg/run_mame_probe.py --banked --bridge --server --lifecycle-load pyenv exec python tests/sdbg/run_mame_probe.py --banked --launcher pyenv exec python tests/sdbg/run_mame_probe.py --banked --launcher --native-debugger pyenv exec python tests/sdbg/run_mame_probe.py --banked --launcher --source-step pyenv exec python tests/sdbg/run_mame_probe.py --banked --launcher --step-out pyenv exec python tests/sdbg/run_vscode_dap_probe.py pyenv exec python tests/sdbg/run_vscode_dap_probe.py --exit-while-stopped pyenv exec python tests/sdbg/run_vscode_dap_probe.py --stop-while-stopped pyenv exec python tests/sdbg/run_vscode_dap_probe.py --term-while-stopped pyenv exec python tests/sdbg/run_vscode_dap_probe.py --mcp-python /tmp/sprinter-sdbg-mcp-venv/bin/python pyenv exec python tests/sdbg/run_vscode_dap_probe.py --waitkey --emulated-key --clear-while-running pyenv exec python tests/sdbg/run_vscode_dap_probe.py --waitkey --manual-key ``` Живой тест использует отдельную дискету, копию системного HDD и отдельные каталоги состояния в `build/sdbg-live/`. Общие media и запущенный вручную MAME не изменяются. Без `--bridge` проверяется шаг из Lua callback; с `--bridge` — отдельный протокол и файловый клиент. `--native-debugger` добавляет родное окно к тому же DAP-сценарию. Скрипт, запущенный системным Python <3.12, перезапускает себя через local pyenv. Результаты — `result.jsonl`, `mame.log`. Остановка процесса в конце bridge-теста относится только к MAME этого теста. Зафиксировано на SDCC 4.5.0 #15242 и MAME v0.287, commit `b0c4527c2edb1ee177fd09b3c412b65b385bf35b`: | Проверка | Результат | |---|---| | Обычная debug-линковка двух TU с общим inline | Воспроизводится rc != 0, `Multiple definition of C$...` | | Уникализация debug-символов | Успешная линковка; функции обоих экземпляров различаются | | Повторные метки sprinter.h:111 | Сохранены начало и эпилог в каждом из трёх TU: 6 адресов | | debug/non-debug probe, banked huge и big | Полные EXE идентичны | | Одинаковые basename двух utils.c | Две функции и два независимых статика | | bank-data в big | Переменная разрешена в банке 1, окне W1 | | Ошибка линковки поверх опубликованной сборки | Предыдущие EXE и manifest не изменились | | Испорченный артефакт / изменённый source | Ошибка проверки / явный stale; старый текст сохранён | | Пер-модульная карта | Только выбранная TU в карте, все компиляционные зависимости учтены | | Быстрая правка header / переключение debug | Пересборка; без изменений повторной компиляции нет | | Архив с libc/string/strlwr.c | L-записи попадают в общий CDB, F/S из архивного adb не импортируются | | Lua step на main | PC=0x8218 сразу после запроса; PC=0x821B на следующем callback | | Порядок DSS → arm → launch | VRAM-detector нашёл стабильный prompt в строке 22 на 4,69 с; только затем включена entry-точка, ложных попаданий 0 | | Новый мост, родной debugger | Проверены образ, регистры, `total`: 0 → 42, C-line breakpoint; instruction step около 32–124 мс в отдельных прогонах | | Банковская точка huge | Условие через W3 page-port; остановка PC=0xC000 разрешена как linker 0x1C000, bank 1 | | Session server + DAP | Owner lock удержан; DAP function breakpoint остановил `worker`; frame сохранил bank 1 | | Production launcher | DSS prompt → `main` с `false_hits=0`; backend `sdbg` и опциональный `osx` прошли одинаковый DAP-сценарий, штатный terminate без нового crash report | | DAP logpoint + breakpoint | В bank 1 напечатано `bank_value=0`; совпавшая function breakpoint сохранила остановку | | Авторский `SDBG_LOG`, 2026-09-15 | Fixture `logmacro`: EXE с/без macro побайтово равны, сообщение отсутствует в EXE; активный wrapper и склейка литералов привязаны к linked-якорю, `#if 0` исключён. Живой DAP launch в `sdbg` и `osx`: `total=1` одновременно в MAME debugger console и VS Code Debug Console, `false_hits=0` | | Source F11/F10 | `main`: `0x42bb` → `0x42c1`; F10 выполнил банковский `worker` и остановился в caller на `0x42c9` | | Source Shift+F11 | Из `worker` bank 1 выполнен выход через trampoline в `main:6`, `0x42c9` | | VS Code stdio DAP launch, 2026-09-15 | Local pyenv shim → DAP → изолированный MAME/DSS → `hello` → `main:17`, PC=`0x8224`; `false_hits=0`, штатный disconnect | | MAME.HT 0.289, 2026-09-17 | Чистая сборка `make SUBTARGET=sprinter SOURCES=src/mame/sinclair/sprinter.cpp` и отдельные рецепты `stock`/`sdbg` создали `sprinter`; DAP в `sdbg` и `osx` на patched, а также `osx` на stock дождался DSS и остановился в `hello.c:17` без ложных точек. `getchar()` получил `x`, общий DAP/MCP сохранил ownership точек. Raw `mamebridge` через официальный MCP stdio-клиент перечислил 30 инструментов и ответил на `status`/`read_registers` при остановленном CPU; устаревший `resp_1.txt` не подменил ответ после перезапуска frontend | | Raw MCP plugin/legacy, 2026-09-17 | Все 16 команд удалённого `mame_bridge.lua` найдены в plugin dispatch; MCP stdio-прогоны проверили общий running-набор. Plugin на `hello` прошёл DSS→`main`, запись/восстановление `errno`, реальное срабатывание watchpoint, ввод `x` до строки 63 после `getchar()`, машинные over/out, снимок и пиксели. После удаления legacy-файла оба plugin-пробника повторно прошли | | Видимый raw MCP `hello`, 2026-09-17 | `tests/sdbg/run_raw_mcp_hello_probe.py` запустил MAME.HT с `-video soft -window`; кадр работающего `hello` показал весь текст и `Press any key to exit...`, затем ввод `x` довёл PC до `hello.c:63` | | Control lease DAP/MCP, 2026-09-17 | `claim_control`/`release_control`, 30-секундный lease с heartbeat; живой DAP+MCP-прогон подтвердил передачу управления обратно DAP и попадание в его точку. Второй видимый прогон дождался `owner_expired`, проверил удаление orphan-точки MCP и отсутствие ложной остановки; отпускание клавиш проверено unit-тестом | | RPC identity и экран C-MCP, 2026-09-17 | Запросы после handshake привязаны к session/build; мутации сверяют generation. 25 C-инструментов: в живом DAP+MCP-прогоне проверены raw program/logical memory, VRAM/share, порты, пиксели и PNG; при running `hello` MCP снял кадр с `Press any key to exit...`, затем `x` завершил шаг через `getchar()` | | Автономный MCP, 2026-09-17 | `start_session` ответил за 5–7 мс, затем официальный MCP-клиент дождался DSS→`hello.exe`→`main`; DAP attach увидел тот же PC, disconnect не завершил MAME. Повторный start отклонён, stop удалил socket и процесс MAME. Codex/Claude UI ещё не проверены | | Публичный MCP `press_key`, 2026-09-17 | В автономном видимом MAME официальный MCP-клиент поставил C-точку перед `getchar()`, продолжил `hello`, ввёл `x` через `press_key` и остановился на следующей строке 63. В автономном режиме доступны 28 инструментов; строковый ввод и мышь остаются в плане | | Список C-точек MCP, 2026-09-17 | В автономном видимом MAME MCP увидел собственную точку перед `getchar()` с owner и адресом; `list_breakpoints` также отдаёт guard-условие банка из bridge, если оно есть. Всего 29 автономных инструментов; вручную созданные debugger-точки пока не перечисляются | | Logical Z80 disassembly MCP, 2026-09-17 | Через официальный MCP-клиент в видимом MAME прочитаны инструкции `main` с `0x8224` (`call $852C`); байты памяти до/после совпали. Адрес/длина ограничены, возвращаются bank_pages и generation. Всего 30 автономных инструментов; raw program disassembly ещё не поддержано | | Строковый ввод MCP, 2026-09-17 | `tests/gets` с C-картой в видимом MAME получил `Ab9` и Enter через один MCP `type_string`; скриншот показал ввод и печать строки, CPU остановился на строке 16 после `gets()`. 31 автономный инструмент; natural keyboard/мышь остаются в плане | | F10 через `getchar()`, 2026-09-15 | Асинхронный `next` ответил за 21,49 мс; при ручном `x` в окне MAME `hello.c:62` → `:63`, возврат `DE.low=0x78`; обе клавиатуры включены в изолированном cfg | | VS Code TaskProvider Build, 2026-09-15 | Одиннадцать Node-проверок: выбор Makefile рядом с пакетом/в `build/`, команда make с Python shim, SDCC matcher, успешный и неуспешный код задачи, pyenv вне workspace; реальный make в `tests/hello` прошёл, VS Code показал Build → MAME/DSS → `main` | | Ошибочная debug-сборка, 2026-09-15 | Изолированный `fault.c` вернул код 2 от make, `file:1: error 20` сохранился, Python traceback удалён; MAME не участвует | | Владение и generation | Второй FileBridge и чтение со stale generation отклоняются | Полный host-набор в этом коммите: 45 тестов (44 прошли, один Unix-socket тест пропущен только из-за запрета `bind` в sandbox). Тот же socket path проверен живым DAP-запуском. После разделения репозиториев установленный VSIX в изолированном профиле VS Code запустил сборку SprPoP и остановился в `src/sprpop.c:264` (`main`) через API extension host. Новый живой пробник закрытия собственного MAME при остановке в `hello/main` подтверждает DAP `terminated` после внезапной потери процесса. Штатный DAP launch в `hello/main` также повторно прошёл с `sdbg` и опциональным `osx` debugger provider. Первоначально прямой `SIGTERM` остановленному MAME не давал DAP `terminated`: через 12 секунд процесс оставался живым. Причина: SDL3 по умолчанию преобразует `SIGTERM` в `SDL_EVENT_QUIT`, а SDL3 OSD MAME это событие не обрабатывает. Launcher теперь выставляет `SDL_NO_SIGNAL_HANDLERS=1` только для своего MAME, если переменная не задана пользователем. Повторный живой прогон подтвердил `SIGTERM` → DAP `terminated`; DAP `disconnect` (VS Code Stop) завершил MAME и адаптер с provider `sdbg` и `osx`. Отдельный патч MAME для этого не требуется. Закрытие окна по-прежнему проверено только через тот же `schedule_exit()` в исходнике MAME, без автоматического UI-клика. Живой lifecycle-пробник на банковой программе теперь прошёл с `sdbg` и опциональным `osx` provider. На остановке в `main` Lua вызвал `machine:exit()`: MAME вышел с кодом 0, DAP получил `terminated`, старый session server отверг запрос. Закрытие SDL3-окна в MAME вызывает тот же `schedule_exit()`; физический клик по кнопке окна не автоматизировался. При save/load state пробник после сохранения поставил банковую точку, загрузил сохранённое состояние и получил `terminated`; post-load проверка `bplist()` показала ноль оставшихся точек, старый session server отверг запрос. Для save/load пробник продолжает CPU после планирования операции: эти команды MAME сами не выводят CPU из debugger stop-loop. Это репро доступности механизма, а не полный benchmark или проверка всех runtime/mapping/lifecycle. Отдельная публикация debug-библиотек требует добавления метаданных извлечённых архивных модулей; одних флагов --debug недостаточно. Режим библиотек пока не включён. ## Новое ограничение MAME `src/osd/modules/debugger/none.cpp::wait_for_debugger()` вызывает `go()`. Поэтому `-debugger none` автоматически продолжает CPU при остановке. Автономные logpoint actions с ним возможны, ожидание интерактивных команд в stopped-состоянии — нет. Поэтому добавлен provider `sdbg`: он возвращается в stopped-loop после короткого sleep, а ядро вызывает Lua periodic перед каждой итерацией. Во время остановки CPU обычная обработка событий окна не работает: ранний `sdbg` только спал, отчего macOS помечала MAME «не отвечает» и окно не открывалось через Cmd-Tab/Dock. Provider теперь опрашивает события активного OSD примерно 100 раз в секунду (в текущем macOS SDL3 build: `input_update(false)` и `process_events()`; в native macOS OSD: `MacPollInputs()`). Новый бинарник проходит DAP launch до `main`; пользователь подтвердил, что при остановке в `main` окно снова открывается через Cmd-Tab/Dock. Регрессионный DAP-проход через `getchar()` с клавишей `x` также завершился на следующей строке с кодом `0x78`. Воспроизводимый patch, установщик и сборочные рецепты находятся в отдельном `../MAME/scripts/sprinter/`. Provider `osx` остаётся доступной launch-опцией и проверен одновременно с DAP. Для непатченного MAME можно использовать `auto`: штатные варианты — `osx` на macOS, `windows` в native Windows build, `qt` или `imgui` в Linux. `qt` зависит от `USE_QTDEBUG=1`, а `imgui` требует графическое окно. Windows-версия самого host-моста пока не готова: FileBridge использует `fcntl`, server — Unix socket. Также startup debugscript с `g` может продолжить первое реальное попадание; живой bridge-тест не использует такой скрипт. Повторная загрузка autoboot на reset защищена от дублирования callback. Raw `-plugin mamebridge` параллельно с `sdbgbridge` не загружать: общая арбитрирующая сессия для двух Lua-мостов ещё не реализована. Два одновременно запущенных процесса MAME через MCP bridge не проверялись; корректная маршрутизация команд между ними не гарантируется. Это отдельная отложенная задача в [TODO.md](TODO.md). ## Размерный регресс и оставшаяся работа `make size-check` теперь проходит (46 свежих карт). Прежние 12 расхождений разобраны: `open()` добавил 9 байт после исправления режимов DSS; `openenv` содержит ещё новый регрессионный тест; прежний размер `w3bgfx` был снят по несвежей карте. Подробное сравнение с исходной ревизией и правила обновления эталона — в [плане разделения](project-reorganization.md). Hard reset из RPC был удалён после воспроизводимого падения MAME 0.287: старый Lua periodic callback обращался к `debugger_manager` во время нового `running_machine::start()`. Reset notifier теперь только инвалидирует plugin, а live-пробник прекращает работу callback до рестарта. До отдельного безаварийного репро reset/restart capability не публикуется. Crash reports в 19:22/19:23 относились к неподдержанному register symbol в условии MAME; публичный протокол теперь принимает только window/page и plugin строит проверенное условие через I/O port. После штатных прогонов в 20:43 и позже новых `mame.arm-*.ips` не появилось. Далее по плану: завершить арбитраж управления CPU и cleanup для MCP-точек при аварийном выходе клиента, затем безопасный restart и расширенные выражения. Низкоуровневые MAME MCP-инструменты (`src/mame_mcp.py` с `-plugin mamebridge`) нельзя просто перенести: они должны проходить через общий session server и получить проверенный контракт для ввода, скриншотов, записи/watchpoints. VSIX уже упакован; для IDE ещё нужны Run-команда, выбор профиля сборки/данных и расширенная диагностика assembler/linker. Базовый attach уже проверяет принадлежность resident/current-bank к build, но не умеет читать неотображённую physical RAM. Нет автоматического чтения неотображённого bank-data, локальных или backtrace. Пути исходников в текущем пакете абсолютные. Снимки и уникальные TU уже есть, переносимый source mapping — следующая доработка. Пока библиотечные описания и отдельные форматы CDB не поддержаны, карта сообщает ограничения.