Skip to content

feat: enforce competitive legacy team policy - #765

Draft
TThanos3000 wants to merge 1 commit into
fix/dev-invite-integrityfrom
feature/dev-competitive-team-policy
Draft

TThanos3000 wants to merge 1 commit into
fix/dev-invite-integrityfrom
feature/dev-competitive-team-policy

Conversation

@TThanos3000

@TThanos3000 TThanos3000 commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Что изменено

Конкурсная legacy-команда теперь проверяет exclusivity, текущий membership программы, min/max и freeze через общую policy. Submitted-состав нельзя изменить через Invite, Collaborator, vacancy, leave/switch, bind/clone и admin/model save. Pending decline/revoke остаются разрешены. Submission повторно проверяет команду под теми же locks.

Зачем

PR C утверждённого hardening. Spec и AC C1–C15: docs/competitive-team-policy.md; read-only диагностика исторических конфликтов: docs/legacy-team-data-audit.sql.

Реализация

  • Base SHA: 3a513846c81dd36e5f3393957ec3450c9fcfb2f7 (PR B fix: make legacy invite transitions atomic and race-safe #764).
  • Head SHA: 88f114b63b954e3faa578420175f598b63022e9b.
  • 44 файла: общий projects/team_policy.py, service/errors/admin; модели и существующие writers; serializers/views; migrations; tests и spec.
  • Порядок существующих объектов: Project → Program по ID → program links → Invite/Vacancy → PUP/Collaborator. Program lock сериализует разные команды одной программы.
  • Draft/submitted участвуют в exclusivity до datetime_finished; завершённые программы сохраняют историю. Leader считается один раз; pending резервирует max, но не min. Каждая NULL-граница отключает только своё ограничение.

API

Optional program_link_id принимает реальный link ID. Ноль links — обычный проект, один — единственный context, несколько — explicit ID или 409 program_context_required. Invite хранит выбранный context. Link-scoped submission URL сохранён. Project list/detail и компактные user-projects возвращают team_policy с freeze и доступными links. Legacy read projection сохранён для совместимости.

409 codes: team_frozen, already_in_program_team, team_min_size, team_max_size, program_context_required, program_context_in_use, submission_closed; коды PR A/B сохраняются. Permission — 403, foreign context — 422, malformed input / существующая case validation — 400.

UI

Angular — отдельный Draft PR PROCOLLAB-github/procollab#392 после backend C. React не менялся. Admin использует form validation / controlled errors.

Permissions

Не вводятся новые роли. Только действующий лидер управляет командой; существующий staff override vacancy service сохранён. Actor перепроверяется после locks. Freeze любого submitted competitive link действует на общий roster, explicit context другой программы не обходит его.

Проверки

  • PostgreSQL 18.1: 115 targeted tests PASS, включая 29 competitive-policy cases, все Invite tests, forward/backward migrations, case locks и admin mutations.
  • Реальные HTTP races: accept A/B, concurrent capacity reservation, submit/accept, submit/remove; inherited PR B races и fault injection.
  • API/model submission required fields, membership, independent NULL bounds, DB configuration checks, clone/bind rollback, ordinary projects.
  • Black / Flake8 изменённых Python файлов, Django check, makemigrations --check --dry-run, git diff --check.
  • Source / requirement review C1–C15.
  • Полный локальный PostgreSQL 18.1 suite: 988 tests PASS, 447.922 s; финальный head без изменения production code после запуска.
  • GitHub PostgreSQL 15 CI PASS на этом head: 988 full-suite tests, 39 existing targeted locking/vacancy tests, schema/configuration/migrations. Стандартные CI Lint / Tests также PASS.

Acceptance criteria

  • C1–C15 подтверждены targeted assertions и полным PostgreSQL suite.
  • Исторические конфликты не удаляются и победитель не выбирается автоматически.
  • Все новые настройки NULL по умолчанию; значения nextgen не копируются.

Migrations / DB constraints

partner_programs/0019_legacy_project_team_policy: nullable legacy_team_min_size / legacy_team_max_size и три checks корректности настройки. PROD nextgen team_min_size/team_max_size имеют несовместимую семантику, поэтому не переиспользованы.

invites/0004_legacy_project_team_policy: nullable FK program_link с RESTRICT; backfill только при ровно одном link. Ноль/несколько links остаются NULL. Forward/backward проверены без удаления Invite/roster.

DB защищает pending Invite (PR B), Collaborator(user,project), PUP(user,program), FK и корректность size settings. Exclusivity, freeze и capacity — согласованный application lock protocol, не независимые cross-table DB constraints. Для такой DB-гарантии потребуется отдельная materialized membership сущность и согласованная миграция; она не добавлена молча.

Не проверено

Live DEV/PROD mutations и production data audit не выполнялись. Нет deploy, merge или browser проверки нового кода. Raw SQL, QuerySet bulk/update и удаление целых родительских сущностей каскадом не являются защищёнными roster-service операциями.

Риски / rollout

Перед B/C на целевой БД выполнить read-only diagnostic SQL. Pending duplicates останавливают migration B без изменения данных. Existing exclusivity conflicts требуют отдельного решения владельца; C сохраняет данные и запрещает новые конфликтующие mutations. Ambiguous legacy Invite требует explicit API context или отдельно согласованного исправления данных. Program-level locks сериализуют writers программы и могут повышать contention. PROD имеет другой migration graph и lifecycle: migrations нельзя переносить туда без адаптации.

Стек согласован: A #763 → dev, B #764 → A, этот C → B. После merge B base C меняется на dev. Merge/deploy не выполняются.

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