You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ADR 004 was revised for issue #121 to split Quotinator.Engine out of Quotinator.Core, specifically
so Quotinator.Data could stay domain-agnostic while something still held Quotinator-domain entities
and SQL that needed to see both Core's domain types and Data's Dapper/SQLite infrastructure. That part
of the reasoning is sound and unaffected by this issue — Quotinator.Data stays exactly as it is.
The separate half of that decision — that Core itself must stay Dapper/SQLite-free, forcing the
domain-implementation code into a third project rather than letting Core depend on Data directly — has
turned out not to be worth its cost. Found while planning #192 (expose Series/Universe on the quote read
path): a response DTO needing both a Core-owned type (MasterDataReference) and a Data-owned type
(CompletenessStatus) cannot be expressed in either project alone, only in Quotinator.Api — which is
why every masterdata response DTO (SourceResponse, CharacterResponse, etc.) ended up in Quotinator.Api.Models instead of alongside QuoteResponse in Quotinator.Core.Models. That's not a
one-off; it will recur for every future Core-layer type that also needs a Data-layer concept.
The boundary has also already blurred in practice, independent of #192:
Quotinator.Core.Tests.csproj already has a direct ProjectReference to Quotinator.Engine.csproj —
it is not a Core-only test project today.
tests/Quotinator.Core.Tests/Data/ already contains QuotinatorMigrationsTests.cs and SqliteQuoteServiceConversationTests.cs/SqliteQuoteServiceSearchTests.cs — tests for Quotinator.Engine.Database.QuotinatorMigrations and Quotinator.Engine.Services.SqliteQuoteService,
filed under a folder name that matches neither Engine namespace.
Nothing else in this codebase consumes Quotinator.Core without also consuming Quotinator.Engine — Quotinator.Api references both together, and always has. The only projects that reference Core alone
are the converter plugins (Quotinator.Converters.RegexArray/Csv/BasicJsonArray), which need only SourceQuote/IQuoteSourceConverter-shaped types and gain Dapper/Microsoft.Data.Sqlite as a transitive
package reference they don't use — an accepted cost, not a functional problem, consistent with this
project's Simplicity priority over minimal per-project dependency footprints.
What needs to be done
Merge every file under src/Quotinator.Engine/ into src/Quotinator.Core/, renamespacing Quotinator.Engine.X → Quotinator.Core.X for each segment (Entities, Queries, Repositories, Database, Services, Models, Helpers) per the File placement rule (folder name = namespace
segment). Check for and resolve any folder-name collisions between Core's and Engine's existing Models//Services//Helpers/ folders (none currently expected, but confirm directly rather than
assume).
Delete src/Quotinator.Engine/Quotinator.Engine.csproj and its folder. Update Quotinator.Core.csproj: add the Dapper, Dapper.Contrib, and Microsoft.Data.Sqlite package
references and the Quotinator.Data.csproj project reference (all currently on Engine's .csproj).
Merge tests/Quotinator.Engine.Tests/ into tests/Quotinator.Core.Tests/, same renamespacing rule.
While merging, fix the existing Data/ vs Database/ folder-naming mismatch found during this
issue's investigation — tests move into the folder matching their type's actual namespace segment,
not the folder they happened to be filed under. Delete Quotinator.Engine.Tests.csproj.
Update src/Quotinator.Api/Quotinator.Api.csproj to remove the now-redundant Quotinator.Engine
project reference (Core already brings in everything Engine provided). Update every using Quotinator.Engine.X; across Quotinator.Api (Program.cs, Endpoints/*.cs) to Quotinator.Core.X.
Update Quotinator.slnx: remove the two deleted projects, confirm the remaining projects' folders
still register correctly.
Update docs/architecture-decisions/004-quotinator-data-project-boundaries.md with a new revision
section recording this merge, its reasoning, and marking the project as two layers again
(Quotinator.Data domain-agnostic infrastructure; Quotinator.Core everything Quotinator-domain,
including its own Dapper/SQLite implementation) under Quotinator.Api.
Update CLAUDE.md's "Project structure" section: remove the Quotinator.Engine/ bullet, update Quotinator.Core/'s description, and update the "Dependency direction" line
(Quotinator.Api → Quotinator.Core; Quotinator.Core → Quotinator.Data; Quotinator.Api → Quotinator.Constants). Update the "Masterdata reference shape" section — MasterDataReference and
every masterdata response DTO can now live in one place (Quotinator.Core.Models), removing the
Api/Core split entirely rather than adding a second parallel type, which is what unblocks Expose series/universe on the quote read path — QuoteResponse fields and filters #192.
Verify: dotnet build --configuration Release → 0 warnings, 0 errors. Full test suite green,
0 warnings, 0 errors. T2 required (touches Program.cs, package references, and the solution
structure) — this project always runs T2 regardless of a documented trigger.
Expected tests
No new behaviour is introduced — this is a structural move. The bar is that the full existing test
suite (all of Quotinator.Core.Tests's and Quotinator.Engine.Tests's current tests, merged) passes
unmodified after the renamespacing, proving nothing's behaviour changed. SqlQueryGuardTests and QuotinatorMigrationsTests/schema-drift tests are the highest-risk regression surface, since they
reflect over type names/namespaces directly — confirm both still pass against the merged assembly.
Definition of done
All files moved and renamespaced; no Quotinator.Engine namespace remains anywhere in the solution
Quotinator.slnx, Quotinator.Api.csproj, ADR 004, and CLAUDE.md all updated in the same change
Full test suite passes unmodified (merge is behavior-preserving)
Build clean (0 warnings, 0 errors); T1 + T2 both green
Background
ADR 004 was revised for issue #121 to split
Quotinator.Engineout ofQuotinator.Core, specificallyso
Quotinator.Datacould stay domain-agnostic while something still held Quotinator-domain entitiesand SQL that needed to see both Core's domain types and Data's Dapper/SQLite infrastructure. That part
of the reasoning is sound and unaffected by this issue —
Quotinator.Datastays exactly as it is.The separate half of that decision — that Core itself must stay Dapper/SQLite-free, forcing the
domain-implementation code into a third project rather than letting Core depend on Data directly — has
turned out not to be worth its cost. Found while planning #192 (expose Series/Universe on the quote read
path): a response DTO needing both a Core-owned type (
MasterDataReference) and a Data-owned type(
CompletenessStatus) cannot be expressed in either project alone, only inQuotinator.Api— which iswhy every masterdata response DTO (
SourceResponse,CharacterResponse, etc.) ended up inQuotinator.Api.Modelsinstead of alongsideQuoteResponseinQuotinator.Core.Models. That's not aone-off; it will recur for every future Core-layer type that also needs a Data-layer concept.
The boundary has also already blurred in practice, independent of #192:
Quotinator.Core.Tests.csprojalready has a directProjectReferencetoQuotinator.Engine.csproj—it is not a Core-only test project today.
tests/Quotinator.Core.Tests/Data/already containsQuotinatorMigrationsTests.csandSqliteQuoteServiceConversationTests.cs/SqliteQuoteServiceSearchTests.cs— tests forQuotinator.Engine.Database.QuotinatorMigrationsandQuotinator.Engine.Services.SqliteQuoteService,filed under a folder name that matches neither Engine namespace.
Nothing else in this codebase consumes
Quotinator.Corewithout also consumingQuotinator.Engine—Quotinator.Apireferences both together, and always has. The only projects that reference Core aloneare the converter plugins (
Quotinator.Converters.RegexArray/Csv/BasicJsonArray), which need onlySourceQuote/IQuoteSourceConverter-shaped types and gain Dapper/Microsoft.Data.Sqlite as a transitivepackage reference they don't use — an accepted cost, not a functional problem, consistent with this
project's Simplicity priority over minimal per-project dependency footprints.
What needs to be done
src/Quotinator.Engine/intosrc/Quotinator.Core/, renamespacingQuotinator.Engine.X→Quotinator.Core.Xfor each segment (Entities,Queries,Repositories,Database,Services,Models,Helpers) per the File placement rule (folder name = namespacesegment). Check for and resolve any folder-name collisions between Core's and Engine's existing
Models//Services//Helpers/folders (none currently expected, but confirm directly rather thanassume).
src/Quotinator.Engine/Quotinator.Engine.csprojand its folder. UpdateQuotinator.Core.csproj: add theDapper,Dapper.Contrib, andMicrosoft.Data.Sqlitepackagereferences and the
Quotinator.Data.csprojproject reference (all currently on Engine's.csproj).tests/Quotinator.Engine.Tests/intotests/Quotinator.Core.Tests/, same renamespacing rule.While merging, fix the existing
Data/vsDatabase/folder-naming mismatch found during thisissue's investigation — tests move into the folder matching their type's actual namespace segment,
not the folder they happened to be filed under. Delete
Quotinator.Engine.Tests.csproj.src/Quotinator.Api/Quotinator.Api.csprojto remove the now-redundantQuotinator.Engineproject reference (Core already brings in everything Engine provided). Update every
using Quotinator.Engine.X;acrossQuotinator.Api(Program.cs,Endpoints/*.cs) toQuotinator.Core.X.Quotinator.slnx: remove the two deleted projects, confirm the remaining projects' foldersstill register correctly.
docs/architecture-decisions/004-quotinator-data-project-boundaries.mdwith a new revisionsection recording this merge, its reasoning, and marking the project as two layers again
(
Quotinator.Datadomain-agnostic infrastructure;Quotinator.Coreeverything Quotinator-domain,including its own Dapper/SQLite implementation) under
Quotinator.Api.CLAUDE.md's "Project structure" section: remove theQuotinator.Engine/bullet, updateQuotinator.Core/'s description, and update the "Dependency direction" line(
Quotinator.Api→Quotinator.Core;Quotinator.Core→Quotinator.Data;Quotinator.Api→Quotinator.Constants). Update the "Masterdata reference shape" section —MasterDataReferenceandevery masterdata response DTO can now live in one place (
Quotinator.Core.Models), removing theApi/Core split entirely rather than adding a second parallel type, which is what unblocks Expose series/universe on the quote read path — QuoteResponse fields and filters #192.
dotnet build --configuration Release→ 0 warnings, 0 errors. Full test suite green,0 warnings, 0 errors. T2 required (touches
Program.cs, package references, and the solutionstructure) — this project always runs T2 regardless of a documented trigger.
Expected tests
No new behaviour is introduced — this is a structural move. The bar is that the full existing test
suite (all of
Quotinator.Core.Tests's andQuotinator.Engine.Tests's current tests, merged) passesunmodified after the renamespacing, proving nothing's behaviour changed.
SqlQueryGuardTestsandQuotinatorMigrationsTests/schema-drift tests are the highest-risk regression surface, since theyreflect over type names/namespaces directly — confirm both still pass against the merged assembly.
Definition of done
Quotinator.Enginenamespace remains anywhere in the solutionQuotinator.slnx,Quotinator.Api.csproj, ADR 004, and CLAUDE.md all updated in the same change