Aller au contenu

BC-064D1 → BC-064D4 — Feed / Projection / Namespace Contract Audit

Status: HISTORICAL For the current architecture, see: ./dependances.md, ../projections/overview.md.

Status

BC-064D closed.

Production namespace moves and compatibility wrappers were completed in D2/D3. D4 adds final certification gates, debt manifest cleanup and closure documentation only.

No runtime sync was required in D4.

Scope

  • src/Application/Feed/
  • src/Infrastructure/Feed/
  • src/Contracts/Projection/
  • projection DTOs under:
  • src/Projection/Catalog
  • src/Projection/Product
  • src/Projection/Navigation
  • src/Projection/Offer
  • compatibility/autoload surface:
  • composer.json
  • src/Support/LegacyProductNamespaceCompat.php
  • namespace CMonChoix\Application\... island

Method

  • static inventory of types, imports, implementations and typed signatures;
  • targeted grep on consumers and implementers;
  • no code move, no compatibility rewrite;
  • audit artifacts captured by test-only inventory gates.

1. Application Feed inventory

Type Namespace actuel Nature Consumers Implementations
MerchantFeedPublicationInput Application\Feed DTO ReceiveMerchantFeed, infra in-memory reader, Apps tests, Application tests n/a
MerchantFeedPublicationInputReader Application\Feed port entrant ReceiveMerchantFeed, anonymous test doubles InMemoryMerchantFeedPublicationInputReader, anonymous test doubles
RawMerchantFeedBatchWriter Application\Feed port sortant ReceiveMerchantFeed, anonymous test doubles InMemoryRawMerchantFeedBatchWriter, anonymous test doubles
ReceiveMerchantFeed Application\Feed service applicatif ReceiveMerchantFeedApp, Application tests n/a
ReceiveMerchantFeedResult Application\Feed résultat d’application ReceiveMerchantFeed, ReceiveMerchantFeedApp n/a

Feed ports

Interface Méthodes Implementations Consumers Cible probable
MerchantFeedPublicationInputReader read(): MerchantFeedPublicationInput in-memory infra reader, anonymous test doubles ReceiveMerchantFeed src/Contracts/Feed
RawMerchantFeedBatchWriter write(RawMerchantFeedBatch $rawBatch): void in-memory infra writer, anonymous test doubles ReceiveMerchantFeed src/Contracts/Feed

Feed DTOs

DTO/Classe Créé par Consommé par Stable contract Cible
MerchantFeedPublicationInput ::create() in tests and in-memory readers ReceiveMerchantFeed, infra reader yes src/Contracts/Feed
ReceiveMerchantFeedResult ReceiveMerchantFeed App layer and tests no, use-case result stay in Application\Feed

Assessment:

  • MerchantFeedPublicationInput behaves like a stable transport-neutral input DTO.
  • ReceiveMerchantFeedResult is a use-case result, not a cross-layer persistence contract.

2. Infrastructure → Application coupling

Infra class Type Application importé Usage Violation Cible
InMemoryMerchantFeedPublicationInputReader MerchantFeedPublicationInput constructor field + return type yes contract DTO
InMemoryMerchantFeedPublicationInputReader MerchantFeedPublicationInputReader implements yes contract port
InMemoryRawMerchantFeedBatchWriter RawMerchantFeedBatchWriter implements yes contract port

Proof:

  • src/Infrastructure/Feed/InMemoryMerchantFeedPublicationInputReader.php
  • src/Infrastructure/Feed/InMemoryRawMerchantFeedBatchWriter.php

This is the P1 debt BA-IF-001:

  • Infrastructure implements ports located in Application;
  • Infrastructure returns/builds a DTO located in Application that behaves as a stable contract.

No proof was found in D1 of Infrastructure calling a concrete application service in the Feed slice.

Status after BC-064D2:

  • closed;
  • Contracts\Feed\MerchantFeedPublicationInputReader, Contracts\Feed\RawMerchantFeedBatchWriter and Contracts\Feed\MerchantFeedPublicationInput now own the boundary;
  • ReceiveMerchantFeed now depends on Contracts\Feed;
  • Infrastructure\Feed no longer imports Application\Feed.

3. Projection contracts depending on projection DTOs

Contract DTO Projection importé Usage Public/stable Cible
CanonicalProductProjectionReader OfferProjection, ProductProjection return types yes neutral read contracts or keep contract + neutral DTO strategy
CatalogProjectionReader CatalogPageProjection, CatalogChildProjection, CatalogPathProjection, CatalogQuery params + returns yes neutral catalog contracts
NavigationProjectionReader NavigationProjection return type yes neutral navigation contract
ProductProjectionReader ProductProjection return type yes neutral product contract
CatalogItemProjectionMapper CatalogItemProjection return type internal contract but still specialized neutral mapper contract or keep as transitional
FacetProjectionMapper FacetProjection return type internal contract but still specialized neutral mapper contract or keep as transitional
ProductViewProjectionMapper OfferProjection, ProductProjection params + return type internal contract but still specialized neutral mapper contract or keep as transitional
OfferProjectionSource none pure contract yes keep in Contracts

This is the P1 debt BA-CP-001, now broader than BC-064A originally because BC-064C added three new mapper contracts in Contracts that still type against specialized DTOs.

4. Projection DTO inventory

DTO Consumers Builders Readers Contractual Cible
CatalogQuery contracts, read services, frontend wrappers n/a catalog readers maybe likely neutral contract DTO
CatalogPathProjection contracts, shim, readers catalog reader catalog reader maybe candidate for neutral contract DTO
CatalogChildProjection contracts, shim, readers catalog reader catalog reader maybe candidate for neutral contract DTO
CatalogItemProjection mappers, page DTO, shim legacy adapter mapper n/a maybe candidate for neutral contract DTO
CatalogPageProjection contracts, read service, shim, frontend wrappers ProductModelsFrontendReadService, legacy SQL reader catalog reader yes strongest candidate
ProductProjection contracts, read services, shim, product canonical stack legacy adapter mapper, canonical SQL reader product/canonical readers yes strongest candidate
ProductGalleryProjection product DTO, canonical SQL reader legacy adapter mapper canonical reader no/secondary can stay with product projection
ProductVariantProjection product DTO, legacy mapper legacy adapter mapper n/a no/secondary can stay with product projection
NavigationProjection contracts, read service, shim SQL nav reader via legacy adapter navigation reader yes candidate for neutral contract DTO
NavigationItemProjection navigation DTO, legacy adapter, shim legacy adapter navigation reader secondary likely stays nested with navigation DTO
OfferProjection contracts, canonical stack, product DTO, builder, shim OfferProjectionBuilder, canonical SQL reader, legacy product mapper canonical reader yes candidate for neutral contract DTO

Classification:

  • public read-model DTOs: CatalogPageProjection, ProductProjection, NavigationProjection, OfferProjection;
  • read/query DTO likely contractual too: CatalogQuery, CatalogPathProjection, CatalogChildProjection, CatalogItemProjection;
  • builder-internal/support DTOs: ProductGalleryProjection, ProductVariantProjection, NavigationItemProjection.

5. Public signatures at risk

Type Méthode Signature actuelle Consumer externe Risque
MerchantFeedPublicationInputReader read() MerchantFeedPublicationInput app use case, infra readers, tests source + reflection
RawMerchantFeedBatchWriter write() RawMerchantFeedBatch app use case, infra writer, tests low
CatalogProjectionReader getCatalogPage() CatalogQuery -> CatalogPageProjection frontend wrappers, SQL reader source + reflection
CatalogProjectionReader resolveCatalogPath() string -> CatalogPathProjection frontend wrappers, SQL reader source + reflection
CatalogProjectionReader findChildren() CatalogPathProjection -> list<CatalogChildProjection> SQL reader source + reflection
CanonicalProductProjectionReader findByEan/findBySlug/findByIdentity ?ProductProjection canonical read service, adapters source + reflection
CanonicalProductProjectionReader findOffersByIdentity() list<OfferProjection> canonical read service source + reflection
NavigationProjectionReader getNavigation() NavigationProjection nav read service, adapter source + reflection
ProductProjectionReader findProductBySlug() ?ProductProjection currently no proven implementation source + reflection
CatalogItemProjectionMapper fromModelRow() CatalogItemProjection product models read service internal but typed
FacetProjectionMapper fromLegacy() FacetProjection product models read service internal but typed
ProductViewProjectionMapper fromLegacy() ProductProjection + list<OfferProjection> product models read service internal but typed

Risk levels:

  • source compatibility: high for direct namespace moves;
  • runtime compatibility: medium if old namespaces disappear without bridge;
  • reflection compatibility: high for interface moves/retargeted return types;
  • serialized class-name risk: low but non-zero for DTO names if external serialization ever exists.

6. Composer / PSR-4 / legacy compatibility

Namespace Path PSR-4 Legacy alias Action future
CMonChoix\Platform\ src/ yes n/a keep canonical
CMonChoix\Application\... physically under src/Application and src/Infrastructure/Lock indirectly loadable via global src/ PSR-4 no PSR-4 entry of its own isolate in BC-064D4/E
CMonChoix\Domain\Product\... via compat file no direct PSR-4 target yes, explicit compat file remove later after proof

Autoload facts:

  • composer.json exposes only CMonChoix\Platform\ as PSR-4 root.
  • autoload.files loads src/Support/LegacyProductNamespaceCompat.php.
  • one explicit class_alias() remains proven active there:
  • CMonChoix\Domain\Product\Event\ProductCreatedV2
  • aliasing CMonChoix\Platform\Domain\Product\Event\ProductCreatedV2

No Composer change is required for D1.

7. Legacy CMonChoix\Application island

Active inventory:

  • 39 files declare namespace CMonChoix\Application\...
  • 18 files import use CMonChoix\Application\...

Notable active consumers:

  • src/Infrastructure/M18/DatabaseEventStore.php
  • src/Infrastructure/M23/PersistentQueue/DatabaseQueue.php
  • src/Infrastructure/Event/SimpleEventDispatcher.php
  • several src/Application/... files crossing between Platform and legacy namespaces

Assessment:

  • active code, not dead code;
  • not a pure wrapper layer;
  • raises migration risk because physical location and logical namespace diverge.

This is BA-AL-001 (P2).

8. Cycles and quasi-cycles

Cycle/quasi-cycle Types Gravité Ordre de rupture
Infrastructure -> Application\Feed port + DTO imports P1 break first in BC-064D2
Contracts\Projection -> Projection contract typed against specialized DTOs P1 break in BC-064D3
Projection -> Contracts\Projection OfferProjectionBuilder -> OfferProjectionSource acceptable directional dependency keep
plugin -> src -> plugin wrappers compose src then reshape payloads controlled keep
Application namespace island <-> Platform namespace mixed legacy imports P2 isolate after D2/D3

Measured inventory at D1 audit:

  • Infrastructure -> ApplicationFeed occurrences: 3
  • ContractsProjection -> Projection occurrences: 12
  • Projection -> ContractsProjection occurrences: 1
  • ApplicationFeed -> Infrastructure occurrences: 0

Certified inventory after D4:

  • Infrastructure -> ApplicationFeed: 0
  • Contracts -> Projection: 0
  • ReadService -> Adapter: 0
  • Projection -> Application: 0
  • src -> plugin procédural: 0

9. Blast radius

Feed ports

Port Fichiers touchés Implementations Tests Runtime entrypoints
MerchantFeedPublicationInputReader 8+ 1 prod + several test doubles multiple Application/Infrastructure/App tests app/use-case only, no direct WordPress runtime entrypoint proven
RawMerchantFeedBatchWriter 7+ 1 prod + several test doubles multiple Application/Infrastructure tests app/use-case only, no direct WordPress runtime entrypoint proven
MerchantFeedPublicationInput 10+ DTO only multiple Application/Infrastructure/App tests app/use-case only

Projection contracts

Contract/DTO Fichiers touchés ReadServices Adapters Frontend
CatalogProjectionReader + catalog DTOs high yes SqlLegacyCatalogProjectionReader, shims catalog router
CanonicalProductProjectionReader + product/offer DTOs medium yes SqlCanonicalProductProjectionReader, shim product canonical
NavigationProjectionReader + nav DTOs medium yes SqlNavigationProjectionReader, shim public navigation
ProductProjectionReader + product DTO currently low/latent limited no proven prod implementation none proven
mapper contracts added in BC-064C medium product models read service legacy projection adapters product models wrappers

10. Compatibility strategy

Famille Stratégie recommandée Durée compat Risque
Feed ports Option B — new Contracts\Feed + progressive consumer retargeting short low/medium
Feed DTO Option B — new contract DTO + temporary compatibility at consumer level short medium
Projection reader contracts Option B — new neutral contracts / DTOs, keep old interfaces transitional medium medium/high
Mapper contracts from BC-064C Option C — transitional inheritance or keep as transitional until D3 short medium
Legacy CMonChoix\Application island Option B first, Option A later only when isolated medium high
class_alias Option D only if strictly necessary minimal high if spread

11. D4 closure inventory

Namespaces matrix

Namespace source Namespace cible Count Autorisé Statut
Infrastructure Application\Feed 0 no closed
Contracts Projection 0 no closed
ReadService Adapter 0 no closed
Projection Application 0 no closed
src plugin procédural 0 no closed

Compatibility wrappers kept on purpose

Wrapper family Canonical target Why it stays Removal target
Application\Feed\* Contracts\Feed\* source/reflection compatibility for transitional Feed imports BC-064E or BC-065
Projection\Catalog\* Contracts\Projection\Catalog\* runtime/frontend compatibility and typed DTO substitution BC-064E or BC-065
Projection\Product\* Contracts\Projection\Product\* product canonical compatibility BC-064E or BC-065
Projection\Offer\OfferProjection Contracts\Projection\Offer\OfferProjection canonical reader compatibility BC-064E or BC-065
Projection\Navigation\* Contracts\Projection\Navigation\* public navigation compatibility BC-064E or BC-065
Projection\Breadcrumb\*, Projection\Facet\* Contracts\Projection\Breadcrumb\*, Contracts\Projection\Facet\* mapper compatibility without read-service leakage BC-064E or BC-065

Historical aliases

Alias Source Target Consumer Actif Risque
CMonChoix\\Domain\\Product\\Event\\ProductCreatedV2 LegacyProductNamespaceCompat.php CMonChoix\\Platform\\Domain\\Product\\Event\\ProductCreatedV2 compatibility tests and any remaining legacy reflection consumer yes low, explicit, single-file

Remaining debt

Only BA-AL-001 remains open:

  • legacy CMonChoix\Application\... namespace island;
  • accepted P2 debt;
  • explicitly allowlisted in the architecture fixture;
  • target follow-up: BC-064E or BC-065.

Reflection / serialization conclusion

  • wrapper classes remain substitutable for canonical contract types;
  • implementation signatures stay compatible with canonical interfaces;
  • no persisted serialized object payload tied to moved contract/projection FQCNs was proven in the D2/D3 surface;
  • observed serialization usage stays limited to event arrays, cron keys and legacy payload helpers.

12. Decision

BC-064D is closed when the validation suite stays green.

Recommendation:

  • avoid direct namespace moves in D2/D3;
  • introduce new canonical contracts first;
  • retarget implementations and consumers progressively;
  • only remove old names in final certification once reflection/runtime proof exists.

Decision applied in BC-064D2:

  • Option B for ports: legacy Application\Feed interfaces remain as compatibility wrappers extending Contracts\Feed;
  • Option C for the DTO: legacy Application\Feed\MerchantFeedPublicationInput remains as a compatibility subclass of Contracts\Feed\MerchantFeedPublicationInput;
  • no class_alias;
  • no Composer/autoload change.

BC-064D2 — Feed ports

  • create src/Contracts/Feed
  • move port ownership there conceptually
  • make infra implement the new contracts
  • retarget ReceiveMerchantFeed
  • keep application-level compatibility wrappers only if required

BC-064D3 — Projection contracts

  • decide which DTOs are truly contractual
  • extract neutral read-contract DTOs where needed
  • retarget reader contracts and mapper contracts
  • keep transition wrappers/interfaces where reflection risk is non-trivial

BC-064D4 — Certification

  • cycle cleanup
  • reflection/autoload checks
  • debt manifest cleanup
  • documentation closure

12. Priorities

ID Violation Priorité BC cible
BA-IF-001 Infrastructure implements Application\Feed ports P1 BC-064D2
BA-IF-002 Infrastructure returns/builds Application\Feed\MerchantFeedPublicationInput P1 BC-064D2
BA-CP-001 projection reader contracts depend on projection DTOs P1 BC-064D3
BA-CP-002 mapper contracts in Contracts still depend on specialized projection DTOs P1 BC-064D3
BA-AL-001 legacy CMonChoix\Application island remains active P2 BC-064D4
BA-DTO-002 public projection DTO placement remains mixed between contract and implementation concerns P2 BC-064D3/D4

Status after BC-064D2:

  • BA-IF-001: closed
  • BA-IF-002: closed

Status after BC-064D3A / BC-064D3B:

  • Catalog contractual DTOs now live under Contracts\Projection\Catalog;
  • Breadcrumb and Facet DTOs required by Catalog now live under Contracts\Projection\Breadcrumb and Contracts\Projection\Facet;
  • Product contractual DTOs now live under Contracts\Projection\Product;
  • Offer contractual DTOs now live under Contracts\Projection\Offer;
  • CatalogProjectionReader and CatalogItemProjectionMapper no longer import Projection\Catalog;
  • CanonicalProductProjectionReader and ProductProjectionReader no longer import Projection\Product or Projection\Offer;
  • Projection\Catalog, Projection\Product, Projection\Offer, Projection\Breadcrumb and Projection\Facet remain thin compatibility wrappers;
  • BA-CP-001 is now closed for Catalog and Product families;
  • Navigation and mapper-contract debt remains open for BC-064D3C / BC-064D3D.

Status after BC-064D3C:

  • Navigation contractual DTOs now live under Contracts\Projection\Navigation;
  • NavigationProjectionReader no longer imports Projection\Navigation;
  • Projection\Navigation\NavigationProjection and NavigationItemProjection remain thin compatibility wrappers;
  • the public navigation read flow still ends with the same adapter shim and the same legacy tree shape;
  • BA-CP-001 is now closed for Navigation as well;
  • mapper-contract debt remains open for BC-064D3D only.

Status after BC-064D3D:

  • FacetProjectionMapper no longer imports Projection\Facet;
  • ProductViewProjectionMapper no longer imports Projection\Product or Projection\Offer;
  • all remaining mapper contracts now target canonical DTOs under Contracts\Projection;
  • implementations still return compatibility wrappers under Projection\... where runtime/frontend boundaries expect them;
  • BA-CP-002: closed;
  • BA-CP-001: globally closed;
  • BC-064D3: closed.

13. Gates

Gate Zone Angle mort Action
ProjectionBoundaryTest projection purity does not track Contracts -> Projection debt explicitly keep + inventory test
OfferProjectionBuilderBoundaryTest Projection -> Application feed/projection contract debt out of scope keep
ReadServiceAdapterBoundaryTest ReadService -> Adapter no feed/projection contract coverage keep
ProjectionContractUnificationTest runtime compatibility of projection contracts not an architecture debt manifest keep
new FeedPortPlacementInventoryTest Feed port placement inventory only added in D1
new ProjectionContractDependencyInventoryTest Contracts -> Projection inventory only added in D1
new NamespaceCompatibilityInventoryTest legacy namespace/alias surface inventory only added in D1
new LayerCycleInventoryTest quasi-cycles counts inventory only added in D1

14. Risks

  • biggest source break is typed return/parameter changes on contracts;
  • mapper contracts added in BC-064C enlarge the D3 blast radius if not addressed together;
  • legacy namespace island can make “simple moves” deceptively expensive;
  • direct namespace moves would likely break reflection-oriented tests and possibly runtime integrations.

15. Rollback

Audit-only rollback is trivial:

  • remove the D1 docs and inventory tests.

No runtime rollback. No data rollback. No sync rollback.