Skip to content

Commit 6d15aec

Browse files
committed
Apply /review-areas -all feedback to AGENTS.md docs
1 parent 29b103e commit 6d15aec

8 files changed

Lines changed: 9 additions & 8 deletions

File tree

.claude/agents/search-reviewer.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Read `src/MongoDB.Driver/Search/AGENTS.md` first; then root `AGENTS.md` for buil
1616
- `$search` / `$vectorSearch` must be the first stage — server-enforced; we don't validate, but we shouldn't generate later-stage variants.
1717
- Compound clauses (`must`, `mustNot`, `should`, `filter`) — semantics on score and inclusion are subtly different; preserve them.
1818
- Vector search tuning — `NumberOfCandidates` >> `Limit` for ANN; ignored when `Exact = true`.
19-
- `QueryVector` types — constructed via constructors / implicit conversions from `double[]` / `float[]` / `int[]` / `ReadOnlyMemory<double|float|int>` (raw numeric embeddings), `BinaryVectorInt8` / `BinaryVectorFloat32` / `BinaryVectorPackedBit` (typed BinaryVector encodings), `string` (auto-embedding flow only), or `BsonBinaryData`; there are no `.Embedded(...)` / `.BinaryVector(...)` factory methods.
19+
- `QueryVector` types — most input shapes have both an explicit constructor and an implicit conversion: `double[]` / `float[]` / `int[]` / `ReadOnlyMemory<double|float|int>` (raw numeric embeddings), `BinaryVectorInt8` / `BinaryVectorFloat32` / `BinaryVectorPackedBit` (typed BinaryVector encodings), and `string` (auto-embedding flow only). The one exception is `BsonBinaryData`, which is **constructor-only**there is no implicit conversion. There are no `.Embedded(...)` / `.BinaryVector(...)` factory methods.
2020
- `UseConfiguredSerializers` — extension method on `SearchDefinition<T>` that downcasts to `OperatorSearchDefinition<T>` (throws `NotSupportedException` otherwise); in practice meaningful on value-comparing operators (Equals/In/Range). **Default is `true`** (registered serializers honored, e.g. enum-as-string). Affects custom-enum representation; flipping the default to `false` is a breaking change.
2121
- Index helpers — `CreateSearchIndexModel`, plus the vector-search family rooted at the abstract `CreateVectorSearchIndexModelBase<TDocument>` with concrete `CreateVectorSearchIndexModel<TDocument>` and `CreateAutoEmbeddingVectorSearchIndexModel<TDocument>`. Coordinate with builders-reviewer.
2222
- All tests gated by `ATLAS_SEARCH_TESTS_ENABLED` and `ATLAS_SEARCH_URI`. Index-helper tests additionally need `ATLAS_SEARCH_INDEX_HELPERS_TESTS_ENABLED`.

src/MongoDB.Bson/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ This is where most newcomer mistakes live.
4545
- **`BsonClassMap`** auto-maps on first use of a CLR type. After the map is **frozen** (automatically on first serialize, or via `Freeze()`), mutation throws. The classic bug is calling `BsonClassMap.RegisterClassMap<T>(...)` after a `T` has already been auto-mapped — you must register **before** the type is first serialized.
4646
- **`BsonMemberMap`** controls element name, default value, ignore-if-null/default, BSON representation, and per-member custom serializer.
4747
- **Conventions.** `ConventionRegistry` maps a `Type` (or filter predicate) to a `IConventionPack` — an ordered list of conventions applied during auto-mapping by `ConventionRunner` (see `Serialization/Conventions/ConventionRunner.cs`). The `__defaults__` and `__attributes__` packs are registered separately and merged by `ConventionRegistry.Lookup` into one ordered combined pack returned to the runner. The default packs (see `ConventionRegistry.cs` and `DefaultConventionPack`) put the attribute conventions **last** in that combined order, so attributes win any conflict — it's an ordering effect within the merged pack, not "conventions first, then attributes." Register custom packs (with a filter and name) once at startup, before any serialization. Note: `ConventionRegistry` synchronizes its merge with a private `lock (__lock)` rather than going through `BsonSerializer.ConfigLock` (see the threading section below); registration paths in the two areas are coordinated by their own locks, not a single global lock.
48-
- **Attributes.** `[BsonElement]`, `[BsonIgnore]`, `[BsonRepresentation]`, `[BsonDefaultValue]`, `[BsonId]`, `[BsonExtraElements]`, `[BsonDiscriminator]`, `[BsonGuidRepresentation]` (the actual attribute type is `BsonGuidRepresentationAttribute` in `Serialization/Attributes/`; sets per-property GUID representation and overrides any class-level or serializer-level setting — there is no global mode any more, see below). Bind at class-map freeze time.
48+
- **Attributes.** `[BsonElement]`, `[BsonIgnore]`, `[BsonRepresentation]`, `[BsonDefaultValue]`, `[BsonId]`, `[BsonExtraElements]`, `[BsonDiscriminator]`, `[BsonGuidRepresentation]` (the actual attribute type is `BsonGuidRepresentationAttribute` in `Serialization/Attributes/`; sets per-property GUID representation and overrides any class-level or serializer-level setting — there is no global mode any more, see below). This list is illustrative, not exhaustive — see `Serialization/Attributes/` for the full set (e.g. `[BsonRequired]`, `[BsonIgnoreIfDefault]`, `[BsonIgnoreIfNull]`, `[BsonDateTimeOptions]`, `[BsonTimeSpanOptions]`, `[BsonNoId]`, `[BsonConstructor]`, `[BsonFactoryMethod]`, `[BinaryVector]`). Bind at class-map freeze time.
4949
- **Polymorphism.** Discriminators land in the `_t` field by default. Use `[BsonDiscriminator(RootClass = true, Required = true)]` on the abstract base, and `[BsonKnownTypes(typeof(SubA), typeof(SubB))]` to make the subtypes register on first lookup. Without knowing about a concrete type, the deserializer can't materialize it. **Security:** when deserializing untrusted BSON into open polymorphic types, an attacker-controlled `_t` value can drive instantiation of any registered known type. `[BsonKnownTypes]` is one path that pre-registers concrete subtypes; the other is `DiscriminatedInterfaceSerializationProvider`, which resolves an interface-typed member to a concrete subtype based on the wire `_t` value at deserialization time — both ride on the same discriminator lookup, and both should be limited to subtypes you actually intend to accept.
5050
- **`[BsonExtraElements]`** is the forward-compat escape hatch: a `Dictionary<string, object>` (or `BsonDocument`) member that absorbs unknown fields. Without it, schema evolution on the server side breaks the client immediately.
5151

src/MongoDB.Driver/AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ User-facing facades, fluent APIs, builders, and option/result records. The Opera
3232
## Client facades & settings
3333

3434
- `MongoClient.cs` / `IMongoClient.cs` — top-level entry. Constructors: parameterless (defaults to `mongodb://localhost`), or one accepting `MongoClientSettings`, `MongoUrl`, or a connection string. Holds the cluster reference; `Dispose()` shuts down connections.
35-
- `IMongoDatabase.cs` / `MongoDatabase.cs`, `IMongoCollection.cs` / `MongoCollectionImpl.cs` (collection generic in `TDocument`) — derived from the client; carry their own settings (read/write concern, read preference, serializer registry). The public abstractions are the interfaces `IMongoDatabase` and `IMongoCollection<TDocument>`; `MongoDatabase`, `MongoCollectionBase<TDocument>`, and `MongoCollectionImpl<TDocument>` are all `internal`.
35+
- `IMongoDatabase.cs` / `MongoDatabase.cs`, `IMongoCollection.cs` / `MongoCollectionImpl.cs` (defining `MongoCollectionImpl<TDocument>`) — derived from the client; carry their own settings (read/write concern, read preference, serializer registry). The public abstractions are the interfaces `IMongoDatabase` and `IMongoCollection<TDocument>`; `MongoDatabase`, `MongoCollectionBase<TDocument>`, and `MongoCollectionImpl<TDocument>` are all `internal`.
3636
- Settings types — `MongoClientSettings`, `MongoDatabaseSettings`, `MongoCollectionSettings`, `SslSettings`, `MongoUrl`, `MongoUrlBuilder`, `MongoServerAddress`, `MongoCredential` (and identity subtypes), `AutoEncryptionOptions`, `ClusterKey`. (`ServerApi` is part of the same surface — surfaced via `MongoClientSettings.ServerApi` — but the type lives at `Core/ServerApi.cs`, not at the driver root.) **`MongoUrl` vs `MongoUrlBuilder`:** `MongoUrl` is immutable (parsed from a connection string, exposes only getters and a `ToString()` round-trip); `MongoUrlBuilder` is the mutable builder counterpart used to assemble or mutate a connection string before calling `ToMongoUrl()` for the immutable form.
3737

3838
**Settings freeze invariant.** All `*Settings` types are mutable until `Freeze()` is called. The driver freezes settings when they're passed into a client/database/collection. After that, mutation throws. Treat settings as immutable once handed to the framework — clone before mutating.
@@ -98,7 +98,7 @@ The change-stream pipeline input type is `ChangeStreamDocument<BsonDocument>` fo
9898

9999
- `IFindFluent<TDocument,TProjection>` / `FindFluentBase<TDocument,TProjection>` (public abstract) / `FindFluent<TDocument,TProjection>` (`internal`) — chain Skip/Limit/Sort/Project/etc.
100100
- `FindOptions<TDocument,TProjection>`, `FindOneAndUpdateOptions`, `FindOneAndDeleteOptions`, `FindOneAndReplaceOptions`.
101-
- `Count` is `[Obsolete]` on `IFindFluent` — use `CountDocuments` on the fluent surface. (`EstimatedDocumentCount` lives on `IMongoCollection<T>`, not on the find-fluent surface.) Per the SemVer rules in **Public-API change discipline** below, removing the obsolete `Count` requires a major-version bump even though it has carried `[Obsolete]` for a release cycle.
101+
- `Count` is `[Obsolete]` on `IFindFluent` — use `CountDocuments` on the fluent surface. (`EstimatedDocumentCount` lives on `IMongoCollection<T>`, not on the find-fluent surface.) Per the SemVer rules in **Public-API change discipline** below, removing the obsolete `Count` requires a major-version bump even though it has carried `[Obsolete]` for several release cycles.
102102

103103
## Bulk write — two layers
104104

src/MongoDB.Driver/Core/AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ This file covers the **Server Discovery And Monitoring (SDAM)** topology layer,
4242
- `PriorityServerSelector``[Obsolete]`. The public, legacy form of the deprioritization filter: a standalone `public sealed` selector that takes a `deprioritizedServers` collection and removes those endpoints from the candidate set on sharded clusters. The internal replacement is `DeprioritizedServersServerSelector` (an `internal sealed` *composing* selector that wraps another `IServerSelector` and filters its output). Neither is related to replica-set priorities; `PriorityServerSelector` is slated for removal in a future release.
4343
- `OperationsCountServerSelector` — load-balances by operation count (for load-balanced deployments).
4444
- `RandomServerSelector` — random tie-breaker when multiple servers are equally good.
45+
- `DelegateServerSelector` — wraps an arbitrary `Func<…>` for ad-hoc selection logic (rarely used in production code; useful for tests and bespoke deployments).
4546

4647
**Selection flow:** `SelectServer(selector, timeout)` blocks until a suitable server is found or timeout expires. Internally it waits on the cluster's `DescriptionChanged` event (via an internal `TaskCompletionSource`) and re-runs the selector each time topology changes. (The `MaxServerSelectionWaitQueueSize` setting on `ClusterSettings` bounds the number of waiters, but there is no public `ServerSelectionWaitQueue` type.)
4748

src/MongoDB.Driver/Core/Operations/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The execution layer between the public driver surface and the wire. Every public
1111

1212
## Operation hierarchy
1313

14-
Two operation interfaces defined in `Core/Operations/IOperation.cs` (both `internal`; no shared `IOperation` base type exists):
14+
Two operation interfaces defined in `Core/Operations/IOperation.cs` (both `internal`; the file is named `IOperation.cs` but contains only the two interfaces below — there is no shared `IOperation` base type):
1515

1616
- `IReadOperation<TResult>``Execute(OperationContext, IReadBinding)` + `ExecuteAsync(...)`. Returns `TResult` (often `IAsyncCursor<T>`).
1717
- `IWriteOperation<TResult>``Execute(OperationContext, IWriteBinding)` + `ExecuteAsync(...)`.

src/MongoDB.Driver/GridFS/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ GridFS stores binary files in two collections per bucket: `<bucket>.files` (meta
2323

2424
Indexes (`{filename:1, uploadDate:1}` on `.files`, `{files_id:1, n:1}` unique on `.chunks`) are created lazily on the first upload **only if the files collection is empty** (via an `IsFilesCollectionEmpty` check). The check is guarded by a `bool` flag (`_ensureIndexesDone`, the one-shot marker) plus a `SemaphoreSlim` (`_ensureIndexesSemaphore`, which serializes concurrent first-upload callers). Subsequent uploads short-circuit on the flag.
2525

26-
`Delete` removes the `.files` document first (the underlying `DeleteRequest` constructor sets `Limit=1`, so at most one `.files` document is matched), then — after that `.files` delete returns (whether it matched anything or not) — unconditionally removes any matching chunks. There is no `try/catch` around either call: an exception from the `.files` delete simply propagates and the chunks delete never runs. After both calls succeed, if the `.files` deletion matched zero documents, `GridFSFileNotFoundException` is thrown. Orphan chunks can still result from any interruption between the two operations — a network error during the chunks delete, but equally a process crash after the `.files` delete succeeds and before the chunks call is issued. `Drop` is the only safe full cleanup.
26+
`Delete` removes the `.files` document first (GridFS calls `new DeleteRequest(filter)` with no explicit `Limit`; the `DeleteRequest` constructor's default `Limit=1` is what caps the match to a single `.files` document — there is no `Limit = 1` literal in the GridFS code itself), then — after that `.files` delete returns (whether it matched anything or not) — unconditionally removes any matching chunks. There is no `try/catch` around either call: an exception from the `.files` delete simply propagates and the chunks delete never runs. After both calls succeed, if the `.files` deletion matched zero documents, `GridFSFileNotFoundException` is thrown. Orphan chunks can still result from any interruption between the two operations — a network error during the chunks delete, but equally a process crash after the `.files` delete succeeds and before the chunks call is issued. `Drop` is the only safe full cleanup.
2727

2828
There is no GridFS-specific JSON spec runner in this repo at present (no `tests/MongoDB.Driver.Tests/Specifications/gridfs/` directory). GridFS coverage lives in the regular xUnit tests under `tests/MongoDB.Driver.Tests/GridFS/`, plus the JSON-driven runners pulled in by other specs: `tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenGridFs*.cs` and `tests/MongoDB.Driver.Tests/UnifiedTestOperations/UnifiedGridFs*Operation.cs` exercise GridFS as part of the unified / JSON-driven runners used by transactions, retryable reads/writes, etc.
2929

src/MongoDB.Driver/Linq/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ And the file most translator work touches (a single class, not a directory): **`
6060

6161
1. Add a `MethodInfo` constant in `Reflection/<Family>Method.cs``EnumerableMethod`/`QueryableMethod` for BCL methods, `MongoQueryableMethod`/`MongoEnumerableMethod`/`LinqExtensionsMethod`/`MqlMethod` for driver-only methods.
6262
2. For **expression-level** operators (used inside lambdas, e.g. `Select`, `Where`): create a translator in `Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/<NewMethod>MethodToAggregationExpressionTranslator.cs` (the `MethodToAggregationExpressionTranslator` suffix is the established convention — match it so the dispatcher's grep-by-name search finds it). **Then add a `case "<MethodName>": return …` branch in the `switch (expression.Method.Name)` block in `MethodCallExpressionToAggregationExpressionTranslator` — this dispatcher edit is required; without it the method is unreachable.** (That guidance reflects the dispatcher's current `switch`-on-name shape; if a future refactor converts it to a dictionary lookup or attribute-based registration, check the file before assuming this exact step still applies.) The per-method translator body should follow an existing method's pattern, but that's about body shape, not about whether you need the dispatch edit. The top-level dispatch is by method *name*; the per-method translators then verify the `MethodInfo` matches the canonical constants from `Reflection/`.
63-
3. For **pipeline-level** operators (top-level LINQ methods like `Where`, `GroupBy`, `Skip`): create a translator under `ExpressionToPipelineTranslators/` instead and register it in the pipeline-level dispatcher `ExpressionToPipelineTranslator.Translate` (the `switch (expression.Method.Name)` block at the top of that file).
63+
3. For **pipeline-level** operators (top-level LINQ methods like `Where`, `GroupBy`, `Skip`): create a translator under `ExpressionToPipelineTranslators/` instead and register it in the pipeline-level dispatcher `ExpressionToPipelineTranslator.Translate` (the `switch` on `Method.Name` at the top of that file).
6464
4. Add a Jira-style integration test under `tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/` asserting the rendered pipeline.
6565

6666
## Custom serializers in projections

src/MongoDB.Driver/Search/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Key types:
3535

3636
- `QueryVector` — note this type lives at the driver root (`src/MongoDB.Driver/QueryVector.cs`), not under `Search/`. Two ways in:
3737
- **Implicit conversions** (common case): from `double[]` / `float[]` / `int[]` / `ReadOnlyMemory<double|float|int>` for raw numeric embeddings, from `BinaryVectorInt8` / `BinaryVectorFloat32` / `BinaryVectorPackedBit` for the typed BinaryVector encodings, or from `string` for Atlas auto-embedding.
38-
- **Explicit constructors** mirroring most of the above, plus one with **no** implicit counterpart: a `BsonBinaryData` ctor (must be called explicitly), a `string` ctor for auto-embedding, and three `ReadOnlyMemory<double|float|int>` ctors that back the `ReadOnlyMemory` implicit conversions and are also directly callable.
38+
- **Explicit constructors** mirroring most of the above (the `string` ctor for auto-embedding and three `ReadOnlyMemory<double|float|int>` ctors that back the `ReadOnlyMemory` implicit conversions are also directly callable). The one ctor with **no** implicit counterpart is `BsonBinaryData` — it must be called explicitly.
3939

4040
See `src/MongoDB.Driver/QueryVector.cs` for the authoritative constructor list.
4141
- `VectorSearchOptions<TDocument>` — for the **top-level** `IAggregateFluent<T>.VectorSearch` stage. Carries `Filter` (a `FilterDefinition<TDocument>` pre-filter), `NestedFilter`, `NumberOfCandidates` (search-set size for ANN), `Exact` (true → ENN, ignores candidates), plus auto-embedding-related fields `IndexName`, `AutoEmbeddingModelName`, `ReturnStoredSource`, and `EmbeddedScoreMode`. The compound-embedded form (`Builders<T>.Search.VectorSearch`) takes the related but distinct `VectorSearchOperatorOptions<TDocument>` — don't conflate them. `VectorSearchOperatorOptions<TDocument>` has a deliberately smaller surface (it omits the auto-embedding fields and `EmbeddedScoreMode` that only make sense at the top-level stage); reach for it only inside a compound query.

0 commit comments

Comments
 (0)