Repository navigation
Conversation
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
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. Comment |
Silo Kody — review completeReview finished. Check the inline comments for findings and verify each suggestion against the code and tests. Reviewing changes in Silo
Review settingsReview OptionsThe following review options are enabled or disabled:
|
fluxis
force-pushed
the
fix/atomic-profile-quota
branch
from
October 8, 2026 18:08
d40a302 to
c8c559d
Compare
Silo Kody — review completeReview finished. Check the inline comments for findings and verify each suggestion against the code and tests. Reviewing changes in Silo
Review settingsReview OptionsThe following review options are enabled or disabled:
|
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.
Problem
Concurrent profile creation can exceed an account's
max_profileslimit. A request that passes its initial check can also create a profile after an administrator lowers the limit. This change checks the current limit and household size within the profile write transaction.Related issue: N/A
Validation tasks: changes #1180 C1; changes #1196 C1. No human revalidation is claimed.
Approach
PostgreSQL profile creation holds the account row lock while checking the limit and inserting the profile. A separate count query sees a preceding creator's commit. The existing native
409 conflictresponse also covers a quota reached during the transaction. Lowering the limit preserves existing profiles and history and blocks further creation until the household falls below the limit.Direct store creation now wraps profile and library membership writes in one transaction. Account provisioning and canonical preference synchronization use that same quota check. The database contract registry includes the new native and store tests and rejects missing or skipped execution.
Apple and Android need no wire changes: the quota error already exists. The shared native handler preserves the v1 error code, and profile provisioning uses the same PostgreSQL path. Jellyfin-compatible clients do not create household profiles through a separate store path. No user manual update is needed: the existing account limit is unchanged.
Validation
Current qualification uses native main
6bdbb7d12f5f89cf17435ceec0c60a7cf70d06a6and headc8c559d31e4b14ac1f859922d05faeb65cb30ee0. The profile quota patch is unchanged. Fresh focused PostgreSQL-store and profile-handler checks passed. The compiled production migration runner initialized a fresh isolated database, and all four added database contracts passed through the strict runner without skips. Removing the transactional quota guard reproduced concurrent overflow and a stale create after a guarded downgrade; restoring it passed both native HTTP cases and preserved household/history data. Exact database, container, volume, and outer test-daemon cleanup passed. Browser captures retain their original build labels. Full local suites were not run.Native quota mutation checks passed against a fresh database using the rebased branch and the production migrations. Removing the transactional cap guard reproduced both concurrent overflow and creation after a guarded downgrade; restoring it passed both cases and preserved the existing household and history. All four new database contract entries passed through the strict CI runner without skips. The affected PostgreSQL store and profile handler regressions also passed.
Formatting and documentation path checks passed. Vet passed for the native API, profile handler and PostgreSQL store packages, and the DB contract runner unit tests passed. Changed-line lint passed with Go 1.26.4 and golangci-lint 2.12.2 over the four affected packages, with zero issues. The full Go and web suites were not run; verification is limited to affected behavior.
Evidence
Surface: native API with synthetic accounts on base
ca186fe3, using the profile quota changes. The before case disables only the transactional quota guard in a private source copy; the after case restores production code. The database was created through the production migration runner.These are observed native response statuses. The existing profile list and history remain equal after refusal. Desktop (1280 × 900) and mobile web (390 × 844) captures show the same synthetic household on the native profile chooser: Parent and both Guest profiles before, Parent and one Guest profile after. Native login, account, session, profile and library services back the browser; no browser API response is mocked. All four captures were visually checked for private information. Build:
d40a302d5ce9d63a6f6a50373c7b3a2b4d5b091a. Publishing to the private evidence site awaits the developer’s evidence CLI login.Risks
Profile creation holds the account row lock until its transaction commits, serializing creation with account updates. Existing over-limit households keep their data. No migration or deployment is included. Rollback evidence covers the profile and canonical-setting transaction and direct library-membership writes; existing later PIN and forced-subtitle writes remain outside that transaction. The separate access-group inheritance work in #1801 would require this check to resolve an effective group limit if it merges first.
Checklist
AI Disclosure
Note
Enforce household profile limits under row locks during profile creation
WithPreferenceSettingsTransactionin profiles.go.createProfilelocks the account row, reads the currentmax_profiles, counts existing profiles, and returns the new typeduserstore.ProfileLimitErrorwhen the household is full. Only the first profile becomes primary.ProfileLimitErrorto HTTP 409 with theprofile_limit_reachedcode and the current limit in the message.WithPreferenceSettingsTransactionin preference_settings_tx.go now uses explicit Read Committed isolation viaBeginTx.max_profiles; existing profiles and history in an over-cap household are preserved.Macroscope summarized d40a302.