Files
claude-skills/1c-analyst/references/meeting-wishes-extraction.md
T
creator 7365242875 fix(1c-analyst): поле Description (не Content) + обязательная верификация GET-ом
Критичный баг-фикс по режиму «Пожелания из совещания».

Проблема: сервер Devprom на POST /issue/items молча игнорирует поле
Content, упомянутое в публичной документации /docs/8835.html.
Запись создаётся с пустым телом, HTTP 200, UID возвращается —
никакого сигнала об ошибке. Правильное имя поля для тела пожелания
на эндпоинте /issue/items — Description.

Выявлено при проверке U-6186 (Артур): поле Description пустое,
хотя POST вернул валидный UID. Та же проблема обнаружилась на 6
пожеланиях Тепловин U-6189..U-6194 — все с пустым телом.
Пересоздано как U-6198..U-6203 с полем Description, размер тела
1565–2172 символа, верификация пройдена.

Правки скилла:
- devprom-alm-api.md §0: новый блок «Критично: сервер молча отбрасывает
  незнакомые поля» + обязательная схема контрольного GET с ассертами.
  Список известных тихих ловушек (Content вместо Description, Type.Id=''
  в request/items, Requirement в POST).
- devprom-alm-api.md §2: рецепт с Description + встроенные ассерты.
- devprom-alm-api.md §3: справочник полей — Description с пояснением
  про Content и документацию, требование GET-проверки.
- devprom-alm-api.md appendix: curl-примеры с Description.
- meeting-wishes-extraction.md Шаг 6: Description в инструкции + ссылка
  на секцию «тихое отбрасывание».
- meeting-wishes-extraction.md Шаг 7: жёсткая формулировка
  «Ответ POST — недостаточное подтверждение успеха», ассерты
  на префикс UID, содержимое Description, Priority, Function;
  визуальная проверка в UI.
- meeting-wishes-extraction.md Python-шаблон: Description + ассерты
  на размер тела (>100 символов).
2026-04-22 07:02:53 +00:00

18 KiB
Raw Blame History

Извлечение Пожеланий из транскрипции совещания

Методика превращения транскрипции рабочего совещания с заказчиком в набор формализованных Пожеланий в Devprom ALM. Проверена на совещании с главбухом АРД (21.04.2026).

Связанные файлы:

  • references/devprom-alm-api.md — как писать в Devprom через API
  • Скилл docx — для возможного экспорта сводки в Word

Критерии отбора: что становится Пожеланием, а что нет

Становится Пожеланием

  1. Доработка конфигурации — новый реквизит, новое правило, новая форма, интеграция. Пример: «Допреквизит „Доступно для менеджера" в справочнике номенклатуры».
  2. Изменение бизнес-процесса с цифровым следом — новая цепочка документов, автоматизация этапа, блокировка операции. Пример: «Запрет проведения отгрузки при отрицательном остатке».
  3. Типовая настройка с конкретным целевым эффектом — использование типового механизма там, где клиент раньше работал руками. Пример: «Использовать типовой механизм Номенклатура контрагентов».
  4. Интеграция с внешней системой — ЭДО, клиент-банк, маркетплейс, CRM, АТС. Пример: «Автоматическая отправка отгрузочных документов в Диадок».

НЕ становится Пожеланием

  1. Методика внутренней работы заказчика — как они сейчас живут в Excel, как главбух разбирает почту.
  2. Нерешённые бизнес-вопросы без автоматизационного следа — «надо решить, кто отвечает за ставку НДС», «КП оформляем в Word или в 1С».
  3. Оргмоменты и ответственность — назначение ролей, регламент согласований без запроса автоматизации.
  4. Общие рассуждения и отступления — истории про то, как раньше работали.

Проверочный вопрос

«Если бы это пожелание взял в работу разработчик конфигурации — что конкретно он бы сделал?» Если ответ неконкретный («поговорил с главбухом», «уточнил процесс», «подумал») — это не пожелание, а открытый вопрос в протокол совещания.


Пайплайн

Шаг 1 — Выделение тем и спикеров

Читаем транскрипцию целиком. Для каждой темы фиксируем:

  • Тему (1 фраза)
  • Инициатора (кто первым её подняла + таймкод)
  • Подтверждающих (кто согласился, уточнил, добавил детали)
  • Открытые вопросы (если обсуждение заблокировалось)

Нотация: [Спикер тайм-код] → ключевая мысль.

Шаг 2 — Кластеризация

Одна тема может обсуждаться несколько раз в разных частях совещания — в начале, в середине (уточнение), в конце («а ещё мы забыли...»). Все упоминания одной темы объединяем в одно Пожелание. В Источники блока перечисляем все таймкоды всех спикеров.

Шаг 3 — Отсев по критериям

Применяем проверочный вопрос из раздела «Критерии отбора». Оставшееся — кандидаты на Пожелания. То, что отсеяли, записываем отдельным списком в сопроводительную заметку («Для обсуждения на внутреннем совещании заказчика») — это протокол, а не Devprom.

Шаг 4 — Классификация

Для каждого Пожелания-кандидата:

  • Caption — одна ёмкая фраза, суть. 10–15 слов. Можно цитировать термин конфигурации («допреквизит», «заказ покупателя»).
  • Priority — по акцентам речи:
    • 1 (Критично) — заказчик повторил несколько раз, сказал «100%», «без этого работать нельзя», или речь про блокировку ошибок/убытков.
    • 2 (Высокий) — инициатор явно настаивал, есть конкретная цель.
    • 3 (Обычный) — обсудили, согласились, без нажима.
  • Function — подсистема КА 2.5 / ERP 2.5. См. references/ka25-capabilities.md. Типично: НСИ, Продажи, Закупки, Склад, Казначейство, Производство, Бухгалтерия, Управленческий учёт.
  • Предметная область — уточнение внутри подсистемы («Управление доступом менеджеров к НСИ», «Контроль остатков»).

Шаг 5 — Формирование Description

Единый шаблон HTML для поля Content в Devprom:

<p><b>Заказчик:</b> ФИО, должность (email)</p>
<p><b>Описание:</b></p>
<p>Полное описание пожелания в свободной форме — что должно делать,
какие условия, какие границы. 3–7 предложений.</p>
<p><b>Источники:</b></p>
<ul>
<li>ФИО спикер-1, должность — роль в обсуждении (тайм-коды)</li>
<li>ФИО спикер-2, роль — (тайм-коды)</li>
</ul>
<p><b>Цитаты:</b></p>
<blockquote>Спикер (тайм-код): «прямая цитата».</blockquote>
<blockquote>Спикер (тайм-код): «прямая цитата».</blockquote>
<p><b>Предметная область:</b> Подсистема / Конкретика</p>
<p><b>Примечание:</b> (опционально) — например, «функционал типовой,
требует настройки процесса, без разработки»</p>
<p><b>Источник:</b> Совещание от DD.MM.YYYY, файл
<code>transcript.txt</code></p>

Правила по содержимому:

  • Цитаты — обязательны, 1–3 штуки на пожелание. Без цитат будущий разработчик не поймёт контекст.
  • Цитаты прямые — без редактуры речи. Сохранять разговорный стиль, паузы, просторечия. Это контекст, а не литература.
  • Описание в повествовательной форме — не «пользователь хочет, чтобы», а прямое «Система должна…», «В справочнике номенклатуры ввести…». Подлежащим делаем объект системы, не пользователя.
  • Никаких оценок объёма и сроков — это предмет gap-анализа, не этапа извлечения пожеланий.
  • Никаких архитектурных решений — если пожелание порождает архитектурные вопросы, они идут отдельным Пожеланием с типом «Архитектурное решение» или в протокол совещания.

Шаг 6 — Загрузка через API

Один POST на одно Пожелание. Никакой привязки к требованиям, никаких PUT. Поля Requirement и RequirementDocument остаются пустыми — пользователь вручную прикрепит их в UI, если/когда появится профильное требование.

Тело пожелания отправляется в поле Description, НЕ Content. Публичная документация Devprom (/docs/8835.html) упоминает Content, но на эндпоинте /issue/items это поле молча игнорируется сервером при POST. Эмпирически проверено — см. references/devprom-alm-api.md, раздел 0 «Сервер молча отбрасывает незнакомые поля».

post_body = {
    "Caption":     wish["caption"],
    "Description": CUSTOMER_NOTE + wish["body"] + SOURCE_NOTE,  # ← Description!
    "Priority":    {"Id": wish["priority"]},    # "1"/"2"/"3"
    "Author":      {"Id": AUTHOR_ID},
    "Function":    {"Id": wish["function_id"]},
    "Company":     {"Id": COMPANY_ID},          # опционально
}
# POST /issue/items → {UID: "U-xxxx", ...}

Подробный справочник полей и поведение API — в references/devprom-alm-api.md.

Шаг 7 — Верификация по факту (обязательно)

Ответ POST — недостаточное подтверждение успеха. Сервер Devprom возвращает HTTP 200 и валидный JSON с UID даже тогда, когда часть полей была молча отброшена (например, из-за неправильного имени). Верификация идёт по результату GET, а не по ответу POST.

Для каждого созданного пожелания — контрольный GET и ассерты:

code, text = call("GET", f"issue/items/{rid}")
g = json.loads(text)
assert g["UID"].startswith("U-"),      f"неверный префикс: {g['UID']}"
assert len(g.get("Description","")) > 100,  "тело пожелания пустое"
assert (g.get("Priority") or {}).get("Id") == expected_priority
assert (g.get("Function") or {}).get("Id") == expected_function_id

Дополнительно — после загрузки всей пачки открыть UI-раздел /pm/<project>/module/requirements/issues, убедиться визуально:

  • Все загруженные пожелания отображаются одним списком
  • UID у всех — префикс U-
  • Случайно выбранная карточка открывается, форматирование HTML работает, ссылки (mailto:) кликабельны, цитаты в <blockquote> отрисованы
  • Поля Requirement и RequirementDocument пустые — это норма, привязку делает пользователь вручную в UI

Шаг 8 — Сводка для пользователя

После загрузки отдать:

  • Таблица «№ / UID / Функция / Приоритет / Название / Ссылка»
  • Список того, что намеренно НЕ стало Пожеланиями — короткие формулировки с причиной («методика», «открытый вопрос», «оргмомент»).

Скрипт-шаблон (Python, без внешних зависимостей)

Шаблон есть в templates/wishes-upload.py (при наличии). Ключевые моменты:

import json, urllib.request, urllib.error, ssl, time

HDR = {"Devprom-Auth-Key": "<KEY>",
       "Content-Type": "application/json",
       "Accept": "application/json"}
BASE = "https://<host>/pm/<project>/api/latest"

def call(method, path, body=None, retries=3):
    """urllib + ретраи по 502/503/504 от egress-прокси."""
    data = json.dumps(body, ensure_ascii=False).encode("utf-8") if body else None
    for attempt in range(1, retries+1):
        req = urllib.request.Request(f"{BASE}/{path}", data=data,
                                     headers=HDR, method=method)
        try:
            with urllib.request.urlopen(req, timeout=25,
                                        context=ssl.create_default_context()) as r:
                return r.status, r.read().decode("utf-8")
        except urllib.error.HTTPError as e:
            if e.code in (502, 503, 504) and attempt < retries:
                time.sleep(3 * attempt); continue
            return e.code, e.read().decode("utf-8")

for wish in WISHES:
    post_body = {
        "Caption":     wish["caption"],
        "Description": CUSTOMER_NOTE + wish["description"] + SOURCE_NOTE,  # ← Description
        "Priority":    {"Id": wish["priority"]},
        "Author":      {"Id": AUTHOR_ID},
        "Function":    {"Id": wish["function"]},
        "Company":     {"Id": COMPANY_ID},      # опционально
    }
    code, text = call("POST", "issue/items", post_body)
    r = json.loads(text); r = r[0] if isinstance(r, list) else r
    issue_id = r["Id"]
    # ⚠ ОБЯЗАТЕЛЬНАЯ верификация: сервер молча отбрасывает незнакомые поля.
    # Ответа POST недостаточно — смотрим, что реально сохранилось.
    _, t = call("GET", f"issue/items/{issue_id}")
    g = json.loads(t)
    assert g["UID"].startswith("U-"),           f"префикс не U-: {g['UID']}"
    assert len(g.get("Description","")) > 100,  f"пустое тело: Id={issue_id}"

Анти-паттерны

  1. Создание через /request/items — даст префикс I- и попадание в «Заявки». Использовать только /issue/items.
  2. Создание документов требований, Company, Feature или IssueAuthor из этого режимаPOST /requirement/items, POST /company/items и т.п. в режиме извлечения Пожеланий не вызывать. Эти справочники готовит владелец проекта вручную через UI Devprom заранее. Если нужных записей нет (например, нет подходящей Function) — остановиться, запросить их создание, и только после этого продолжать загрузку.
  3. Привязка Пожелания к документу требований при создании — поля Requirement и RequirementDocument в теле POST не передавать. Пользователь сам прикрепит пожелание к нужному требованию в UI, когда это требование появится. Попытка «сразу правильно» привязать ломает процесс согласования с заказчиком.
  4. Цитаты в пересказе — обезличивают пожелание, делают его неотличимым от прочих. Только прямые цитаты в blockquote.
  5. Смешение в одном Пожелании двух разных требований — потом невозможно оценить объём и трассировать. Один атомарный запрос — одно Пожелание.
  6. Создание IssueAuthor через API — заблокировано на уровне прав. Только через UI.
  7. Попытка удалить запись через DELETE /request/items/{id} — сервер отвечает 200 + Unable access entity. Удалять через DELETE /issue/items/{id} — он работает для любой записи, в том числе для I- (созданных через /request/items).

Memo для будущих расширений

Потенциальные улучшения, если появится потребность:

  • Автопривязка транскрипции к пожеланию через /attachment/items (прикрепление .txt файла с полной транскрипцией к одному «главному» Пожеланию или к документу требований).
  • Экспорт сводки в Word через скилл docx — для отправки клиенту или приобщения к протоколу.
  • Автоопределение Priority по акцентам — через LLM-классификацию фраз типа «100%», «критично», «можем обсудить позже».
  • Автоопределение Function — словарь ключевых слов → подсистема (см. references/ka25-capabilities.md).