Catch replacement-adapter drift before declaring tenant parity
Both adapters pass the happy-path tests, but the replacement sorts equal-name accounts differently and rounds stored revision values when decoding a database result. Parity dashboards currently compare only HTTP status codes.
- Focused work estimate
- 3h + prerequisites
- Priority in the scenario
- High
- Engineering practice
- Contract testing · Data fidelity · Regression diagnosis
Estimated field mix
- Quality engineering50%
- System design30%
- Database engineering20%
Field percentages are editorial estimates of the ticket's engineering focus. They total 100%; they are not measured time, proficiency scores, or ownership evidence.
Pattern topics
- Ports and AdaptersApply
Use the shared port as a behavioral contract for interchangeable adapters, testing semantic parity without binding the contract to either storage implementation.
Review it, then add it to your workspace.
The board opens an editable draft; nothing is saved until you confirm it. Sign-in and workspace permissions apply, and Demo boards remain ephemeral.
Project context
A fictional B2B scheduling service stores account settings in a legacy module whose database access leaks into HTTP handlers. A replacement must support existing clients and migration by tenant. Build a local modular application, a synthetic two-tenant dataset, and controllable old/new adapters; no baseline repository or fixtures are supplied. Keep the exercise in one application and local database, with no live customer traffic.
Setup prerequisites
- REST contracts
- Tenant authorization
- Transactions
- Dependency injection
Preceding work
Complete these dependencies, or supply their agreed outputs before taking this ticket.
- PMIGRATE-101 · Put legacy account lookups behind a contract the replacement can keep
- PMIGRATE-102 · Remove the process-wide current-tenant account client
- PMIGRATE-103 · Separate account policy from legacy SQL and replacement storage
- PMIGRATE-104 · Shadow account reads without duplicating booking-channel writes
- PMIGRATE-105 · Preserve tenant scope and conditional reads through the migration proxy
- PMIGRATE-107 · Delete account facade layers that only rename the same call
Acceptance criteria
- Extend the shared port contract to stable sort tie-breakers, null handling, exact revisions, and documented domain error mapping.
- Run a fixed synthetic corpus against each adapter and compare normalized semantic results rather than timestamps or implementation-only columns.
- A mismatch report identifies the contract case and differing public fields without dumping tenant data or silently accepting expected failures.
Implementation constraints
- Keep adapter-specific SQL assertions separate from the shared behavior contract so the suite does not require identical internal implementations.
Verification to include
- Use equal-name accounts, null settings, and large valid revision values to verify exact contract parity.
- Inject a deliberate order reversal and stale-revision acceptance into one local adapter; confirm the comparison fails with an actionable case identifier.
Deliverables
- Expanded adapter contract suite and sanitized parity report
Rollout and recovery
Require a clean contract report before moving the next synthetic tenant; keep mismatched tenants on their current owner until the discrepancy is resolved.
Value of the work
For the engineer: Practice incremental migration, dependency boundaries, compatibility testing, and removing abstractions that obscure behavior rather than enabling change.
For the team: Inspect a migration plan with measurable parity, explicit write ownership, tenant-safe routing, and rollback limits instead of accepting a rewrite diagram alone.
Evidence boundaries
Outcome Evidence: Tests, patches, and runbooks are requested deliverables. They become Outcome Evidence only through a qualified Mission and immutable Evidence IDs.
Ownership Evidence: Independent adaptation must be observed under a declared verification policy and cite immutable Evidence IDs. Completing a planning ticket establishes no Ownership Evidence.