What happens
Polecat.Tests/Harness/IntegrationContext.StoreOptions(...) builds a custom DocumentStore and calls ApplyAllConfiguredChangesToDatabaseAsync(), but never deletes existing data. Every test class that routes through it inherits whatever earlier runs left in its schema.
protected async Task<string> StoreOptions(Action<StoreOptions> configure)
{
var options = new StoreOptions { ... };
configure(options);
_customStore = new DocumentStore(options);
_database = _customStore.Database;
await _database.ApplyAllConfiguredChangesToDatabaseAsync(); // schema only -- no data cleanup
...
}
Because the suite isolates by DatabaseSchemaName inside one shared master database rather than by database, that residue survives across runs indefinitely.
Concrete failure
Storage/single_tenant_has_no_tenant_id_column_tests.full_lifecycle_works_without_tenant_id_column (line 93):
Shouldly.ShouldAssertException : byLinq.Count
should be
1
but was
3
The class has two tests, both configured onto schema no_tenant_col, and both store a Widget. The lifecycle test then asserts Query<Widget>().Where(w => w.Name == "Original") returns exactly one row. On a second run that count is 2, then 3, and so on. Confirmed directly against the container:
1> SELECT COUNT(*) FROM master.no_tenant_col.pc_doc_widget;
7
Why CI never sees it
CI provisions a fresh SQL Server per run, so the table is always empty on the first pass. This is a local-only failure — and a confusing one, because it presents as a flaky assertion in an area the developer did not touch.
Suggested fix
Either is defensible; the second is the smaller blast radius:
- Have
StoreOptions clean documents after applying schema changes (_customStore.Advanced.Clean.DeleteAllDocumentsAsync()), matching what a developer reasonably expects from a per-test store, or
- Fix the two tests to clean their own
Widget rows — but note this pattern is not unique to that class, so (1) is likelier to be the real answer.
Worth auditing which other StoreOptions callers assert on absolute counts before choosing.
Found by
Compliance wave 2 (marten#5118 / marten#5123) — surfaced while establishing a trustworthy full-suite baseline. Not caused by that work.
🤖 Generated with Claude Code
What happens
Polecat.Tests/Harness/IntegrationContext.StoreOptions(...)builds a customDocumentStoreand callsApplyAllConfiguredChangesToDatabaseAsync(), but never deletes existing data. Every test class that routes through it inherits whatever earlier runs left in its schema.Because the suite isolates by
DatabaseSchemaNameinside one sharedmasterdatabase rather than by database, that residue survives across runs indefinitely.Concrete failure
Storage/single_tenant_has_no_tenant_id_column_tests.full_lifecycle_works_without_tenant_id_column(line 93):The class has two tests, both configured onto schema
no_tenant_col, and both store aWidget. The lifecycle test then assertsQuery<Widget>().Where(w => w.Name == "Original")returns exactly one row. On a second run that count is 2, then 3, and so on. Confirmed directly against the container:Why CI never sees it
CI provisions a fresh SQL Server per run, so the table is always empty on the first pass. This is a local-only failure — and a confusing one, because it presents as a flaky assertion in an area the developer did not touch.
Suggested fix
Either is defensible; the second is the smaller blast radius:
StoreOptionsclean documents after applying schema changes (_customStore.Advanced.Clean.DeleteAllDocumentsAsync()), matching what a developer reasonably expects from a per-test store, orWidgetrows — but note this pattern is not unique to that class, so (1) is likelier to be the real answer.Worth auditing which other
StoreOptionscallers assert on absolute counts before choosing.Found by
Compliance wave 2 (marten#5118 / marten#5123) — surfaced while establishing a trustworthy full-suite baseline. Not caused by that work.
🤖 Generated with Claude Code