What this describes: how ownership/responsibility for a single data attribute is distributed across multiple parties, and how that responsibility hands off as the attribute (or its governing lifecycle) moves through states.
Fill in every ‹ › placeholder. Delete the guidance notes when done.
1. Identity
| Field | Value |
|---|---|
| Attribute | ‹name of the attribute being governed› |
| Type / shape | ‹e.g. enum, string, money, nested object› |
| Owning entity | ‹the record/aggregate it belongs to, e.g. Order, Claim› |
| Governing state | ‹the attribute/field whose value decides ownership — may be the attribute itself or a sibling lifecycle field› |
| Spec owner | ‹person/team accountable for this document› |
| Last updated | ‹date› |
2. Parties
The distributed set of owners. Each is a service, team, or role that may hold responsibility at some point. Keep the list closed — every state must resolve to exactly one of these.
| ID | Party | Kind (service / team / role) | Notes |
|---|---|---|---|
| P1 | ‹e.g. Billing Service› | ‹service› | |
| P2 | ‹e.g. Fulfilment Team› | ‹team› | |
| P3 | ‹…› |
3. States
Enumerate every state the governing field can hold. One row each.
| State | Meaning | Entry condition |
|---|---|---|
| ‹STATE_A› | ‹what it represents› | ‹how the entity arrives here› |
| ‹STATE_B› | ||
| ‹STATE_C› | ||
| ‹TERMINAL› | ‹final state, if any› |
4. Ownership matrix — the core
For each state, who is the single accountable owner, and what may others do.
Owner: the one party responsible for the attribute in this state.
Can write: parties permitted to modify the attribute’s value.
Can transition: parties permitted to change the state.
Read: who may read it (default all unless restricted).Rule of thumb: exactly one owner per state; writers and transitioners are subsets of the parties in §2.
| State | Owner | Can write (value) | Can transition (state) | Read | Locked for everyone else? |
|---|---|---|---|---|---|
| ‹STATE_A› | ‹P1› | ‹P1› | ‹P1› | ‹all› | ‹yes/no› |
| ‹STATE_B› | ‹P2› | ‹P2› | ‹P2, P3› | ‹all› | ‹yes/no› |
| ‹STATE_C› | ‹P3› | ‹none — frozen› | ‹P3› | ‹all› | ‹yes› |
| ‹TERMINAL› | ‹—› | ‹none› | ‹none› | ‹all› | ‹yes› |
5. Transitions & handoffs
One row per allowed transition. The handoff column is where ownership actually changes hands — list the side effects (lock, notify, validate, snapshot) that must fire atomically with the state change.
| From → To | Triggered by | Guard / precondition | Handoff actions on transition |
|---|---|---|---|
| ‹STATE_A → STATE_B› | ‹P1› | ‹condition that must hold› | ‹e.g. freeze value, notify P2, write audit entry› |
| ‹STATE_B → STATE_C› | ‹P2 or P3› | ‹…› | ‹…› |
Any transition not listed here is forbidden.
6. Invariants
Statements that must hold true regardless of state. These are what reviewers and tests check against.
- ‹e.g. The attribute is never null once it leaves STATE_A.›
- ‹e.g. Exactly one party is owner at any moment.›
- ‹e.g. Value cannot change after entering STATE_C.›
7. Contention & conflict handling
| Concern | Rule |
|---|---|
| Concurrent writes | ‹e.g. optimistic lock on version; last-writer rejected› |
| Write by non-owner | ‹reject with error / queue / escalate› |
| Disputed ownership | ‹tie-break rule, e.g. governing state is source of truth› |
| Out-of-order transition | ‹reject / idempotent no-op› |
| Party unavailable | ‹fallback owner, timeout, manual override path› |
8. Observability & audit
| Field | Value |
|---|---|
| Audit trail | ‹what is logged on each write/transition: who, when, from→to› |
| Where stored | ‹event log / table / topic› |
| Alerting | ‹conditions that page someone, e.g. stuck in STATE_B > N hours› |
9. Edge cases & open questions
- ‹e.g. What happens if the entity is deleted mid-lifecycle?›
- ‹e.g. Can a state be re-entered (loops)? Who owns it the second time?›
- ‹open question still to resolve›
Worked example — Order.status
Attribute: total_price · Governing state: Order.status · Owning entity: Order
Parties: P1 Cart Service · P2 Billing Service · P3 Fulfilment Team
Ownership matrix:
| State | Owner | Can write | Can transition | Locked? |
|---|---|---|---|---|
| cart | P1 | P1 | P1 | no |
| payment_pending | P2 | P2 (taxes/fees only) | P2 | partial |
| paid | P2 | none — frozen | P2, P3 | yes |
| shipped | P3 | none | P3 | yes |
Key transition: cart → payment_pending, triggered by P1, guard = cart non-empty, handoff = snapshot price, freeze line items, notify Billing.
Invariant: once status = paid, total_price never changes.
Leave a Reply