diff --git a/applications/PoP/roomtest/bug_closed.md b/applications/PoP/roomtest/bug_closed.md
index 23b5405..d131b35 100644
--- a/applications/PoP/roomtest/bug_closed.md
+++ b/applications/PoP/roomtest/bug_closed.md
@@ -1739,7 +1739,7 @@ Kid ставится на первый пол. Номер комнаты — п
Вторая волна того же прогона (вечер) дала ещё четыре наблюдения — BUG-KBD-4,
BUG-RESPAWN-2, BUG-DRAWORDER-1, BUG-LOOSE-2, — все закрыты, разборы выше.
Тогда же закрыт как невоспроизводящийся BUG-SEAM-DRAW-1 и заведён
-BUG-GATE-PASS-1, который остаётся открытым (ждёт сценария).
+BUG-GATE-PASS-1 (он закрыт ниже, 2026-08-09).
---
@@ -1807,3 +1807,167 @@ pop_guard_hurt = 0;`), а не безусловно — это и экономи
**Цвет брызг** зависит от палитры стража (слоты `0x90..0x9F`), поэтому он
изменится вместе с [BUG-GUARD-COLOR-1](bug_list.md#bug-guard-color-1) —
отдельной работы не требует.
+
+
+---
+
+
+## BUG-GATE-PASS-1. Проход сквозь закрывшуюся решётку — **ЗАКРЫТ 2026-08-09**
+
+**Приёмка:** смоук-прогон уровня 1 (пользователь, 2026-08-09) — с проблемного
+`x` Кид больше сквозь решётку не пробегает, пинг-понг у шва не вернулся.
+
+> **ВОСПРОИЗВЕДЁН И РАЗОБРАН.** Сценарий: уровень 1, комната 8, ряд 0,
+> `Kid.x = 170`, лицом ВПРАВО, решётка шва (комната 8, колонка 9) ЗАКРЫТА.
+> Разбежаться вправо и НЕ ОТПУСКАТЬ клавишу. Кид проходит сквозь решётку и
+> убегает вглубь комнаты 6.
+>
+> Ниже — новый разбор; всё, что было раньше (гипотеза про x > 205), не
+> подтвердилось и оставлено в конце для истории.
+
+### Корень: история флагов коллизии индексируется НЕ ТАК, как в оригинале
+
+Сняты две трассы — наша (брейкпоинт на резидентном `kid_tick`) и оригинала
+(SDLPoP, собран с `POP_TRACE=1`, печать в `play_kid_frame` + маркеры в
+`bumped` и `exit_room`). Стартовая позиция совпала до пикселя, поэтому
+сравнение построчное.
+
+**Оригинал:**
+
+```
+LEAVE dir=1 x=61 cxl=184 cxr=201 room=6 смена комнаты — ШТАТНАЯ
+BUMPED dx=-2 push=-1 x=63 tile=4 col=9 и СРАЗУ бамп о решётку, откат
+KID f=15 x=60 act=0 col=-1 room=6 drawn=6 сел за решёткой, стоит
+```
+
+**Мы:**
+
+```
+x 170 -> 196 бегом, col 7 -> 8 -> 9, НИ ОДНОГО бампа
+x=198 -> room 8 -> 6
+при удержании ВПРАВО доезжает до col 1 комнаты 6 и бежит дальше
+```
+
+Смена комнаты в этой точке правильна и у нас, и у оригинала: `leave_room`
+(seg002:423) вправо блокируют ТОЛЬКО `doortop`-тайлы, решётки в списке нет, а
+порог `char_x_right >= 201` совпадает с плоскостью ворот
+(`x_bump[9+FIRST_ONSCREEN_COLUMN] + TILE_MIDX + wall_dist_from_left[1]`
+= 191 + 10). Оригинал полагается не на запрет ухода, а на бамп СРАЗУ ПОСЛЕ
+перехода.
+
+**Почему бамп есть у них и нет у нас.** `check_collisions` (seg004:0004)
+хранит флаги так:
+
+```c
+row_coll_flags_ptr[tile_col] = curr_flags; // индекс — колонка В РАЗРЕШЁННОЙ комнате
+row_coll_room_ptr [tile_col] = curr_room; // и рядом — НОМЕР ЭТОЙ КОМНАТЫ
+...
+if (curr_row_coll_room[column] >= 0 &&
+ prev_coll_room[column] == curr_row_coll_room[column]) { /* только тогда сравниваем */ }
+```
+
+То есть история привязана к паре **(колонка внутри своей комнаты, комната)**.
+Решётка комнаты 8 и до перехода, и после лежит в слоте 9 с `room = 8` —
+переход 8->6 историю НЕ рвёт, переход флага 0->1 виден, бамп срабатывает.
+
+У нас массив `coll_prev/coll_curr` индексируется колонкой ОТНОСИТЕЛЬНО
+отрисованной комнаты (−2…11). При смене комнаты все индексы уезжают на 10,
+сопоставить прошлый кадр с текущим нечем, и `enter_room` вынужден звать
+`pop_coll_invalidate()`; тот ставит «прошлые флаги = уже перекрывал» (3), то
+есть ПОДАВЛЯЕТ бамп на кадре входа. А к следующему кадру Кид уже за
+плоскостью ворот — перехода 0->1 не будет никогда.
+
+### Фикс сделан 2026-08-09 (вариант B — сдвиг истории), ЖДЁТ ПРИЁМКИ В MAME
+
+Рассматривались два пути:
+
+- **A, дословный порт.** 10 слотов + параллельный массив номера комнаты,
+ индекс по колонке разрешённой комнаты, бамп только при совпадении номеров;
+ `pop_coll_invalidate()` тогда не нужен вовсе. **Не взят:** оригиналу
+ хватает десяти слотов только потому, что он перебирает узкое окно вокруг
+ Кида, а мы намеренно считаем все четырнадцать колонок (FIX_COLL_FLAGS,
+ чтобы не оставалось протухших ячеек) — при таком переборе колонки −2/−1 и
+ 8/9 сядут в одни слоты 8/9. То есть A тянет за собой ещё и сужение окна.
+- **B, сдвиг истории (сделано).** Индексацию оставляем свою, но при
+ БОКОВОМ переходе историю не выбрасываем, а перенумеровываем на 10 слотов:
+ `check_leave` двигает `x` ровно на ∓140 = 10 тайлов, координата грани
+ (`pop_x_bump`) едет на те же 140 вместе с габаритом Кида, значит сами
+ флаги инвариантны — меняется только номер слота.
+
+Реализация: `pop_coll_shift(int8_t dcol)` в `pop_map.c` сдвигает
+`coll_curr/above/below` (не `prev` — его на следующем кадре всё равно
+перезапишет `move_coll_to_prev`), освободившиеся слоты = 3 («уже
+перекрывал», бампа нет — ровно то, что в оригинале даёт несовпадение номера
+комнаты). `enter_room_side` зовёт её сразу после `pop_map_set_edges`:
+`side == 0` (ушёл влево) → `+10`, `side == 1` (вправо) → `−10`. Переходы
+вверх/вниз и все прочие входы в комнату остаются на полной инвалидации —
+там колонки не сдвигаются, но тайлы под ними уже из другой комнаты.
+
+Расхождение с дословным вариантом A записано в `../docs/impl_diff.md` (D-1).
+
+**Осторожно:** это сердце коллизии, вокруг которого разбирался
+BUG-SEAM-PINGPONG (см. `bug_closed.md`). Приёмка:
+
+1. Комнаты 6 ↔ 8 уровня 1, закрытая решётка, **обе** стороны.
+2. Мелким шагом (упереться) И с разбега (не пройти насквозь) — сценарий
+ выше воспроизводится с `Kid.x = 170`, комната 8, ряд 0, лицом вправо.
+3. Пинг-понг у шва не вернулся (экран не перескакивает туда-сюда).
+4. `make -C tests-host` — прошли все 5 наборов (2026-08-09).
+
+**Инструмент для сверки готов:** SDLPoP собран с трассой, включается
+`POP_TRACE=1` (правки в `seg000.c` play_kid_frame, `seg004.c` bumped,
+`seg002.c` exit_room, чтение переменной — `main.c`). Сборка на macOS:
+`make CFLAGS="-std=gnu99 -O2 -I/opt/homebrew/include -Wno-implicit-function-declaration" LIBS="-L/opt/homebrew/lib -lSDL2 -lSDL2_image"`
+(в системе нет pkg-config, штатный Makefile без этого не собирается).
+
+---
+
+### История: прежний разбор (гипотеза НЕ подтвердилась)
+
+**Статус: наблюдался один раз (2026-08-03), воспроизвести не удалось ни
+тогда, ни прогоном всех комнат уровня 1 (2026-08-07).** Заведён, чтобы
+наблюдение не потерялось; закрывать нельзя — ни как исправленный, ни как
+«не баг», пока нет надёжного сценария. Оговорка: BUG-GATEMOD-1, из-за
+которого решётка стартовала не в том состоянии, с тех пор закрыт, и
+наблюдение могло быть его следствием.
+
+**Что наблюдалось.** Комната 5: Кид стоял НА тайле решётки (0,9)
+и ждал, пока она опустится. После закрытия пошёл вправо — прошёл в комнату 1
+и упал на (1,1).
+
+**Что уже измерено и в чём загвоздка.** Сразу после наблюдения повторить не
+получилось: в том же месте Кид стоит на `x = 196`, `col = 9`, и решётка его
+ДЕРЖИТ — то есть штатно.
+
+Арифметика оригинала объясняет разницу. `is_obstacle` (seg004) ставит
+плоскость блокировки в `x_bump[col + FIRST_ONSCREEN_COLUMN] + TILE_MIDX`, для
+колонки 9 это **x = 205**. При этом «колонка 9» по `get_tile_div_mod_m7` —
+это `x ∈ [191, 205)`. Пока `curr_col == 9`, Кид гарантированно левее
+плоскости и обязан блокироваться; чтобы пройти, он должен оказаться **правее
+205**, то есть уже на дальней стороне решётки, — и тогда уход вправо законен:
+решётка закрылась у него за спиной, в оригинале она блокирует плоскость, а не
+весь тайл.
+
+Отсюда рабочая гипотеза: в момент наблюдения Кид стоял правее 205 (успел зайти
+по тайлу дальше, пока решётка была поднята), и поведение штатное. Но повторить
+эту позу и снять `x` пока не удалось, поэтому гипотеза НЕ подтверждена.
+
+**Что снять в следующий раз** (без этих чисел вопрос не закрыть):
+
+1. `Kid.x` и `Kid.curr_col` в момент, когда решётка уже закрылась, а Кид ещё
+ стоит на её тайле — до шага вправо;
+2. модификатор решётки (openness) комнаты 5, тайл 9 — `can_bump_into_gate()`
+ считает её препятствием только пока `(modif >> 2) + 6 < char_height`, то
+ есть пока она опустилась достаточно низко относительно РОСТА кадра;
+3. `Kid.x` покадрово на самом шаге вправо — где именно перестал блокировать.
+
+Быстрый способ снять первое: отладочный стоп-кадр (**1** заморозить, **2**
+продолжить), затем чтение `_Kid` из отладчика MAME; подгонка позы по пикселю —
+читы `[`/`]`.
+
+**Возможный корень, если гипотеза не подтвердится.** Проверка идёт по колонке,
+которая на шве уже принадлежит СОСЕДНЕЙ комнате (`curr_row_coll_room[]` в
+оригинале); у нас межкомнатная коллизия на шве — исторически проблемное место
+(ср. закрытый BUG-SEAM-PINGPONG). Второй кандидат — `char_height` в
+`can_bump_into_gate()`: если он берётся не от того кадра, решётка может
+перестать считаться препятствием раньше времени.
diff --git a/applications/PoP/roomtest/bug_list.md b/applications/PoP/roomtest/bug_list.md
index b9843df..bd81356 100644
--- a/applications/PoP/roomtest/bug_list.md
+++ b/applications/PoP/roomtest/bug_list.md
@@ -18,11 +18,11 @@
| ID | что | тип | статус |
|----|-----|-----|--------|
| [BUG-CHEAT-FIGHT-1](#bug-cheat-fight-1) | `+`/`−` в бою с вынутым мечом → Кид теряет управление | Major (чит) | открыт |
-| [BUG-GATE-PASS-1](#bug-gate-pass-1) | проход сквозь закрытую решётку шва (комн. 8 -> 6) | Major | **фикс сделан 2026-08-09** (сдвиг истории флагов, вариант B) — ждёт приёмки в MAME |
| [BUG-SPIKE-1](#bug-spike-1) | пики залипают выдвинутыми рядом с Кидом | **низкий** | маловоспроизводимый: ни сценарием, ни попиксельной подгонкой X не поднимается |
| [BUG-CHOMP-JUMP-1](#bug-chomp-jump-1) | прыжок с места вплотную к чомперу: кадр с отступом назад | **низкий** | маловоспроизводимый: на повторе не поднялся; на пререлиз |
| [T-1](#t-1) | пики перерисовываются безусловно | оптимизация | открыт |
| ~~T-2~~ | Кид перерисовывается в покое | оптимизация | **ЗАКРЫТ 2026-08-08** — [DRAW-COST шаг 1](TASKS_OPEN.md#draw-cost) |
+| ~~BUG-GATE-PASS-1~~ | проход сквозь закрытую решётку шва | Major | **ЗАКРЫТ 2026-08-09** — [bug_closed.md](bug_closed.md#bug-gate-pass-1), смоук уровня 1 пройден |
---
@@ -190,168 +190,6 @@ Smoke-прогон уровня 3 (пользователь, 2026-08-05) дал
---
-# Открытые баги уровня 1
-
-
-## BUG-GATE-PASS-1. Проход сквозь закрывшуюся решётку — **КОРЕНЬ НАЙДЕН 2026-08-08**
-
-> **ВОСПРОИЗВЕДЁН И РАЗОБРАН.** Сценарий: уровень 1, комната 8, ряд 0,
-> `Kid.x = 170`, лицом ВПРАВО, решётка шва (комната 8, колонка 9) ЗАКРЫТА.
-> Разбежаться вправо и НЕ ОТПУСКАТЬ клавишу. Кид проходит сквозь решётку и
-> убегает вглубь комнаты 6.
->
-> Ниже — новый разбор; всё, что было раньше (гипотеза про x > 205), не
-> подтвердилось и оставлено в конце для истории.
-
-### Корень: история флагов коллизии индексируется НЕ ТАК, как в оригинале
-
-Сняты две трассы — наша (брейкпоинт на резидентном `kid_tick`) и оригинала
-(SDLPoP, собран с `POP_TRACE=1`, печать в `play_kid_frame` + маркеры в
-`bumped` и `exit_room`). Стартовая позиция совпала до пикселя, поэтому
-сравнение построчное.
-
-**Оригинал:**
-
-```
-LEAVE dir=1 x=61 cxl=184 cxr=201 room=6 смена комнаты — ШТАТНАЯ
-BUMPED dx=-2 push=-1 x=63 tile=4 col=9 и СРАЗУ бамп о решётку, откат
-KID f=15 x=60 act=0 col=-1 room=6 drawn=6 сел за решёткой, стоит
-```
-
-**Мы:**
-
-```
-x 170 -> 196 бегом, col 7 -> 8 -> 9, НИ ОДНОГО бампа
-x=198 -> room 8 -> 6
-при удержании ВПРАВО доезжает до col 1 комнаты 6 и бежит дальше
-```
-
-Смена комнаты в этой точке правильна и у нас, и у оригинала: `leave_room`
-(seg002:423) вправо блокируют ТОЛЬКО `doortop`-тайлы, решётки в списке нет, а
-порог `char_x_right >= 201` совпадает с плоскостью ворот
-(`x_bump[9+FIRST_ONSCREEN_COLUMN] + TILE_MIDX + wall_dist_from_left[1]`
-= 191 + 10). Оригинал полагается не на запрет ухода, а на бамп СРАЗУ ПОСЛЕ
-перехода.
-
-**Почему бамп есть у них и нет у нас.** `check_collisions` (seg004:0004)
-хранит флаги так:
-
-```c
-row_coll_flags_ptr[tile_col] = curr_flags; // индекс — колонка В РАЗРЕШЁННОЙ комнате
-row_coll_room_ptr [tile_col] = curr_room; // и рядом — НОМЕР ЭТОЙ КОМНАТЫ
-...
-if (curr_row_coll_room[column] >= 0 &&
- prev_coll_room[column] == curr_row_coll_room[column]) { /* только тогда сравниваем */ }
-```
-
-То есть история привязана к паре **(колонка внутри своей комнаты, комната)**.
-Решётка комнаты 8 и до перехода, и после лежит в слоте 9 с `room = 8` —
-переход 8->6 историю НЕ рвёт, переход флага 0->1 виден, бамп срабатывает.
-
-У нас массив `coll_prev/coll_curr` индексируется колонкой ОТНОСИТЕЛЬНО
-отрисованной комнаты (−2…11). При смене комнаты все индексы уезжают на 10,
-сопоставить прошлый кадр с текущим нечем, и `enter_room` вынужден звать
-`pop_coll_invalidate()`; тот ставит «прошлые флаги = уже перекрывал» (3), то
-есть ПОДАВЛЯЕТ бамп на кадре входа. А к следующему кадру Кид уже за
-плоскостью ворот — перехода 0->1 не будет никогда.
-
-### Фикс сделан 2026-08-09 (вариант B — сдвиг истории), ЖДЁТ ПРИЁМКИ В MAME
-
-Рассматривались два пути:
-
-- **A, дословный порт.** 10 слотов + параллельный массив номера комнаты,
- индекс по колонке разрешённой комнаты, бамп только при совпадении номеров;
- `pop_coll_invalidate()` тогда не нужен вовсе. **Не взят:** оригиналу
- хватает десяти слотов только потому, что он перебирает узкое окно вокруг
- Кида, а мы намеренно считаем все четырнадцать колонок (FIX_COLL_FLAGS,
- чтобы не оставалось протухших ячеек) — при таком переборе колонки −2/−1 и
- 8/9 сядут в одни слоты 8/9. То есть A тянет за собой ещё и сужение окна.
-- **B, сдвиг истории (сделано).** Индексацию оставляем свою, но при
- БОКОВОМ переходе историю не выбрасываем, а перенумеровываем на 10 слотов:
- `check_leave` двигает `x` ровно на ∓140 = 10 тайлов, координата грани
- (`pop_x_bump`) едет на те же 140 вместе с габаритом Кида, значит сами
- флаги инвариантны — меняется только номер слота.
-
-Реализация: `pop_coll_shift(int8_t dcol)` в `pop_map.c` сдвигает
-`coll_curr/above/below` (не `prev` — его на следующем кадре всё равно
-перезапишет `move_coll_to_prev`), освободившиеся слоты = 3 («уже
-перекрывал», бампа нет — ровно то, что в оригинале даёт несовпадение номера
-комнаты). `enter_room_side` зовёт её сразу после `pop_map_set_edges`:
-`side == 0` (ушёл влево) → `+10`, `side == 1` (вправо) → `−10`. Переходы
-вверх/вниз и все прочие входы в комнату остаются на полной инвалидации —
-там колонки не сдвигаются, но тайлы под ними уже из другой комнаты.
-
-Расхождение с дословным вариантом A записано в `../docs/impl_diff.md` (D-1).
-
-**Осторожно:** это сердце коллизии, вокруг которого разбирался
-BUG-SEAM-PINGPONG (см. `bug_closed.md`). Приёмка:
-
-1. Комнаты 6 ↔ 8 уровня 1, закрытая решётка, **обе** стороны.
-2. Мелким шагом (упереться) И с разбега (не пройти насквозь) — сценарий
- выше воспроизводится с `Kid.x = 170`, комната 8, ряд 0, лицом вправо.
-3. Пинг-понг у шва не вернулся (экран не перескакивает туда-сюда).
-4. `make -C tests-host` — прошли все 5 наборов (2026-08-09).
-
-**Инструмент для сверки готов:** SDLPoP собран с трассой, включается
-`POP_TRACE=1` (правки в `seg000.c` play_kid_frame, `seg004.c` bumped,
-`seg002.c` exit_room, чтение переменной — `main.c`). Сборка на macOS:
-`make CFLAGS="-std=gnu99 -O2 -I/opt/homebrew/include -Wno-implicit-function-declaration" LIBS="-L/opt/homebrew/lib -lSDL2 -lSDL2_image"`
-(в системе нет pkg-config, штатный Makefile без этого не собирается).
-
----
-
-### История: прежний разбор (гипотеза НЕ подтвердилась)
-
-**Статус: наблюдался один раз (2026-08-03), воспроизвести не удалось ни
-тогда, ни прогоном всех комнат уровня 1 (2026-08-07).** Заведён, чтобы
-наблюдение не потерялось; закрывать нельзя — ни как исправленный, ни как
-«не баг», пока нет надёжного сценария. Оговорка: BUG-GATEMOD-1, из-за
-которого решётка стартовала не в том состоянии, с тех пор закрыт, и
-наблюдение могло быть его следствием.
-
-**Что наблюдалось.** Комната 5: Кид стоял НА тайле решётки (0,9)
-и ждал, пока она опустится. После закрытия пошёл вправо — прошёл в комнату 1
-и упал на (1,1).
-
-**Что уже измерено и в чём загвоздка.** Сразу после наблюдения повторить не
-получилось: в том же месте Кид стоит на `x = 196`, `col = 9`, и решётка его
-ДЕРЖИТ — то есть штатно.
-
-Арифметика оригинала объясняет разницу. `is_obstacle` (seg004) ставит
-плоскость блокировки в `x_bump[col + FIRST_ONSCREEN_COLUMN] + TILE_MIDX`, для
-колонки 9 это **x = 205**. При этом «колонка 9» по `get_tile_div_mod_m7` —
-это `x ∈ [191, 205)`. Пока `curr_col == 9`, Кид гарантированно левее
-плоскости и обязан блокироваться; чтобы пройти, он должен оказаться **правее
-205**, то есть уже на дальней стороне решётки, — и тогда уход вправо законен:
-решётка закрылась у него за спиной, в оригинале она блокирует плоскость, а не
-весь тайл.
-
-Отсюда рабочая гипотеза: в момент наблюдения Кид стоял правее 205 (успел зайти
-по тайлу дальше, пока решётка была поднята), и поведение штатное. Но повторить
-эту позу и снять `x` пока не удалось, поэтому гипотеза НЕ подтверждена.
-
-**Что снять в следующий раз** (без этих чисел вопрос не закрыть):
-
-1. `Kid.x` и `Kid.curr_col` в момент, когда решётка уже закрылась, а Кид ещё
- стоит на её тайле — до шага вправо;
-2. модификатор решётки (openness) комнаты 5, тайл 9 — `can_bump_into_gate()`
- считает её препятствием только пока `(modif >> 2) + 6 < char_height`, то
- есть пока она опустилась достаточно низко относительно РОСТА кадра;
-3. `Kid.x` покадрово на самом шаге вправо — где именно перестал блокировать.
-
-Быстрый способ снять первое: отладочный стоп-кадр (**1** заморозить, **2**
-продолжить), затем чтение `_Kid` из отладчика MAME; подгонка позы по пикселю —
-читы `[`/`]`.
-
-**Возможный корень, если гипотеза не подтвердится.** Проверка идёт по колонке,
-которая на шве уже принадлежит СОСЕДНЕЙ комнате (`curr_row_coll_room[]` в
-оригинале); у нас межкомнатная коллизия на шве — исторически проблемное место
-(ср. закрытый BUG-SEAM-PINGPONG). Второй кандидат — `char_height` в
-`can_bump_into_gate()`: если он берётся не от того кадра, решётка может
-перестать считаться препятствием раньше времени.
-
----
-
# Оптимизация отрисовки (записано 2026-07-29)
Не баги — план работ. Оба пункта про одно: у оригинала пометка тайла к