Architecture and product decisions¶
What is planned next lives in the roadmap. Detailed module authoring requirements live in module conventions.
| ID | Accepted decision | Reason and consequence |
|---|---|---|
| D01 | Keep the current capability-based module architecture | Small lifecycle interfaces, named registration and typed configuration are sufficient for incremental expansion; no module-system rewrite is planned |
| D02 | Run real applications against real dependencies | Application projects use their native production clients and contain no Stove dependency; configuration points them to the test environment |
| D03 | Keep modules independently consumable | Each provider has its own package and acceptance project; adding MongoDB must not pull it into SQL Server tests or every example |
| D04 | Preserve native APIs | Provider-specific parameters, filters and clients remain accessible; shared helpers should not erase useful database or protocol behavior |
| D05 | Separate test responsibilities | Core tests verify orchestration; module suites verify provider behavior; real-app contracts verify public setup; OrderService demonstrates composition; package smoke tests verify distribution |
| D06 | Share contracts without coupling providers | The shared testing project has no database-driver dependencies; each provider owns its adapter, application and runtime fixture |
| D07 | Keep OrderService focused | It demonstrates PostgreSQL, Redis, Kafka and external HTTP interactions; it is not a registry of every available module |
| D08 | Make isolation explicit | A named instance is not a per-test reset; correlation does not isolate rows, and a test-owned transaction does not include the app's separate connections |
| D09 | Preserve failures while releasing resources | Cleanup failure must not skip later disposal; rollback waits for starts already in flight and retains startup/rollback errors |
| D10 | State messaging guarantees precisely | Publication, routing, offset commits and successful business processing are different observations; negative assertions describe a bounded observation window |
| D11 | Use independent CI suite jobs | A failing provider must not suppress other suite results; packaging and release wait for the suite matrix |
| D12 | Expand database coverage first | SQL Server, MongoDB and MySQL are implemented; messaging/protocol/cloud follow with explicit scope |
| D13 | MongoDB uses native document APIs and explicit database selection | Default mongo:8.0 single-node replica set supports verified native transactions; standalone is optional. Ordered Setup manages collections/indexes/seeds without a migration-history engine |
| D14 | MySQL uses MySqlConnector and the relational acceptance contract | Default mysql:8.4 is tested with MySqlConnector 2.6.2; callbacks and parameters remain native; MariaDB parity is not claimed |
| D15 | Bound broker evidence per test and require correlation by default | Kafka/RabbitMQ share count/byte limits; overflow invalidates assertions. Headerless fallback is opt-in and limited to one active scope; arrival time cannot identify delayed old work |
| D16 | RabbitMQ observes dedicated queues and exposes native confirms | Bind an exclusive queue to named exchanges; never compete for application messages. Keep publisher confirms, routing and application processing distinct; fail on observer loss rather than hide gaps with recovery |
| D17 | Azure is a package family; Service Bus is independently consumable | StoveDotnet.Azure.ServiceBus owns its SDK/emulator dependencies; a future StoveDotnet.Azure may be a convenience meta-package |
| D18 | Service Bus separates broker state, destructive receive and business processing | Peek scheduled state without waiting; explicit receive settlement may compete, and successful processing requires a business-visible assertion |
| D19 | HTTP responses offer fluent status checks with bounded, redacted diagnostics | Raw access and lazy deserialization stay; raw response data remains caller-controlled |
| D20 | One retry rule per method | AssertAsync retries every exception; UntilAsync polls a value and lets exceptions propagate; RetryOn overrides either. Probes are awaited sequentially, never abandoned or overlapped. Replaces an earlier decision to keep a separate legacy retry behavior |
| D21 | Test time uses Microsoft's FakeTimeProvider, owned by the fixture |
No second timer scheduler; fixtures register a clock per application. External database and token-validation clocks stay independent |
| D22 | The OIDC module stays generic | Local discovery/JWKS and signed-token scenarios verified through real JWT bearer validation; domain roles and interactive identity-provider flows are out of scope |
| D23 | Applications are named and run in-process | APIs and Generic Host workers keep separate configuration and lifetimes while sharing dependencies; registration order is startup order and shutdown reverses it. Separate-process hosting and per-application instrumentation isolation are out of scope |
| D24 | Core has no test-framework dependency | xUnit v3, NUnit, MSTest and TUnit examples share only application and environment setup; CI verifies runner outcomes and teardown for each |
| D25 | Custom containers reuse native Testcontainers builders | Stove owns startup, configuration mapping, failure evidence and disposal, and adds no second Docker API. Adopting existing containers, resource reuse and Compose orchestration are out of scope |
| D26 | Systems declare startup prerequisites through ISystemDependencies |
Independent systems still start in parallel; shutdown reverses the dependency order |
| D27 | Borrow capabilities from the original Stove, not its shape | Useful references are structured operation reporting, container/provided runtime modes, migrations and separate gRPC client/mock modules. JVM-specific abstractions and feature parity are not goals |
| D28 | Failure evidence needs no application cooperation | A failed test reports the requests it sent and the application's in-process logs whichever assertion library failed; telemetry adds the trace tree |
| D30 | Traces are captured in-process with an ActivityListener |
Applications only run in-process (D23), so a listener sees every activity without an exporter, collector or export delay, and works for applications with no OpenTelemetry setup. Replaces the earlier OTLP/HTTP receiver. Given up: verifying what the application would export, a service name per span, and a path for out-of-process participants; reintroduce an OTLP source behind the same API if separate-process hosting is ever added |
| D29 | Startup failures name what failed | StoveStartupException names the system or application, repeats the cause and lists every system that failed in a parallel start |
Open questions¶
gRPC streaming scope and the choice of emulators for further cloud services are not decided. Resolve them with the module's implementation and acceptance evidence; the roadmap proposes the initial boundaries.
Changing a decision¶
Record the new requirement, the tradeoff and which earlier decision it replaces. Do not silently rewrite an implemented limitation as a guaranteed capability.