Correct Pulsar architecture anti-patterns
A Pulsar anti-pattern is corrected by moving behavior to its named owner, not by adding abstraction or hidden callback. This catalog pairs every current forbidden shape with source-backed correction and rationale owner.
Correct entrypoint and workflow shortcuts
| Prohibited | Correct | Rationale |
|---|---|---|
| Fat Controller; Controller calls Query, Operation, or Action. | Validate, authorize, establish boundary data, call one UseCase, then assemble delivery. | Inbound adapters |
| Job or Command branches business work, opens a transaction, or enters multiple/direct workflows. | Reconstruct and authorize, then call one UseCase. | Inbound adapters |
| Action calls an Action or Query. | UseCase or Operation coordinates; Action stays atomic. | Workflows |
| UseCase calls UseCase or Operation calls Operation. | Extract one reusable Operation from the callers. | Workflows |
| Action or Operation owns a transaction or emits an Event; Event dispatch occurs elsewhere. | UseCase owns transaction and Event dispatch. | Transactions and Events |
Context: ❌ Prohibited nested workflow — nested entrypoints duplicate ownership.
php
$anotherUseCase->execute($data);Context: ✅ Correct reusable fragment — the owning UseCase selects one Operation.
php
$operation->execute($data);Correct dependency and discovery boundaries
| Prohibited | Correct | Rationale |
|---|---|---|
| Fat Adapter or Infrastructure imports delivery/workflows. | Adapter implements its Contract and translates boundary failure inward. | Contracts and Adapters |
| Domain or Service imports concrete Infrastructure. | Depend on the consumer-owned Contract and bind it in the provider. | Contracts and Adapters |
A Contract/Interface suffix for every class. | Define a suffix-free capability only for an alternate, fake, or strategy. | Contracts and Adapters |
| Hidden observer workflow. | Register an observer explicitly in the provider and document the workflow boundary. | Bootstrap discovery |
| Serialized live Model across Job, Event, or queued Listener. | Carry IDs, DTOs, or Value Objects; reconstruct and tenant-scope. | Listeners and Tenancy |
Correct identifiers and worker state
| Prohibited | Correct | Rationale |
|---|---|---|
| God Enum, label as identifier, casual persisted/protocol rename. | Per-Domain closed Enum, configuration for open values, immutable machine value. | Stable identifiers |
| Stateful singleton, runtime constructor data, or static tenant cache. | Runtime arguments or scoped context; singleton only when deliberately stateless. | Octane |
| Scoped or contextual binding treated as authorization, tenancy, or idempotency. | Enforce each concern independently. | Authorization, Tenancy, and Octane |
The optional preset checks a structural subset only. It is not an AST linter and does not prove behavioral ownership; review and focused tests retain that work.