Skip to content

feat(invitations): bind profile limits and guard v2 creation - #2089

Closed
fluxis wants to merge 2 commits into
Silo-Server:mainfrom
fluxis:feat/v2-invitation-limits-guarded-create
Closed

fluxis wants to merge 2 commits into
Silo-Server:mainfrom
fluxis:feat/v2-invitation-limits-guarded-create

Conversation

@fluxis

@fluxis fluxis commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Related issue: #135
Validation tasks: changes #1196 C2; changes #1197 C1/C2

Invitations currently create accounts with the default profile limit until an administrator edits the account after acceptance. Creating another invitation for an address also replaces its pending link. This adds v2 options to bind the initial account limit during acceptance and to refuse an existing pending invitation when the caller asks to preserve it.

Approach

An optional positive max_profiles is stored with the invitation and applied in the same transaction as the account, optional default profile and claim. Omission keeps the default of 5. Resend copies the limit from its locked source. Migration rollback refuses to discard an explicit cap from an invitation that can still be claimed.

Optional replace_existing: false uses transactional address admission and the pending-invitation unique index to return 409 without changing another invitation or sending mail. Omission or true keeps ordinary replacement. Exact-source resend remains an explicit replacement and refuses stale source IDs. Both additions have capability fields.

The public claim request and frozen v1 invitation DTOs stay unchanged. Apple and Android have no administrator invitation consumers to update; the existing account profile-limit field continues to carry the claimed limit. Jellyfin has no native administrator invitation surface. The manual follow-up documents the new native invitation options after merge.

Validation

The invitation implementation was qualified against native main 6bdbb7d12f5f89cf17435ceec0c60a7cf70d06a6 at 84032788c216495f7ab7796a072a24b4a549f1d0; the implementation patch is unchanged by the rebase. Fresh focused invitation tests, actual-router OpenAPI generation, router fixture/schema checks, web type freshness, TypeScript project build, scoped ESLint/Prettier, and all 17 affected web tests passed. All 11 added PostgreSQL contracts passed through the strict runner without skips in a fresh isolated environment. Removing initial-cap or guarded-create forwarding produced failures; restoring each passed. The compiled migration runner refused rollback while a capped invitation remained, preserving the exact invitation and ledger, then completed Down/Up after revocation. Exact database, container, volume, and outer test-daemon cleanup passed.

Final head 321f1e4142cd5b01b446f261e09364ac4192cd51 adds only the removal of 13 already-merged approval entries required by the native contract policy; their provenance remains in git history. With that exact staged change frozen, the production semantic gate and focused contract-policy/CLI tests passed. Restoring the stale entries reproduced the failure; removing them again passed. The gate reports 10 additive invitation changes and no breaking changes. Exact private builder and outer daemon cleanup passed. Browser captures retain their original build labels. Full local suites were not run.

  • Focused native HTTP, service and PostgreSQL tests cover cap binding, omission, exact resend, committed delivery/login errors, atomic rollback, guarded creation races and migration refusal. Deliberate forwarding/guard/rollback mutations failed and restored implementations passed in the private test environment. All 11 new database contract pins passed without skips on the invitation-only branch. Native HTTP mutation testing returned 201 and called the mailer after bypassing the guard; the restored guard returned 409 without effects.
  • Invitation web transport, admin hooks and invitation settings: 17 tests passed. Removing guarded-create forwarding failed its request assertion. Scoped ESLint, Prettier, Goose validation, documentation path and case-collision checks passed. The production bundle stayed within its budget.
  • OpenAPI, fixtures and web types regenerated from the invitation-only branch; web type freshness passed. TypeScript project build passed. The web production build passed (existing font and chunk-size warnings); native changed-line lint passed with zero issues. Native OpenAPI, semantic contract, real-router fixture/schema and route-inventory checks passed. The semantic comparison found 10 additive changes and no breaking changes. The compiled server refused Goose rollback without changing the capped invitation or migration ledger, then completed Down/Up after that fixture was revoked; the disposable database was removed and its absence checked.
  • Full suites were not run; verification is limited to affected contracts and production paths.

Evidence

Desktop and phone captures show the native web administrator Profiles card with the same synthetic profile, Alex. The legacy request omits the cap and displays “1 of 5 allowed”; the new request binds 2 and displays “1 of 2 allowed”. Both use the actual compiled server and native PostgreSQL/auth/session stores through the pinned frontend. The claimed accounts were deleted and canonical reads returned 404. No new invitation editor control is added.

Evidence publication pending. Surface/build: invitation-only frozen source; commit 04f338c0df829b85e728f54f9dc30c91db99465c.

Risks

The cap column must be migrated before serving this contract. Rollback intentionally refuses while an unexpired, unaccepted, unrevoked explicitly capped invitation remains. Accepted account limits remain stored independently. Delivery and login failures after commit retain their existing non-retryable outcome semantics. Open PR #1801 changes profile-limit inheritance; whichever change lands second needs a rebase and an account-provisioning/default-policy review.

Checklist

  • I read and can explain the complete diff.
  • This pull request addresses native invitation provisioning and admission.
  • Publish the inspected desktop and phone evidence.

AI Disclosure

  • Harness: OpenAI Codex multi-agent
  • Tool(s): Codex tools, Git, GitHub CLI, Go, pnpm, Playwright with Google Chrome
  • Model(s): configured model gpt-6.1-sol; exact runtime SKU is not separately exposed
  • Involvement: AI-generated; human review pending
  • Adversarial review: A separate agent reviewed transactional pending-address admission, acceptance/replacement races, exact-source resend, v1 compatibility and migration locking. It found no production blocker. Private mutation tests verified that removing admission or rollback protection is detected; runtime evidence scope is reported above.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@silo-kody

silo-kody Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Silo Kody — review complete

Review finished. Check the inline comments for findings and verify each suggestion against the code and tests.

Reviewing changes in Silo
  • Include the related issue, expected behavior, and validation steps in the PR description.
  • For API changes, describe the effect on Apple and Android clients and Jellyfin compatibility.
  • For plugin changes, identify the affected SDK contract, plugin, and catalog entry.
  • Follow this repository's AGENTS.md and CONTRIBUTING.md.
  • Request another review with @kody start-review in a PR comment.
  • React with 👍 or 👎 to give feedback on individual suggestions.
Review settings
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug ✅
Performance ✅
Security ✅
Business Logic ❌

@fluxis
fluxis force-pushed the feat/v2-invitation-limits-guarded-create branch from 04f338c to 8403278 Compare October 8, 2026 18:08
@silo-kody

silo-kody Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Silo Kody — review complete

Review finished. Check the inline comments for findings and verify each suggestion against the code and tests.

Reviewing changes in Silo
  • Include the related issue, expected behavior, and validation steps in the PR description.
  • For API changes, describe the effect on Apple and Android clients and Jellyfin compatibility.
  • For plugin changes, identify the affected SDK contract, plugin, and catalog entry.
  • Follow this repository's AGENTS.md and CONTRIBUTING.md.
  • Request another review with @kody start-review in a PR comment.
  • React with 👍 or 👎 to give feedback on individual suggestions.
Review settings
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug ✅
Performance ✅
Security ✅
Business Logic ❌

The collection and section removals are already in main. Remove their stale approval entries as required by the native contract policy; their approval provenance remains in git history. The invitation contract remains additive.
@fluxis fluxis closed this Oct 8, 2026
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.

1 participant