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/Catalogsrc/Projection/Productsrc/Projection/Navigationsrc/Projection/Offer- compatibility/autoload surface:
composer.jsonsrc/Support/LegacyProductNamespaceCompat.phpnamespace 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:
MerchantFeedPublicationInputbehaves like a stable transport-neutral input DTO.ReceiveMerchantFeedResultis 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.phpsrc/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\RawMerchantFeedBatchWriterandContracts\Feed\MerchantFeedPublicationInputnow own the boundary;ReceiveMerchantFeednow depends onContracts\Feed;Infrastructure\Feedno longer importsApplication\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.jsonexposes onlyCMonChoix\Platform\as PSR-4 root.autoload.filesloadssrc/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.phpsrc/Infrastructure/M23/PersistentQueue/DatabaseQueue.phpsrc/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 -> ApplicationFeedoccurrences: 3ContractsProjection -> Projectionoccurrences: 12Projection -> ContractsProjectionoccurrences: 1ApplicationFeed -> Infrastructureoccurrences: 0
Certified inventory after D4:
Infrastructure -> ApplicationFeed: 0Contracts -> Projection: 0ReadService -> Adapter: 0Projection -> Application: 0src -> 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\Feedinterfaces remain as compatibility wrappers extendingContracts\Feed; - Option C for the DTO: legacy
Application\Feed\MerchantFeedPublicationInputremains as a compatibility subclass ofContracts\Feed\MerchantFeedPublicationInput; - no
class_alias; - no Composer/autoload change.
11. Recommended order¶
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: closedBA-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\BreadcrumbandContracts\Projection\Facet; - Product contractual DTOs now live under
Contracts\Projection\Product; - Offer contractual DTOs now live under
Contracts\Projection\Offer; CatalogProjectionReaderandCatalogItemProjectionMapperno longer importProjection\Catalog;CanonicalProductProjectionReaderandProductProjectionReaderno longer importProjection\ProductorProjection\Offer;Projection\Catalog,Projection\Product,Projection\Offer,Projection\BreadcrumbandProjection\Facetremain thin compatibility wrappers;BA-CP-001is 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; NavigationProjectionReaderno longer importsProjection\Navigation;Projection\Navigation\NavigationProjectionandNavigationItemProjectionremain thin compatibility wrappers;- the public navigation read flow still ends with the same adapter shim and the same legacy tree shape;
BA-CP-001is now closed for Navigation as well;- mapper-contract debt remains open for BC-064D3D only.
Status after BC-064D3D:
FacetProjectionMapperno longer importsProjection\Facet;ProductViewProjectionMapperno longer importsProjection\ProductorProjection\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.