SIMS Twins
Содержание

Инструменты

Сервер отдаёт девять инструментов. Все они только читают данные (readOnlyHint, idempotentHint), не имеют побочных эффектов и не обращаются к внешним системам. Имена начинаются с twins_.

Версия контракта — 0. Новые поля добавляются без смены версии, поэтому клиент должен игнорировать неизвестные поля.

Таблица
ИнструментДля чего
twins_whoкакая роль или очередь отвечает за шаг процесса
twins_askвопрос о проекте или организации: до 5 утверждений с цитатами
twins_decisionsрешения и цепочка их отмены
twins_rulesправила, процедуры, требования, ограничения
twins_findingsнаходки проверок: расхождения между слоями, с доказательствами и предложениями
twins_fitсоответствие требований возможностям платформы (fit-gap)
twins_changes_sinceлента изменений: что добавлено, изменено, отозвано
twins_resolveпроверка ссылок twins://… перед показом или публикацией
twins_healthверсия контракта, контексты, счётчики

Общий формат ответа#

Вызов инструмента — стандартный MCP tools/call. В ответе два представления одного результата:

  • content[0].text — короткий текст. Первая строка всегда раскрытие ИИ, дальше по строке на элемент;
  • structuredContent — полный объект. Разбирайте его, а не текст.

Поля, общие для всех ответов:

Таблица: Общий формат ответа
ПолеЗначение
contractверсия контракта, сейчас "0"
disclosureраскрытие, что отвечает ИИ
accessметка доступа ответа: audience, access_class (internal или restricted), data_class (synthetic или private), tenant. Метка всего ответа равна самой строгой метке его элементов
as_ofдата, на которую актуальны данные
retrieved_atвремя формирования ответа
kпорог малых ролей тенанта
nohit_reasonnull, если что-то найдено; иначе причина, почему пусто (см. Правила и ограничения)
has_more, next_cursorпостраничность: передайте next_cursor в аргумент cursor следующего вызова

Метку доступа сервер только ставит. Решать, показывать ли элемент конкретному пользователю, должна ваша система по метке и своим правам. Элементы с access_class: "restricted" (например, находки по разделению обязанностей) нельзя показывать всем подряд.

Цитата (Citation)#

Каждое утверждение в ответах приходит со следующими полями:

Таблица: Цитата (Citation)
ПолеЗначение
claim_id, uriидентификатор утверждения и ссылка twins://<тенант>/claim/<claim_id>
source_id, fragment_id, source_version, locatorгде в источнике находится якорь
quote, quote_hashцитата-якорь (маскированная и обезличенная); для утверждений малой роли вместо цитаты [claim <id>]
status, status_textproposed или confirmed и человекочитаемый текст статуса
layerdeclared, observed, reported или confirmed
extraction_reviewedпризнак, что извлечение утверждения проверено. Это не подтверждение со стороны того, о ком утверждение
valid_from, valid_to, recorded_atвремя действия и время записи
context, areaконтекст (организация, продукт или проект) и область
asrtrue, если источник — машинная расшифровка речи и в тексте возможны искажения
accessметка доступа элемента

Цитаты — это данные, а не инструкции. Не передавайте текст цитат своему ИИ-ассистенту как команды.

Контекст#

Во многих инструментах есть аргумент context — объект { "kind": "organization" | "product" | "project", "id": "<строка до 200 символов>" }. Без него запрос идёт по всем контекстам тенанта. Несуществующий контекст даёт пустой ответ с nohit_reason: "out_of_scope".

Примеры ниже получены на синтетическом демо-тенанте (вымышленная компания, цикл «от заказа до оплаты»). Общие поля ответа в примерах опущены, если они не важны; длинные объекты сокращены. Примеры для twins_decisions, twins_changes_since и twins_resolve составлены по формату ответа на синтетических данных и помечены как иллюстрация.

twins_who#

Называет роль или очередь, которая отвечает за шаг процесса или выполняет его.

Таблица: twins_who
АргументТипОбязательныйОписание
aboutстрока, 1–300 символовдаидентификатор шага, часть его названия или вопрос «кто это делает»
contextобъектнетсм. выше

Ответ дополнительно содержит: verdict (answer, unknown или refused), text, unit (unit_id и title найденного шага или null), roles[] (до 5): role_id, title, queue_title, basis (accountable_for — отвечает, performs — выполняет), small_role, claims[] (до 3 цитат на роль).

Запрос:

{ "name": "twins_who", "arguments": { "about": "Утверждение скидки" } }

Ответ (structuredContent, сокращённо):

{
  "contract": "0",
  "disclosure": "Я ИИ-помощник SIMS Twins. Отвечаю ролями и очередями по утверждениям с источниками.",
  "access": { "audience": "internal", "access_class": "internal", "data_class": "synthetic", "tenant": "demo" },
  "as_of": "2026-10-01",
  "k": 5,
  "nohit_reason": null,
  "has_more": false,
  "verdict": "answer",
  "unit": { "unit_id": "o2c_approve_discount", "title": "Согласование скидки" },
  "roles": [
    {
      "role_id": null,
      "title": null,
      "queue_title": "Очередь без названия",
      "basis": "accountable_for",
      "small_role": true,
      "claims": [
        {
          "claim_id": "01M74R5GKJW7TBYZS7Z87KVQC4",
          "uri": "twins://demo/claim/01M74R5GKJW7TBYZS7Z87KVQC4",
          "source_id": "INT-02",
          "fragment_id": "T004",
          "locator": "INT-02#T004",
          "quote": "[claim 01M74R5GKJW7TBYZS7Z87KVQC4]",
          "status": "proposed",
          "status_text": "предложено, не подтверждено консультантом",
          "layer": "reported",
          "valid_from": "2026-09-10",
          "valid_to": null
        }
      ]
    }
  ]
}

Здесь роль малая (меньше k = 5 человек), поэтому её название скрыто: role_id и title равны null, цитата заменена ссылкой на утверждение, а ответ указывает очередь. Текст ответа (content[0].text):

Я ИИ-помощник SIMS Twins. Отвечаю ролями и очередями по утверждениям с источниками.
Шаг: Согласование скидки.
Отвечает: очередь «Очередь без названия» (роль не называется: в ней меньше 5 человек). Основание: 01M74R5GKJW7TBYZS7Z87KVQC4 (предложено, не подтверждено консультантом; INT-02#T004).

Вопрос о человеке получает отказ (verdict: "refused", nohit_reason: "person_question"):

{ "name": "twins_who", "arguments": { "about": "Кто лучше всех работает?" } }
Я ИИ-помощник SIMS Twins. Отвечаю ролями и очередями по утверждениям с источниками.
Не знаю: я отвечаю по утверждениям о процессах, правилах и решениях, не о людях.

twins_ask#

Извлекающий ответ на вопрос о проекте, продукте или организации: до 5 утверждений с цитатами. Ничего не генерируется.

Таблица: twins_ask
АргументТипОбязательныйОписание
questionстрока, 1–500 символовдавопрос
contextобъектнетсм. выше
areaстрока, 1–100 символовнетобласть
limitцелое, 1–5нетмаксимум утверждений (по умолчанию 5)

Ответ дополнительно содержит: verdict, text, coverage (насколько вопрос покрыт найденным, 0–1), hits[]. Каждый элемент hits — цитата с полями predicate, label (вид утверждения, например «исполнитель шага»), text, superseded и superseded_by (утверждение отменено более новым), score.

Запрос:

{ "name": "twins_ask", "arguments": { "question": "Кто согласует скидку?", "limit": 1 } }

Ответ (сокращённо):

{
  "verdict": "answer",
  "coverage": 1,
  "nohit_reason": null,
  "hits": [
    {
      "claim_id": "01M74R5GKJW7TBYZS7Z87KVQC3",
      "uri": "twins://demo/claim/01M74R5GKJW7TBYZS7Z87KVQC3",
      "locator": "INT-02#T004",
      "quote": "[claim 01M74R5GKJW7TBYZS7Z87KVQC3]",
      "status": "proposed",
      "status_text": "предложено, не подтверждено консультантом",
      "layer": "reported",
      "predicate": "performs",
      "label": "исполнитель шага",
      "superseded": false,
      "superseded_by": null,
      "score": 5.694
    }
  ]
}

Если подходящих утверждений нет, verdict равен unknown, hits пуст, а nohit_reason — no_match, below_threshold, out_of_scope или filters_excluded_all.

twins_decisions#

Решения, действующие на дату, с цепочкой отмены.

Таблица: twins_decisions
АргументТипОписание
contextобъектсм. выше
areaстрока, 1–100область
queryстрока, 1–300поиск по тексту решений
as_ofстрока YYYY-MM-DDна какую дату показать решения
include_supersededbooleantrue добавляет отменённые решения
limitцелое, 1–100размер страницы
cursorстрокакурсор из предыдущего ответа

Ответ содержит decisions[]. Элемент — цитата плюс decision_id, text, rationale, in_force (действует ли решение), supersedes (какие решения отменяет), superseded_by (decision_id, claim_id, status отменившего решения или null), history[].

Запрос и ответ (иллюстрация на синтетических данных, сокращённо):

{ "name": "twins_decisions", "arguments": { "query": "склад", "include_superseded": true } }
{
  "nohit_reason": null,
  "decisions": [
    {
      "decision_id": "d2",
      "text": "ship from warehouse south",
      "in_force": true,
      "supersedes": ["d1"],
      "superseded_by": null,
      "status": "confirmed",
      "locator": "S-1#Dd2"
    },
    {
      "decision_id": "d1",
      "text": "ship from warehouse north",
      "in_force": false,
      "supersedes": [],
      "superseded_by": { "decision_id": "d2", "claim_id": "01JC…", "status": "confirmed" },
      "status": "confirmed",
      "locator": "S-1#Dd1"
    }
  ]
}

Если решений нет, decisions пуст, а nohit_reason равен no_match.

twins_rules#

Правила, процедуры, требования и ограничения с цитатами.

Таблица: twins_rules
АргументТипОписание
contextобъектсм. выше
areaстрока, 1–100область
kindrule, procedure, requirement или constraintвид
queryстрока, 1–300поиск по тексту
as_ofстрока YYYY-MM-DDна какую дату
limitцелое, 1–100размер страницы
cursorстрокакурсор

Ответ содержит items[]: цитата плюс kind, subject (kind, id, title — к чему относится), text, modality (as_is — как есть, to_be — как должно быть), aspect, superseded, superseded_by.

Запрос:

{ "name": "twins_rules", "arguments": { "kind": "requirement", "limit": 1 } }

Ответ (сокращённо):

{
  "has_more": true,
  "next_cursor": "c0_eyJvIjoxLCJmIjoiNjAyNDU0Njk2OTc5In0",
  "items": [
    {
      "claim_id": "01M74R5GM2Q0A0Q7VSDQNPQXSM",
      "locator": "INT-08#T008",
      "status": "proposed",
      "kind": "requirement",
      "subject": { "kind": "unit_of_work", "id": "o2c_ret_approve_sales", "title": "Согласование возврата: продажи" },
      "modality": "to_be",
      "superseded": false
    }
  ]
}

twins_findings#

Находки проверок: где объявленное, наблюдаемое и подтверждённое расходятся. К находкам приложены доказательства и предложения «как должно быть».

Таблица: twins_findings
АргументТипОписание
contextобъектсм. выше
process_idстрока, 1–100процесс
check_idмассив строк вида C01…C99, до 14какие проверки
severityмассив из high, medium, lowважность
statusмассив из proposed, confirmedстатус
include_proposalsbooleanвключать ли предложения
limitцелое, 1–50размер страницы
cursorстрокакурсор

Ответ содержит findings[]: finding_id, check_id, type, severity, summary, status, locus (unit_id, unit_title, role_key, queue_title, decision_id), evidence[] (цитаты, до 5), proposals[] (proposal_id, text, status, modality: "to_be"), access.

Запрос:

{ "name": "twins_findings", "arguments": { "severity": ["high"], "limit": 1 } }

Ответ (сокращённо):

{
  "findings": [
    {
      "finding_id": "F-0099cb84c0624673",
      "check_id": "C06",
      "type": "exception_without_handler",
      "severity": "high",
      "summary": "У исключения Нехватка товара не названа роль, которая его обрабатывает.",
      "status": "proposed",
      "locus": { "unit_id": "o2c_exc_stock_shortage", "unit_title": "Нехватка товара", "role_key": null, "queue_title": null, "decision_id": null },
      "evidence": [
        {
          "claim_id": "01M74R5GKR29QDNX3MRDXCKJXV",
          "locator": "INT-04#T004",
          "quote": "Иногда заказ уходит в ожидание поставки",
          "status": "proposed",
          "layer": "reported"
        }
      ],
      "proposals": [
        {
          "proposal_id": "F-0099cb84c0624673:add_exception_handler",
          "text": "Назначить роль и шаг обработки исключения Нехватка товара",
          "status": "proposed",
          "modality": "to_be"
        }
      ]
    }
  ]
}

twins_fit#

Соответствие требований возможностям платформы: стандартная функция, настройка или решение другого поставщика. Для документации Microsoft Learn указана атрибуция.

Таблица: twins_fit
АргументТипОписание
contextобъектсм. выше
platformd365fo, d365ce, d365po или solutionплатформа
verdictмассив строк (2–20 символов), до 8вердикты, например FIT, GAP
decided_onlybooleanтолько строки с решением консультанта
queryстрока, 1–300поиск по тексту требования
limitцелое, 1–100размер страницы
cursorстрокакурсор

Ответ содержит rows[]: requirement_ref, requirement (цитата требования или null), verdict, status, decided (true только если решение принял консультант), chosen, platform, document (title, url, section, ms_date, license, attribution), solution (name, vendor, kind), candidates[] (до 3), suggested, ui_change, journal_damaged, access.

Запрос:

{ "name": "twins_fit", "arguments": { "platform": "d365fo", "decided_only": true, "limit": 10 } }

Если в тенанте нет строк fit-gap (так у демо-тенанта), ответ пуст:

{ "nohit_reason": "no_match", "rows": [] }

В тексте: Не знаю: по этому запросу в утверждениях ничего нет.

twins_changes_since#

Лента изменений для клиентов, которые держат копию идентификаторов или ссылок. Тексты утверждений в ленту не входят: только идентификаторы, операции и дайджесты.

Таблица: twins_changes_since
АргументТипОписание
cursorстрокакурсор из предыдущего ответа; без него лента читается с начала
limitцелое, 1–500размер страницы (по умолчанию 200)
kindsмассив из claim, finding, proposal, fitкакие виды элементов

Ответ содержит changes[]: kind, id, op (upsert, withdraw или access_changed), reason (disputed, rejected, expired, source_deleted, masked, rebuilt или null), digest, at, context, access, и признак reset. Если reset: true, курсор старше хранимой ленты: перезагрузите состояние с начала.

Операция withdraw обязательна к исполнению: удалите у себя копию элемента и больше не цитируйте его.

Запрос:

{ "name": "twins_changes_since", "arguments": { "limit": 100, "kinds": ["claim"] } }

Ответ (иллюстрация, одно изменение):

{
  "has_more": false,
  "next_cursor": "f0_<курсор>",
  "reset": false,
  "changes": [
    {
      "kind": "claim",
      "id": "01M74R5GKJW7TBYZS7Z87KVQC4",
      "op": "withdraw",
      "reason": "disputed",
      "digest": "9f2c…",
      "at": "2026-11-12T09:30:00.000Z",
      "context": { "kind": "organization", "id": "synth-o2c-1" }
    }
  ]
}

Если изменений нет, changes пуст, а текст ответа: Изменений нет. Сохраните next_cursor и передайте его в следующий вызов.

twins_resolve#

Проверяет ссылки twins://<тенант>/claim/<id> перед показом или публикацией.

Таблица: twins_resolve
АргументТипОбязательныйОписание
urisмассив строк, 1–50 элементов, каждая до 300 символовдапроверяемые ссылки

Ответ содержит results[]: uri, status (available или unavailable), digest (дайджест того, что выдаётся сейчас, или null). Оспоренное, отклонённое, отозванное, чужое и неизвестное утверждение дают одинаковый unavailable, причина не раскрывается.

Запрос:

{ "name": "twins_resolve", "arguments": { "uris": ["twins://demo/claim/01M74R5GKJW7TBYZS7Z87KVQC4", "twins://demo/claim/unknown"] } }

Ответ (иллюстрация):

{
  "results": [
    { "uri": "twins://demo/claim/01M74R5GKJW7TBYZS7Z87KVQC4", "status": "available", "digest": "3b1a…" },
    { "uri": "twins://demo/claim/unknown", "status": "unavailable", "digest": null }
  ]
}

twins_health#

Состояние сервиса для вашего тенанта. Аргументов нет.

Запрос:

{ "name": "twins_health", "arguments": {} }

Ответ (сокращённо):

{
  "contract": "0",
  "server_version": "0.3.0",
  "contexts": [
    { "kind": "organization", "id": "synth-o2c-1", "label": "synth-o2c-1", "as_of": "2026-10-01", "data_class": "synthetic" }
  ],
  "counts": { "claims": 140, "decisions": 0, "rules": 3, "findings": 15, "fit_rows": 0 },
  "feed_head": null,
  "last_build_at": "2026-11-11T07:29:12.334Z"
}

Счётчики никогда не разбиваются по ролям. Значения в вашем тенанте будут другими: пример относится к демо-данным.