| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 0 | 9 | 23 | 0% |
| Commands | 0 | 3 | 3 | 0% |
| Section tags | 3 | 1 | 6 | 30% |
What each file covers
Sections
0 shared · 9 only in A · 23 only in B- − Bitwarden Server - Claude Code Configuration
- − Project Context Files
- − Critical Rules
- − Project Structure
- − Security Requirements
- − Common Commands
- − Development Workflow
- − Key Architectural Decisions
- − References
- + Bitwarden Seeder Library - Claude Code Configuration
- + Quick Reference
- + Commands
- + Build
- + Run tests
- + Run single test
- + Pattern Decision Tree
- + Pipeline Architecture
- + Parallelism
- + Performance A/B Testing
- + Density Profiles
- + Data/ File Organization
- + The Recipe Contract
- + Zero-Knowledge Architecture
- + Data Flow
- + Pipeline path (fixture → entity)
- + Core encryption (shared by all paths)
- + Rust Crypto Dependency
- + Encryption Schemes (crypto taxonomy)
- + Deterministic Data Generation
- + Scenarios
- + Collection Management Settings
- + Security Reminders
Commands
0 shared · 3 only in A · 3 only in B- − dotnet build
- − dotnet test
- − dotnet run --project src/Api
- + dotnet build util/Seeder/Seeder.csproj
- + dotnet test test/SeederApi.IntegrationTest/
- + dotnet test test/SeederApi.IntegrationTest/ --filter "FullyQualifiedName~TestMethodName"
Section tags
3 shared · 1 only in A · 6 only in B- − architecture
- + build
- + test
- + testing-strategy
- + api
- + performance
- + deployment
- security
- do-not
- agent-behaviour
Line diff
bitwarden/server · .claude/CLAUDE.md
@@ −1 @@
1# Bitwarden Server - Claude Code Configuration
2
3## Project Context Files
4
5**Read these files before reviewing to ensure that you fully understand the project and contributing guidelines**
6
71. @README.md
82. @CONTRIBUTING.md
93. @.github/PULL_REQUEST_TEMPLATE.md
10
11## Critical Rules
12
13- **NEVER** use code regions: If complexity suggests regions, refactor for better readability
14- **NEVER** compromise zero-knowledge principles: User vault data must remain encrypted and inaccessible to Bitwarden
15- **NEVER** log or expose sensitive data: No PII, passwords, keys, or vault data in logs or error messages
16- **ALWAYS** use secure communication channels: Enforce confidentiality, integrity, and authenticity
17- **ALWAYS** encrypt sensitive data: All vault data must be encrypted at rest, in transit, and in use
18- **ALWAYS** prioritize cryptographic integrity and data protection
19- **ALWAYS** add unit tests (with mocking) for any new feature development
20
21## Project Structure
22
23- **Source Code**: `/src/` - Services and core infrastructure
24- **Tests**: `/test/` - Test logic aligning with the source structure, albeit with a `.Test` suffix
25- **Utilities**: `/util/` - Migration tools, seeders, and setup scripts
26- **Dev Tools**: `/dev/` - Local development helpers
27- **Configuration**: `appsettings.{Environment}.json`, `/dev/secrets.json` for local development
28
29## Security Requirements
30
31- **Compliance**: SOC 2 Type II, SOC 3, HIPAA, ISO 27001, GDPR, CCPA
32- **Principles**: Zero-knowledge, end-to-end encryption, secure defaults
33- **Validation**: Input sanitization, parameterized queries, rate limiting
34- **Logging**: Structured logs, no PII/sensitive data in logs
35
36## Common Commands
37
38- **Build**: `dotnet build`
39- **Test**: `dotnet test`
40- **Run locally**: `dotnet run --project src/Api`
41- **Database update**: `pwsh dev/migrate.ps1`
42- **Generate OpenAPI**: `pwsh dev/generate_openapi_files.ps1`
43
44## Development Workflow
45
46- Security impact assessed
47- xUnit tests added / updated
48- Performance impact considered
49- Error handling implemented
50- Breaking changes documented
51- CI passes: build, test, lint
52- Feature flags considered for new features
53- CODEOWNERS file respected
54
55### Key Architectural Decisions
56
57- Use .NET nullable reference types (ADR 0024)
58- TryAdd dependency injection pattern (ADR 0026)
59- Authorization patterns (ADR 0022)
60- OpenTelemetry for observability (ADR 0020)
61- Log to standard output (ADR 0021)
62
63## References
64
65- [Server architecture](https://contributing.bitwarden.com/architecture/server/)
66- [Architectural Decision Records (ADRs)](https://contributing.bitwarden.com/architecture/adr/)
67- [Contributing guidelines](https://contributing.bitwarden.com/contributing/)
68- [Setup guide](https://contributing.bitwarden.com/getting-started/server/guide/)
69- [Code style](https://contributing.bitwarden.com/contributing/code-style/)
70- [Bitwarden security whitepaper](https://bitwarden.com/help/bitwarden-security-white-paper/)
71- [Bitwarden security definitions](https://contributing.bitwarden.com/architecture/security/definitions)
72
bitwarden/server · util/Seeder/CLAUDE.md
@@ +1 @@
1# Bitwarden Seeder Library - Claude Code Configuration
2
3## Quick Reference
4
5**For detailed pattern descriptions (Factories, Recipes, Models, Scenes, Queries, Data), read `README.md`.**
6
7**For detailed usages of the Seeder library, read `util/SeederUtility/README.md` and `util/SeederApi/README.md`**
8
9## Commands
10
11```bash
12# Build
13dotnet build util/Seeder/Seeder.csproj
14
15# Run tests
16dotnet test test/SeederApi.IntegrationTest/
17
18# Run single test
19dotnet test test/SeederApi.IntegrationTest/ --filter "FullyQualifiedName~TestMethodName"
20```
21
22## Pattern Decision Tree
23
24```
25Need to create test data?
26├─ ONE entity with encryption? → Factory
27├─ ONE cipher from a SeedVaultItem? → CipherSeed.FromSeedItem() + {Type}CipherSeeder.Create()
28├─ MANY entities as cohesive operation? → Recipe or Pipeline
29├─ Flexible preset-based seeding? → Pipeline (RecipeBuilder + Steps)
30├─ Complete test scenario with ID mangling? → Scene
31├─ READ existing seeded data? → Query
32└─ Data transformation plaintext ↔ encrypted? → Model
33```
34
35## Pipeline Architecture
36
37**Modern pattern for composable fixture-based and generated seeding.**
38
39**Flow**: Preset JSON or Options → RecipeOrchestrator → RecipeBuilder → IStep/IAsyncStep[] → RecipeExecutor → SeederContext → BulkCommitter → IPostCommitStep[]
40
41**Key actors**:
42
43- **RecipeBuilder**: Fluent API with dependency validation
44- **IStep / IAsyncStep**: Isolated units of work (CreateOrganizationStep, CreateUsersStep, etc.). Use `IAsyncStep` for steps that do real I/O. A step additionally marked `IPostCommitStep` is deferred until after the bulk commit, so it observes committed rows — but sees cleared entity lists, since only the `EntityRegistry` and the context's scalar properties survive the commit.
45- **SeederContext**: Shared mutable state bag (NOT thread-safe)
46- **RecipeExecutor**: Awaits steps sequentially, captures statistics, commits via BulkCommitter, then runs any post-commit steps
47- **RecipeOrchestrator**: Orchestrates recipe building and execution (from presets or options)
48- **SeederDependencies** (`Options/`): Bundles infrastructure services (`DatabaseContext`, `IMapper`, `IPasswordHasher<User>`, `IManglerService`, `ILicensingService`, `IAttachmentStorageService`) into a single record. Recipes and the Orchestrator accept this instead of loose parameters. The CLI utility builds it via `SeederServiceFactory.Create().ToDependencies()`.
49
50**Why two step interfaces, not one async contract?** Deliberate — don't unify. Collapsing to one `Task ExecuteAsync(SeederContext)` costs: rewrite 22 step classes (18 in `Steps/`, 4 test doubles); force 20 `.Execute(context)` sites in `test/SeederApi.IntegrationTest/Steps/` to `await`, their test methods to `async`; and `TreatWarningsAsErrors` is on repo-wide (`Directory.Build.props`), so CS1998 makes `async` without `await` a build error — every sync step needs `return Task.CompletedTask`. Permanent trap. The split costs less: two-arm union in `OrderedStep`, `object`-typed `Inner`, one duplicated `RecipeBuilder` registration. Diverges from `IScene`/`IQuery` — single `Task`-returning, no sync twin.
51
52**Fixture/preset separation**: Fixtures (organizations, rosters, ciphers) are independent and never reference each other. The preset is the only layer that composes fixtures and defines cross-cutting relationships (folder assignments, favorites). See `Seeds/docs/architecture.md`.
53
54**Phase order (org presets)**: Org → OrgApiKey → Roster → Owner (conditional) → Generator (conditional) → Users → Groups → Collections → Folders → Ciphers → CipherAttachments → CipherCollections → CipherFolders → CipherFavorites → PersonalCiphers
55**Phase order (individual presets)**: IndividualUser → NamedFolders → Generator → Folders → Ciphers → CipherAttachments → FolderAssignments → FavoriteAssignments
56
57**Individual user presets** use the Pipeline with `CreateIndividualUserStep` (no org, no groups, no collections). These presets live in `Seeds/fixtures/presets/individual/` and are identified by having a `"user"` key instead of `"organization"`. They support `folderNames`, `folderAssignments`, and `favoriteAssignments` for fixture-driven personal vault organization. See `Seeds/docs/presets.md` for the catalog.
58
59See `Pipeline/` folder for implementation.
60
61## Parallelism
62
63Steps execute sequentially (phase order preserved by RecipeExecutor). Async steps are awaited one at a time and MUST NOT be batched with `Task.WhenAll` — `SeederContext` is not thread-safe and each step reads state written by the ones before it. Within a step, `CreateUsersStep` and `GeneratePersonalCiphersStep` use `Parallel.For` internally for CPU-bound Rust FFI work (key generation, encryption).
64
65**Thread-safety requirements:**
66
67- `GeneratorContext` lazy properties (`??=`) must be force-initialized before any `Parallel.For` loop to prevent a data race
68- Generators use `ThreadLocal<Faker>` for thread-safe deterministic data generation
69- `ManglerService` and `SeederContext` are NOT thread-safe -- pre-compute their outputs before entering parallel loops
70
71## Performance A/B Testing
72
73When measuring step-level performance changes, use paired worktrees:
74
75- Create `server-PM-XXXXX/perf-baseline` and `server-PM-XXXXX/perf-optimized` worktrees
76- Both worktrees get `Stopwatch` timing in `RecipeExecutor.ExecuteAsync()` (the baseline measurement)
77- Only the optimized worktree gets actual code changes
78- Run presets with `--mangle` flag to avoid DB collisions between runs
79- Compare per-step timings across 3+ runs each, discard the first run (JIT warmup)
80- `.worktrees/` is already in `.gitignore`
81
82## Density Profiles
83
84Steps accept an optional `DensityProfile` that controls relationship patterns between users, groups, collections, and ciphers. When null, steps use the original round-robin behavior. When present, steps branch into density-aware algorithms.
85
86**Key files**:
87
88- `Options/DensityProfile.cs` — strongly-typed options (public class)
89- `Models/SeedPresetDensity.cs` — JSON preset deserialization targets (internal records)
90- `Data/Enums/MembershipDistributionShape.cs` — Uniform, PowerLaw, MegaGroup
91- `Data/Enums/CollectionFanOutShape.cs` — Uniform, PowerLaw, FrontLoaded
92- `Data/Enums/CipherCollectionSkew.cs` — Uniform, HeavyRight
93- `Data/Distributions/PermissionDistributions.cs` — 11 named distributions by org tier
94
95**Backward compatibility contract**: `DensityProfile? == null` MUST produce identical output to the original code. Every step guards this with `if (_density == null) { /* original path */ }`.
96
97**Preset JSON**: Add an optional `"density": { ... }` block. See `Seeds/schemas/preset.schema.json` for the full schema.
98
99**Presets**: Organized into `features/`, `qa/`, `scale/`, `validation/` folders under `Seeds/fixtures/presets/`. See `Seeds/docs/presets.md` for the full catalog.
100
101**Verification**: SQL queries for validating density algorithms are in `Seeds/docs/verification.md`.
102
103## Data/ File Organization
104
105New files under `Data/` belong in the matching subfolder (`Distributions/`, `Enums/`, `Generators/`, `Static/`) — never loose at the top level. See `Data/README.md` for what each subfolder holds. If a new file's concern doesn't fit an existing subfolder, that's a signal to create one, not to drop it loose.
106
107**Two Enums homes, by concern:** `Data/Enums/` (namespace `Bit.Seeder.Data.Enums`) holds the generation-config surface (`CompanyType`, `PasswordStrength`, distribution shapes, etc. — "Enums are the API"). Crypto-taxonomy enums that describe how seeded vault data is encrypted (`CipherEncryptionType`, `AttachmentSchemeType`) live in the top-level `Enums/` folder (namespace `Bit.Seeder.Enums`), one enum per file.
108
109## The Recipe Contract
110
111Recipes follow strict rules:
112
1131. A Recipe SHALL accept `SeederDependencies` as its single constructor parameter
1142. A Recipe SHALL have exactly one public entry point — `Seed()` when synchronous, `SeedAsync()` when it returns `Task`/`Task<T>`. Pipeline-backed Recipes (`OrganizationRecipe`, `IndividualUserRecipe`) are async; the direct-to-database Recipes (`CollectionsRecipe`, `GroupsRecipe`, `OrganizationDomainRecipe`, `OrganizationWithUsersRecipe`) remain synchronous.
1153. A Recipe MUST produce one cohesive result
1164. A Recipe MAY overload that entry point with different parameters
1175. A Recipe SHALL use private helper methods for internal steps
1186. A Recipe SHALL use BulkCopy for performance when creating multiple entities
1197. A Recipe SHALL compose Factories for individual entity creation
1208. A Recipe SHALL NOT expose implementation details as public methods
121
122## Zero-Knowledge Architecture
123
124**Critical:** Unencrypted vault data never leaves the client. The server never sees plaintext.
125
126The Seeder uses the Rust SDK via FFI because it must behave like a real Bitwarden client:
127
1281. Generate encryption keys (like client account setup)
1292. Encrypt vault data client-side (same SDK as real clients)
1303. Store only encrypted result
131
132## Data Flow
133
134### Pipeline path (fixture → entity)
135
136```
137SeedVaultItem → CipherSeed.FromSeedItem() → CipherSeed → {Type}CipherSeeder.Create(options) → CipherViewDto → encrypt_fields (Rust FFI) → EncryptedCipherDto → EncryptedCipherDtoExtensions → Server Cipher Entity
138```
139
140### Core encryption (shared by all paths)
141
142```
143CipherViewDto → JSON + [EncryptProperty] field paths → encrypt_fields (Rust FFI, bitwarden_crypto) → EncryptedCipherDto → EncryptedCipherDtoExtensions → Server Cipher Entity
144```
145
146Shared logic: `Factories/CipherEncryption.cs`, `Models/EncryptedCipherDtoExtensions.cs`
147
148## Rust Crypto Dependency
149
150The Rust shim (`util/RustSdk/rust/`) depends only on `bitwarden_crypto`. It does **not** depend on `bitwarden_vault` — the seeder drives field selection via `[EncryptProperty]` attributes, not SDK cipher types.
151
152Before modifying encryption integration, run `RustSdkCipherTests` to validate roundtrip encryption.
153
154## Encryption Schemes (crypto taxonomy)
155
156Seeded data spans two orthogonal encryption axes, named with Bitwarden's canonical vocabulary (defined in `Enums/CipherEncryptionType.cs` and `Enums/AttachmentSchemeType.cs`):
157
158- **Cipher encryption** (`cipherEncryption`): `userKey` (no cipher key; `Cipher.Key` null) or `cipherKey` (per-cipher key wrapped by the vault key).
159- **Attachment scheme version** (`attachmentVersion`): `v0` (no attachment key), `v1` (attachment key wrapped by the vault key), `v2` (attachment key wrapped by the cipher key).
160
161**Invariant:** a cipher and its attachments use the same strategy — `v2` requires a `cipherKey` host. `Steps/CreateCipherAttachmentsStep.cs` and `Seeds/schemas/cipher.schema.json` both enforce this; keep them in sync.
162
163**Wire mapping:** `AttachmentSchemeType.{V0,V1,V2}` casts to `u32 {0,1,2}` and is matched verbatim in `util/RustSdk/rust/src/attachment.rs`. The value *is* the version number — do not reintroduce an offset.
164
165**Do not conflate with account Encryption V1/V2.** Attachment `v0/v1/v2` is key-wrapping only. Everything the seeder emits is Encryption-V1 type-2 `EncString` (AES-256-CBC-HMAC); no COSE/type-7 path exists. A future V2/COSE capability is a **separate** axis (a new enum), never a new attachment version.
166
167## Deterministic Data Generation
168
169Same domain = same seed = reproducible data:
170
171```csharp
172var seed = options.Seed ?? DeriveStableSeed(options.Domain);
173```
174
175## Scenarios
176
177Developer-facing documentation in `Seeds/docs/scenarios/`. Each file maps an engineering problem to a Seeder command.
178
179**Maintenance rules:**
180
181- When adding a new preset, check if an existing scenario should reference it as a variation
182- When adding a new command or flag, check if it enables a new scenario or changes an existing one
183- When CLI flags, commands, or preset names change, scan all `*.md` files under `Seeds/` and `SeederUtility/` for stale references
184- Scenario files follow the template in `Seeds/docs/scenarios/README.md`
185- Never duplicate CLI flag documentation — link to `SeederUtility/README.md`
186- Never duplicate preset catalog details — link to `Seeds/docs/presets.md`
187- Scenarios describe _why_ (the problem). READMEs describe _how_ (the tool). Keep the split clean.
188
189**File relationships:**
190
191- `SeederUtility/README.md` → CLI reference (commands, flags, examples) → links to scenarios
192- `Seeds/docs/presets.md` → what exists (the catalog) → scenarios link back to it
193- `Seeds/docs/scenarios/` → why you'd use it (problem → command)
194
195## Collection Management Settings
196
197**Collection management settings are not plan-gated.** `AllowAdminAccessToAllCollectionItems`, `LimitCollectionCreation`, `LimitCollectionDeletion`, and `LimitItemDeletion` apply identically across all plan types. They are org-level admin settings, not billing-plan features.
198
199**These settings alter access control behavior.** When seeding scenarios that test member vs. admin permissions, collection creation/deletion policies, or item-level access, set them explicitly in the preset rather than relying on defaults.
200
201**Configurable in presets and CLI.** Use the JSON preset `organization` block (e.g. `"limitCollectionCreation": true`) or the CLI flags: `--limit-collection-creation`, `--limit-collection-deletion`, `--limit-item-deletion`, `--allow-admin-collection-access`.
202
203## Security Reminders
204
205- Default test password: `asdfasdfasdf` (overridable via `--password` CLI flag or `SeederSettings`)
206- Never commit database dumps with seeded data
207- Seeded keys are for testing only
208
@@ −1 +1 @@
1−# Bitwarden Server - Claude Code Configuration
1+# Bitwarden Seeder Library - Claude Code Configuration
22
3−## Project Context Files
3+## Quick Reference
44
5−**Read these files before reviewing to ensure that you fully understand the project and contributing guidelines**
5+**For detailed pattern descriptions (Factories, Recipes, Models, Scenes, Queries, Data), read `README.md`.**
66
7−1. @README.md
8−2. @CONTRIBUTING.md
9−3. @.github/PULL_REQUEST_TEMPLATE.md
7+**For detailed usages of the Seeder library, read `util/SeederUtility/README.md` and `util/SeederApi/README.md`**
108
11−## Critical Rules
9+## Commands
1210
13−- **NEVER** use code regions: If complexity suggests regions, refactor for better readability
14−- **NEVER** compromise zero-knowledge principles: User vault data must remain encrypted and inaccessible to Bitwarden
15−- **NEVER** log or expose sensitive data: No PII, passwords, keys, or vault data in logs or error messages
16−- **ALWAYS** use secure communication channels: Enforce confidentiality, integrity, and authenticity
17−- **ALWAYS** encrypt sensitive data: All vault data must be encrypted at rest, in transit, and in use
18−- **ALWAYS** prioritize cryptographic integrity and data protection
19−- **ALWAYS** add unit tests (with mocking) for any new feature development
11+```bash
12+# Build
13+dotnet build util/Seeder/Seeder.csproj
2014
21−## Project Structure
15+# Run tests
16+dotnet test test/SeederApi.IntegrationTest/
2217
23−- **Source Code**: `/src/` - Services and core infrastructure
24−- **Tests**: `/test/` - Test logic aligning with the source structure, albeit with a `.Test` suffix
25−- **Utilities**: `/util/` - Migration tools, seeders, and setup scripts
26−- **Dev Tools**: `/dev/` - Local development helpers
27−- **Configuration**: `appsettings.{Environment}.json`, `/dev/secrets.json` for local development
18+# Run single test
19+dotnet test test/SeederApi.IntegrationTest/ --filter "FullyQualifiedName~TestMethodName"
20+```
2821
29−## Security Requirements
22+## Pattern Decision Tree
3023
31−- **Compliance**: SOC 2 Type II, SOC 3, HIPAA, ISO 27001, GDPR, CCPA
32−- **Principles**: Zero-knowledge, end-to-end encryption, secure defaults
33−- **Validation**: Input sanitization, parameterized queries, rate limiting
34−- **Logging**: Structured logs, no PII/sensitive data in logs
24+```
25+Need to create test data?
26+├─ ONE entity with encryption? → Factory
27+├─ ONE cipher from a SeedVaultItem? → CipherSeed.FromSeedItem() + {Type}CipherSeeder.Create()
28+├─ MANY entities as cohesive operation? → Recipe or Pipeline
29+├─ Flexible preset-based seeding? → Pipeline (RecipeBuilder + Steps)
30+├─ Complete test scenario with ID mangling? → Scene
31+├─ READ existing seeded data? → Query
32+└─ Data transformation plaintext ↔ encrypted? → Model
33+```
3534
36−## Common Commands
35+## Pipeline Architecture
3736
38−- **Build**: `dotnet build`
39−- **Test**: `dotnet test`
40−- **Run locally**: `dotnet run --project src/Api`
41−- **Database update**: `pwsh dev/migrate.ps1`
42−- **Generate OpenAPI**: `pwsh dev/generate_openapi_files.ps1`
37+**Modern pattern for composable fixture-based and generated seeding.**
4338
44−## Development Workflow
39+**Flow**: Preset JSON or Options → RecipeOrchestrator → RecipeBuilder → IStep/IAsyncStep[] → RecipeExecutor → SeederContext → BulkCommitter → IPostCommitStep[]
4540
46−- Security impact assessed
47−- xUnit tests added / updated
48−- Performance impact considered
49−- Error handling implemented
50−- Breaking changes documented
51−- CI passes: build, test, lint
52−- Feature flags considered for new features
53−- CODEOWNERS file respected
41+**Key actors**:
5442
55−### Key Architectural Decisions
43+- **RecipeBuilder**: Fluent API with dependency validation
44+- **IStep / IAsyncStep**: Isolated units of work (CreateOrganizationStep, CreateUsersStep, etc.). Use `IAsyncStep` for steps that do real I/O. A step additionally marked `IPostCommitStep` is deferred until after the bulk commit, so it observes committed rows — but sees cleared entity lists, since only the `EntityRegistry` and the context's scalar properties survive the commit.
45+- **SeederContext**: Shared mutable state bag (NOT thread-safe)
46+- **RecipeExecutor**: Awaits steps sequentially, captures statistics, commits via BulkCommitter, then runs any post-commit steps
47+- **RecipeOrchestrator**: Orchestrates recipe building and execution (from presets or options)
48+- **SeederDependencies** (`Options/`): Bundles infrastructure services (`DatabaseContext`, `IMapper`, `IPasswordHasher<User>`, `IManglerService`, `ILicensingService`, `IAttachmentStorageService`) into a single record. Recipes and the Orchestrator accept this instead of loose parameters. The CLI utility builds it via `SeederServiceFactory.Create().ToDependencies()`.
5649
57−- Use .NET nullable reference types (ADR 0024)
58−- TryAdd dependency injection pattern (ADR 0026)
59−- Authorization patterns (ADR 0022)
60−- OpenTelemetry for observability (ADR 0020)
61−- Log to standard output (ADR 0021)
50+**Why two step interfaces, not one async contract?** Deliberate — don't unify. Collapsing to one `Task ExecuteAsync(SeederContext)` costs: rewrite 22 step classes (18 in `Steps/`, 4 test doubles); force 20 `.Execute(context)` sites in `test/SeederApi.IntegrationTest/Steps/` to `await`, their test methods to `async`; and `TreatWarningsAsErrors` is on repo-wide (`Directory.Build.props`), so CS1998 makes `async` without `await` a build error — every sync step needs `return Task.CompletedTask`. Permanent trap. The split costs less: two-arm union in `OrderedStep`, `object`-typed `Inner`, one duplicated `RecipeBuilder` registration. Diverges from `IScene`/`IQuery` — single `Task`-returning, no sync twin.
6251
63−## References
52+**Fixture/preset separation**: Fixtures (organizations, rosters, ciphers) are independent and never reference each other. The preset is the only layer that composes fixtures and defines cross-cutting relationships (folder assignments, favorites). See `Seeds/docs/architecture.md`.
6453
65−- [Server architecture](https://contributing.bitwarden.com/architecture/server/)
66−- [Architectural Decision Records (ADRs)](https://contributing.bitwarden.com/architecture/adr/)
67−- [Contributing guidelines](https://contributing.bitwarden.com/contributing/)
68−- [Setup guide](https://contributing.bitwarden.com/getting-started/server/guide/)
69−- [Code style](https://contributing.bitwarden.com/contributing/code-style/)
70−- [Bitwarden security whitepaper](https://bitwarden.com/help/bitwarden-security-white-paper/)
71−- [Bitwarden security definitions](https://contributing.bitwarden.com/architecture/security/definitions)
54+**Phase order (org presets)**: Org → OrgApiKey → Roster → Owner (conditional) → Generator (conditional) → Users → Groups → Collections → Folders → Ciphers → CipherAttachments → CipherCollections → CipherFolders → CipherFavorites → PersonalCiphers
55+**Phase order (individual presets)**: IndividualUser → NamedFolders → Generator → Folders → Ciphers → CipherAttachments → FolderAssignments → FavoriteAssignments
56+
57+**Individual user presets** use the Pipeline with `CreateIndividualUserStep` (no org, no groups, no collections). These presets live in `Seeds/fixtures/presets/individual/` and are identified by having a `"user"` key instead of `"organization"`. They support `folderNames`, `folderAssignments`, and `favoriteAssignments` for fixture-driven personal vault organization. See `Seeds/docs/presets.md` for the catalog.
58+
59+See `Pipeline/` folder for implementation.
60+
61+## Parallelism
62+
63+Steps execute sequentially (phase order preserved by RecipeExecutor). Async steps are awaited one at a time and MUST NOT be batched with `Task.WhenAll` — `SeederContext` is not thread-safe and each step reads state written by the ones before it. Within a step, `CreateUsersStep` and `GeneratePersonalCiphersStep` use `Parallel.For` internally for CPU-bound Rust FFI work (key generation, encryption).
64+
65+**Thread-safety requirements:**
66+
67+- `GeneratorContext` lazy properties (`??=`) must be force-initialized before any `Parallel.For` loop to prevent a data race
68+- Generators use `ThreadLocal<Faker>` for thread-safe deterministic data generation
69+- `ManglerService` and `SeederContext` are NOT thread-safe -- pre-compute their outputs before entering parallel loops
70+
71+## Performance A/B Testing
72+
73+When measuring step-level performance changes, use paired worktrees:
74+
75+- Create `server-PM-XXXXX/perf-baseline` and `server-PM-XXXXX/perf-optimized` worktrees
76+- Both worktrees get `Stopwatch` timing in `RecipeExecutor.ExecuteAsync()` (the baseline measurement)
77+- Only the optimized worktree gets actual code changes
78+- Run presets with `--mangle` flag to avoid DB collisions between runs
79+- Compare per-step timings across 3+ runs each, discard the first run (JIT warmup)
80+- `.worktrees/` is already in `.gitignore`
81+
82+## Density Profiles
83+
84+Steps accept an optional `DensityProfile` that controls relationship patterns between users, groups, collections, and ciphers. When null, steps use the original round-robin behavior. When present, steps branch into density-aware algorithms.
85+
86+**Key files**:
87+
88+- `Options/DensityProfile.cs` — strongly-typed options (public class)
89+- `Models/SeedPresetDensity.cs` — JSON preset deserialization targets (internal records)
90+- `Data/Enums/MembershipDistributionShape.cs` — Uniform, PowerLaw, MegaGroup
91+- `Data/Enums/CollectionFanOutShape.cs` — Uniform, PowerLaw, FrontLoaded
92+- `Data/Enums/CipherCollectionSkew.cs` — Uniform, HeavyRight
93+- `Data/Distributions/PermissionDistributions.cs` — 11 named distributions by org tier
94+
95+**Backward compatibility contract**: `DensityProfile? == null` MUST produce identical output to the original code. Every step guards this with `if (_density == null) { /* original path */ }`.
96+
97+**Preset JSON**: Add an optional `"density": { ... }` block. See `Seeds/schemas/preset.schema.json` for the full schema.
98+
99+**Presets**: Organized into `features/`, `qa/`, `scale/`, `validation/` folders under `Seeds/fixtures/presets/`. See `Seeds/docs/presets.md` for the full catalog.
100+
101+**Verification**: SQL queries for validating density algorithms are in `Seeds/docs/verification.md`.
102+
103+## Data/ File Organization
104+
105+New files under `Data/` belong in the matching subfolder (`Distributions/`, `Enums/`, `Generators/`, `Static/`) — never loose at the top level. See `Data/README.md` for what each subfolder holds. If a new file's concern doesn't fit an existing subfolder, that's a signal to create one, not to drop it loose.
106+
107+**Two Enums homes, by concern:** `Data/Enums/` (namespace `Bit.Seeder.Data.Enums`) holds the generation-config surface (`CompanyType`, `PasswordStrength`, distribution shapes, etc. — "Enums are the API"). Crypto-taxonomy enums that describe how seeded vault data is encrypted (`CipherEncryptionType`, `AttachmentSchemeType`) live in the top-level `Enums/` folder (namespace `Bit.Seeder.Enums`), one enum per file.
108+
109+## The Recipe Contract
110+
111+Recipes follow strict rules:
112+
113+1. A Recipe SHALL accept `SeederDependencies` as its single constructor parameter
114+2. A Recipe SHALL have exactly one public entry point — `Seed()` when synchronous, `SeedAsync()` when it returns `Task`/`Task<T>`. Pipeline-backed Recipes (`OrganizationRecipe`, `IndividualUserRecipe`) are async; the direct-to-database Recipes (`CollectionsRecipe`, `GroupsRecipe`, `OrganizationDomainRecipe`, `OrganizationWithUsersRecipe`) remain synchronous.
115+3. A Recipe MUST produce one cohesive result
116+4. A Recipe MAY overload that entry point with different parameters
117+5. A Recipe SHALL use private helper methods for internal steps
118+6. A Recipe SHALL use BulkCopy for performance when creating multiple entities
119+7. A Recipe SHALL compose Factories for individual entity creation
120+8. A Recipe SHALL NOT expose implementation details as public methods
121+
122+## Zero-Knowledge Architecture
123+
124+**Critical:** Unencrypted vault data never leaves the client. The server never sees plaintext.
125+
126+The Seeder uses the Rust SDK via FFI because it must behave like a real Bitwarden client:
127+
128+1. Generate encryption keys (like client account setup)
129+2. Encrypt vault data client-side (same SDK as real clients)
130+3. Store only encrypted result
131+
132+## Data Flow
133+
134+### Pipeline path (fixture → entity)
135+
136+```
137+SeedVaultItem → CipherSeed.FromSeedItem() → CipherSeed → {Type}CipherSeeder.Create(options) → CipherViewDto → encrypt_fields (Rust FFI) → EncryptedCipherDto → EncryptedCipherDtoExtensions → Server Cipher Entity
138+```
139+
140+### Core encryption (shared by all paths)
141+
142+```
143+CipherViewDto → JSON + [EncryptProperty] field paths → encrypt_fields (Rust FFI, bitwarden_crypto) → EncryptedCipherDto → EncryptedCipherDtoExtensions → Server Cipher Entity
144+```
145+
146+Shared logic: `Factories/CipherEncryption.cs`, `Models/EncryptedCipherDtoExtensions.cs`
147+
148+## Rust Crypto Dependency
149+
150+The Rust shim (`util/RustSdk/rust/`) depends only on `bitwarden_crypto`. It does **not** depend on `bitwarden_vault` — the seeder drives field selection via `[EncryptProperty]` attributes, not SDK cipher types.
151+
152+Before modifying encryption integration, run `RustSdkCipherTests` to validate roundtrip encryption.
153+
154+## Encryption Schemes (crypto taxonomy)
155+
156+Seeded data spans two orthogonal encryption axes, named with Bitwarden's canonical vocabulary (defined in `Enums/CipherEncryptionType.cs` and `Enums/AttachmentSchemeType.cs`):
157+
158+- **Cipher encryption** (`cipherEncryption`): `userKey` (no cipher key; `Cipher.Key` null) or `cipherKey` (per-cipher key wrapped by the vault key).
159+- **Attachment scheme version** (`attachmentVersion`): `v0` (no attachment key), `v1` (attachment key wrapped by the vault key), `v2` (attachment key wrapped by the cipher key).
160+
161+**Invariant:** a cipher and its attachments use the same strategy — `v2` requires a `cipherKey` host. `Steps/CreateCipherAttachmentsStep.cs` and `Seeds/schemas/cipher.schema.json` both enforce this; keep them in sync.
162+
163+**Wire mapping:** `AttachmentSchemeType.{V0,V1,V2}` casts to `u32 {0,1,2}` and is matched verbatim in `util/RustSdk/rust/src/attachment.rs`. The value *is* the version number — do not reintroduce an offset.
164+
165+**Do not conflate with account Encryption V1/V2.** Attachment `v0/v1/v2` is key-wrapping only. Everything the seeder emits is Encryption-V1 type-2 `EncString` (AES-256-CBC-HMAC); no COSE/type-7 path exists. A future V2/COSE capability is a **separate** axis (a new enum), never a new attachment version.
166+
167+## Deterministic Data Generation
168+
169+Same domain = same seed = reproducible data:
170+
171+```csharp
172+var seed = options.Seed ?? DeriveStableSeed(options.Domain);
173+```
174+
175+## Scenarios
176+
177+Developer-facing documentation in `Seeds/docs/scenarios/`. Each file maps an engineering problem to a Seeder command.
178+
179+**Maintenance rules:**
180+
181+- When adding a new preset, check if an existing scenario should reference it as a variation
182+- When adding a new command or flag, check if it enables a new scenario or changes an existing one
183+- When CLI flags, commands, or preset names change, scan all `*.md` files under `Seeds/` and `SeederUtility/` for stale references
184+- Scenario files follow the template in `Seeds/docs/scenarios/README.md`
185+- Never duplicate CLI flag documentation — link to `SeederUtility/README.md`
186+- Never duplicate preset catalog details — link to `Seeds/docs/presets.md`
187+- Scenarios describe _why_ (the problem). READMEs describe _how_ (the tool). Keep the split clean.
188+
189+**File relationships:**
190+
191+- `SeederUtility/README.md` → CLI reference (commands, flags, examples) → links to scenarios
192+- `Seeds/docs/presets.md` → what exists (the catalog) → scenarios link back to it
193+- `Seeds/docs/scenarios/` → why you'd use it (problem → command)
194+
195+## Collection Management Settings
196+
197+**Collection management settings are not plan-gated.** `AllowAdminAccessToAllCollectionItems`, `LimitCollectionCreation`, `LimitCollectionDeletion`, and `LimitItemDeletion` apply identically across all plan types. They are org-level admin settings, not billing-plan features.
198+
199+**These settings alter access control behavior.** When seeding scenarios that test member vs. admin permissions, collection creation/deletion policies, or item-level access, set them explicitly in the preset rather than relying on defaults.
200+
201+**Configurable in presets and CLI.** Use the JSON preset `organization` block (e.g. `"limitCollectionCreation": true`) or the CLI flags: `--limit-collection-creation`, `--limit-collection-deletion`, `--limit-item-deletion`, `--allow-admin-collection-access`.
202+
203+## Security Reminders
204+
205+- Default test password: `asdfasdfasdf` (overridable via `--password` CLI flag or `SeederSettings`)
206+- Never commit database dumps with seeded data
207+- Seeded keys are for testing only
72208
