Контракты между треками¶
Контракты — это форматы данных, на которых встречаются три трека. Пока они не меняются, треки работают параллельно и не ждут друг друга.
Статус: определены в задаче T00, версия CONTRACT_VERSION = "1.0". Каждое решение (Decision) хранит версию контракта, по которой оно построено.
Где лежат¶
apps/api/contracts.py— Pydantic-модели. Это единственный источник правды; описание ниже только перечисляет, что там есть.tests/fixtures/— пример JSON для каждой модели. Трек 2 строит движок на этих примерах, трек 3 — экраны, ещё до того, как готов синтетический мир.tests/test_contracts.py— проверяет, что каждый пример проходит валидацию, совпадает со своей сериализацией (нет лишних полей и молча добавленных значений по умолчанию) и согласован с остальными примерами.
Соглашения¶
- Деньги — целые рубли (
int). - Ставки, доли, PD и LGD — доли единицы:
0.209означает 20,9%. - Даты и время — ISO 8601, месяцы —
"YYYY-MM". nullзначит «нет данных», а не ноль (SPEC §5.1). ВFeaturesвсе поля обязательны: если признак посчитать нельзя, производитель явно пишетnull, и признак попадает в интервал «нет данных».- Все модели запрещают неизвестные поля: опечатка в имени поля — ошибка валидации, а не тихо потерянное значение.
- Пороги (границы уровней качества данных, минимальный DSCR, таблица LGD, потолок ставки) — это кредитная политика, они лежат в
config/:config/data_quality.json(T09),config/credit_policy.json(T16, лимит и ставка). Контракты переносят только посчитанные по ним значения и версию политики (policy_version).
Что входит¶
| Контракт | Кто производит → кто потребляет | Модель | Примеры |
|---|---|---|---|
| Заявка | клиентский интерфейс (трек 3) → конвейер (трек 2) | ApplicationRequest: цель, сумма, срок, когда нужны деньги, заявленная выручка, оборудование для инвестиционного кредита, согласия (БКИ 218-ФЗ по компании и собственнику, ПДн 152-ФЗ) |
application_request.json |
| Ответы источников | мок-сервис apps/sources/ (трек 1, T06) → адаптеры и оркестратор apps/sources/enrichment.py (трек 1, T07) → досье (трек 3) |
SourceResponse — конверт вызова (статус, время запроса и ответа, задержка, число попыток, ошибка) и payload своего типа для каждого источника: AccountsPayload, ClientCardPayload, EgrulPayload (ЕГРЮЛ и ЕГРИП), FnsPayload (+ГИР БО для ООО, декларация для ИП), BkiPayload (отчёты по компании и собственнику), FsspPayload, ArbitrationPayload (арбитраж и Федресурс), AmlPayload (115-ФЗ). Тип ответа выбирается по полю source |
sources/*.json, в том числе fssp_timeout.json — недоступный источник после трёх попыток |
Fact |
адаптеры, apps/sources/facts.py (трек 1, T07) → движок (трек 2) |
Название, заявленное значение, подтверждённое значение, источник, уровень надёжности, время получения; относительное расхождение заполняется само, если оба значения числовые. Один факт на пару «название — источник». Факты из загруженных клиентом выписок (T23) идут с источником statement_upload и уровнем client_document |
facts.json |
DataQuality |
признаки, apps/api/features/data_quality.py (трек 1, T09; пороги — config/data_quality.json) → движок (трек 2), досье (трек 3) |
Четыре показателя со своими уровнями, итоговый уровень FULL / PARTIAL / THIN (модель проверяет, что он худший из четырёх), база для покрытия выручки (ФНС или заявленная), фраза для клиента |
data_quality_full.json, data_quality_thin.json |
Features |
признаки (трек 1) → скоринг (трек 2) | Признаки скоринговой карты из SPEC §8 с типами; запрошенной суммы среди них нет намеренно | features.json |
| Файл скоринговой карты | обучение (трек 1) → скоринг (трек 2) | Scorecard — формат scorecard_vN.json: версия, происхождение (hand_set / trained), масштабирование (600 баллов = шансы 50:1, +20 баллов = шансы ×2), базовые баллы, интервалы и баллы по каждому признаку с обязательным интервалом «нет данных», границы грейдов A–E. Обученная карта — apps/ml/scorecard_v1.json (T10), как она читает признаки — apps/ml/score.py, применяет карту скоринговый модуль apps/api/scoring.py (T15) |
scorecard_example.json — пример формата, не рабочие веса |
Decision |
движок (трек 2; лимит и ставка предложений — apps/api/limits.py, apps/api/pricing.py, T16; набор предложений и контрфактические подсказки — apps/api/offers.py, T17; маршрут и его причины — apps/api/routing.py, T18; собирает и хранит решение apps/api/workflow.py, T19; решение сотрудника — apps/api/staff_actions.py, T20; запрос выписок и пересчёт с ними — apps/api/statements.py, T23) → интерфейсы (трек 3) |
Статус (offered, declined, in_review, needs_data), matches_request, маршрут и его причины, причины решения, стоп-факторы, флаги, PD, баллы, грейд и вклады факторов, результат модели-претендента, качество данных, до четырёх предложений с расчётом лимита (все ограничения, определяющее отмечено) и ставки по составляющим, контрфактические подсказки, запрошенные документы, дата повторного обращения, версии модели и политики |
decision_offered.json, decision_in_review.json, decision_declined.json |
Тестовая персона в примерах¶
Источники, заявка, факты, признаки, data_quality_full.json и decision_offered.json описывают одну синтетическую компанию — ООО «Зёрна», оптовую пекарню (ИНН 5406000001). Числа в примерах получены по формулам SPEC §5.1, §8 и §9, поэтому они согласованы между собой:
- клиент просит 1 млн ₽ на 12 месяцев, CFADS около 109 тыс. ₽, грейд B, текущий платёж по кредиту 15 270 ₽;
- лимит ограничен денежным потоком, поэтому предложений два: 1 млн ₽ на 17 месяцев или 730 тыс. ₽ на 12 месяцев;
- контрфактическая подсказка: без текущего кредита на 12 месяцев было бы доступно 890 тыс. ₽ (движок T17 даёт 900 тыс. ₽, потому что пересчитывает ставку под новую сумму,
apps/api/OFFERS.md).
decision_in_review.json — та же компания, но заявленная выручка расходится с данными ФНС больше чем на 30%. Это флаг, поэтому заявка уходит андеррайтеру, и расходы на обработку поднимают ставку. decision_declined.json, egrip_ip.json, fns_ip.json и data_quality_thin.json относятся к ИП Петровой с недавно открытым счётом (уровень THIN) и стоп-фактором по просрочке 90+ дней.
Примеры — не ожидаемые результаты движка. Это образец формата с правдоподобными числами. Эталонные исходы — у демо-персон из синтетического мира: apps/world/PERSONAS.md (T12); тесты по ним — T33.
Упрощения в контрактах¶
# MOCK:зона риска ЦБ «Знай своего клиента» в ответе 115-ФЗ и гарантия Корпорации МСП как вид обеспечения — моки. В реальности это отдельные интеграции со своими форматами.# SIMPLIFICATION:ответы источников урезаны до полей, которые нужны конвейеру (SPEC §5). Реальные ответы ЕГРЮЛ, ФНС и БКИ намного шире.
Как менять контракт¶
- Отдельный PR, который меняет
contracts.pyи соответствующие примеры вtests/fixtures/. - Тесты проходят.
- PR одобряют все три программиста.
- Если изменение ломает совместимость, поднимается
CONTRACT_VERSION, а в журнал решений вTASKS.mdдобавляется строка.