4 Commits

Author SHA1 Message Date
Andrey Epifancev
eaee3ec5f9 feat(model): DBML v5.16 — counterparty_match_kind, миграция 0004, шаг резолва в маппинге
Enum counterparty_match_kind (INN, NAME, ALIAS, MANUAL, PROPAGATED) и nullable-колонка osv_entry.counterparty_match_kind
(NULL <=> counterparty_id NULL). Миграция 0004_dbml_v5_16: enum, колонка, backfill тремя UPDATE по уже смапленным
строкам (ИНН без пробелов -> INN, trim(имя) -> NAME, остальные -> ALIAS), откат удаляет колонку и тип.
CounterpartyIndex.resolve возвращает Resolution(entity_id, kind) (определение в domain/osv_mapping, R-4);
маппинг пишет kind; EntryOut.match_kind. DBML_VERSION 5.16, Makefile/dbml_parity/CLAUDE/README/config.yaml.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-06 03:23:02 +04:00
Andrey Epifancev
ab606dc59a feat(model): DBML v5.15 — osv_data_type NU, email в нижнем регистре, миграция 0003
- OsvDataType.NU после BU, DBML_VERSION = 5.15, Makefile/dbml_parity/docstring'и на data-model-v5.15.dbml;
- миграция 0003_dbml_v5_15: ADD VALUE 'NU' AFTER 'BU' + lower(app_user.email); downgrade пересоздаёт osv_data_type
  (регистр email не возвращается);
- email хранится в нижнем регистре: users_admin.create_user и seed (_apply_users); с UNIQUE по строчному email гонка
  создания в другом регистре теперь ловится индексом (тест test_api_constraint_races обновлён);
- тесты: enum NU, откат на шаг, lower email на миграции, seed/админка, вставка NU, фиктивная v5.16.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-05 21:28:04 +04:00
Andrey Epifancev
458392e94d feat(model): DBML v5.14 — related_group_member.kind, audit_action +2, миграция 0002, последовательности кодов
- RelatedGroupMember.kind (related_group_kind, NOT NULL) между legal_entity_id и valid_from, как в DBML;
  частичный уникальный индекс uq_related_group_member_entity_kind_current (legal_entity_id, kind) WHERE is_current —
  ЮЛ одновременно в одной ГСК и одной ГСЗ.
- AuditAction: LEGAL_ENTITY_CHANGE (после GROUP_CHANGE), USER_CHANGE (после USER_ROLE_CHANGE).
- Последовательности company_group_code_seq / related_group_code_seq в metadata (design D-5).
- Миграция 0002_dbml_v5_14: related_group_member пересоздаётся с переносом строк (kind из группы), чтобы порядок
  колонок совпал с DBML и create_all; ALTER TYPE ADD VALUE ×2; downgrade пересоздаёт audit_action v5.13.
- DBML_VERSION = 5.14, пути к data-model-v5.14.dbml (Makefile, dbml_parity), тесты: откат на шаг, перенос строк,
  уникальность gsk+gsz, офлайн-SQL до head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-04 20:49:32 +04:00
Andrey Epifancev
e064830702 feat: scripts/check_dbml_vs_orm.py — CLI сверки ORM с DBML (версия, таблицы, колонки, типы, FK, индексы, enum'ы)
Ядро сверки перенесено из tests/dbml_parity.py в scripts/dbml_parity.py (единственная
реализация, R-14); tests/dbml_parity.py и dbml_helpers.py — тонкие обёртки с пропуском
теста без docs. Единый формат строк: `<объект>: ожидалось X / фактически Y`,
`<объект>: отсутствует в ORM|DBML`; тип и nullability — одной строкой в нотации DBML.
Версия из шапки DBML сверяется с DBML_VERSION до сравнения таблиц. Коды: 0/1/2.
Без рабочего .env скрипт берёт api/.env.example. Makefile: dbml-check (в check-full),
mypy проверяет scripts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 19:56:58 +04:00