Background
Follow-up from PR #4039 (review comment). ADR 0053 §5 documents a single-connection design for box provisioning, but each ProvisionAsync call currently opens three separate connections:
DetectTableStateAsync (provisioner) — schema introspection.
ValidatePayloadModeAsync (payload validator) — column-type check.
MigrateAsync (runner) — advisory lock + migrations.
The advisory lock must live on its own connection for its lifetime, but detection and payload validation could share that connection — performed pre-lock on the same DbConnection the runner is going to use.
Why we deferred this from #4039
It's a pure refactor with no functional impact. PR #4039 already addresses the correctness gaps the reviews flagged (R1, R2, R4, R5 via spec 0027); this is a connection-pool ergonomics improvement worth doing on its own.
Proposed approach
- Open one
DbConnection at the top of ProvisionAsync.
- Pass it (or a
Func<DbConnection> factory) into DetectTableStateAsync → ValidatePayloadModeAsync → MigrateAsync.
- Acquire the advisory lock on that same connection before running migrations.
- Apply per-backend (MSSQL, Postgres, MySQL, SQLite, Spanner).
Acceptance
- A single
ProvisionAsync call opens exactly one DbConnection.
- All existing integration tests still pass (fresh / bootstrap / idempotent / concurrent).
- Backend behaviour unchanged from the caller's perspective.
Out of scope
Any change to the public IAmABoxProvisioner / IAmABoxMigrationRunner interfaces — connection plumbing should stay an internal concern of each backend implementation.
Background
Follow-up from PR #4039 (review comment). ADR 0053 §5 documents a single-connection design for box provisioning, but each
ProvisionAsynccall currently opens three separate connections:DetectTableStateAsync(provisioner) — schema introspection.ValidatePayloadModeAsync(payload validator) — column-type check.MigrateAsync(runner) — advisory lock + migrations.The advisory lock must live on its own connection for its lifetime, but detection and payload validation could share that connection — performed pre-lock on the same
DbConnectionthe runner is going to use.Why we deferred this from #4039
It's a pure refactor with no functional impact. PR #4039 already addresses the correctness gaps the reviews flagged (R1, R2, R4, R5 via spec 0027); this is a connection-pool ergonomics improvement worth doing on its own.
Proposed approach
DbConnectionat the top ofProvisionAsync.Func<DbConnection>factory) intoDetectTableStateAsync→ValidatePayloadModeAsync→MigrateAsync.Acceptance
ProvisionAsynccall opens exactly oneDbConnection.Out of scope
Any change to the public
IAmABoxProvisioner/IAmABoxMigrationRunnerinterfaces — connection plumbing should stay an internal concern of each backend implementation.