[{"data":1,"prerenderedAt":1221},["ShallowReactive",2],{"navigation_docs":3,"-methodology-feedback":238,"-methodology-feedback-surround":1218},[4,45,60],{"title":5,"description":6,"icon":7,"path":8,"stem":9,"children":10},"Методология",null,"ruler","\u002Fmethodology","1.methodology",[11,15,20,25,30,35,40],{"title":12,"path":8,"stem":13,"description":14},"bxshef: методология и проверка навыков","1.methodology\u002Findex","Как писать навыки ИИ-агентов для Битрикса и как проверять, что им можно верить",{"title":16,"path":17,"stem":18,"description":19},"Стандарт навыка","\u002Fmethodology\u002Fstandard","1.methodology\u002F1.standard","11 правил, каждое из провала на стенде",{"title":21,"path":22,"stem":23,"description":24},"Методология проверки","\u002Fmethodology\u002Fmethod","1.methodology\u002F2.method","lint → eval → стенд; что измерено",{"title":26,"path":27,"stem":28,"description":29},"bxshef — CLI","\u002Fmethodology\u002Fbxshef","1.methodology\u002F3.bxshef","lint, eval, feedback",{"title":31,"path":32,"stem":33,"description":34},"GitHub Action","\u002Fmethodology\u002Faction","1.methodology\u002F4.action","тот же lint + eval в любом репозитории навыков",{"title":36,"path":37,"stem":38,"description":39},"Заготовка репозитория","\u002Fmethodology\u002Ftemplate","1.methodology\u002F5.template","с чего начать автору модуля",{"title":41,"path":42,"stem":43,"description":44},"Приёмник отзывов","\u002Fmethodology\u002Ffeedback","1.methodology\u002F6.feedback","куда уходят отзывы ИИ-агентов",{"title":46,"description":6,"icon":47,"path":48,"stem":49,"children":50},"Навыки","sparkles","\u002Fskills","2.skills",[51,55],{"title":52,"path":48,"stem":53,"description":54},"Навыки shef.*","2.skills\u002Findex","npx skills add bx-shef\u002Fskills",{"title":56,"path":57,"stem":58,"description":59},"shef-feedback","\u002Fskills\u002Fshef-feedback","2.skills\u002F1.shef-feedback","Отправить отзыв о навыке shef-* или навыке команды. Брать ВСЕГДА, когда просят оставить или отправить отзыв о навыке — даже если сам навык в диалоге не виден, —",{"title":61,"description":6,"icon":62,"path":63,"stem":64,"children":65},"Модули shef.*","package","\u002Fmodules","3.modules",[66,69,131,179],{"title":61,"path":63,"stem":67,"description":68},"3.modules\u002Findex","Что за чем ставить",{"title":70,"description":6,"path":71,"stem":72,"children":73},"shef.options","\u002Fmodules\u002Foptions","3.modules\u002F1.options\u002Findex",[74,76,81,86,91,96,101,106,110,114,119,123,127],{"title":70,"path":71,"stem":72,"description":75},"фундамент: настройки, трейты, компоненты",{"title":77,"path":78,"stem":79,"description":80},"[`\\Shef\\Options\\Installator`] Installer","\u002Fmodules\u002Foptions\u002Finstaller","3.modules\u002F1.options\u002F1.installer","Для облегчения установок.",{"title":82,"path":83,"stem":84,"description":85},"Сборка, CI и релиз","\u002Fmodules\u002Foptions\u002Fbuild-and-install","3.modules\u002F1.options\u002F10.build-and-install","Раскладка репозитория — в module-structure.md, процесс —\nв CONTRIBUTING.md, установка глазами пользователя —\nв README.md.",{"title":87,"path":88,"stem":89,"description":90},"Раскладка репозитория","\u002Fmodules\u002Foptions\u002Fmodule-structure","3.modules\u002F1.options\u002F11.module-structure","Файл про устройство репозитория. Опорные точки модуля — в CLAUDE.md,\nпроцесс — в CONTRIBUTING.md, сборка — в\nbuild-and-install.md.",{"title":92,"path":93,"stem":94,"description":95},"Проверка на портале","\u002Fmodules\u002Foptions\u002Fportal-check","3.modules\u002F1.options\u002F12.portal-check","Всё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, кеш,\nраскладка файлов, поведение при обновлении. Проверять это приходится руками —\nи лучше по списку, потому что забытый шаг находит не разработчик, а клиент.",{"title":97,"path":98,"stem":99,"description":100},"[`\\Shef\\Options\\Main\\Options`] Опции настроек модуля","\u002Fmodules\u002Foptions\u002Foptions","3.modules\u002F1.options\u002F2.options","Поддерживает следующие типы:",{"title":102,"path":103,"stem":104,"description":105},"Работа с пользователями","\u002Fmodules\u002Foptions\u002Fsecurity","3.modules\u002F1.options\u002F3.security","",{"title":107,"path":108,"stem":109,"description":105},"[`\\Shef\\Options\\Main\\Utils`] Утилиты","\u002Fmodules\u002Foptions\u002Futils","3.modules\u002F1.options\u002F4.utils",{"title":111,"path":112,"stem":113,"description":105},"[`\\Shef\\Options\\Components`] Работа с компонентами","\u002Fmodules\u002Foptions\u002Fcomponents","3.modules\u002F1.options\u002F5.components",{"title":115,"path":116,"stem":117,"description":118},"[`\\Shef\\Options\\Options`] Паттерны","\u002Fmodules\u002Foptions\u002Fpattern","3.modules\u002F1.options\u002F6.pattern","Запускаемые примеры: singleton.php,\nconfig.php, smartstd.php —\nкак их гонять, написано в examples\u002FREADME.md.",{"title":120,"path":121,"stem":122,"description":105},"[`\\Shef\\Options\\Tests`] Тестирование","\u002Fmodules\u002Foptions\u002Ftests","3.modules\u002F1.options\u002F7.tests",{"title":124,"path":125,"stem":126,"description":105},"[`\\Shef\\Options\\TraitList`] Набор трейтов","\u002Fmodules\u002Foptions\u002Ftraitlist","3.modules\u002F1.options\u002F8.traitlist",{"title":128,"path":129,"stem":130,"description":105},"Правила для ИИ-агентов в этом репозитории","\u002Fmodules\u002Foptions\u002Fagent-rules","3.modules\u002F1.options\u002F9.agent-rules",{"title":132,"description":6,"path":133,"stem":134,"children":135},"shef.problems","\u002Fmodules\u002Fproblems","3.modules\u002F2.problems\u002Findex",[136,138,143,147,152,157,161,166,169,172,175],{"title":132,"path":133,"stem":134,"description":137},"логи, журнал событий, учёт проблем",{"title":139,"path":140,"stem":141,"description":142},"[`\\Shef\\Problems\\Integration`] События и меню","\u002Fmodules\u002Fproblems\u002Fevents","3.modules\u002F2.problems\u002F1.events","Что модуль регистрирует в ядре при установке. Список — в .settings.php, ключ\ninstallEvents; что каждый обработчик существует, сверяет\ntests\u002Fsettings_test.php.",{"title":144,"path":145,"stem":146,"description":105},"Безопасность логов","\u002Fmodules\u002Fproblems\u002Fsecurity","3.modules\u002F2.problems\u002F10.security",{"title":148,"path":149,"stem":150,"description":151},"Быстрая отладка: `_pr`, `_log`, `_log1`","\u002Fmodules\u002Fproblems\u002Fdeffunctions","3.modules\u002F2.problems\u002F2.deffunctions","Функции объявляет def-functions.php, подключается он из include.php.",{"title":153,"path":154,"stem":155,"description":156},"Уровни логирования","\u002Fmodules\u002Fproblems\u002Floglevel","3.modules\u002F2.problems\u002F3.loglevel","Уровни — стандарт PSR-3, в Monolog это \\Monolog\\Level. Ниже — когда какой брать.",{"title":158,"path":159,"stem":160,"description":105},"[`\\Shef\\Problems\\Integration\\Monolog`] Monolog","\u002Fmodules\u002Fproblems\u002Fmonolog","3.modules\u002F2.problems\u002F4.monolog",{"title":162,"path":163,"stem":164,"description":165},"Ротация логов","\u002Fmodules\u002Fproblems\u002Flogrotate","3.modules\u002F2.problems\u002F5.logrotate","Логи модуля лежат в каталоге логов — по умолчанию на уровень выше корня сайта,\nдля BitrixVM \u002Fhome\u002Fbitrix\u002Fsh_log\u002F*.log, — и сами не чистятся. Ротацию делает\nlogrotate — системная утилита, а не Monolog: Monolog тоже умеет\n(RotatingFileHandler), но тогда за файлами следит каждый PHP-процесс, а не\nодна служба.",{"title":128,"path":167,"stem":168,"description":105},"\u002Fmodules\u002Fproblems\u002Fagent-rules","3.modules\u002F2.problems\u002F6.agent-rules",{"title":82,"path":170,"stem":171,"description":85},"\u002Fmodules\u002Fproblems\u002Fbuild-and-install","3.modules\u002F2.problems\u002F7.build-and-install",{"title":87,"path":173,"stem":174,"description":90},"\u002Fmodules\u002Fproblems\u002Fmodule-structure","3.modules\u002F2.problems\u002F8.module-structure",{"title":92,"path":176,"stem":177,"description":178},"\u002Fmodules\u002Fproblems\u002Fportal-check","3.modules\u002F2.problems\u002F9.portal-check","Всё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, меню,\nраскладка файлов, журнал событий, поведение при обновлении. Проверять это\nприходится руками — и лучше по списку, потому что забытый шаг находит не\nразработчик, а клиент.",{"title":180,"description":6,"path":181,"stem":182,"children":183},"shef.insync","\u002Fmodules\u002Finsync","3.modules\u002F3.insync\u002Findex",[184,186,191,194,198,203,208,213,218,222,227,232,235],{"title":180,"path":181,"stem":182,"description":185},"агенты, импорт, API-клиенты, модели",{"title":187,"path":188,"stem":189,"description":190},"[`\\Shef\\InSync\\Agents`] Агенты","\u002Fmodules\u002Finsync\u002Fagents","3.modules\u002F3.insync\u002F1.agents","Агент импорта — наследник \\Shef\\InSync\\Agents\\AAgent. Описание агента для\nb_agent — \\Shef\\InSync\\Agents\\Entity, установку и управление берёт на себя\n\\Shef\\InSync\\Agents\\Manager.",{"title":87,"path":192,"stem":193,"description":90},"\u002Fmodules\u002Finsync\u002Fmodule-structure","3.modules\u002F3.insync\u002F10.module-structure",{"title":92,"path":195,"stem":196,"description":197},"\u002Fmodules\u002Finsync\u002Fportal-check","3.modules\u002F3.insync\u002F11.portal-check","Всё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, левое\nменю, раскладка компонентов, агенты, таблица импорта, поведение при\nобновлении. Проверять это приходится руками — и лучше по списку, потому что\nзабытый шаг находит не разработчик, а клиент.",{"title":199,"path":200,"stem":201,"description":202},"Безопасность","\u002Fmodules\u002Finsync\u002Fsecurity","3.modules\u002F3.insync\u002F12.security","Модуль даёт другим модулям заготовки для синхронизаций, и самые опасные места\nу него общие с ними: кто может запускать агенты и импорт, что ложится в каталоги\nимпорта, что уходит в SQL и в лог. Ниже — что держит модуль и что остаётся\nпроекту.",{"title":204,"path":205,"stem":206,"description":207},"[`\\Shef\\InSync\\Sync`] Импорт","\u002Fmodules\u002Finsync\u002Fimport","3.modules\u002F3.insync\u002F2.import","Импорт идёт в два шага через таблицу импорта \\Shef\\InSync\\Sync\\Model\\SyncTable\n(shef_insync_model):",{"title":209,"path":210,"stem":211,"description":212},"[`\\Shef\\InSync\\Api`] API","\u002Fmodules\u002Finsync\u002Fapi","3.modules\u002F3.insync\u002F3.api","Обращение к внешнему API по HTTP — наследник \\Shef\\InSync\\Api\\AConnector.",{"title":214,"path":215,"stem":216,"description":217},"[`\\Shef\\InSync\\TraitList\\Xml`] Парсинг XML","\u002Fmodules\u002Finsync\u002Fxml","3.modules\u002F3.insync\u002F4.xml","Разбор XML сделан через SbWereWolf\u002Fxml-navigator\n(статья на Хабре): XMLReader идёт по\nдокументу потоком, а каждый элемент с нужным тегом HierarchyComposer\nпревращает в массив — n имя, v значение, a атрибуты, s вложенные\nэлементы.",{"title":219,"path":220,"stem":221,"description":105},"Компоненты","\u002Fmodules\u002Finsync\u002Fcomponents","3.modules\u002F3.insync\u002F5.components",{"title":223,"path":224,"stem":225,"description":226},"Страницы","\u002Fmodules\u002Finsync\u002Fpage","3.modules\u002F3.insync\u002F6.page","Страницы модуля — в левом меню, штатным разделом intranet\n(Bitrix\\Intranet\\CustomSection): раздел «SH Импорт», код shinsync.\nВерхней панели и shef.uiclear больше нет.",{"title":228,"path":229,"stem":230,"description":231},"[`\\Shef\\InSync\\Main\\Options`] Опции настроек модуля","\u002Fmodules\u002Finsync\u002Foptions","3.modules\u002F3.insync\u002F7.options","Опции для страницы настроек модуля импорта (на ShOptionsConfig из\nshef.options): добавьте их во вкладку своего options_conf.php.",{"title":128,"path":233,"stem":234,"description":105},"\u002Fmodules\u002Finsync\u002Fagent-rules","3.modules\u002F3.insync\u002F8.agent-rules",{"title":82,"path":236,"stem":237,"description":85},"\u002Fmodules\u002Finsync\u002Fbuild-and-install","3.modules\u002F3.insync\u002F9.build-and-install",{"id":239,"title":41,"body":240,"description":44,"extension":1212,"meta":1213,"navigation":1214,"path":42,"rawbody":1215,"seo":1216,"stem":43,"__hash__":1217},"docs\u002F1.methodology\u002F6.feedback.md",{"type":241,"value":242,"toc":1203},"minimark",[243,252,304,322,327,346,351,354,415,439,450,454,469,604,630,634,661,676,823,866,884,939,953,957,960,995,1036,1042,1072,1082,1086,1174,1187,1199],[244,245,246,247,251],"p",{},"Куда ИИ-агенты сами отправляют отзывы о навыках — обычным HTTP POST с JSON по адресу из навыка\nотзыва (",[248,249,250],"code",{},"\u003Cпрефикс>-feedback","), без bxshef и конфигов. Один файл на Node без\nзависимостей, хранение — JSON-файлы в каталоге, Docker.",[253,254,258],"pre",{"className":255,"code":256,"language":257,"meta":105,"style":105},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","cd feedback && make build-local               # на переднем плане: 127.0.0.1:8787, токен чтения — dev\ncurl -s localhost:8787\u002Fhealth                 # в другом терминале: {\"ok\":true}\n","bash",[248,259,260,288],{"__ignoreMap":105},[261,262,265,269,273,277,281,284],"span",{"class":263,"line":264},"line",1,[261,266,268],{"class":267},"sptTA","cd",[261,270,272],{"class":271},"s_sjI"," feedback",[261,274,276],{"class":275},"sP7_E"," &&",[261,278,280],{"class":279},"sbgvK"," make",[261,282,283],{"class":271}," build-local",[261,285,287],{"class":286},"sutJx","               # на переднем плане: 127.0.0.1:8787, токен чтения — dev\n",[261,289,291,294,298,301],{"class":263,"line":290},2,[261,292,293],{"class":279},"curl",[261,295,297],{"class":296},"stzsN"," -s",[261,299,300],{"class":271}," localhost:8787\u002Fhealth",[261,302,303],{"class":286},"                 # в другом терминале: {\"ok\":true}\n",[244,305,306,309,310,313,314,317,318,321],{},[248,307,308],{},"make"," без цели печатает список целей. Образ собирает CI (",[248,311,312],{},".github\u002Fworkflows\u002Ffeedback-image.yml",")\nи публикует в ",[248,315,316],{},"ghcr.io\u002Fbx-shef\u002Fskills-standard-feedback:latest"," при каждом изменении ",[248,319,320],{},"feedback\u002F"," в main.",[323,324,326],"h2",{"id":325},"сервер","Сервер",[244,328,329,330,333,334,337,338,341,342,345],{},"Схема та же, что у остальных приложений bx-shef (эталон — ",[248,331,332],{},"client-bank-alfa-by","): на хосте общий\nnginx-proxy + acme-companion (TLS Let's Encrypt) в docker-сети ",[248,335,336],{},"proxy-net"," и общий Watchtower.\nПриёмник отдаёт прокси ",[248,339,340],{},"VIRTUAL_HOST"," \u002F ",[248,343,344],{},"LETSENCRYPT_HOST"," — сертификат выпускается и\nпродлевается сам, своего nginx и certbot нет.",[347,348,350],"h3",{"id":349},"один-раз-на-хост","Один раз на хост",[244,352,353],{},"Если на сервере уже есть client-bank, invoice-from-tasks или currency-converter — всё стоит:",[253,355,357],{"className":255,"code":356,"language":257,"meta":105,"style":105},"docker network ls | grep proxy-net\ndocker ps --format '{{.Names}}\\t{{.Image}}' | grep -E 'nginx-proxy|acme-companion|watchtower'\n",[248,358,359,380],{"__ignoreMap":105},[261,360,361,364,367,370,374,377],{"class":263,"line":264},[261,362,363],{"class":279},"docker",[261,365,366],{"class":271}," network",[261,368,369],{"class":271}," ls",[261,371,373],{"class":372},"smGrS"," |",[261,375,376],{"class":279}," grep",[261,378,379],{"class":271}," proxy-net\n",[261,381,382,384,387,390,394,397,400,402,404,407,409,412],{"class":263,"line":290},[261,383,363],{"class":279},[261,385,386],{"class":271}," ps",[261,388,389],{"class":296}," --format",[261,391,393],{"class":392},"sjJ54"," '",[261,395,396],{"class":271},"{{.Names}}\\t{{.Image}}",[261,398,399],{"class":392},"'",[261,401,373],{"class":372},[261,403,376],{"class":279},[261,405,406],{"class":296}," -E",[261,408,393],{"class":392},[261,410,411],{"class":271},"nginx-proxy|acme-companion|watchtower",[261,413,414],{"class":392},"'\n",[244,416,417,418,427,428,430,431,434,435,438],{},"Чего-то нет — поставить по разделу «Если nginx-proxy \u002F Watchtower ещё не стоят» в\n",[419,420,424],"a",{"href":421,"rel":422},"https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Fclient-bank-alfa-by\u002Fblob\u002Fmain\u002Fdocs\u002FDEPLOY.md",[423],"nofollow",[248,425,426],{},"client-bank-alfa-by\u002Fdocs\u002FDEPLOY.md",":\nсеть ",[248,429,336],{},", прокси из ",[248,432,433],{},"currency-converter\u002Fdocker-compose.nginxproxy.yml",", Watchtower с\n",[248,436,437],{},"--label-enable",". Второй Watchtower не поднимать.",[244,440,441,442,445,446,449],{},"Пакет ",[248,443,444],{},"skills-standard-feedback"," в GHCR — публичный (Package settings → Change visibility), тогда\nсерверу и Watchtower не нужен ",[248,447,448],{},"docker login",".",[347,451,453],{"id":452},"развёртывание","Развёртывание",[244,455,456,457,461,462,465,466,449],{},"DNS A-запись домена — на сервер ",[458,459,460],"strong",{},"до"," ",[248,463,464],{},"make prod-up",", иначе сертификат не выпустится.\nРепозиторий на сервер не нужен: два файла и ",[248,467,468],{},".env",[253,470,472],{"className":255,"code":471,"language":257,"meta":105,"style":105},"mkdir -p \u002Fhome\u002Fbitrix\u002Fskills-feedback && cd \u002Fhome\u002Fbitrix\u002Fskills-feedback\ncurl -fsSL -O https:\u002F\u002Fraw.githubusercontent.com\u002Fbx-shef\u002Fskills-standard\u002Fmain\u002Ffeedback\u002Fdocker-compose.prod.yml\ncurl -fsSL -O https:\u002F\u002Fraw.githubusercontent.com\u002Fbx-shef\u002Fskills-standard\u002Fmain\u002Ffeedback\u002FMakefile\ncurl -fsSL -o .env https:\u002F\u002Fraw.githubusercontent.com\u002Fbx-shef\u002Fskills-standard\u002Fmain\u002Ffeedback\u002F.env.example\nopenssl rand -hex 32             # это значение — в FEEDBACK_READ_TOKEN (.env не выполняет команды)\nchmod 600 .env && nano .env      # DOMAIN, LETSENCRYPT_EMAIL, FEEDBACK_READ_TOKEN; остальное — по умолчанию\nmake prod-up\nmake doctor                      # контейнер, прокси, https, сертификат, чтение закрыто, диск\nmake read                        # сводка отзывов\n",[248,473,474,493,506,518,534,553,574,582,593],{"__ignoreMap":105},[261,475,476,479,482,485,487,490],{"class":263,"line":264},[261,477,478],{"class":279},"mkdir",[261,480,481],{"class":296}," -p",[261,483,484],{"class":271}," \u002Fhome\u002Fbitrix\u002Fskills-feedback",[261,486,276],{"class":275},[261,488,489],{"class":267}," cd",[261,491,492],{"class":271}," \u002Fhome\u002Fbitrix\u002Fskills-feedback\n",[261,494,495,497,500,503],{"class":263,"line":290},[261,496,293],{"class":279},[261,498,499],{"class":296}," -fsSL",[261,501,502],{"class":296}," -O",[261,504,505],{"class":271}," https:\u002F\u002Fraw.githubusercontent.com\u002Fbx-shef\u002Fskills-standard\u002Fmain\u002Ffeedback\u002Fdocker-compose.prod.yml\n",[261,507,509,511,513,515],{"class":263,"line":508},3,[261,510,293],{"class":279},[261,512,499],{"class":296},[261,514,502],{"class":296},[261,516,517],{"class":271}," https:\u002F\u002Fraw.githubusercontent.com\u002Fbx-shef\u002Fskills-standard\u002Fmain\u002Ffeedback\u002FMakefile\n",[261,519,521,523,525,528,531],{"class":263,"line":520},4,[261,522,293],{"class":279},[261,524,499],{"class":296},[261,526,527],{"class":296}," -o",[261,529,530],{"class":271}," .env",[261,532,533],{"class":271}," https:\u002F\u002Fraw.githubusercontent.com\u002Fbx-shef\u002Fskills-standard\u002Fmain\u002Ffeedback\u002F.env.example\n",[261,535,537,540,543,546,550],{"class":263,"line":536},5,[261,538,539],{"class":279},"openssl",[261,541,542],{"class":271}," rand",[261,544,545],{"class":296}," -hex",[261,547,549],{"class":548},"srdBf"," 32",[261,551,552],{"class":286},"             # это значение — в FEEDBACK_READ_TOKEN (.env не выполняет команды)\n",[261,554,556,559,562,564,566,569,571],{"class":263,"line":555},6,[261,557,558],{"class":279},"chmod",[261,560,561],{"class":548}," 600",[261,563,530],{"class":271},[261,565,276],{"class":275},[261,567,568],{"class":279}," nano",[261,570,530],{"class":271},[261,572,573],{"class":286},"      # DOMAIN, LETSENCRYPT_EMAIL, FEEDBACK_READ_TOKEN; остальное — по умолчанию\n",[261,575,577,579],{"class":263,"line":576},7,[261,578,308],{"class":279},[261,580,581],{"class":271}," prod-up\n",[261,583,585,587,590],{"class":263,"line":584},8,[261,586,308],{"class":279},[261,588,589],{"class":271}," doctor",[261,591,592],{"class":286},"                      # контейнер, прокси, https, сертификат, чтение закрыто, диск\n",[261,594,596,598,601],{"class":263,"line":595},9,[261,597,308],{"class":279},[261,599,600],{"class":271}," read",[261,602,603],{"class":286},"                        # сводка отзывов\n",[244,605,606,607,610,611,614,615,618,619,622,623,626,627,449],{},"Дальше обновления приходят сами: CI публикует образ, Watchtower его подхватывает. Сразу —\n",[248,608,609],{},"make prod-redeploy",". Новые версии compose-файла и Makefile — ",[248,612,613],{},"make compose-update",",\n",[248,616,617],{},"make self-update",". Копия отзывов — ",[248,620,621],{},"make backup"," (в ",[248,624,625],{},".\u002Fbackups","), читать — ",[248,628,629],{},"make read",[323,631,633],{"id":632},"подключить-навыки","Подключить навыки",[244,635,636,637,640,641,644,645,648,649,652,653,656,657,660],{},"Адрес приёмника — ",[248,638,639],{},"https:\u002F\u002F\u003CDOMAIN>\u002Ffeedback",". Его вписывают ",[458,642,643],{},"в сам навык отзыва"," набора\n(раздел «Отправить» в ",[248,646,647],{},"template\u002Fskills\u002Facme-feedback\u002FSKILL.md"," — заменить\n",[248,650,651],{},"feedback.example.org","). Навыки ставятся штатно (",[248,654,655],{},"npx skills add \u003Cowner\u002Frepo>","), и агент\nотправляет отзыв сам — одной командой ",[248,658,659],{},"curl --data-urlencode …","; в проектах ничего ставить и\nнастраивать не нужно.",[244,662,663,664,667,668,671,672,675],{},"Тикет — поля ниже, формой (так шлёт навык) или JSON; ответ\n",[248,665,666],{},"201 {\"success\": true, \"data\": {\"id\", \"category\", \"title\", \"status\": \"NEW\", \"createdAt\"}}",", ошибки\n",[248,669,670],{},"{\"success\": false, \"error\": {\"code\", \"message\"}}"," (",[248,673,674],{},"VALIDATION_ERROR"," перечисляет поля).",[677,678,679,696],"table",{},[680,681,682],"thead",{},[683,684,685,689,693],"tr",{},[686,687,688],"th",{},"Поле",[686,690,692],{"align":691},"center","Обяз.",[686,694,695],{},"Что",[697,698,699,732,744,756,772,793,805],"tbody",{},[683,700,701,707,710],{},[702,703,704],"td",{},[248,705,706],{},"category",[702,708,709],{"align":691},"да",[702,711,712,715,716,715,719,715,722,715,725,715,728,731],{},[248,713,714],{},"BUG",", ",[248,717,718],{},"SUGGESTION",[248,720,721],{},"DOCS",[248,723,724],{},"CHAT",[248,726,727],{},"BOTS",[248,729,730],{},"OTHER"," (регистр не важен)",[683,733,734,739,741],{},[702,735,736],{},[248,737,738],{},"title",[702,740,709],{"align":691},[702,742,743],{},"3–200 символов",[683,745,746,751,753],{},[702,747,748],{},[248,749,750],{},"body",[702,752,709],{"align":691},[702,754,755],{},"10–20000 символов",[683,757,758,763,765],{},[702,759,760],{},[248,761,762],{},"context",[702,764,709],{"align":691},[702,766,767,768,771],{},"объект до 10 КБ; ",[248,769,770],{},"skill"," — обязательно (имя навыка)",[683,773,774,779,782],{},[702,775,776],{},[248,777,778],{},"context.outcome",[702,780,781],{"align":691},"нет",[702,783,784,715,787,715,790],{},[248,785,786],{},"done",[248,788,789],{},"partial",[248,791,792],{},"failed",[683,794,795,800,802],{},[702,796,797],{},[248,798,799],{},"context.helped",[702,801,781],{"align":691},[702,803,804],{},"массив строк — что пригодилось (до 20)",[683,806,807,818,820],{},[702,808,809,715,812,715,815],{},[248,810,811],{},"context.agent",[248,813,814],{},".version",[248,816,817],{},".main",[702,819,781],{"align":691},[702,821,822],{},"короткие строки",[244,824,825,826,671,829,832,833,715,835,715,837,715,839,715,841,715,844,715,847,715,850,853,854,857,858,861,862,865],{},"Тот же тикет принимается ",[458,827,828],{},"формой",[248,830,831],{},"application\u002Fx-www-form-urlencoded",") — так шлёт навык:\n",[248,834,706],{},[248,836,738],{},[248,838,750],{},[248,840,770],{},[248,842,843],{},"outcome",[248,845,846],{},"agent",[248,848,849],{},"version",[248,851,852],{},"main"," плоско, ",[248,855,856],{},"helped"," —\nповторяется (",[248,859,860],{},"--data-urlencode helped=… --data-urlencode helped=…","). Зачем: JSON в самой команде\n(",[248,863,864],{},"{\"…",") проверки оболочки у агентов не пропускают — Claude Code отклоняет такую команду, — а\nформа проходит без файла и без heredoc.",[244,867,868,869,871,872,874,875,877,878,880,881,883],{},"Прочие поля тела и ",[248,870,762],{}," отбрасываются. Для навыков категории значат: ",[248,873,714],{}," — навык\nрасходится с кодом, ",[248,876,721],{}," — неясно или лишнее, ",[248,879,718],{}," — не хватило, ",[248,882,730],{}," — замечаний нет.",[244,885,886,889,890,715,892,894,895,897,898,901,902,715,905,715,908,911,912,915,916,919,920,923,924,715,927,930,931,934,935,938],{},[458,887,888],{},"Чистка."," Агенту велено не писать в отзыв проект и секреты, но приёмник на слово не верит: в\n",[248,891,738],{},[248,893,750],{}," и ",[248,896,856],{}," до записи на диск заменяются пометкой ",[248,899,900],{},"[скрыто: …]"," ключи и токены\n(",[248,903,904],{},"vibe_api_…",[248,906,907],{},"sk-…",[248,909,910],{},"ghp_…",", JWT, ",[248,913,914],{},"Bearer …",", AWS, приватные ключи, ",[248,917,918],{},"password=…","\u002F",[248,921,922],{},"token: …",",\nдлинные hex\u002Fbase64), адреса (URL), домены, почта, IP, пути (",[248,925,926],{},"\u002Fhome\u002F…",[248,928,929],{},"C:\\…",") и телефоны.\nЧисло замен — в поле ",[248,932,933],{},"redacted"," отзыва. Имена классов, методов, событий и файлы вида\n",[248,936,937],{},"lang\u002Fru\u002Finstall.php"," остаются.",[244,940,941,944,945,948,949,952],{},[248,942,943],{},"bxshef feedback send"," шлёт тот же тикет (адрес — ",[248,946,947],{},".bxshef.json"," или ",[248,950,951],{},"BXSHEF_FEEDBACK_URL","),\nно навыку он не нужен.",[323,954,956],{"id":955},"кто-читает","Кто читает",[244,958,959],{},"Отзывы читает автор навыков, и только он. Два замка:",[961,962,963,975],"ul",{},[964,965,966,461,969,622,972,974],"li",{},[458,967,968],{},"токен",[248,970,971],{},"FEEDBACK_READ_TOKEN",[248,973,468],{},"). Не задан — чтение закрыто совсем (403);",[964,976,977,980,981,983,984,987,988,990,991,994],{},[458,978,979],{},"откуда",": по умолчанию только с самого сервера — ",[248,982,629],{},". Снаружи, через\n",[248,985,986],{},"https:\u002F\u002F\u003CDOMAIN>\u002Ffeedback.md",", — 403 даже с верным токеном, пока в ",[248,989,468],{}," не\n",[248,992,993],{},"FEEDBACK_READ_REMOTE=1",". Так утёкший токен сам по себе отзывы не открывает.",[253,996,998],{"className":255,"code":997,"language":257,"meta":105,"style":105},"make read                      # сводка: навыки и последние замечания\nmake read SKILL=acme-feedback  # JSON по одному навыку\nmake read JSON=1               # все отзывы JSON\n",[248,999,1000,1009,1021],{"__ignoreMap":105},[261,1001,1002,1004,1006],{"class":263,"line":264},[261,1003,308],{"class":279},[261,1005,600],{"class":271},[261,1007,1008],{"class":286},"                      # сводка: навыки и последние замечания\n",[261,1010,1011,1013,1015,1018],{"class":263,"line":290},[261,1012,308],{"class":279},[261,1014,600],{"class":271},[261,1016,1017],{"class":271}," SKILL=acme-feedback",[261,1019,1020],{"class":286},"  # JSON по одному навыку\n",[261,1022,1023,1025,1027,1030,1033],{"class":263,"line":508},[261,1024,308],{"class":279},[261,1026,600],{"class":271},[261,1028,1029],{"class":271}," JSON=",[261,1031,1032],{"class":548},"1",[261,1034,1035],{"class":286},"               # все отзывы JSON\n",[244,1037,1038,1039,1041],{},"С ",[248,1040,993],{}," — снаружи с токеном:",[253,1043,1045],{"className":255,"code":1044,"language":257,"meta":105,"style":105},"curl -s -H \"Authorization: Bearer $FEEDBACK_READ_TOKEN\" https:\u002F\u002Ffeedback.example.org\u002Ffeedback.md\n",[248,1046,1047],{"__ignoreMap":105},[261,1048,1049,1051,1053,1056,1059,1062,1066,1069],{"class":263,"line":264},[261,1050,293],{"class":279},[261,1052,297],{"class":296},[261,1054,1055],{"class":296}," -H",[261,1057,1058],{"class":392}," \"",[261,1060,1061],{"class":271},"Authorization: Bearer ",[261,1063,1065],{"class":1064},"su5hD","$FEEDBACK_READ_TOKEN",[261,1067,1068],{"class":392},"\"",[261,1070,1071],{"class":271}," https:\u002F\u002Ffeedback.example.org\u002Ffeedback.md\n",[244,1073,1074,1075,1078,1079,1081],{},"Подбор токена: после ",[248,1076,1077],{},"FEEDBACK_AUTH_FAILS"," (5) неверных попыток в минуту с одного адреса —\n429 до конца минуты, даже с верным токеном. Сводка экранирует разметку и управляющие символы\nиз отзывов: ",[248,1080,629],{}," печатает её в терминал, и чужой текст не должен им управлять.",[323,1083,1085],{"id":1084},"лимиты-и-хранение","Лимиты и хранение",[961,1087,1088,1121,1127,1140,1156],{},[964,1089,1090,1093,1094,1097,1098,1101,1102,1105,1106,1109,1110,1113,1114,1117,1118,1120],{},[458,1091,1092],{},"Отправка",": не больше ",[248,1095,1096],{},"FEEDBACK_RATE"," (20) в минуту с одного адреса и\n",[248,1099,1100],{},"FEEDBACK_RATE_TOTAL"," (300) в минуту всего; сверх — 429 с ",[248,1103,1104],{},"Retry-After",". Адрес клиента\nза nginx-proxy — последний в ",[248,1107,1108],{},"X-Forwarded-For",", держится только в памяти для счётчика и на\nдиск не пишется. ",[248,1111,1112],{},"TRUST_PROXY=1"," верит заголовку от всей частной сети; строже —\n",[248,1115,1116],{},"TRUST_PROXY=\u003Cимя контейнера nginx-proxy>",": тогда соседи по ",[248,1119,336],{}," не подделают адрес.",[964,1122,1123,1126],{},[458,1124,1125],{},"Что принимается",": тикет до 64 КБ (поля — «Подключить навыки»). Сохраняются только\nизвестные поля, вычищенные, и время приёма — ни IP, ни заголовков, ни посторонних полей.",[964,1128,1129,1093,1132,1135,1136,1139],{},[458,1130,1131],{},"Место",[248,1133,1134],{},"FEEDBACK_MAX_FILES"," (20000) отзывов и ",[248,1137,1138],{},"FEEDBACK_MAX_MB"," (200);\nсверх — 507, пока старые не уйдут по сроку. Диск сервера общий — приёмник его не забьёт.",[964,1141,1142,1145,1146,1149,1150,1153,1154,449],{},[458,1143,1144],{},"Срок",": отзывы старше ",[248,1147,1148],{},"FEEDBACK_RETENTION_DAYS"," (3) дней удаляются — при старте и раз в\nчас; ",[248,1151,1152],{},"0"," — не удалять. Отзыв — сырьё для правки навыка: за три дня его читают, остальное\nкопируйте ",[248,1155,621],{},[964,1157,1158,671,1161,1164,1165,1167,1168,622,1171,1173],{},[458,1159,1160],{},"Токен на отправку",[248,1162,1163],{},"FEEDBACK_TOKEN",") — по желанию, для приёмника, куда шлют только свои\nлюди и CI: ",[248,1166,943],{}," подставит его из переменной окружения\n",[248,1169,1170],{},"BXSHEF_FEEDBACK_TOKEN",[248,1172,947],{}," не класть — файл коммитят). Навыкам он не\nподходит: адрес и запрос в навыке публичны, токен в нём перестал бы быть секретом — с\nтокеном отзывы агентов получат 401.",[244,1175,1176,1177,919,1180,1183,1184,449],{},"Как это замыкает цикл: отзыв → правка навыка → PR в репозиторий навыков →\n",[248,1178,1179],{},"lint",[248,1181,1182],{},"eval"," → новая версия, которую агенты получат через ",[248,1185,1186],{},"npx skills update",[1188,1189,1190],"note",{},[244,1191,1192,1193,1198],{},"Источник: ",[419,1194,1197],{"href":1195,"rel":1196},"https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Fskills-standard\u002Fblob\u002Fmain\u002Ffeedback\u002FREADME.md",[423],"skills-standard\u002Ffeedback\u002FREADME.md"," — правки туда, сайт пересобирается сам.",[1200,1201,1202],"style",{},"html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":105,"searchDepth":508,"depth":508,"links":1204},[1205,1209,1210,1211],{"id":325,"depth":290,"text":326,"children":1206},[1207,1208],{"id":349,"depth":508,"text":350},{"id":452,"depth":508,"text":453},{"id":632,"depth":290,"text":633},{"id":955,"depth":290,"text":956},{"id":1084,"depth":290,"text":1085},"md",{},true,"---\ntitle: \"Приёмник отзывов\"\ndescription: \"куда уходят отзывы ИИ-агентов\"\n---\n\nКуда ИИ-агенты сами отправляют отзывы о навыках — обычным HTTP POST с JSON по адресу из навыка\nотзыва (`\u003Cпрефикс>-feedback`), без bxshef и конфигов. Один файл на Node без\nзависимостей, хранение — JSON-файлы в каталоге, Docker.\n\n```bash\ncd feedback && make build-local               # на переднем плане: 127.0.0.1:8787, токен чтения — dev\ncurl -s localhost:8787\u002Fhealth                 # в другом терминале: {\"ok\":true}\n```\n\n`make` без цели печатает список целей. Образ собирает CI (`.github\u002Fworkflows\u002Ffeedback-image.yml`)\nи публикует в `ghcr.io\u002Fbx-shef\u002Fskills-standard-feedback:latest` при каждом изменении `feedback\u002F` в main.\n\n## Сервер\n\nСхема та же, что у остальных приложений bx-shef (эталон — `client-bank-alfa-by`): на хосте общий\nnginx-proxy + acme-companion (TLS Let's Encrypt) в docker-сети `proxy-net` и общий Watchtower.\nПриёмник отдаёт прокси `VIRTUAL_HOST` \u002F `LETSENCRYPT_HOST` — сертификат выпускается и\nпродлевается сам, своего nginx и certbot нет.\n\n### Один раз на хост\n\nЕсли на сервере уже есть client-bank, invoice-from-tasks или currency-converter — всё стоит:\n\n```bash\ndocker network ls | grep proxy-net\ndocker ps --format '{{.Names}}\\t{{.Image}}' | grep -E 'nginx-proxy|acme-companion|watchtower'\n```\n\nЧего-то нет — поставить по разделу «Если nginx-proxy \u002F Watchtower ещё не стоят» в\n[`client-bank-alfa-by\u002Fdocs\u002FDEPLOY.md`](https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Fclient-bank-alfa-by\u002Fblob\u002Fmain\u002Fdocs\u002FDEPLOY.md):\nсеть `proxy-net`, прокси из `currency-converter\u002Fdocker-compose.nginxproxy.yml`, Watchtower с\n`--label-enable`. Второй Watchtower не поднимать.\n\nПакет `skills-standard-feedback` в GHCR — публичный (Package settings → Change visibility), тогда\nсерверу и Watchtower не нужен `docker login`.\n\n### Развёртывание\n\nDNS A-запись домена — на сервер **до** `make prod-up`, иначе сертификат не выпустится.\nРепозиторий на сервер не нужен: два файла и `.env`.\n\n```bash\nmkdir -p \u002Fhome\u002Fbitrix\u002Fskills-feedback && cd \u002Fhome\u002Fbitrix\u002Fskills-feedback\ncurl -fsSL -O https:\u002F\u002Fraw.githubusercontent.com\u002Fbx-shef\u002Fskills-standard\u002Fmain\u002Ffeedback\u002Fdocker-compose.prod.yml\ncurl -fsSL -O https:\u002F\u002Fraw.githubusercontent.com\u002Fbx-shef\u002Fskills-standard\u002Fmain\u002Ffeedback\u002FMakefile\ncurl -fsSL -o .env https:\u002F\u002Fraw.githubusercontent.com\u002Fbx-shef\u002Fskills-standard\u002Fmain\u002Ffeedback\u002F.env.example\nopenssl rand -hex 32             # это значение — в FEEDBACK_READ_TOKEN (.env не выполняет команды)\nchmod 600 .env && nano .env      # DOMAIN, LETSENCRYPT_EMAIL, FEEDBACK_READ_TOKEN; остальное — по умолчанию\nmake prod-up\nmake doctor                      # контейнер, прокси, https, сертификат, чтение закрыто, диск\nmake read                        # сводка отзывов\n```\n\nДальше обновления приходят сами: CI публикует образ, Watchtower его подхватывает. Сразу —\n`make prod-redeploy`. Новые версии compose-файла и Makefile — `make compose-update`,\n`make self-update`. Копия отзывов — `make backup` (в `.\u002Fbackups`), читать — `make read`.\n\n## Подключить навыки\n\nАдрес приёмника — `https:\u002F\u002F\u003CDOMAIN>\u002Ffeedback`. Его вписывают **в сам навык отзыва** набора\n(раздел «Отправить» в `template\u002Fskills\u002Facme-feedback\u002FSKILL.md` — заменить\n`feedback.example.org`). Навыки ставятся штатно (`npx skills add \u003Cowner\u002Frepo>`), и агент\nотправляет отзыв сам — одной командой `curl --data-urlencode …`; в проектах ничего ставить и\nнастраивать не нужно.\n\nТикет — поля ниже, формой (так шлёт навык) или JSON; ответ\n`201 {\"success\": true, \"data\": {\"id\", \"category\", \"title\", \"status\": \"NEW\", \"createdAt\"}}`, ошибки\n`{\"success\": false, \"error\": {\"code\", \"message\"}}` (`VALIDATION_ERROR` перечисляет поля).\n\n| Поле | Обяз. | Что |\n|---|:-:|---|\n| `category` | да | `BUG`, `SUGGESTION`, `DOCS`, `CHAT`, `BOTS`, `OTHER` (регистр не важен) |\n| `title` | да | 3–200 символов |\n| `body` | да | 10–20000 символов |\n| `context` | да | объект до 10 КБ; `skill` — обязательно (имя навыка) |\n| `context.outcome` | нет | `done`, `partial`, `failed` |\n| `context.helped` | нет | массив строк — что пригодилось (до 20) |\n| `context.agent`, `.version`, `.main` | нет | короткие строки |\n\nТот же тикет принимается **формой** (`application\u002Fx-www-form-urlencoded`) — так шлёт навык:\n`category`, `title`, `body`, `skill`, `outcome`, `agent`, `version`, `main` плоско, `helped` —\nповторяется (`--data-urlencode helped=… --data-urlencode helped=…`). Зачем: JSON в самой команде\n(`{\"…`) проверки оболочки у агентов не пропускают — Claude Code отклоняет такую команду, — а\nформа проходит без файла и без heredoc.\n\nПрочие поля тела и `context` отбрасываются. Для навыков категории значат: `BUG` — навык\nрасходится с кодом, `DOCS` — неясно или лишнее, `SUGGESTION` — не хватило, `OTHER` — замечаний нет.\n\n**Чистка.** Агенту велено не писать в отзыв проект и секреты, но приёмник на слово не верит: в\n`title`, `body` и `helped` до записи на диск заменяются пометкой `[скрыто: …]` ключи и токены\n(`vibe_api_…`, `sk-…`, `ghp_…`, JWT, `Bearer …`, AWS, приватные ключи, `password=…`\u002F`token: …`,\nдлинные hex\u002Fbase64), адреса (URL), домены, почта, IP, пути (`\u002Fhome\u002F…`, `C:\\…`) и телефоны.\nЧисло замен — в поле `redacted` отзыва. Имена классов, методов, событий и файлы вида\n`lang\u002Fru\u002Finstall.php` остаются.\n\n`bxshef feedback send` шлёт тот же тикет (адрес — `.bxshef.json` или `BXSHEF_FEEDBACK_URL`),\nно навыку он не нужен.\n\n## Кто читает\n\nОтзывы читает автор навыков, и только он. Два замка:\n\n- **токен** `FEEDBACK_READ_TOKEN` (в `.env`). Не задан — чтение закрыто совсем (403);\n- **откуда**: по умолчанию только с самого сервера — `make read`. Снаружи, через\n  `https:\u002F\u002F\u003CDOMAIN>\u002Ffeedback.md`, — 403 даже с верным токеном, пока в `.env` не\n  `FEEDBACK_READ_REMOTE=1`. Так утёкший токен сам по себе отзывы не открывает.\n\n```bash\nmake read                      # сводка: навыки и последние замечания\nmake read SKILL=acme-feedback  # JSON по одному навыку\nmake read JSON=1               # все отзывы JSON\n```\n\nС `FEEDBACK_READ_REMOTE=1` — снаружи с токеном:\n\n```bash\ncurl -s -H \"Authorization: Bearer $FEEDBACK_READ_TOKEN\" https:\u002F\u002Ffeedback.example.org\u002Ffeedback.md\n```\n\nПодбор токена: после `FEEDBACK_AUTH_FAILS` (5) неверных попыток в минуту с одного адреса —\n429 до конца минуты, даже с верным токеном. Сводка экранирует разметку и управляющие символы\nиз отзывов: `make read` печатает её в терминал, и чужой текст не должен им управлять.\n\n## Лимиты и хранение\n\n- **Отправка**: не больше `FEEDBACK_RATE` (20) в минуту с одного адреса и\n  `FEEDBACK_RATE_TOTAL` (300) в минуту всего; сверх — 429 с `Retry-After`. Адрес клиента\n  за nginx-proxy — последний в `X-Forwarded-For`, держится только в памяти для счётчика и на\n  диск не пишется. `TRUST_PROXY=1` верит заголовку от всей частной сети; строже —\n  `TRUST_PROXY=\u003Cимя контейнера nginx-proxy>`: тогда соседи по `proxy-net` не подделают адрес.\n- **Что принимается**: тикет до 64 КБ (поля — «Подключить навыки»). Сохраняются только\n  известные поля, вычищенные, и время приёма — ни IP, ни заголовков, ни посторонних полей.\n- **Место**: не больше `FEEDBACK_MAX_FILES` (20000) отзывов и `FEEDBACK_MAX_MB` (200);\n  сверх — 507, пока старые не уйдут по сроку. Диск сервера общий — приёмник его не забьёт.\n- **Срок**: отзывы старше `FEEDBACK_RETENTION_DAYS` (3) дней удаляются — при старте и раз в\n  час; `0` — не удалять. Отзыв — сырьё для правки навыка: за три дня его читают, остальное\n  копируйте `make backup`.\n- **Токен на отправку** (`FEEDBACK_TOKEN`) — по желанию, для приёмника, куда шлют только свои\n  люди и CI: `bxshef feedback send` подставит его из переменной окружения\n  `BXSHEF_FEEDBACK_TOKEN` (в `.bxshef.json` не класть — файл коммитят). Навыкам он не\n  подходит: адрес и запрос в навыке публичны, токен в нём перестал бы быть секретом — с\n  токеном отзывы агентов получат 401.\n\nКак это замыкает цикл: отзыв → правка навыка → PR в репозиторий навыков →\n`lint`\u002F`eval` → новая версия, которую агенты получат через `npx skills update`.\n\n::note\nИсточник: [skills-standard\u002Ffeedback\u002FREADME.md](https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Fskills-standard\u002Fblob\u002Fmain\u002Ffeedback\u002FREADME.md) — правки туда, сайт пересобирается сам.\n::\n\n",{"title":41,"description":44},"4noX0USG7W_QjxInclDMjVP5IBv81HysKLGk_A98WCI",[1219,1220],{"title":36,"path":37,"stem":38,"description":39,"children":-1},{"title":52,"path":48,"stem":53,"description":54,"children":-1},1790857268559]