Files
dev-skills/av-dev/skills/code-resolve/references/maintain.md
T
av b287cdf71f resolve: хвост задачи собран в один агентский запуск
Архивация change и синк документации уходят одному агенту одним заданием:
второй шаг читает то, что оставил первый, и платить дважды за сбор того же
контекста незачем. Гейт после правок документов доводит тот же агент, вычитку
языка зовёт сам doc-sync. Коммит и закрытие задачи остаются оркестратору —
они необратимы для учёта. В обслуживании синк тоже ушёл агенту. Журнал —
тема 75.
2026-08-23 15:29:03 +03:00

43 KiB
Raw Blame History

Сценарий «обслуживание»

Способ решения известен, а того, что нормирует спека, задача не трогает: тулчейн и сборка, зависимости, гит-хуки и шаги гейта, перенос и чистка. Сценарий пишет код, но не заводит change и не пишет требований. Исход — работающая оснастка и синхронная ей документация.

Сценарий выбирается развилкой на входе скилла (SKILL.md, раздел «Развилка: какой сценарий») и называется вслух первой репликой. Здесь только его ход; общее для всех трёх сценариев — вход, чего может не быть, правило записанного вопроса, правило необратимого — живёт в SKILL.md и тут не пересказывается.

Почему цикл SDD здесь не урезан, а остался без входа

Это не поблажка по цене, и называть сценарий «коротким путём для мелких задач» нельзя: путь, выбираемый по самооценке размера, и есть тот самый дешёвый способ «ускориться», против которого написана вся защита сценария решения.

У обслуживания нет дельта-спек по построению. Тип chore определён через «наблюдаемое поведение не меняется», а на дельтах стоит весь цикл: propose их порождает, разметка выведена из них, review-specs сверяет с ними, объяснение чекпоинта собирается из proposal.md и design.md, archive вливает их в актуальные спеки. Change без дельт — пустой артефакт, который потом надо архивировать, и разметчик по нему назовёт не те темы.

Шаги цикла здесь не пропущены — им нечего обрабатывать. Отсюда и состав сценария: выпали ровно те шаги, у которых нет предмета, и не выпал ни один из тех, у которых он есть.

Признак — связка, а не одно условие

Сценарий выбирается двумя проверками сразу, и обе обязательны:

  1. тип записи предлагаетchore, реже fix, чьё исправление возвращает поведение к уже записанному в спеке;
  2. отсутствие дельт подтверждает — прочитав постановку, ты не находишь требования, которое пришлось бы добавить, изменить или снять.

Один признак без второго не выбирает сценарий. Тип объявляет автор записи, и он может ошибиться в обе стороны; отсутствие дельт — суждение исполнителя, и оно принимается только тогда, когда согласуется с объявленным типом. Расхождение двух признаков — это не развилка, а стоп: скажи, что тип и предмет работы разошлись, и остановись.

Имя сценария не равно имени типа, и это намеренно. fix без дельта-спеки идёт сюда законно — поведение разошлось с заявленным, значит заявленное уже записано, и менять спеку не нужно. Сценарий, названный именем типа, такую задачу либо отправил бы в полный цикл ради пустого change, либо принял бы как исключение, а исключения не исполняются.

Постановка текстом — тип называешь ты, и называешь вслух

Первый признак приходит от автора записи; текст типа не несёт (SKILL.md, «Постановка текстом»). Оба признака тогда твои, и связка выродилась бы в одно суждение — то самое, ради разведения которого она и заведена.

Разведённость здесь восстанавливается местом, а не вторым автором: тип и предмет работы называются до начала работы, первой репликой — «иду обслуживанием: считаю это chore, потому что …; спека не меняется, потому что …». Человек, написавший текст, читает это раньше первой правки и поправляет одной фразой. Названный после работы тип не признак, а объяснение уже сделанного: к этому моменту у тебя есть готовый дифф, и он всегда подтверждает тот тип, под который писался.

Не назвал — признака нет вовсе, и сценарий выбрал сам себя. Это ровно тот случай, где «самый частый способ соврать этим сценарием» (раздел «Тонкости») ничего не стоит: автора, чей тип можно было бы опровергнуть, здесь нет.

Дельта нашлась по ходу — стоп, и у него свой порядок

Признак тот же, что на шаге 7 сценария решения: меняется ли то, что записано в openspec/specs/. Обнаружилось, что меняется, — работа перестала быть обслуживанием в ту же секунду, и продолжать её нельзя: коммит обслуживания заявляет «поведение не менялось», а оно меняется.

Задача при этом не сломалась — она оказалась шире своего типа. Поэтому стоп здесь не «бросить и доложить», а три шага по порядку.

1. Назови тип, которым задача оказалась. Разрез тот же, по которому типы и разведены:

  • fix — поведение расходится с заявленным: спека уже описывает верное, и правка возвращает систему к записанному;
  • feature — снаружи появляется то, чего не было: спеке нужно новое требование.

Тип называется прямо и с причиной. «Нужно менять спеки» без имени типа перекладывает классификацию на человека в тот момент, когда весь материал для неё у тебя.

2. Объясни человеку простым языком. Экран текста, не больше:

  • что просили сделать — одной фразой из записи;
  • что нашлось — какое поведение меняется, словами домена, а не именами файлов и функций;
  • почему это перестало быть обслуживанием — одной фразой: у обслуживания поведение не меняется по определению;
  • чем задача становитсяfix или feature, с причиной из разреза выше;
  • что уже сделано и что из этого лежит в рабочем дереве.

Проверка на простой язык — общая у трёх сценариев:

в тексте нет SHALL, нет имён файлов и функций там, где вещь называется по-русски, и нет слов, которых нет в паспорте проекта.

3. Дай два решения и жди ответа. Их ровно два, и оба законны:

  • переформулировать запись — тип меняется на названный, и дальше задача идёт процессом своего типа: сценарием решения, следующим прогоном. Формат записи правит av-dev:task-track, а не ты: у нового типа своя схема разделов, и готовность её проверит ready — той же машиной, что и на входе. Прогон обслуживания на этом кончается, исход — «меняется спека». Постановка пришла текстом — переформулировать нечего: человек либо запускает следующий прогон тем же текстом, и он пойдёт решением, либо заводит запись через av-dev:task-track, если работа должна пережить разговор. Выбор между этими двумя — его, не твой: заводить запись сам этот скилл не вправе;
  • прекратить работу — человек не готов расширять задачу сейчас. Исход тот же, запись остаётся как была, вопрос записывается там, где проект держит вопросы.

Третьего решения — «доделать как обслуживание» — нет. Оно и есть то самое молчаливое изменение поведения, против которого стоит весь разрез: под коммитом, заявляющим «поменяли оснастку», уехала бы правка, не прошедшая ни чекпоинта, ни ревью по метке, и не оставившая следа в спеках.

Сделанное не выбрасывается ни при каком из двух решений. Оно остаётся в рабочем дереве незакоммиченным: при переформулировке уезжает в change следующим прогоном, при отказе — человек решает сам, откатить или оставить. Коммитить его сообщением про обслуживание нельзя.

Прогон, дошедший до этого стопа, стоит дороже обычного — и это довод за проверку признака на шаге 1, а не после написанного кода.

OpenSpec здесь не предпосылка

Как и разведке, обслуживанию OpenSpec не нужен: оно не заводит change, не пишет дельта-спек и не архивирует. Ни один из проходов его плана ревью на дельта-спеки не завязан — это сказано и в av-dev:code-review, раздел «Прогон без change». Каталога в проекте нет — обслуживание идёт целиком, и деградацией это не является.

Планового стопа у этого сценария нет

И это следствие, а не упрощение. Чекпоинт решения объясняет человеку выбор: в чём проблема, как решаем, чем рискуем. У обслуживания выбора нет по построению — что делать, сказано в записи, а критерии приёмки у него самые дешёвые из всех типов: команда, которая раньше падала или требовала трёх шагов. Объяснение свелось бы к пересказу задачи её же автору. Стоп, на котором нечего решать, вырождается в обряд одобрения и обесценивает те стопы, где решать есть что.

Место, где ответа всё же ждут, одно, и плановым оно не является — стоп по найденной дельте (раздел «Дельта нашлась по ходу»). Через него проходят не все прогоны, а только те, где задача оказалась не тем, чем объявлена.

Правило необратимого при этом действует полностью (SKILL.md, «Когда спрашивать вне чекпоинта»), и здесь оно опаснее, чем кажется. Единственный сценарий без планового стопа — ровно тот, чья работа чаще прочих лезет в выкладку, в токены, в хуки и в чужие данные. Правка оснастки выглядит безобидной до момента, когда её уже не откатить.

Ход работы

flowchart TD
    in["сценарий выбран: обслуживание"]
    s1["1. прочитать задачу<br/>критерии приёмки и границы"]
    s2["2. правка агентом<br/>гейт тронут — состав снять до правки"]
    s3["3. гейт проекта до зелёного"]
    s4["4. ревью фиксированным планом<br/>av-dev:code-review, без change"]
    s5["5. синк документации — av-dev:doc-sync"]
    s6["6. коммит работы — av-dev-git:commit"]
    s7["7. закрыть задачу — av-dev:task-track,<br/>вторым коммитом учёта"]
    out["исход назван"]

    in --> s1 --> s2 --> s3 --> s4 --> s5 --> s6 --> s7 --> out
    s1 -.->|"форма правки неизвестна"| stop1["стоп: нужна разведка"]
    s2 -.->|"нашлась дельта-спека"| stop2["стоп: назвать тип,<br/>объяснить, дать два решения"]

Схема — сводка: содержание каждого шага в его разделе ниже, и при расхождении прав текст.

Наблюдаемые исходы сценария

Четыре, и каждый обязан быть назван в докладе прямо:

  • сделана — определение сделанного выполнено целиком;
  • не доведена — с причиной и с записанным вопросом; названо, что именно сделано и до какой границы;
  • меняется спека — работа оказалась шире своего типа. Стоп с объяснением и двумя решениями человека: переформулировать запись в fix или feature и решать её процессом того типа следующим прогоном — либо прекратить. Сделанное остаётся в рабочем дереве незакоммиченным. Доклад называет оба: какой тип предложен и что человек выбрал;
  • нужна разведка — форма правки неизвестна (мажорное обновление, смена сборщика, переезд гейта на другой инструмент) или сработал триггер ADR. Перечень триггеров не пересказывается: он живёт в canon.md, и здесь он работает стоп-признаком — то есть от его точности зависит выбор сценария, а пересказ расходится с домом молча. Стоп с названной причиной, разведка идёт следующим прогоном.

Последний исход — не редкость, и его стоит ждать. Незнакомое обслуживание — это выбор подхода с ценой и с тем, что становится невозможным, — предмет чекпоинта вариантов, а не работы без стопа. И там же решение получает законный источник для ADR: список источников канон закрыл двумя — архивный design.md и записка разведки, — а обслуживание не производит ни того ни другого.

Определение сделанного

Задача сделана, когда верно всё:

  1. гейт проекта зелёный, и если правка трогала сам гейт — сверен его состав, а не только цвет;
  2. ревью проведено фиксированным планом сценария, исход назван по каждой теме плана, а темы, которых в плане нет, названы в границах покрытия;
  3. документация синхронизирована с принуждённым отрицанием — каждый документ канона получил строку;
  4. коммит сделан в текущую ветку;
  5. критерии приёмки, если проект их дал, выписаны поимённо, и по каждому назван оракул и наблюдаемый исход. Это доклад приёмщику, а не отметка «принято»: исполнитель и приёмщик здесь совпали, и правило то же, что в решении.

Шаги

1. Прочитать задачу

Прочитай запись. У chore обязательны два раздела, и оба нужны тебе прямо сейчас: «Затрагивает» — границы, которые у обслуживания часто не в коде (конфиг и его образцы, версия зависимости, команда сборки, файл CI), и «Критерии приёмки»с оракулами.

Постановка пришла текстом — этих двух разделов нет, и оба нужны тебе тем же составом. Границы назови сам и покажи в первой реплике, вместе с типом: обслуживание чаще прочих сценариев расползается, а границы у него лежат не в коде, и невидимая граница расползание не удержит. Критериев приёмки в тексте может не быть вовсе — тогда скажи строкой, что их нет и приёмка идёт по докладу. Сочинить их себе здесь нельзя даже так, как это делает решение: чекпоинта, на котором человек их утвердит, у обслуживания нет.

Здесь же обе проверки признака: тип предлагает, отсутствие дельт подтверждает (раздел «Признак — связка»); постановка текстом типа не объявляла — тогда называешь его ты, и вслух (раздел «Постановка текстом»). И здесь же — проверка на незнакомое: если форма правки не известна до начала, а нащупывается по ходу, объявляй исход нужна разведка и не начинай.

Проверка на «заодно». Обслуживание любит склеиваться в пачку — обновить зависимости, переписать сборку и убрать мёртвый код одной задачей. Не мерджится порознь — это несколько задач: объявляй исход не доведена с причиной «задача не одна» и останавливайся. Нарезкой владеет av-dev:task-track, а не ты, и делать её по ходу нельзя — получится один коммит, в котором обновление зависимости не отделить от чистки.

2. Сделать правку

Правку делает агент (SKILL.md, «Кто пишет: письмо уходит агентам»): задание несёт постановку, конвенции проекта, границы правки и требование довести гейт до зелёного; возврат — адреса тронутого и исход гейта. Код и конфиги — по конвенциям проекта. Правка по размеру задачи: чинится названное в записи, соседнее не улучшается заодно.

Гейта ещё нет — сказать это, а не изображать сверку. Первые шаги плана стройки заводят гейт, сборку и хуки: у них нет ни «до», ни «прежнего», и определение сделанного через зелёный гейт на них не выполнимо буквально. Такая задача сделана, когда заведённое работает на чистом клоне и это показано в докладе; пункты 1 и 3 определения ниже закрываются строкой «заводится впервые, сверять не с чем». Изображать сверку с несуществующим прежним состоянием нельзя — это ровно то враньё, против которого весь абзац ниже и написан.

Гейт правится — сверь состав, а не цвет. Красный, ставший зелёным, виден сразу; убыли проверок гейт не покажет — он зелёный и до, и после. Это самая дорогая из возможных правок оснастки: молча выключено то, чем проверяется всё остальное. Состав проверок и способ его снять — дело проекта: он объявляет их семантикой гейта в CLAUDE.md. Снимай исходное состояние до правки, по тому, как проект это описал.

Исходный состав снимаешь ты, а не агент, и это не мелочь. Сверка «до и после» уезжает в твой доклад, а снятое тем же, кто правил, сверкой не является: агент вернёт состав, который получился, и назовёт его исходным. Снимок делается до того, как задание ушло.

Проект состав не описал — скажи строкой доклада, что сверен только цвет. Обходного пути не выдумывай: угаданный состав хуже отсутствующего, потому что читается как сверенный. Это же строка и повод — предложить проекту дописать слот в CLAUDE.md.

3. Гейт до зелёного

Прогони гейт и добейся зелёного — он же условие следующего шага: пока гейт красный, проходы с мнением не запускаются.

Сразу после зелёного сними отпечаток дерева (av-dev:code-review, ступень 1) и сохрани его вместе со сводкой и путём к логам шагов. Шаг 4 передаёт их ревью, и тогда ступень автотестов не гоняет тот же гейт второй раз.

Поведенческая верификация здесь другая, чем в решении. Проверяется не новое поведение, а то, что прежнее не поехало: команда из CLAUDE.md поднимается, шаг сборки отрабатывает, хук ставится на чистом клоне. У оснастки, заводимой впервые, прежнего нет — тогда проверяется, что заведённое работает на чистом клоне, и в докладе это называется своим именем, а не «регрессий не найдено». Правка, которую нельзя проверить ничем, кроме «у меня локально работает», называется в докладе строкой.

4. Ревью — план фиксирован сценарием

Вызови Skill av-dev:code-review, дав базу диффа, режим, план сценария и исход гейта с шага 3 — сводку, путь к логам шагов и отпечаток дерева. Change ты не передаёшь — его нет.

Разметчик здесь не зовётся, и это правило, а не пропуск. Обе оси, по которым он судит, у обслуживания не определены: размер он меряет по proposal.md, design.md, tasks.md и дельта-спекам, а незнакомость — по форме решения, которой здесь нет (незнакомое ушло в разведку шагом 1). Разметчик без своего корпуса вернул бы метку, выведенную из ничего.

Поэтому план у сценария свой и постоянный, и глубину он называет сам — проходы берут её из метки, а метки здесь нет:

Тема Дом Кто закрывает Глубина и вход Когда
autotests CLAUDE.md, семантика гейта review-autotests как обычно: гейт запускается целиком всегда
operations architecture.*, раздел эксплуатации review-basics сверка: дом темы против диффа, потолок 2 всегда
conventions + технический разбор conventions.* review-code вход small: только индекс конвенций; потолки 3 технических и 2 конвенционных; третья половина включена — сверка с инвариантами CLAUDE.md, потолок 1 дифф трогает код, а не только оснастку

Глубина названа в плане потому, что иначе её неоткуда взять. Вход и потолки review-code заданы меткой, у review-basics меткой задана и сама возможность запуска; на прогоне без метки оба взяли бы их наугад — то есть по-разному от прогона к прогону, и молча.

Третья половина review-code включена намеренно. В конвейере она живёт при метке small, где приёмник тем не запускается, и сверяет дифф с записанными инвариантами CLAUDE.md по темам security, operations и architecture. Здесь у неё та же работа: без неё security не смотрит вообще никто.

Триаж обязателен, как и на всяком прогоне: он единственный сток и единственный, кто сверяет план с исходом. На его вход подаётся этот план — вместо плана разметки, которого нет.

Условие третьей строки проверяемое, и смотрится оно по диффу, а не по намерению: обновление зависимости или правка файла CI кода не трогают, чистка и перенос — трогают. review-code — единственный проход, который вообще говорит «здесь ошибка в логике», и чистка, прошедшая без него, проверена только на то, что она собирается.

Сигнал о заниженной метке на этом прогоне не работает — метки нет, и поднимать нечего. Его место занимает признак сценария: показалось, что глубины мало, потому что задача крупнее заявленного, — ищи дельту, а не метку.

Границы покрытия называются полностью:

  • requirements — предмета нет, дельта-спек не существует;
  • security — своего прохода нет; сверена против записанных инвариантов внутри review-code, а он шёл не всегда. Не шёл — тему не смотрел никто, и это говорится прямо;
  • architecture — то же: только против инвариантов, и только если шёл code.

Отчёт, из которого исчезло «что не смотрел никто», сообщает «проверено», не сообщая, что именно.

Отработка — как в решении: помеченное инлайн чинит агент (SKILL.md, «Кто пишет»), находки уходят ему дословно с оракулом, гейт после правок гоняет он же, логировать их не надо; развилка — вопросом в запись, и агенту она не отдаётся. Отложенные находки собери в секцию доклада Урожай; задачи из него заводит av-dev:task-track, не ты.

5. Синк документации — главный шаг этого сценария, и делает его агент

Синк уходит агенту (SKILL.md, «Кто пишет»): работа письменная и нормирована чек-листом скилла av-dev:doc-sync, а не суждением оркестратора. В задании — корень проекта, база диффа, что было тронуто правкой, требование принуждённого отрицания и требование довести гейт до зелёного после правок. Вычитку языка av-dev:doc-sync зовёт сам.

Правило то же и такое же жёсткое: принуждённое отрицание — каждый документ канона либо назван обновлённым, либо получает «не требуется, потому что…». Нетронутые группируются одной строкой. Возврат приходит в этой же форме и уезжает в доклад целиком: тронутое без нетронутого не отличается от невыполненного шага.

Здесь этот шаг весит больше, чем в решении, и вот почему. Обслуживание не меняет поведения — значит, почти всё, что оно меняет, это документация: команды, шаги гейта, зависимости поимённо, пути, имя основной ветки, настройки с числовым значением, место механизации правила. Ровно эти факты doc-code-drift и сверяет с кодом (перечень закрыт, живёт в каноне) — то есть сценарий, чаще всех прочих двигающий сверяемые факты, обязан отчитаться по ним раньше всех прочих.

Отдельно один документ, которого нет в перечне тем, а синку он нужен: conventions.*, раздел «Механизировано» — если правило переехало в линтер, и тогда его проза из конвенций удаляется, а не остаётся вторым домом.

adr/ этот сценарий не пополняет, и это не пропуск. У ADR закрытый список источников — архивный design.md либо записка разведки, — и ни того ни другого обслуживание не производит. Поэтому триггеры ADR здесь работают стоп-признаком, а не поводом завести запись: сработал любой из них — сценарий выбран неверно, объявляй исход нужна разведка и останавливайся. Перечень триггеров — в canon.md и здесь не пересказывается. Решение с ценой обязано пройти чекпоинт вариантов, а не появиться в коммите обслуживания, чей смысл — «ничего не решали, поменяли оснастку».

Список документов и их триггеров здесь не дублируется — он в чек-листе скилла av-dev:doc-sync; копия уже однажды разошлась с оригиналом. Документов канона в проекте нет — синка нет вовсе: скажи это исходом и предложи завести канон скиллом av-dev:canon.

6. Коммит

Коммить в текущую ветку (git rev-parse --abbrev-ref HEAD), сам ветку не создавай и не переключай, ничего не пушь.

Сообщение — по-русски, скиллом av-dev-git:commit. Вызов не разрешился — напиши сам и скажи строкой, что форму коммита не сверял никто. Одна задача — один осмысленный коммит.

7. Закрыть задачу — после коммита, не раньше

Вызови Skill av-dev:task-track и попроси закрыть задачу как реализованную. Порядок обязателен: закрытие удаляет файл задачи, и сделанное до коммита оно оставило бы задачу закрытой без следа работы, если шаг 6 упадёт.

Закрытие тоже коммитится — вторым коммитом, тут же, сообщением про учёт: закрыта задача <slug>. Каталога задач в проекте нет — ничего не выдумывай: скажи, что учёт остаётся за владельцем, и назови исход.

Постановка пришла текстом — шага нет вовсе: записи не было, закрывать нечего, след работы — коммит шага 6. Заводить запись задним числом ради закрытия нельзя.

Границы: чего обслуживание не делает

  • Не меняет поведения. Обнаружилось, что меняет, — стоп с исходом «меняется спека»: назвать тип, объяснить, дать два решения. Это единственная граница сценария, у которой есть проверяемый признак, и она же единственная, которую выгодно нарушить молча.
  • Не переписывает запись задачи сам. Тип ты предлагаешь с причиной, меняет его av-dev:task-track и только после ответа человека: исполнитель, переклеивший тип на ходу, назначает себе другой процесс и другую глубину проверки.
  • Не решает, нужна ли работа. Как и оба соседних сценария: «надо ли» — вопрос человека.
  • Не нарезает пачку на задачи. «Обновить зависимости и переписать сборку» — это av-dev:task-track и его правила нарезки.
  • Не выбирает форму правки, когда она незнакома, и не принимает решений с ценой. Мажорное обновление, смена инструмента, намеренный отказ идут разведкой: там есть чекпоинт вариантов и законный источник для ADR, здесь нет ни того ни другого.
  • Не заводит задачи из урожая ревью. Урожай передаётся списком.

Доклад обслуживания

Общее ядро доклада — в SKILL.md; сверх него сценарий обязан назвать:

  • что подтвердило признак — тип записи и то, что дельта-спек не нашлось; постановка пришла текстом — тип назвал ты, и это говорится прямо, вместе с границами, которые ты объявил себе сам; дельта нашлась — какой тип предложен, с причиной, и что человек выбрал: переформулировать или прекратить;
  • что стало иначе для разработчика — одной фразой, адресуясь ему, а не выдуманному пользователю;
  • состав гейта до и после, если правка его трогала; не сверялся — почему;
  • по каждому критерию приёмки: оракул и наблюдаемый исход;
  • Урожай — отложенные находки списком;
  • строка границ покрытия: план сценария фиксирован, разметчик не запускался, requirements не смотрел никто, а security и architecture — только против записанных инвариантов, и то если шёл проход code.

Тонкости сценария

  • Самый частый способ соврать этим сценарием — назвать chore то, что меняет поведение. Тип, оставшийся от первой формулировки, врёт ровно там, где по нему выбирают путь; проверка признака стоит одного чтения записи и делается на шаге 1, а не после написанного кода.
  • Отсутствие чекпоинта не делает сценарий автономнее прочих. Правило необратимого здесь то же, и срабатывает оно чаще: выкладка, токены, хуки, чужие данные — обычное содержимое задач обслуживания.
  • Зелёный гейт после правки гейта ничего не доказывает. Это единственное место конвейера, где инструмент проверяет сам себя, и потому состав сверяется отдельно от цвета.
  • Правка оснастки, сделанная «заодно» внутри чужой задачи, этим сценарием не проходит вовсе — она едет в чужом коммите и не получает ни своего ревью, ни своей строки синка. Заметил нужную правку по ходу решения — вопрос в запись, а не правка мимоходом.