WEB board

всеканоны и докиворкеры↗ iOS↗ Легаси
WEB-41 · Обслуживание · Аркады · web

Cleanup: 4 wave-F price-knob (shopPrice*) → deprecated после F-CRUD (DB-price каноничен через каталог-CMS)

Закрыт P3 ведёт: codex-web41
Суть
## 2026-08-23 BOARDSWEEP: STALE-NOT-DEPLOYED
- Evidence: buildFixed is empty. Canonical economy files/tests exist, but the ticket body says the cleanup waits for a subsequent landing; no v4-081ff4fb5 deployment pointer is present.
- buildFixed: <empty>; canonical: v4-081ff4fb5 / 081ff4fb5f6110f8001daec7ed910ccef2e395dc.
- Status preserved by sweep: review.
Доказательства
ТРЕЙЛ (кумулятивно). 13.08 ~00:48 запуск волны m1-web41 (codex gpt-5.5, M1, клон ~/work/nc-m1 от 71c03bd6; клон чинился: pnpm-workspace.yaml в хоуме путал pnpm — .npmrc ignore-workspace=true). 01:20 СДАНО+СПАСЕНО: коммит 71fa91a, ветка agent/admin-defaults-f1-20260812 (клон). Скоуп: ручки shopPrice* wave-F выведены из пути цены — DB-каталог каноничен; env-override убит, при выставленной env-переменной warn-лог на старте (deprecation). Файлы: economyConfig.ts, economyService.ts + тесты econ-admin-wave-f/shopPrismaSpend. Отчёт WEB41-REPORT.md + web41.patch в корне клона. RESULT: DONE, тесты по отчёту зелёные. Ждёт: посадка со следующим билдом (ship-dark не требуется — поведение уже DB-канонично после F-CRUD).
[2026-08-26 07:48Z] Автор web41: 4 ключа shopPrice* помечены deprecated (JSDoc + runtime-warning), stale-значения сохранены, цены берутся из DB-каталога ShopItem.price. -> review (acc41, МОНЕТАРНАЯ: сверка цен до/после до копейки, поиск остаточных путей чтения shopPrice*).
[2026-08-26 08:12Z] acc41 NO-GO по ОДНОМУ пункту: getEconomyKnob('shopPriceBoostXpSurge') логирует warning И БРОСАЕТ 'Deprecated economy knob' — deprecated должен предупреждать, а не ломать поток. Остальное PASS: stale не effective и сохраняются, цены из каталога (item.price), в price consumers чтений shopPrice* нет. Фикс web41fix.
[2026-08-26 09:05Z] acc41c NO-GO (конкретно): warning больше не бросает и не флудит (20000 вызовов -> 1 warning), НО каждый вызов идёт в ХРАНИЛИЩЕ — fastReads=20000; при задержке 2мс 250 вызовов = 250 чтений и 555.76мс (unbounded I/O в горячем пути). Фикс web41fix2: кэширование значения с инвалидацией по версии конфига.
[2026-08-26 09:25Z] ФИКС web41fix2 готов: значение deprecated shopPrice* берётся из уже загруженного snapshot RuntimeConfig, TTL-кэш 30с, in-flight dedup, инвалидация (setEconomyOverrides/clearEconomyConfigCache/смена стора), generation-guard. ЦИФРЫ: 20000 вызовов -> reads=1, warnings=1, exceptions=0; 250 вызовов при задержке 2мс -> reads=1, 20.65мс (было 250 reads / 555.76мс). Цены byte-identical: shopItems.ts SHA-256 9760ebcc... до=после, seed-миграция 74b96886... до=после. Регрессии: economy 129/129 (18 suites), wave-F 3/3, shop spend 5/5. -> независимая приёмка acc41d (4-й приёмщик, свои негативы: смешивание значений между ключами/тенантами, устаревание цены на TTL, гонка invalidate+in-flight, кэширование ошибки, рост кэша).
[2026-08-26 10:02Z] КАРТА ДЛЯ НУЛЕВОГО АГЕНТА (как войти в задачу с нуля):
Бокс A1: ssh a1nc. Родительское дерево /home/ubuntu/waves/wt-l40 (из него делаются worktree: git -C /home/ubuntu/waves/wt-l40 worktree add <путь> <ветка>). Запуск работника: ~/codex-a1.sh exec -m gpt-5.6-luna -c model_reasoning_effort=xhigh --dangerously-bypass-approvals-and-sandbox "$(cat <бриф>)"; работа держится в tmux (tmux ls), логи /home/ubuntu/waves/<имя>-codex.log, отчёты /home/ubuntu/waves/<ИМЯ>-REPORT.md, готовность = маркер-ФАЙЛ <ИМЯ>_DONE (не строка в отчёте!).
Ветка web41, worktree wt-web41fix2 (автор) и wt-acc41d (приёмка). Суть: 4 knob-а shopPrice* объявлены deprecated; надо, чтобы обращение к ним не било по хранилищу на каждый вызов и НЕ меняло реальные цены. Как доказывать: счётчик чтений хранилища при 20000 вызовов; замер времени при инъецированной задержке 2мс на 250 вызовов; SHA-256 файла shopItems.ts и seed-миграции ДО и ПОСЛЕ (должны совпасть). Опасность: TTL-кэш цен может отдавать устаревшую цену — окно устаревания надо честно измерить и описать.
ПРАВИЛА ДОМА: (1) приёмку делает НЕ автор и НЕ прежний приёмщик, со СВОИМИ новыми тестами и обязательным НЕГАТИВНЫМ тестом (проверка, которая всё пропускает, ничего не стоит); (2) отсутствие ошибок != фича жива, нужен сквозной пруф; (3) починка одного слоя != починка фичи; (4) правило 10 — catch без лога и маячка запрещён; (5) монетарные файлы и цены не трогать без отдельного решения; (6) прод/деплой/платные вызовы — только по явному разрешению.

[2026-08-26 10:20Z] ПРИЁМКА acc41d: NO-GO. Нашла ровно тот негативный класс, который был заказан: КЭШ НАВСЕГДА ЗАПОМИНАЕТ СБОЙ. Три провала из 13 (10 pass / 3 fail, exit 1): (1) исключение RuntimeConfig — первый вызов дал fallback 30, следующий должен был вернуть 77, фактически снова 30, reads=1 (повтора попытки нет); (2) исключение каталога — fallback 180, ожидалось 888, фактически 180, catalog reads=1; (3) отсутствующая/undefined строка каталога — fallback 180, ожидалось 889, фактически 180. Т.е. разовый сбой хранилища замораживает запасное значение до истечения TTL/рестарта. ВСЁ ОСТАЛЬНОЕ PASS: 20000 вызовов -> 1 read/1 warning; 250 вызовов при задержке 2мс -> 1 read/20.68мс; изоляция ключей (RuntimeConfig [101,202,303,404] и каталог [501,502,503,504] без смешения); TTL ровно 30000мс (на 29999 старое, на 30000 новое); clearEconomyConfigCache и setEconomyOverrides инвалидируют; смена стора корректна; generation-guard работает (старый read 611 не перетёр свежий 622); память ограничена (10000 незнакомых ключей -> 0 удержано, effective 47 из фиксированного реестра); ⭐ ЦЕНА СКВОЗНЯКОМ: строка БД 987 -> отображение 987 -> фактическая сумма списания 987, баланс 1000->13. Отдельно приёмщик проверил контракт данных: RuntimeConfig — ГЛОБАЛЬНАЯ модель (key String @id, без tenantId/scope), поэтому межтенантного смешения по устройству быть не может. -> волна web41fix3: не кэшировать сбой и отсутствующее значение (повторять попытку), сохранив все достигнутые PASS.
[2026-08-26 14:35Z] ХЕНДОФФ ПОД КОМПАКТ: полное состояние в /Users/annakorin/Downloads/HANDOFF-COMPACT-2026-08-26.md. ⚠️ АВАРИЯ A1 (с ~09:30Z): бокс не пускает по ssh. Волна по этому тикету была запущена на A1 и её состояние НЕИЗВЕСТНО до восстановления. Бриф сохранён — волна перезапускается той же постановкой. Доказано: диск НЕ полон (74%, свободно 52ГБ), IP НЕ забанен (отказ и с M1, и с Pi), инстанс RUNNING, консоль гипервизора отвечает мгновенно; версия — повреждение ФС после жёсткой перезагрузки. Работа на диске не потеряна.
[2026-08-26 14:15Z] Автор web41fix3 @f5e43c4/6b61683 (волна пережила рестарт A1): дефект acc41d устранён — кэш пишется ТОЛЬКО после успешного чтения (RuntimeConfig: exception 30->77 c повторным чтением; catalog: exception/missing/'undefined' 180->888/889 с восстановлением, readCount-доказательства); negative cache НЕ введён (немедленный retry обязателен: N=8 fail = 8 reads); успех кэшируется (20000 вызовов -> 1 чтение, 250@2ms -> 17.96ms); TTL-граница 29999/30000мс точная; invalidation чистит оба кэша; цены/каталог не менялись (diff exit 0); тесты 42/42 + 47/47. -> review, диспатчу независимую приёмку acc41e с НОВЫМИ классами (гонки invalidation/coalescing).
[2026-08-26 14:45Z] ПРИНЯТ acc41e (независимый, СВОЙ harness 12/12 PASS): все классы acc41d устранены + НОВЫЕ классы проходят (гонки clear/setEconomyOverrides против in-flight coalesced read — generation-guard работает, provalue после успеха fail-open один раз, flap N=50, конкурентная смесь 500+500 без кэшированных провалов); негативный контроль (возврат «кэшируй всё» в песочнице) пойман 6 тестами, exit 1. Цены/каталог не менялись. Цикл: acc41c NO-GO -> web41fix2 -> acc41d NO-GO (новый класс) -> web41fix3 -> acc41e GO. -> done.
Починено в
6b61683
Воркер
не привязан — привязать: curl -X POST https://bugs.wool2.online/api/web/assign -H 'content-type: application/json' \ -d '{"issueId":"WEB-41","session":"<имя tmux-сессии>","host":"m4"}'
Обновлён
2026-08-26T13:48:20.031Z