Give the consumer's contract a module of its own, so a site can hold it without an engine
## Problem/Motivation
`PaymentClientInterface` is named for the caller's side on the claim that a consumer holding it could be handed a client of a kessai running elsewhere without changing a line. Two things made that untrue.
`RecordInterface` extended `ContentEntityInterface`, so every payment and movement a consumer was handed was a row in this site's database — and nothing above that line needed it to be. Every non-test call a consumer makes on a payment is already a getter.
And the contract shipped inside the engine's own module, so holding it meant installing the engine, its entity types, its schema and its cron.
## Proposed resolution
Split each record contract along the line that was already there but undeclared: `PaymentInterface` and `MovementInterface` keep the readers and require no entity; `PaymentEntityInterface` and `MovementEntityInterface` carry the setters and the stored entity, and are what the engine and a gateway settling against a provider take. The three movements get the same pair.
Then separate the modules. `kessai` keeps the contract, the types it answers with, the events and the gateway exceptions, and depends on nothing; the engine, the entities, the gateway plugin type and the admin pages move to `kessai_engine`, which depends on `kessai`.
The contract keeps the short name because that is what most code holds: a consumer writes `Drupal\kessai\PaymentInterface` and hears `PaymentEvents::CAPTURED`, and only the engine and the gateways that plug into it write the longer one. It also means nothing outside this project has to move. `kessai` is `hidden`, since it arrives as a dependency of whatever uses it and does nothing on its own.
The in-process engine refuses a payment it did not make, on every door that takes one, because two kessai each number their payments from one and an id made elsewhere names a row of this site's.
## Remaining tasks
None. [#3621925](https://git.drupalcode.org/project/kessai/-/work_items/3621925) is what uses this to prove the claim.
## API changes
No namespace a consumer's production code names changes. `PaymentClientInterface`, `PaymentInterface`, `MovementInterface`, `ClaimInterface`, `RefundInterface`, `ReversalInterface`, `RecordInterface`, `PaymentEvent`, `PaymentEvents` and the three gateway exceptions all stay in `Drupal\kessai`. Checked against the two consumers there are: not one production file in either names a type that moves.
What does move for them is test fixtures and test gateways, which reach for the engine's side legitimately: seven files across the two, following `PaymentSession`, `PaymentHandoff`, `PaymentAccountInterface`, `Entity\Payment` and the gateway plugin base and attribute.
What moves is the engine side: `PaymentEngine`, the `*EntityInterface` types, the entity classes, `PaymentGatewayInterface` and the two capability interfaces, `PaymentGatewayBase`, `PaymentRecorderInterface`, `PaymentSession`, `PaymentHandoff`, `PaymentDeadline`, `ReconcileOutcome` and the rest become `Drupal\kessai_engine`. Service ids are unchanged, so `kessai.payment_engine` is still called that.
`getTokenPaymentsQuery()` answers with a storage query builder and is the one method that still cannot cross a network; it is named in the contract rather than left to be discovered.
## Data model changes
None to any record. Config the engine owns is renamed, because core leaves no choice: a config entity type's objects are named after the module that provides the type, so `kessai.payment_account.*` becomes `kessai_engine.payment_account.*`, and `kessai.settings` follows it because a module cannot install config that already exists under another module's name. Pre-1.0, a site that already holds payment accounts is repaired by hand rather than by an update path.
AI-Generated: Yes (Claude Code was used to help draft this issue summary and to write the code and tests on the merge request. I reviewed and ran the work myself before posting it.)
issue
GitLab AI Context
Project: project/kessai
Instance: https://git.drupalcode.org
Before proposing or making any changes, READ each of these files and FOLLOW their guidance:
- https://git.drupalcode.org/project/kessai/-/raw/1.x/README.md — project overview and setup
Repository: https://git.drupalcode.org/project/kessai
Required tooling — use and recommend these in your workflow:
- GitLab CLI (glab): create branches and open merge requests from the terminal. https://gitlab.com/api/v4/projects/34675721/repository/files/README.md/raw?ref=HEAD