Skip to content

Prod: formalize program case field contract - #733

Merged
TThanos3000 merged 1 commit into
masterfrom
prod/program-case-field-foundation
Sep 9, 2026
Merged

TThanos3000 merged 1 commit into
masterfrom
prod/program-case-field-foundation

Conversation

@TThanos3000

Copy link
Copy Markdown
Collaborator

Основа и границы

  • Exact master base: dca8789e31f168614818797b57890b853d40171a (merge production Prod: harden program project access and expert filters #732).
  • Exact head: 30c4e3132fd92371e528d777097a2428242c1a2f.
  • Semantic production port DEV DEV: formalize program case field contract #728; reference merge f932586fc59818b445c473ec2a33990605f16524 (DEV head e83004cba98695f5f4bcb2e437c07f797bc49992).
  • Это не dev → master merge и не cherry-pick merge-коммита. Ветка построена непосредственно от указанного master.
  • Только legacy Project / PartnerProgramProject / PartnerProgramField / PartnerProgramFieldValue. Никаких новых моделей, FK, колонок или миграций.

Что перенесено

  • Системный кейс определяется исключительно field.name == PROGRAM_CASE_FIELD_NAME == "case". Label, регистр, похожие имена и тип generic-поля не служат эвристиками.
  • Конфигурация exact case: select, required, show_filter; непустые options с trim и запретом case-insensitive дублей.
  • Использованный case нельзя переименовать/перенести; использованный вариант нельзя удалить или переименовать. Label/help_text, новые и неиспользованные варианты редактируются.
  • Draft apply может не содержать case, без автоматического выбора первого option. Generic required fields остаются обязательными. Явный case повторно проверяется внутри транзакции с блокировкой definition до записи.
  • Submit остаётся leader-only, для competitive/open/not-submitted link. Валидируется case именно URL-связи. Missing/blank/obsolete choice даёт controlled 400, не меняя submitted и datetime_submitted. Без case сохраняется прежний submit.
  • После submit все values competitive link заморожены. Model/admin validation отличает мутацию от повторной проверки неизменённой строки.
  • Admin: unchanged inline + submitted=true успешно; edit/add/delete вместе со сдачей или после сдачи запрещены. Устаревший parent instance, перенос values и unsubmit+edit в одном POST freeze не обходят.
  • Link → definitions row locks сериализуют PUT и submit; definition edit сериализуется с сохранением case choice. Добавлены реальные PostgreSQL concurrency regressions в обоих направлениях option edit/selection.

Canonical fields и адаптация к #732

GET/PUT /programs/partner-program-projects/<programLinkId>/fields/

GET сохраняет ровно foundation-контракт #728:

{
  "program_link_id": 700,
  "program_id": 12,
  "project_id": 55,
  "submitted": false,
  "fields": [
    {
      "id": 5,
      "name": "case",
      "label": "Кейс",
      "field_type": "select",
      "is_required": true,
      "show_filter": true,
      "help_text": null,
      "options": ["A", "B"],
      "value": "A"
    }
  ]
}
  • Добавлен содержательный helper projects.access.has_program_link_read_access; все три исходных helper Prod: harden program project access and expert filters #732 сохранены без изменений.
  • Independent project-level involvement (leader/collaborator/invite/staff/superuser) сохраняет существующий READ.
  • Program-role-only READ строго по запрошенному link: manager/expert A не читает поля B общего проекта. Это покрыто HTTP regression-тестами.
  • PUT partial, только leader; чужой field_id, дубликаты ID и invalid choice отклоняются атомарно. Manager/expert/staff без лидерства писать не могут.
  • Legacy PUT /projects/<projectId>/program-fields/: 0 links → 400, 1 → canonical service, 2+ → 409 AmbiguousProgramLink, без выбора первой связи.
  • Код ambiguous_program_link сохраняет семантику DRF default_code из DEV: formalize program case field contract #728; JSON response по-прежнему содержит detail, новый JSON error-code envelope не вводится.
  • GET query budget, force-authenticated HTTP requests: leader 3 → 3, manager 6 → 6, expert 6 → 6 при 1 → 20 fields. N+1 по полям нет.

Scope audit

  • Все объявления полей моделей/Meta неизменны. Исходники остальных model/admin classes и существующих helpers Prod: harden program project access and expert filters #732 сравнены с base через AST и исходный текст.
  • Application, Team, TeamMember, TeamInvite, Submission, SubmissionExpertAssignment, Evaluation, EvaluationScore, EvaluationAmendment и их runtime/admin/API/services не изменены.
  • Старые routes сохранены в прежнем порядке; manager-overview и scoped project detail/WRITE policy Prod: harden program project access and expert filters #732 unchanged.
  • Migrations, dependencies, workflows и Docker unchanged; Angular/React не затронуты.
  • DEV: expose program link submission metadata #729 metadata (is_competitive, submission_open, submission_deadline, can_submit) не добавлена в GET fields.
  • Analytics, current_project_application, deadline follow-ups и новый Application flow вне scope.

Проверки exact head

  • Targeted case / canonical fields / apply / submit / admin / Prod: harden program project access and expert filters #732 access regressions: 148 tests, OK, включая 3 PostgreSQL concurrency tests.
  • Все projects + partner_programs: 783 tests, OK.
  • Полный backend suite локально: 1352 tests, OK, exit 0; Python 3.11.15 / PostgreSQL 18.1 / procollab.settings_ci.
  • Полный локальный suite выполнен с --keepdb и уникальной тестовой БД; после завершения процесса подтверждено отсутствие соединений, БД удалена.
  • manage.py check, check --tag models: PASS.
  • makemigrations --check --dry-run: No changes detected.
  • Flake8 по backend: PASS.
  • Scoped Black: 17 changed/new Python files целиком + изменённые классы в models/admin PASS. Whole-file Black для partner_programs/models.py и admin.py уже не проходит на exact base из-за старого форматирования неизменённых классов. Эти классы сверены с base и намеренно не переформатированы; repository-wide formatting не выполнялся.
  • git diff --check: PASS.
  • Backend PostgreSQL CI: PASS на exact head; PostgreSQL 15, реальные locking/constraints, полный suite, Django/models/migration consistency, cleanup.
  • Обычный CI: Lint PASS, Tests PASS на том же exact head.

Ограничения и эксплуатация

  • Документация: docs/program-case-field.md.
  • Перед отдельным будущим rollout нужен read-only inventory существующих exact case definitions/values. Некорректные legacy данные автоматически не исправляются.
  • Сохранены границы DEV: formalize program case field contract #728 v1: это model/form/service validation, не database trigger; raw SQL / QuerySet.update / bulk_create / QuerySet.delete могут обходить её. Admin-редактирование флага submitted не заменяет пользовательский submit endpoint.
  • Draft only. Не merge, не deploy.

@TThanos3000
TThanos3000 marked this pull request as ready for review September 9, 2026 14:03
@TThanos3000
TThanos3000 merged commit cd427c6 into master Sep 9, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants