Implements the mongodb-superpowers-package design: Stable Tasks 1-50 and Advanced Tasks 1-15. The design assumes 19 Stable + 12 Advanced Gradle projects under modules/mongodb*. This repository's fail-closed registry declares exactly 19 leaf identities, so those modules become package boundaries inside the registered leaf :adapter:outbound:persistence-mongo, with the design's module dependency table enforced by ten ArchUnit rules. The mapping and every deviation are recorded in docs/mongodb/repository-adaptation.md. Contract highlights, all enforced by tests rather than convention: - Transaction body retry and commit retry are separate loops. A new session per body attempt; commit-only retry on an unknown commit. The body is never replayed after a commit ambiguity, so a failover cannot become a duplicate. - MongoExecutionOutcome keeps both ambiguous outcomes distinct from success and failure, and MongoFailureContext records only the design-permitted fields. - Failure classification reads server error labels before numeric codes. - BSON representations come from a pinned manifest, never a library default, and a golden type-signature gate fails on any drift. - Index and validator changes go through the manifest and the admin plane; metadata ownership gates every drop. - Every Advanced capability refuses construction unless its flag is enabled. Verified against real servers, not only unit tests. Running the lanes for the first time exposed four defects that a green `check` had hidden: - Four release lanes passed while executing zero tests; the gate now counts executed tests per lane and fails on zero. - The "single replica set" fixture was a standalone, because Testcontainers 2.x needs withReplicaSet(); its test only asserted a connection string. - The three-node fixture was three independent clusters, so no election could occur, and awaitNewPrimary() compared against the post-stop primary. - The migration lease checked modifiedCount, so a same-millisecond refresh read as a lost lease. scripts/verify-mongodb-platform.sh now reports: 9 lanes, 0 skipped, 0 failed, every evidence category produced. scripts/verify-mongodb-advanced.sh reports NOT PROMOTABLE: actual-topology evidence (real sharded cluster, real KMS, real target deployment) is unobtainable here, so it is named rather than assumed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
9.3 KiB
MongoDB Document Persistence Platform — Repository Adaptation Contract
Design source: mongodb-superpowers-package/docs/superpowers/specs/2026-08-11-mongodb-document-persistence-platform-design.md
Stable plan: mongodb-superpowers-package/docs/superpowers/plans/2026-08-11-mongodb-document-persistence-platform-implementation-plan.md
Advanced plan: mongodb-superpowers-package/docs/superpowers/plans/2026-08-11-mongodb-advanced-capabilities-expansion-plan.md
The design package declares its own module root (modules/mongodb) and root package
(io.backend.skeleton.mongodb) as implementation assumptions, not as contract. This file is the
single record of how that assumed layout was mapped onto this repository. Only paths, build DSL,
and composition-root ownership changed. Public contracts, policy order, and error semantics are
implemented exactly as specified.
1. Why the module layout differs
The design assumes 19 Stable Gradle projects under modules/mongodb/ and 12 Advanced projects
under modules/mongodb-advanced/. This repository is a Clean Architecture template whose
fail-closed registry (src/config/architecture/modules.json, enforced by src/settings.gradle
and verifyCleanArchitectureDependencies) declares exactly 19 leaf identities. Creating 31 more
Gradle projects would violate HARD-STOP #5 in AGENTS.md.
Therefore the design's 31 modules become package boundaries inside the registered leaf
:adapter:outbound:persistence-mongo, following the precedent already set by
docs/httpclient/repository-adaptation.md. The design's
module dependency table (§6.3) is reproduced as ten ArchUnit rules in MongoModuleBoundaryTest, so
a forbidden edge fails the build the same way a missing Gradle dependency would.
2. Package mapping
Root package: io.backend.skeleton.mongodb → dev.caskeleton.adapter.outbound.mongo.
2.1 Stable modules
| Design module | Repository package |
|---|---|
mongodb-core-api |
…outbound.mongo.api (+ .capability, .consistency, .error, .mapping, .observation, .profile, .schema) |
mongodb-spring-data |
…outbound.mongo.mapping (+ .type), …outbound.mongo.failure |
mongodb-imperative |
…outbound.mongo.imperative (+ .atomic, .bulk, .revision) |
mongodb-reactive |
…outbound.mongo.reactive (+ .cursor) |
mongodb-query |
…outbound.mongo.query (+ .budget, .pagination) |
mongodb-aggregation |
…outbound.mongo.aggregation |
mongodb-transaction |
…outbound.mongo.transaction (+ .retry, .session) |
mongodb-index-schema |
…outbound.mongo.schema (+ .index, .manifest, .model, .ttl, .validation) |
mongodb-change-stream |
…outbound.mongo.changestream (+ .projector, .recovery) |
mongodb-geospatial |
…outbound.mongo.geo |
mongodb-migration-core |
…outbound.mongo.migration |
mongodb-migration-flamingock |
…outbound.mongo.migration.flamingock |
mongodb-observability |
…outbound.mongo.observation |
mongodb-security |
…outbound.mongo.security (+ .admin), …outbound.mongo.nativecap |
mongodb-spring-boot-starter |
…outbound.mongo.autoconfigure |
mongodb-testkit-core |
…outbound.mongo.testkit.mapping, .compat, .performance (testkit source set) |
mongodb-testkit-replicaset |
…outbound.mongo.testkit.rs (testkit source set) |
mongodb-testkit-failover |
…outbound.mongo.testkit.failover (testkit source set) |
mongodb-testkit-migration |
…outbound.mongo.testkit.migration (testkit source set) |
…outbound.mongo.architecture has no design counterpart: it holds the @MongoOperation marker and
the reusable ArchUnit rule set a fork applies to its own document/repository code.
2.2 Advanced modules
| Design module | Repository package |
|---|---|
mongodb-sharding |
…outbound.mongo.advanced.sharding (+ .admin for the D4 shard plane) |
mongodb-timeseries |
…outbound.mongo.advanced.timeseries |
mongodb-csfle |
…outbound.mongo.advanced.encryption.csfle |
mongodb-queryable-encryption |
…outbound.mongo.advanced.encryption.qe |
mongodb-search |
…outbound.mongo.advanced.search |
mongodb-vector-search |
…outbound.mongo.advanced.vector |
mongodb-tenancy-shared |
…outbound.mongo.advanced.tenancy.shared |
mongodb-tenancy-database |
…outbound.mongo.advanced.tenancy.database |
mongodb-change-stream-messaging-bridge |
…outbound.mongo.advanced.bridge |
mongodb-gridfs-compat |
…outbound.mongo.advanced.gridfs |
mongodb-testkit-sharded |
…outbound.mongo.testkit.sharded (testkit source set) |
mongodb-testkit-atlas |
…outbound.mongo.testkit.atlas (testkit source set) |
The design's rule that a Stable module never depends on an Advanced one survives as an ArchUnit rule
(stableNeverDependsOnAdvanced) plus the opt-in flag: every Advanced entry point requires
MongoAdvancedCapabilityFlags to have the matching capability enabled and refuses construction
otherwise. Being on the classpath is not being enabled.
3. Other deliberate substitutions
| Design assumption | Repository reality | Adaptation |
|---|---|---|
Gradle Kotlin DSL under modules/mongodb* |
Groovy DSL, root build.gradle conventions, LockMode.STRICT locking |
Dependencies declared in src/adapter/outbound/persistence-mongo/build.gradle; gradle.lockfile regenerated. |
mongodb-spring-boot-starter is a separate module the app depends on |
modules.json gives adapter-outbound-persistence-mongo runtime_memberships: [] and does not list it among app-bootstrap's allowed dependencies |
The autoconfigure package stays inside the leaf and registers through the leaf's own META-INF/spring/…AutoConfiguration.imports. This differs from the httpclient precedent, where the starter moved to :app-bootstrap; here the registry forbids that edge. |
| Spring Boot 4.1 / Spring Data MongoDB 5.1 baseline | Repository baseline is Spring Boot 4.0.0 / Spring Data MongoDB 5.0.0 | The platform targets the Spring Data MongoDB API surface common to both; no 5.1-only type is referenced. The support matrix records the actual pinned versions. |
MongoRetryScope lives in mongodb-transaction |
The mongodb-spring-data failure translator must classify retry scope, and it cannot depend on mongodb-transaction |
MongoRetryScope lives in …api.error (core-api), which both packages already depend on. Same values, same meaning, one legal position in the DAG. |
mongodb-migration-flamingock depends on Flamingock |
Adding an unvetted external dependency is out of scope for this task, and the design itself requires the public contract not to depend on Flamingock types | The adapter is provider-neutral: it consumes a platform-owned FlamingockChangeUnitView. Wiring an actual Flamingock distribution is a one-file change behind that view. |
| Testkit as its own Gradle module | The design forbids production modules depending on the testkit | A dedicated testkit source set whose output is on the test compile/runtime classpaths only. ArchUnit rule productionNeverDependsOnTestkit enforces the direction. |
Per-task git commit |
AGENTS.md: commit policy is human-only |
Implementation is delivered unstaged; commits are the human's action. This is the only plan step intentionally not executed, and it is recorded here. |
docs/mongodb/**, scripts/verify-mongodb-*.sh |
Repository already owns docs/ and scripts/ |
Created at the same repository-relative paths. |
4. What is unchanged from the design
- D1 / D2 / D3 / D4 exposure planes and the ordered D3 admission sequence (§5).
- Stable API V1 with
apiStrict=trueon the D1/D2 client generation; D3/D4 on separate generations. MongoExecutionOutcome, including both ambiguous outcomes (WRITE_RESULT_UNKNOWN,TRANSACTION_COMMIT_UNKNOWN), andMongoFailureContext's permitted-field list.- The complete stable exception hierarchy and the label-before-code classification order.
- The BSON representation manifest (UUID
STANDARD,Decimal128, UTC instants, alias type metadata) and the document-size budget. - Update-operator-first writes, and optimistic revision as the precondition for whole-document replacement.
- Transaction body retry and commit retry as separate loops: a new session per body attempt, and commit-only retry on unknown commit. The body is never replayed after a commit ambiguity.
- Registered operation names and manifests for query, aggregation and index; no free-form JSON query and no unbounded pipeline.
- Keyset pagination with an authenticated cursor and a unique tie-breaker requirement.
- Change stream as an at-least-once projector with resume-token checkpointing and explicit history-lost handling.
- TTL as physical cleanup only, never the sole basis for access denial or business scheduling.
- Manifest-owned index/validator state with an apply policy that never drops what it does not own.
- Low-cardinality observation tags, command redaction, and the credential reference indirection.
- The Stable release gate's evidence categories, and the Advanced promotion gate's requirement for actual-topology evidence.
5. Verification
bash scripts/verify-mongodb-platform.sh # Stable gate
bash scripts/verify-mongodb-advanced.sh # Advanced gate (opt-in lanes)
Both scripts run from the repository root and delegate to src/gradlew.