Skip to content
bflo.sh

Rules of engagement — three rules, no exceptions

Contract-first, tier direction, coordinated cross-tier work — and the mechanics that make each one enforceable.

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.

  1. Contract-first across members.
  2. Tier direction holds between members.
  3. 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-owner sequences producer and consumer tasks explicitly.
  • Nobody edits contract/ except contract-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:

  1. Stops at the boundary (does not edit the foreign files).
  2. Sends a task/message to contract-owner stating: the need, the consuming use case, and a suggested shape if helpful.
  3. contract-owner either (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.
  4. 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.