Widens the two provider gates so an authored `{"provider":"Postgres"}` or
`{"provider":"Oracle"}` binds that provider's own dialect instead of failing
"not available in this build":
- `SqlDriverFactoryExtensions.CreateDialect` gains a Postgres and an Oracle
arm. There is deliberately no fallback arm — a default resolving to
SqlServerDialect would construct happily and then emit T-SQL at a Postgres
or Oracle server. The rejection message now names the three supported and
the two still-reserved providers.
- `SqlDriverBrowser.DefaultDialectSelector` widens identically, so a provider
the runtime constructs is also browsable; MySql/Odbc keep resolving to null
and the caller keeps reporting them as unavailable.
Tests: the existing rejected-provider controls flip from Postgres to MySql
(factory) and Odbc (browser) so the reserved half stays falsifiable, and the
new legs assert the bound dialect TYPE rather than mere construction —
"no throw" alone would pass against a SqlServer fallback.
Doc-comment sweep (contract addition, one line each): the "v1 constructs
SqlServer only" / "reserved for P2" claims in SqlProvider, SqlDriverConfigDto,
ISqlDialect.Provider and SqlServerDialect are now false and were corrected in
the same change.
SqlDriverFactoryExtensions turns a deployed DriverConfig blob into a live
SqlDriver, and SqlConnectionStringResolver resolves the authored
connectionStringRef NAME from Sql__ConnectionStrings__<ref> so credentials
never ride in a config blob (design §8.2).
Three behaviours worth naming:
- String-enum guard. JsonOptions carries JsonStringEnumConverter +
camelCase, so `provider` parses whether authored as a name or an ordinal
and always round-trips as the NAME — the systemic AdminUI defect where a
page serialised an enum numerically against a string-typed DTO.
- Config validation lands here because nothing below does it.
operationTimeout must be STRICTLY greater than commandTimeout (design
§8.3); the reader and the driver stay deliberately usable with the pair
inverted so the frozen-database tests can prove the client-side bound
fires. Non-positive timeouts / poll interval and maxConcurrentGroups < 1
are rejected too.
- Credential hygiene. The resolved connection string reaches the provider
and nothing else: messages name the ref, the environment variable, or
SqlDriver.Endpoint's credential-free server/database rendering. Both a
log-leak and an exception-leak test cover it.
DTO changes:
- Adds RawTags (List<RawTagEntry>), following the Modbus precedent — the
deploy artifact delivers a driver's tags this way and the DTO had no way
to receive them, so an authored Sql tag could never reach the driver.
- Deletes SqlProbeDto + the `probe` key. It had no consumer: SqlDriver was
specified without a background probe loop, and deliberately so — its
IHostConnectivityProbe state is a by-product of the Initialize liveness
check and of every poll, i.e. a statement about traffic that actually
happened rather than a synthetic ping. On-demand connectivity is Task
10's SqlDriverProbe. Shipping a config key that silently does nothing is
worse than not shipping it; UnmappedMemberHandling.Skip means a blob that
still carries `probe` keeps parsing.
allowWrites stays inert (SqlDriver implements no write capability) but an
authored `true` now WARNS rather than passing silently — the flag cannot do
harm, an operator who believes writes are enabled can.
Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW