Adapted from the repo's docs/rules-of-engagement.md — Part of Internals: the platform's design set, published as content on the platform it describes.
Three rules, all non-negotiable. Everything else in this document is mechanics.
- Contract-first across members.
- Tier direction holds between members.
- Cross-tier work is coordinated via tasks/messages through
contract-owner, not direct cross-file edits.
1. Contract-first
contract/ (OpenAPI 3.1 + AsyncAPI 3.1, linted by contract/.spectral.yaml) is the single
source of truth for every cross-team interface: REST endpoints, payloads, status codes,
error shapes, async events.
Nothing is implemented against an unpublished interface. "Published" means: present in
contract/, passing Spectral, version bumped, noted in contract/CHANGELOG.md.
Change protocol
consumer/producer need
│ message/task with use case
▼
contract-owner: design review → semver decision → edit spec → spectral lint → publish
│ version bump + changelog entry
▼
impacted members implement against the new version (tasks issued/routed by contract-owner)
- Additive change (new endpoint, new optional field, new event) → minor bump, consumers adopt at their own pace.
- Breaking change (removed/renamed field, changed semantics, stricter validation) →
major bump,
contract-ownersequences producer and consumer tasks explicitly. - Nobody edits
contract/exceptcontract-owner. Proposals travel as messages/tasks, optionally with a suggested diff.
Conformance
- Backend implements the contract exactly; the spec is never retro-fitted to match code drift without a reviewed contract change.
- Frontend consumes generated types/clients derived from the published spec, never hand-guessed shapes.
- Error responses follow RFC 9457 problem details as defined in the contract.
2. Tier direction
Allowed dependency edges — anything not listed is forbidden:
frontend/ ──► contract/
backend/ ──► contract/ (conforms-to)
backend Http ──► backend Domain
backend Domain ──► backend Data PORTS (interfaces defined in Domain)
backend Data ──► implements those ports (+ PostgreSQL, Redis)
infra/ ──► (nothing) (supports all, depends on none)
Canonical violations to reject on sight:
| Violation | Correct move |
|---|---|
| frontend imports backend types or reads backend source | consume generated contract types; ask contract-owner for missing shapes |
| controller queries Eloquent directly | route through a Domain action |
| Domain imports an Http request/resource class | pass primitives/DTOs into Domain |
| Domain news up a concrete repository | depend on a Domain port; binding lives in the Data layer's service provider |
Data layer emits HTTP responses or reads app/Http |
return domain results; transport mapping is backend-api's job |
| app code configures DDEV services | file a task for platform-engineer |
Verification is part of done: a member finishing a task confirms no forbidden edge was introduced (import scan of touched files at minimum).
3. Cross-tier coordination
A member whose task requires a change outside its ownership area:
- Stops at the boundary (does not edit the foreign files).
- Sends a task/message to
contract-ownerstating: the need, the consuming use case, and a suggested shape if helpful. contract-ownereither (a) turns it into a contract change and routes implementation tasks, or (b) routes a direct task to the owning member when it's implementation-level with no interface impact.- The requesting member proceeds when the dependency is published/merged into the working tree — or parks the task and reports the blockage.
If a proposed diff spans two ownership areas, it is by definition two tasks. Arbitration of
disputes belongs to contract-owner; significant rulings become ADRs.
Working agreement
Autonomy boundaries and version-control rules (never push; commit only on explicit user
request) are defined in working-agreement.md — binding for the
lead and every member.