DEV: formalize program case field contract - #728
Merged
Conversation
TThanos3000
marked this pull request as ready for review
September 6, 2026 18:05
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Основа
dev,a12e36bc4cca5934e68c309681f7ff1df757ca35(актуальный при повторном fetch).e83004cba98695f5f4bcb2e437c07f797bc49992.feature/dev-program-case-field-foundation.+1820 / −115. Follow-up отдельно: 7 файлов, +462 / −12.
Follow-up: неизменённый inline при сдаче через Admin
Bug воспроизведён реальным POST в admin change view с parent form и inline
formset для generic и case. До исправления оба позитивных теста возвращали
форму (200) вместо успешного redirect (302).
PartnerProgramFieldValue.clean()теперь сравнивает сохранённыеprogram_project_id,field_id,value_textс текущим instance. Повторнаяvalidation неизменённой строки разрешена; новый объект/перенос/смена поля или
текста считаются мутацией.
Одновременная сдача + mutation запрещена. Устаревший parent, перенос из
сданной связи и снятие checkbox вместе с mutation не обходят правило.
больше не заменяется копией из БД, теряющей pending
submitted=true.POST. Обычная model validation недостаточна: Django игнорирует её ошибки
на помеченных DELETE формах.
rgdftb+ сдача,A→B + сдача, edit/add/delete после сдачи и одновременно со сдачей, неизменённый
inline + несвязанная metadata, сохранение обычного редактирования до сдачи.
case validation и запрет даже идентичного PUT после сдачи.
update_program_link_fields(),submit_program_project(), case-validator,serializers, link-scoped API и URL не изменены follow-up коммитом.
Что изменено
Отдельной Case-модели нет: существующие
PartnerProgramField/PartnerProgramFieldValueуже хранят определение и выбор для конкретной связи Project × Program.
name="case"является системным; используется единая константа.без учёта регистра и внешних пробелов. Label произвольный. Generic fields не
становятся системными по названию/подписи/типу и не получают новых ограничений.
Остальные required fields остаются обязательными. Явный case валидируется.
выбор даёт контролируемую 400 без изменения флага или даты сдачи. Нет case —
прежний сценарий. После сдачи конкурсной связи все field values заблокированы.
definition согласованы блокировкой definition. Два новых PostgreSQL-теста
проверяют реальную конкуренцию записи со сдачей и удаления option с выбором.
нельзя переименовать или перенести. Добавление, удаление неиспользованного option,
изменение label/help_text допустимы. Admin ModelForm использует те же правила;
стандартные inline и delete confirmation защищают использованный case field.
API и доступ
Новый канонический endpoint:
GET/PUT /programs/partner-program-projects/{programLinkId}/fields/GET возвращает
program_link_id,program_id,project_id,submitted,definitions по pk с
options: string[]иvalue: string|null.PUT принимает прежний массив
{field_id, value_text}, допускает partial update,отклоняет чужие/повторные IDs и неверные значения атомарно. Пишет только лидер;
manager/expert/staff override не добавлен. GET использует существующий restricted
read helper, с ограничением program-ролей конкретной программой из URL.
Legacy
PUT /projects/{projectId}/program-fields/: одна связь работает; 0 → 400;несколько → 409, без выбора первой и без 500. Регрессии проверяют один Project
с разными case values в двух программах.
Существующий
GET /programs/{id}/filters/и manager / expert rate filtersпереиспользованы без изменения. A, B и A+B возвращают правильные проекты;
значения другой программы не подмешиваются. Scoring не менялся.
SQL-бюджет
Link-scoped GET для лидера: ровно 3 SQL-запроса при 1 и 20 полях:
join link/program/project + definitions + values. Для остальных ролей только
фиксированное число дополнительных EXISTS проверок доступа; N+1 по fields нет.
Проверки нового head
124 теста, OK, 2 PostgreSQL-only skip локально (122 passed).
804/804 passed, без skip, включая новые admin/model tests и case locking;
отдельный locking/vacancy stage 39/39 passed; PostgreSQL vendor и
select_for_update подтверждены, migrations применены на пустой БД.
804 теста, OK, 4 PostgreSQL-only skip (800 passed); полный lint passed.
admin.pyиservices/project_apply.pypassed. Четыре существующих formatting-hunk в этихдвух файлах оставлены как в origin/dev; новых замечаний Black нет.
manage.py check,check --tag models: passed.makemigrations --check --dry-run: No changes detected.git diff --checkи проверка diff против origin/dev: passed.Локальный Windows suite использует существующий внешний stub WeasyPrint из-за
недоступного Pango; он не входит в репозиторий/PR. PostgreSQL CI на Linux прошёл
с реальными зависимостями, без этого локального обхода.
Документация и ограничения v1
Полный контракт:
docs/program-case-field.md.обновлять options и все values.
удаление всей родительской программы администратором и административное ручное
изменение submitted требуют отдельного контроля. Пользовательский lifecycle
использует защищённые endpoints. Исторические невалидные значения автоматически
не исправляются, а отклоняются при submit с понятным сообщением.
Границы
Angular, React, analytics contract, scoring semantics, dependencies, workflows,
Docker и deploy не изменены. Новых моделей/колонок/FK и migrations нет.
Draft PR. Не merge / не deploy.